2009-09-11 13 views
36

Estoy usando Hibernate Annotations.Hibernate Mapping Package

En todas mis clases del modelo que anotar la siguiente manera:

@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 agrego a la com.fooPackage tengo que añadir una línea en el hibernate.cfg.xml así:

<mapping class="com.fooPackage.AnotherModelClass" /> 

¿hay alguna manera de añadir nuevas clases del modelo, pero no necesito agregar esta línea a hibernate.cfg.xml?

+16

Vale la pena comentar que la entrada ' skaffman

Respuesta

18

Fuera de la caja - no. Sin embargo, puedes escribir tu propio código para detectar/registrar tus clases anotadas. Si está utilizando la primavera, se 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 usted no está usando la primavera (y que debe estar :-)) usted puede escribir su propio código para la detección de clases apropiadas y regístrelos con su AnnotationConfiguration a través del método addAnnotatedClass().

Por cierto, no es necesario mapear paquetes a menos que realmente haya declarado algo a nivel de paquete.

+0

Wow, es la primera vez que veo ClassPathScanningCandidateComponentProvider. Muy bien. –

11

Acabo de encontrarme con este problema, y ​​descubro que parece haber una solución obsoleta para esto. Mi integración aún no ha salido, actualizaré esto más tarde.

Desde el Javadoc, especialmente la parte packagesToScan:

org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean

subclase de LocalSessionFactoryBean estándar de la primavera de hibernación, soporte JDK 1.5 + metadatos anotación para asignaciones.

Nota: Esta clase requiere Hibernate 3.2 o posterior, con la API de persistencia Java y el complemento de anotaciones de Hibernate.

Ejemplo de una definición AnnotationSessionFactoryBean frijol:

<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 cuando se utiliza la exploración ruta de clase para la detección automática 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 Holler

+0

confirmado, está funcionando como se esperaba. –

+0

Esto funcionó para mí también. Gracias por su respuesta ... –

10

Poco nigromancia de hilos aquí ...

Todavía no parece que haya una buena manera de hacer lo que quiera. Si no desea utilizar la primavera, aquí hay un método similar usando 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.

+0

Tenga en cuenta que esta forma de configuración no funciona para Hibernate 5. debería ser cambiado. –

1

Si no desea utilizar spring o cualquier otra biblioteca, puede lograrlo de esta manera. Mismo enfoque que luke's pero sin Reflections biblioteca

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

He hecho algunas investigaciones sobre los enfoques de exploración de clase, usando respuestas de StackOverflow. Así que reuní todo junto, usando un escaneo de entidades Hibernate como una prueba, en el proyecto de prueba: hibernate-scanners-test.

El uso de fluidez-hibernación

Si usted está buscando un enfoque de exploración rápida y sin dependencias adicionales, puede intentar fluent-hibernate biblioteca (que no necesitará tener otros frascos, excepto la biblioteca). Aparte de esto, tiene algunas funciones útiles para Hibernate 5 e Hibernate 4, incluido el escaneo de entidades, una estrategia de nomenclatura implícita de Hibernate 5, un transformador anidado y otros.

sólo tiene que descargar la biblioteca desde la página del proyecto: fluent-hibernate y utilizar :

Para Hibernate 4 y Hibernate 5:

Configuration configuration = new Configuration(); 
EntityScanner.scanPackages("my.com.entities", "my.com.other.entities") 
    .addTo(configuration); 
SessionFactory sessionFactory = configuration.buildSessionFactory(); 

El uso de una nueva API de Hibernate 5 reinicialización:

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(); 
-1
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");