HHH-13103 - Allow Hibernate Types to get access to the current configuration properties
This commit is contained in:
parent
9084ce497e
commit
c346171b23
|
@ -347,6 +347,25 @@ public final class ReflectHelper {
|
|||
|
||||
}
|
||||
|
||||
public static <T> Constructor<T> getConstructor(
|
||||
Class<T> clazz,
|
||||
Class... constructorArgs) {
|
||||
Constructor<T> constructor = null;
|
||||
try {
|
||||
constructor = clazz.getDeclaredConstructor( constructorArgs );
|
||||
try {
|
||||
ReflectHelper.ensureAccessibility( constructor );
|
||||
}
|
||||
catch ( SecurityException e ) {
|
||||
constructor = null;
|
||||
}
|
||||
}
|
||||
catch ( NoSuchMethodException ignore ) {
|
||||
}
|
||||
|
||||
return constructor;
|
||||
}
|
||||
|
||||
public static Method getMethod(Class clazz, Method method) {
|
||||
try {
|
||||
return clazz.getMethod( method.getName(), method.getParameterTypes() );
|
||||
|
|
|
@ -7,15 +7,19 @@
|
|||
package org.hibernate.type;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.classic.Lifecycle;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.tuple.component.ComponentMetamodel;
|
||||
import org.hibernate.type.spi.TypeBootstrapContext;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
import org.hibernate.type.spi.TypeConfigurationAware;
|
||||
import org.hibernate.usertype.CompositeUserType;
|
||||
|
@ -88,7 +92,24 @@ public final class TypeFactory implements Serializable {
|
|||
|
||||
public Type type(Class<Type> typeClass, Properties parameters) {
|
||||
try {
|
||||
Type type = typeClass.newInstance();
|
||||
Type type;
|
||||
|
||||
Constructor<Type> bootstrapContextAwareTypeConstructor = ReflectHelper.getConstructor(
|
||||
typeClass,
|
||||
TypeBootstrapContext.class
|
||||
);
|
||||
if ( bootstrapContextAwareTypeConstructor != null ) {
|
||||
ConfigurationService configurationService = typeConfiguration.getServiceRegistry().getService(
|
||||
ConfigurationService.class );
|
||||
Map<String, Object> configurationSettings = configurationService.getSettings();
|
||||
type = bootstrapContextAwareTypeConstructor.newInstance( new TypeBootstrapContext(
|
||||
configurationSettings
|
||||
) );
|
||||
}
|
||||
else {
|
||||
type = typeClass.newInstance();
|
||||
}
|
||||
|
||||
injectParameters( type, parameters );
|
||||
return type;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.type.spi;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Provide a way to customize the {@link org.hibernate.type.Type} instantiation process.
|
||||
* <p/>
|
||||
* If a custom {@link org.hibernate.type.Type} defines a constructor which takes the
|
||||
* {@link TypeBootstrapContext} argument, Hibernate will use this instead of the
|
||||
* default constructor.
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*
|
||||
* @since 5.4
|
||||
*/
|
||||
public class TypeBootstrapContext {
|
||||
|
||||
private final Map<String, Object> configurationSettings;
|
||||
|
||||
public TypeBootstrapContext(Map<String, Object> configurationSettings) {
|
||||
this.configurationSettings = configurationSettings;
|
||||
}
|
||||
|
||||
public Map<String, Object> getConfigurationSettings() {
|
||||
return configurationSettings;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,12 @@
|
|||
package org.hibernate.test.type.contributor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.type.AbstractSingleColumnStandardBasicType;
|
||||
import org.hibernate.type.DiscriminatorType;
|
||||
import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeBootstrapContext;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
|
@ -14,10 +17,17 @@ public class ArrayType
|
|||
|
||||
public static final ArrayType INSTANCE = new ArrayType();
|
||||
|
||||
private Map<String, Object> settings;
|
||||
|
||||
public ArrayType() {
|
||||
super( VarcharTypeDescriptor.INSTANCE, ArrayTypeDescriptor.INSTANCE );
|
||||
}
|
||||
|
||||
public ArrayType(TypeBootstrapContext typeBootstrapContext) {
|
||||
super( VarcharTypeDescriptor.INSTANCE, ArrayTypeDescriptor.INSTANCE );
|
||||
this.settings = typeBootstrapContext.getConfigurationSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array stringToObject(String xml) throws Exception {
|
||||
return fromString( xml );
|
||||
|
@ -33,4 +43,7 @@ public class ArrayType
|
|||
return "comma-separated-array";
|
||||
}
|
||||
|
||||
public Map<String, Object> getSettings() {
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,29 +6,33 @@
|
|||
*/
|
||||
package org.hibernate.test.type.contributor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.boot.spi.MetadataBuilderContributor;
|
||||
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.test.collection.custom.basic.MyList;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-11409" )
|
||||
public class ArrayTypeContributorTest extends BaseCoreFunctionalTestCase {
|
||||
public class ArrayTypeContributorTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
|
@ -36,36 +40,33 @@ public class ArrayTypeContributorTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Configuration constructAndConfigureConfiguration() {
|
||||
Configuration configuration = super.constructAndConfigureConfiguration();
|
||||
configuration.registerTypeContributor( (typeContributions, serviceRegistry) -> {
|
||||
typeContributions.contributeType( ArrayType.INSTANCE );
|
||||
} );
|
||||
return configuration;
|
||||
protected void addConfigOptions(Map options) {
|
||||
options.put(
|
||||
EntityManagerFactoryBuilderImpl.METADATA_BUILDER_CONTRIBUTOR,
|
||||
(MetadataBuilderContributor) metadataBuilder ->
|
||||
metadataBuilder.applyTypes( (typeContributions, serviceRegistry) -> {
|
||||
typeContributions.contributeType( ArrayType.INSTANCE );
|
||||
} ));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareTest() throws Exception {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
protected void afterEntityManagerFactoryBuilt() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
CorporateUser user = new CorporateUser();
|
||||
user.setUserName( "Vlad" );
|
||||
session.persist( user );
|
||||
entityManager.persist( user );
|
||||
|
||||
user.getEmailAddresses().add( "vlad@hibernate.info" );
|
||||
user.getEmailAddresses().add( "vlad@hibernate.net" );
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isCleanupTestDataRequired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
List<CorporateUser> users = session.createQuery(
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
List<CorporateUser> users = entityManager.createQuery(
|
||||
"select u from CorporateUser u where u.emailAddresses = :address", CorporateUser.class )
|
||||
.unwrap( Query.class )
|
||||
.setParameter( "address", new Array(), ArrayType.INSTANCE )
|
||||
.getResultList();
|
||||
|
||||
|
@ -75,8 +76,8 @@ public class ArrayTypeContributorTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
@Test
|
||||
public void testNativeSQL() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
List<Array> emails = session.createNativeQuery(
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
List<Array> emails = entityManager.createNativeQuery(
|
||||
"select u.emailAddresses from CorporateUser u where u.userName = :name" )
|
||||
.setParameter( "name", "Vlad" )
|
||||
.getResultList();
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.type.contributor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.annotations.TypeDef;
|
||||
import org.hibernate.boot.spi.MetadataBuilderContributor;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-13103" )
|
||||
public class ArrayTypePropertiesTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { CorporateUser.class };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
options.put( "hibernate.type.array.config", new Integer[]{1, 2, 3} );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterEntityManagerFactoryBuilt() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
CorporateUser user = new CorporateUser();
|
||||
user.setUserName( "Vlad" );
|
||||
entityManager.persist( user );
|
||||
|
||||
user.getEmailAddresses().add( "vlad@hibernate.info" );
|
||||
user.getEmailAddresses().add( "vlad@hibernate.net" );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
List<CorporateUser> users = entityManager.createQuery(
|
||||
"select u from CorporateUser u where u.emailAddresses = :address", CorporateUser.class )
|
||||
.unwrap( Query.class )
|
||||
.setParameter( "address", new Array(), ArrayType.INSTANCE )
|
||||
.getResultList();
|
||||
|
||||
assertTrue( users.isEmpty() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNativeSQL() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
List<Array> emails = entityManager.createNativeQuery(
|
||||
"select u.emailAddresses from CorporateUser u where u.userName = :name" )
|
||||
.setParameter( "name", "Vlad" )
|
||||
.getResultList();
|
||||
|
||||
assertEquals( 1, emails.size() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConfigurationSettings() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
SharedSessionContractImplementor session = entityManager.unwrap( SharedSessionContractImplementor.class );
|
||||
|
||||
CorporateUser corporateUser = entityManager.find( CorporateUser.class, "Vlad" );
|
||||
PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
EntityPersister entityPersister = persistenceContext.getEntry( corporateUser ).getPersister();
|
||||
ArrayType arrayType = (ArrayType) entityPersister.getPropertyType( "emailAddresses" );
|
||||
|
||||
Map<String, Object> settings = arrayType.getSettings();
|
||||
Integer[] arrayConfig = (Integer[]) settings.get( "hibernate.type.array.config" );
|
||||
assertNotNull( arrayConfig );
|
||||
assertArrayEquals( new Integer[]{1, 2, 3}, arrayConfig );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "CorporateUser")
|
||||
@TypeDef( typeClass = ArrayType.class, defaultForType = Array.class )
|
||||
public static class CorporateUser {
|
||||
|
||||
@Id
|
||||
private String userName;
|
||||
|
||||
private Array emailAddresses = new Array();
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public Array getEmailAddresses() {
|
||||
return emailAddresses;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue