问题
I use Spring Data and decided that I want to create new custom data type that can be used in Hibernate entities. I checked the documentation and choose BasicType and implemented it according to this official user guide.
I wanted to be able to register the type under its class name and be able to use the new type in entities without need for @Type annotation. Unfortunately, I’m unable to get reference to the MetadataBuilder or Hibernate configuration to register the new type. Is there a way how to get it in Spring Data? It seems that initialization of the Hibernate is hidden from the user and cannot be easily accessed. We use following class to initialize the JPA:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager",
basePackages = {
"..." // omitted
}
)
public class JpaConfiguration implements TransactionManagementConfigurer {
@Primary
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean configureEntityManagerFactory(
DataSource dataSource,
SchemaPerTenantConnectionProviderImpl provider) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setPersistenceUnitName("defaultPersistenceUnit");
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setPackagesToScan(
"..." // omitted
);
entityManagerFactoryBean.setJpaProperties(properties(provider));
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return entityManagerFactoryBean;
}
@Primary
@Bean(name = "transactionManager")
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new JpaTransactionManager();
}
private Properties properties(SchemaPerTenantConnectionProviderImpl provider) {
Properties properties = new Properties();
// omitted
return properties;
}
}
I found lots of articles about way how to do it with Hibernate’s Configuration object but this one refers to Hibernate 3 and 4. I also found way how to do it via Hibernate org.hibernate.integrator.spi.Integrator but when I use it according to the articles I found I will get exception with the message “org.hibernate.HibernateException: Can not alter TypeRegistry at this time”
What is the correct way to register custom types in Spring Data?
回答1:
I finally figured it out. I will post it here for others:
I created a new class that implements org.hibernate.boot.spi.SessionFactoryBuilderFactory interface. In this class I can get reference to the TypeResolver from metadata and register my custom type.
package com.example.configuration;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryBuilderFactory;
import org.hibernate.boot.spi.SessionFactoryBuilderImplementor;
import org.slf4j.LoggerFactory;
import com.example.CustomType;
public class CustomDataTypesRegistration implements SessionFactoryBuilderFactory {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(CustomDataTypesRegistration.class);
@Override
public SessionFactoryBuilder getSessionFactoryBuilder(final MetadataImplementor metadata, final SessionFactoryBuilderImplementor defaultBuilder) {
logger.info("Registering custom Hibernate data types");
metadata.getTypeResolver().registerTypeOverride(CustomType.INSTANCE);
return defaultBuilder;
}
}
The class must be then registered via Java ServiceLoader mechanism by adding full name of the class with its packages into the file with name org.hibernate.boot.spi.SessionFactoryBuilderFactory into the java module’s META-INF/services directory:
src/main/resources/META-INF/services/org.hibernate.boot.spi.SessionFactoryBuilderFactory
The file can contain multiple lines, each referencing different class. In this case it is:
com.example.configuration.CustomDataTypesRegistration
This way the Spring Data starts and custom type is successfully registered during Hibernate initialization.
What helped my quite a lot was this SO answer that deals with schema export in Hibernate 5 under Spring Data.
回答2:
There's a much easier solution to this -- in fact, it's just 1 line of code. You can just use the @TypeDef annotation and thus avoid having to register the custom type:
@Entity(name = "Product")
@TypeDef(
name = "bitset",
defaultForType = BitSet.class,
typeClass = BitSetType.class
)
public static class Product {
@Id
private Integer id;
private BitSet bitSet;
For an example, see "Example 11. Using @TypeDef to register a custom Type" in http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html
回答3:
I use JPA with Spring 4.3.9 and Hibernate 5.0.5 and I use custom property EntityManagerFactoryBuilderImpl.TYPE_CONTRIBUTORS with Spring LocalContainerEntityManagerFactoryBean to override Hibernate BasicTypes.
final Properties jpaProperties = new Properties();
jpaProperties.put(EntityManagerFactoryBuilderImpl.TYPE_CONTRIBUTORS, new TypeContributorList() {
@Override
public List<TypeContributor> getTypeContributors() {
return Lists.newArrayList(new CustomDateTimeTypeContributor());
}
});
final LocalContainerEntityManagerFactoryBean factoryBean = new
LocalContainerEntityManagerFactoryBean();
factoryBean.setJpaProperties(jpaProperties);
factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
return factoryBean;
回答4:
An alternative to what xMort did, can be registering a org.hibernate.boot.model.TypeContributor via ServiceLoader mechanism.
- Implement TypeContributor
package com.example.configuration;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.service.ServiceRegistry;
public class CustomTypeContributor implements TypeContributor {
@Override
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
typeContributions.contributeType(CustomType.INSTANCE);
}
}
- Create a file org.hibernate.boot.model.TypeContributor into the java module’s META-INF/services
src/main/resources/META-INF/services/org.hibernate.boot.model.TypeContributor
- Reference the TypeContributor, file content:
ru.eastbanctech.scs.air.transaction.repositories.StringArrayTypeContributor
As of Hibernate 5.2.17, the code that picks up the TypeContributor service can be found at org.hibernate.boot.model.process.spi.MetadataBuildingProcess#handleTypes.
来源:https://stackoverflow.com/questions/42695339/how-should-i-register-custom-hibernate-5-data-type-basictype-when-spring-data