【问题标题】:Hibernate Mapping PackageHibernate 映射包
【发布时间】:2010-11-27 15:27:57
【问题描述】:

我正在使用 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?

【问题讨论】:

  • 值得一提的是,&lt;mapping package="com.fooPackage/&gt; 条目用于配置在包本身上定义的元数据,而不是用于该包中的类in

标签: java hibernate hibernate-annotations


【解决方案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(并且您应该是 :-)),您可以编写自己的代码来检测适当的类,并通过 addAnnotatedClass() 方法将它们注册到您的 AnnotationConfiguration

顺便说一句,除非您实际上在包级别声明了某些内容,否则没有必要映射包。

【讨论】:

  • 哇,这是我第一次看到 ClassPathScanningCandidateComponentProvider。非常好。
【解决方案2】:

我刚遇到这个问题,发现似乎有一个开箱即用的解决方案。我的集成尚未完成,稍后会更新。

来自 Javadoc,尤其是 packagesToScan 部分:

org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean

Spring 的标准 LocalSessionFactoryBean 的子类,用于 Hibernate, 支持用于映射的 JDK 1.5+ 注释元数据。

注意:此类需要 Hibernate 3.2 或更高版本,使用 Java 存在 Persistence API 和 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 反射库。

【讨论】:

  • 请记住,这种配置方式不适用于 Hibernate 5。应该更改它。
【解决方案4】:

如果您不想使用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;
    }
}

【讨论】:

    【解决方案5】:

    我使用 StackOverflow 的答案对类扫描方法进行了一些调查。所以我将所有这些收集在一起,使用 Hibernate 实体扫描作为测试,在一个测试项目中:hibernate-scanners-test

    使用流畅的休眠

    如果您正在寻找一种无需额外依赖的快速扫描方法,您可以尝试fluent-hibernate 库(您不需要其他jar,除了库)。 除此之外,它还为 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();
    

    使用新的 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();
    

    【讨论】:

      【解决方案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");
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-07-26
        • 2011-07-23
        • 2013-04-25
        • 1970-01-01
        • 1970-01-01
        • 2016-01-23
        • 1970-01-01
        相关资源
        最近更新 更多