Hibernate Annotationsを使用しています。
すべてのモデルクラスで、次のように注釈を付けます。
@Entity
@Table
public class SomeModelClass {
//
}
私のhibernate.cfg.xmlは
<hibernate-configuration>
<session-factory>
<!-- some properties -->
<mapping package="com.fooPackage" />
<mapping class="com.fooPackage.SomeModelClass" />
</session-factory>
</hibernate-configuration>
Com.fooPackageに追加するクラスごとに、次のようにhibernate.cfg.xmlに行を追加する必要があります。
<mapping class="com.fooPackage.AnotherModelClass" />
新しいモデルクラスを追加する方法はありますが、この行をhibernate.cfg.xmlに追加する必要はありませんか?
箱から出して-いいえ。ただし、注釈付きクラスを検出/登録する独自のコードを作成できます。 Springを使用している場合は、AnnotationSessionFactoryBean
を拡張して次のようなことができます。
_@Override
protected SessionFactory buildSessionFactory() throws Exception {
ArrayList<Class> classes = new ArrayList<Class>();
// the following will detect all classes that are annotated as @Entity
ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class));
// only register classes within "com.fooPackage" package
for (BeanDefinition bd : scanner.findCandidateComponents("com.fooPackage")) {
String name = bd.getBeanClassName();
try {
classes.add(Class.forName(name));
} catch (Exception E) {
// TODO: handle exception - couldn't load class in question
}
} // for
// register detected classes with AnnotationSessionFactoryBean
setAnnotatedClasses(classes.toArray(new Class[classes.size()]));
return super.buildSessionFactory();
}
_
Springを使用していない場合(:-))、適切なクラスを検出するための独自のコードを記述し、addAnnotatedClass()
メソッドを介してAnnotationConfiguration
に登録できます。
ちなみに、実際にパッケージレベルで何かを宣言していない限り、パッケージをマップする必要はありません。
私はこの問題に出くわしましたが、このためのすぐに使える解決策があるようです。私の統合はまだ出ていませんが、これは後で更新します。
Javadocから、特にpackagesToScan
部分:
org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
Hibernate用のSpringの標準LocalSessionFactoryBeanのサブクラス。マッピング用のJDK 1.5+アノテーションメタデータをサポートします。
注:このクラスには、Java Persistence APIおよびHibernate Annotationsアドオンが存在するHibernate 3.2以降が必要です。
AnnotationSessionFactoryBean
Bean定義の例:<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="annotatedClasses"> <list> <value>test.package.Foo</value> <value>test.package.Bar</value> </list> </property> </bean>
または、エンティティクラスの自動検出にクラスパススキャンを使用する場合:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="test.package"/> </bean>
以降:1.2.2
著者:ユルゲン・ホラー
ここでスレッドのネクロマンシーのビット...
それでも、あなたがやりたいことをする良い方法があるようには見えません。 Springを使用したくない場合は、 Reflections を使用した同様の方法があります。
// Create your SessionFactory with mappings for every `Entity` in a specific package
Configuration configuration = new Configuration();
configuration.configure("your_hibernate.cfg.xml");
Reflections reflections = new Reflections("your_package");
Set<Class<?>> classes = reflections.getTypesAnnotatedWith(javax.persistence.Entity.class);
for(Class<?> clazz : classes)
{
configuration.addAnnotatedClass(clazz);
}
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
同じアプローチは、他のJavaリフレクションライブラリに対しても実行可能です。
StackOverflowからの回答を使用して、クラススキャンアプローチの調査を行いました。そのため、1つのテストプロジェクトでテストとしてスキャンするHibernateエンティティを使用して、すべてをまとめます: hibernate-scanners-test 。
fluent-hibernateの使用
追加の依存関係のないクイックスキャンアプローチを探している場合は、 fluent-hibernate libraryを試すことができます(ライブラリ以外の他のjarは必要ありません)。これとは別に、エンティティスキャン、Hibernate 5の暗黙的な命名戦略、ネストされたトランスフォーマーなど、Hibernate 5およびHibernate 4に役立つ機能がいくつかあります。
プロジェクトページからライブラリをダウンロードするだけです: fluent-hibernate を使用して、 EntityScanner :
Hibernate 4およびHibernate 5の場合:
Configuration configuration = new Configuration();
EntityScanner.scanPackages("my.com.entities", "my.com.other.entities")
.addTo(configuration);
SessionFactory sessionFactory = configuration.buildSessionFactory();
新しいHibernate 5ブートストラップAPIの使用:
List<Class<?>> classes = EntityScanner
.scanPackages("my.com.entities", "my.com.other.entities").result();
MetadataSources metadataSources = new MetadataSources();
for (Class<?> annotatedClass : classes) {
metadataSources.addAnnotatedClass(annotatedClass);
}
SessionFactory sessionFactory = metadataSources.buildMetadata()
.buildSessionFactory();
spring
または他のライブラリを使用したくない場合は、このように実現できます。 luke's と同じアプローチですが、Reflections
ライブラリなし
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import javax.persistence.Entity;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import Java.io.File;
import Java.io.IOException;
import Java.util.ArrayList;
import Java.util.Collection;
import Java.util.Collections;
import Java.util.regex.Pattern;
import Java.util.stream.Collectors;
import Java.util.stream.StreamSupport;
public class SessionFactoryWrapper {
private final SessionFactory sessionFactory;
public SessionFactoryWrapper(final String...packagesToScan) {
this.sessionFactory = this.createSessionFactory(packagesToScan);
}
private SessionFactory createSessionFactory(final String[] packagesToScan) {
final Configuration configuration = new Configuration();
configuration.configure(); // Reads hibernate.cfg.xml from classpath
for (String packageToScan : packagesToScan) {
this.getEntityClasses(packageToScan).stream().forEach( configuration::addAnnotatedClass);
}
final ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
return configuration.buildSessionFactory(serviceRegistry);
}
private Collection<Class> getEntityClasses(final String pack) {
final StandardJavaFileManager fileManager = ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null);
try {
return StreamSupport.stream(fileManager.list(StandardLocation.CLASS_PATH, pack, Collections.singleton(JavaFileObject.Kind.CLASS), false).spliterator(), false)
.map(FileObject::getName)
.map(name -> {
try {
final String[] split = name
.replace(".class", "")
.replace(")", "")
.split(Pattern.quote(File.separator));
final String fullClassName = pack + "." + split[split.length - 1];
return Class.forName(fullClassName);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
})
.filter(aClass -> aClass.isAnnotationPresent(Entity.class))
.collect(Collectors.toCollection(ArrayList::new));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
}