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を変更できません」で例外が発生することがわかりましたカスタムタイプを登録する正しい方法は何ですか春のデータで?
私はついにそれを理解しました。他の人のためにここに投稿します:
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でのスキーマエクスポートを扱っていることでした。
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;
これにははるかに簡単な解決策があります。実際、それはたった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を使用したカスタムタイプの登録」を参照してください。
XMortが行ったことの代わりに、ServiceLoaderメカニズムを介してorg.hibernate.boot.model.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);
}
}
src/main/resources/META-INF/services/org.hibernate.boot.model.TypeContributor
ru.eastbanctech.scs.air.transaction.repositories.StringArrayTypeContributor
Hibernate 5.2.17以降、TypeContributorサービスを取得するコードはorg.hibernate.boot.model.process.spi.MetadataBuildingProcess#handleTypesにあります。