Пакет Hibernate Mapping
Я использую аннотации Hibernate.
Во всех моих классах моделей я комментирую вот так:
@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?
Ответы
Ответ 1
Из коробки - нет. Однако вы можете написать свой собственный код для определения/регистрации ваших аннотированных классов. Если вы используете 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 (и вы должны быть:-)), вы можете написать свой собственный код для обнаружения соответствующих классов и зарегистрировать их с помощью метода AnnotationConfiguration
через addAnnotatedClass()
.
Кстати, нет необходимости отображать пакеты, если вы фактически не объявили что-то на уровне пакета.
Ответ 2
Я просто столкнулся с этой проблемой и выяснил, что для этого есть решение из коробки. Моя интеграция еще не вышла, обновит ее позже.
Из Javadoc, особенно часть packagesToScan
:
org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
Подкласс Spring standard LocalSessionFactoryBean для Hibernate, поддержка метаданных аннотации JDK 1.5+ для сопоставлений.
Примечание. Для этого класса требуется Hibernate 3.2 или новее, с Java API-интерфейс Persistence и добавление дополнений Hibernate Annotations.
Пример для определения 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
Автор: Юрген Хуллер
Ответ 3
Немного некромантии нити здесь...
По-прежнему не похоже, что есть хороший способ сделать то, что вы хотите. Если вы не хотите использовать 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.
Ответ 4
Если вы не хотите использовать spring
или любую другую библиотеку, вы можете добиться этого, как это. Такой же подход, как luke, но без библиотеки 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;
}
}
Ответ 5
Я провел несколько исследований подходов к классу сканирования, используя ответы от StackOverflow. Поэтому я собираю все это вместе, используя объекты Hibernate, сканирующие как тест, в одном тестовом проекте: hibernate-scanners-test.
Использование спящего спящего режима
Если вы ищете быстрый метод сканирования без дополнительных зависимостей, вы можете попробовать fluent-hibernate библиотеку (вам не нужно будет иметь другую банки, кроме библиотеки).
Помимо этого, у него есть некоторые полезные функции для Hibernate 5 и Hibernate 4, в том числе для сканирования объектов, стратегии неявного именования Hibernate 5, вложенного трансформатора и других.
Просто загрузите библиотеку со страницы проекта: 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();
Использование нового API загрузки для Hibernate 5:
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();
Ответ 6
1. XML
<mapping class="com.concretepage.Person"/>
2. Class
Configuration configuration = new Configuration().configure().addAnnotatedClass(Person.class);
//Configure all the classes.
Set<Class> entityClasses = new HashSet<>(Arrays.asList(Person.class,PersonDetails.class));
//Iterate all the Classes.
for (Class cls : entityClasses ) {
configuration.addAnnotatedClass(cls);
}
3. Add package
//Or you can add package
configuration.addPackage("com.domain.entity");