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 an
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
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.
An alternative to what xMort did, can be registering a org.hibernate.boot.model.TypeContributor via ServiceLoader mechanism.
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);
}
}
src/main/resources/META-INF/services/org.hibernate.boot.model.TypeContributor
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.
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;