Uso Spring Data y decidí que quiero crear un nuevo tipo de datos personalizado que se pueda usar en las entidades de Hibernate. Revisé la documentación y elegí BasicType y lo implementé de acuerdo con esta guía oficial del usuario .
Quería poder registrar el tipo con su nombre de clase y poder usar el nuevo tipo en entidades sin necesidad de la anotación @Type . Desafortunadamente, no puedo obtener una referencia a la configuración de MetadataBuilder o Hibernate para registrar el nuevo tipo. ¿Hay alguna manera de obtenerlo en Spring Data? Parece que la inicialización de Hibernate está oculta para el usuario y no se puede acceder fácilmente. Usamos la siguiente clase para inicializar el 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; } } Encontré muchos artículos sobre cómo hacerlo con el objeto de configuración de Hibernate, pero este se refiere a Hibernate 3 y 4. También encontré la forma de hacerlo a través de Hibernate org.hibernate.integrator.spi.Integrator pero cuando lo uso de acuerdo a los artículos que encontré, obtendré una excepción con el mensaje "org.hibernate.HibernateException: no se puede modificar TypeRegistry en este momento" ¿Cuál es la forma correcta de registrar tipos personalizados en Spring Data?
Finalmente lo resolví. Lo publicaré aquí para otros:
Creé una nueva clase que implementa la interfaz org.hibernate.boot.spi.SessionFactoryBuilderFactory . En esta clase, puedo obtener referencias a TypeResolver a partir de metadatos y registrar mi tipo personalizado.
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; } } Luego, la clase debe registrarse a través del mecanismo Java ServiceLoader agregando el nombre completo de la clase con sus paquetes en el archivo con el nombre org.hibernate.boot.spi.SessionFactoryBuilderFactory en el directorio META-INF/services del módulo Java:
src/main/resources/META-INF/services/org.hibernate.boot.spi.SessionFactoryBuilderFactoryEl archivo puede contener varias líneas, cada una de las cuales hace referencia a una clase diferente. En este caso lo es:
com.example.configuration.CustomDataTypesRegistrationDe esta forma, Spring Data se inicia y el tipo personalizado se registra correctamente durante la inicialización de Hibernate.
Lo que me ayudó bastante fue esta respuesta SO que se ocupa de la exportación de esquemas en Hibernate 5 en Spring Data.
Hay una solución mucho más fácil para esto; de hecho, es solo 1 línea de código. Puede simplemente usar la anotación @TypeDef y así evitar tener que registrar el tipo personalizado:
@Entity(name = "Product") @TypeDef( name = "bitset", defaultForType = BitSet.class, typeClass = BitSetType.class ) public static class Product { @Id private Integer id; private BitSet bitSet;Para ver un ejemplo, consulte "Ejemplo 11. Uso de @TypeDef para registrar un tipo personalizado" en http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html
Uso JPA con Spring 4.3.9 e Hibernate 5.0.5 y uso la propiedad personalizada EntityManagerFactoryBuilderImpl.TYPE_CONTRIBUTORS con Spring LocalContainerEntityManagerFactoryBean para anular 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;