web-dev-qa-db-ja.com

Spring Dataを使用する場合、カスタムHibernate 5データ型(BasicType)を登録するにはどうすればよいですか?

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

HibernateのConfigurationオブジェクトを使用してそれを行う方法についての記事をたくさん見つけましたが、これはHibernate 3および4を参照しています。Hibernateorg.hibernate.integrator.spi.Integratorを介してそれを行う方法も見つけましたが、記事に従って使用するとメッセージ「org.hibernate.HibernateException:現時点ではTypeRegistryを変更できません」で例外が発生することがわかりましたカスタムタイプを登録する正しい方法は何ですか春のデータで?

11
xMort

私はついにそれを理解しました。他の人のためにここに投稿します:

org.hibernate.boot.spi.SessionFactoryBuilderFactoryインターフェースを実装する新しいクラスを作成しました。このクラスでは、メタデータからTypeResolverへの参照を取得し、カスタムタイプを登録できます。

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

次に、クラスは Java ServiceLoaderメカニズム を介して登録する必要があります。クラスのフルネームとそのパッケージをorg.hibernate.boot.spi.SessionFactoryBuilderFactoryという名前のファイルにJavaモジュールのMETA-INF/servicesディレクトリ:

src/main/resources/META-INF/services/org.hibernate.boot.spi.SessionFactoryBuilderFactory

ファイルには複数の行を含めることができ、それぞれが異なるクラスを参照します。この場合は次のとおりです。

com.example.configuration.CustomDataTypesRegistration 

このようにして、Spring Dataが起動し、Hibernateの初期化中にカスタムタイプが正常に登録されます。

私を大いに助けたのは、これが SO answer SpringDataの下のHibernate5でのスキーマエクスポートを扱っていることでした。

10
xMort

Spring4.3.9およびHibernate5.0.5でJPAを使用し、Spring LocalContainerEntityManagerFactoryBeanでカスタムプロパティEntityManagerFactoryBuilderImpl.TYPE_CONTRIBUTORSを使用してHibernateBasicTypesをオーバーライドします。

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;
4
alex.tran

これにははるかに簡単な解決策があります。実際、それはたった1行のコードです。 @TypeDefアノテーションを使用するだけで、カスタムタイプを登録する必要がなくなります。

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

    @Id
    private Integer id;

    private BitSet bitSet;

例については、 http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html の「例11. @ TypeDefを使用したカスタムタイプの登録」を参照してください。

4
user64141

XMortが行ったことの代わりに、ServiceLoaderメカニズムを介してorg.hibernate.boot.model.TypeContributorを登録することもできます。

  1. TypeContributorを実装する
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);
    }
}

  1. ファイルorg.hibernate.boot.model.TypeContributorをJavaモジュールのMETA-INF/servicesに作成します
src/main/resources/META-INF/services/org.hibernate.boot.model.TypeContributor
  1. TypeContributor、ファイルコンテンツを参照します。
ru.eastbanctech.scs.air.transaction.repositories.StringArrayTypeContributor

Hibernate 5.2.17以降、TypeContributorサービスを取得するコードはorg.hibernate.boot.model.process.spi.MetadataBuildingProcess#handleTypesにあります。

0
cinereo