Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 624
xMort Avatar asked Mar 09 '17 12:03

xMort


People also ask

Can you use spring and hibernate together?

We can simply integrate hibernate application with spring application. In hibernate framework, we provide all the database information hibernate. cfg. xml file.

Which version of hibernate is compatible with spring 5?

Spring 5x is compatible with hibernate 4x unless you are using it as an implementation of JPA which might not be compatible. A suggestion would be using the latest hibernate.

Can we use spring data JPA with hibernate?

With Spring Data, you may use Hibernate, Eclipse Link, or any other JPA provider. A very interesting benefit is that you can control transaction boundaries declaratively using the @Transactional annotation.


1 Answers

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.

like image 59
xMort Avatar answered Nov 15 '22 12:11

xMort