java - propiedades - persistencia hibernate
Paquete de Mapeo de Hibernate (6)
Estoy usando Hibernate Annotations.
En todas mis clases modelo, hago una anotación como esta:
@Entity
@Table
public class SomeModelClass {
//
}
Mi hibernate.cfg.xml es
<hibernate-configuration>
<session-factory>
<!-- some properties -->
<mapping package="com.fooPackage" />
<mapping class="com.fooPackage.SomeModelClass" />
</session-factory>
</hibernate-configuration>
Para cada clase que agregue a com.fooPackage, tengo que agregar una línea en hibernate.cfg.xml como esta:
<mapping class="com.fooPackage.AnotherModelClass" />
¿Hay alguna manera de agregar nuevas clases de modelo pero no es necesario agregar esta línea a hibernate.cfg.xml?
Acabo de encontrarme con este problema, y descubro que parece haber una solución que viene de la caja para esto. Mi integración aún no ha salido, actualizaré esto más tarde.
Desde el Javadoc, especialmente la parte de packagesToScan
:
org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean
Subclase del Estándar LocalSessionFactoryBean de Spring para Hibernate, que admite metadatos de anotación JDK 1.5+ para mapeos.
Nota: Esta clase requiere Hibernate 3.2 o posterior, con la API Java Persistence y el complemento Hibernate Annotations.
Ejemplo para una definición de bean
AnnotationSessionFactoryBean
:
<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>
O al usar classpath escaneo para autodetección de clases de entidad:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="test.package"/> </bean>
Desde: 1.2.2
Autor: Juergen Hoeller
Fuera de la caja - no. Sin embargo, puedes escribir tu propio código para detectar / registrar tus clases anotadas. Si está utilizando Spring, puede extender AnnotationSessionFactoryBean
y hacer algo como:
@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();
}
Si no está utilizando Spring (y debería ser :-)) puede escribir su propio código para detectar las clases apropiadas y registrarlas con su AnnotationConfiguration
través del método addAnnotatedClass()
.
Por cierto, no es necesario mapear paquetes a menos que hayas declarado algo a nivel de paquete.
He realizado algunas investigaciones de enfoques de escaneo de clases, usando respuestas de . Así que reuní todo junto, usando un escaneo de entidades Hibernate como una prueba, en el único proyecto de prueba: hibernate-scanners-test .
Usando fluencia-hibernación
Si está buscando un enfoque de escaneo rápido sin dependencias adicionales, puede probar la biblioteca fluent-hibernate (no necesitará tener otros archivos jar, excepto la biblioteca). Aparte de esto, tiene algunas funciones útiles para Hibernate 5 e Hibernate 4, que incluyen el escaneo de entidades, una estrategia de nomenclatura implícita de Hibernate 5, un transformador anidado y otros.
Simplemente descargue la biblioteca de la página del proyecto: EntityScanner fluent-hibernate y use EntityScanner :
Para Hibernate 4 e Hibernate 5:
Configuration configuration = new Configuration();
EntityScanner.scanPackages("my.com.entities", "my.com.other.entities")
.addTo(configuration);
SessionFactory sessionFactory = configuration.buildSessionFactory();
Usando una nueva API de bootstrapping de 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();
Si no desea utilizar la spring
o cualquier otra biblioteca, puede lograrlo de esta manera. Mismo enfoque que el de luke''s pero sin la biblioteca 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;
}
}
Un poco de nigromancia de hilos aquí ...
Todavía no parece que haya una buena manera de hacer lo que quieras. Si no quiere usar Spring, aquí hay un método similar que usa 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);
El mismo enfoque es probablemente viable para otras bibliotecas de reflexión de Java.
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");