使用Spring Data时,如何注册自定义Hibernate 5数据类型(BasicType)?

xMo*_*ort 9 java spring hibernate hibernate-mapping spring-data

我使用Spring Data并决定创建可以在Hibernate实体中使用的新自定义数据类型.我检查了文档,BasicType并根据此官方用户指南选择并实施它.

我希望能够在其类名下注册该类型,并且能够在实体中使用新类型而无需@Type注释.不幸的是,我无法引用MetadataBuilder或Hibernate配置来注册新类型.有没有办法在Spring Data中获取它?似乎Hibernate的初始化对用户是隐藏的,并且不能轻易访问.我们使用以下类来初始化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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现很多关于如何使用Hibernate的Configuration对象的文章,但是这个引用了Hibernate 3和4.我也找到了如何通过Hibernate来做到这一点org.hibernate.integrator.spi.Integrator但是当我根据我发现的文章使用它时我会得到异常消息"org.hibernate.HibernateException:此时无法更改TypeRegistry" 在Spring Data中注册自定义类型的正确方法是什么?

xMo*_*ort 12

我终于弄明白了.我会在这里发布给其他人:

我创建了一个实现org.hibernate.boot.spi.SessionFactoryBuilderFactory接口的新类.在这个类中,我可以引用TypeResolverfrom元数据并注册我的自定义类型.

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后必须通过Java ServiceLoader机制注册该类,方法是将带有包的类的全名添加到名为org.hibernate.boot.spi.SessionFactoryBuilderFactoryjava模块META-INF/services目录的文件中:

src/main/resources/META-INF/services/org.hibernate.boot.spi.SessionFactoryBuilderFactory
Run Code Online (Sandbox Code Playgroud)

该文件可以包含多行,每行引用不同的类.在这种情况下,它是:

com.example.configuration.CustomDataTypesRegistration 
Run Code Online (Sandbox Code Playgroud)

这样,Spring数据启动并在Hibernate初始化期间成功注册了自定义类型.

在Spring Data下,Hibernate 5中的模式导出处理了这个SO答案,这对我的帮助很大.

  • 在询问和回答之间花了大约20秒钟,我想“ *我终于想通了*”是个玩笑,对吗?; P (3认同)
  • 我昨天写了这个问题,但没有发布。今天我想通了。我决定将其与将遇到相同问题的其他人的答案一起发布。对我来说,发布之前有延迟;) (3认同)

小智 8

xMort 所做的替代方法是通过 ServiceLoader 机制注册 org.hibernate.boot.model.TypeContributor。

\n\n
    \n
  1. 实现类型Contributor
  2. \n
\n\n
package com.example.configuration;\n\nimport org.hibernate.boot.model.TypeContributions;\nimport org.hibernate.boot.model.TypeContributor;\nimport org.hibernate.service.ServiceRegistry;\n\npublic class CustomTypeContributor implements TypeContributor {\n    @Override\n    public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {\n        typeContributions.contributeType(CustomType.INSTANCE);\n    }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  1. 在 java module\xe2\x80\x99s META-INF/services 中创建文件 org.hibernate.boot.model.TypeContributor
  2. \n
\n\n
src/main/resources/META-INF/services/org.hibernate.boot.model.TypeContributor\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  1. 引用TypeContributor,文件内容:
  2. \n
\n\n
ru.eastbanctech.scs.air.transaction.repositories.StringArrayTypeContributor\n
Run Code Online (Sandbox Code Playgroud)\n\n

从 Hibernate 5.2.17 开始,可以在 org.hibernate.boot.model.process.spi.MetadataBuildingProcess#handleTypes 中找到获取 TypeContributor 服务的代码。

\n


小智 6

我将 JPA 与 Spring 4.3.9 和 Hibernate 5.0.5 一起使用,并使用自定义属性EntityManagerFactoryBuilderImpl.TYPE_CONTRIBUTORS和 Spring LocalContainerEntityManagerFactoryBean 来覆盖 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;
Run Code Online (Sandbox Code Playgroud)


use*_*141 5

有一个更简单的解决方案-实际上,这只是一行代码。您可以只使用@TypeDef批注,从而避免必须注册自定义类型:

@Entity(name = "Product")
@TypeDef(
    name = "bitset",
    defaultForType = BitSet.class,
    typeClass = BitSetType.class
)
public static class Product {

    @Id
    private Integer id;

    private BitSet bitSet;
Run Code Online (Sandbox Code Playgroud)

有关示例,请参见http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html中的 “示例11。使用@TypeDef注册自定义类型”。

  • 也可以在 package-info.java 中: `@TypeDef(name = "bitset", defaultForType = BitSet.class, typeClass = BitSetType.class) package mypackage` (2认同)