How should I register custom Hibernate 5 data type (BasicType) when Spring Data is used?

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.


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 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;