Java 休眠映射包

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1413190/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:49:31  来源:igfitidea点击:

Hibernate Mapping Package

javahibernatehibernate-annotations

提问by Daniel Moura

I'm using Hibernate Annotations.

我正在使用 Hibernate 注释。

In all my model classes I annotate like this:

在我所有的模型类中,我都这样注释:

@Entity
@Table
public class SomeModelClass {
//
}

My hibernate.cfg.xml is

我的 hibernate.cfg.xml 是

<hibernate-configuration>
   <session-factory>
      <!-- some properties -->

      <mapping package="com.fooPackage" />
      <mapping class="com.fooPackage.SomeModelClass" />
    </session-factory>
</hibernate-configuration>

For every class I add to the com.fooPackage I have to add a line in the hibernate.cfg.xml like this:

对于我添加到 com.fooPackage 的每个类,我必须在 hibernate.cfg.xml 中添加一行,如下所示:

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

Is there a way I can add new model classes but don't need to add this line to hibernate.cfg.xml?

有没有办法可以添加新的模型类但不需要将此行添加到 hibernate.cfg.xml?

回答by ChssPly76

Out of the box - no. You can write your own code to detect / register your annotated classes, however. If you're using Spring, you can extend AnnotationSessionFactoryBeanand do something like:

开箱即用 - 没有。但是,您可以编写自己的代码来检测/注册带注释的类。如果您使用的是 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();
}

If you're not using Spring (and you should be :-) ) you can write your own code for detecting appropriate classes and register them with your AnnotationConfigurationvia addAnnotatedClass()method.

如果您不使用 Spring(并且您应该使用 :-)),您可以编写自己的代码来检测适当的类并使用您的AnnotationConfigurationviaaddAnnotatedClass()方法注册它们。

Incidentally, it's not necessary to map packages unless you've actually declared something at package level.

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

回答by Jerry Tian

I just come across this problem, and find out there seems an out of box solution for this. My integration is not out yet, will update this later.

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

From the Javadoc, especially the packagesToScanpart:

来自 Javadoc,尤其是packagesToScan部分:

org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean

Subclass of Spring's standard LocalSessionFactoryBean for Hibernate, supporting JDK 1.5+ annotation metadata for mappings.

Note: This class requires Hibernate 3.2 or later, with the Java Persistence API and the Hibernate Annotations add-on present.

Example for an AnnotationSessionFactoryBeanbean definition:

<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>

Or when using classpath scanning for autodetection of entity classes:

<bean id="sessionFactory"
      class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
  <property name="dataSource" ref="dataSource"/>
  <property name="packagesToScan" value="test.package"/>
</bean>

Since: 1.2.2
Author: Juergen Hoeller

org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean

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

注意:此类需要 Hibernate 3.2 或更高版本,并带有 Java Persistence API 和 Hibernate Annotations 附加组件。

AnnotationSessionFactoryBeanbean定义示例:

<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
作者:Juergen Hoeller

回答by luke

Bit of thread necromancy here...

这里有点线程死灵法......

It still doesn't look like there's a good way to do what you want. If you don't want to use Spring, here's a similar method using Reflections:

看起来仍然没有什么好方法可以做你想做的事。如果您不想使用 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);

The same approach is probably viable for other Java reflection libraries.

相同的方法可能适用于其他 Java 反射库。

回答by bhdrkn

If you do not want to use springor any other library, you can achieve that like this. Same approach as luke'sbut without Reflectionslibrary

如果您不想使用spring或任何其他库,您可以像这样实现。与卢克的方法相同,但没有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;
    }
}

回答by v.ladynev

I have done some investigations of class scanning approaches, using answers from StackOverflow. So I gather all it together, using a Hibernate entities scanning as a test, in the one test project: hibernate-scanners-test.

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

Using fluent-hibernate

使用流畅的休眠

If you are looking for a quick scanning approach without additional dependencies, you can try fluent-hibernatelibrary (you will not need to have other jars, except the library). Apart this, it has some useful features for Hibernate 5 and Hibernate 4, including entities scanning, a Hibernate 5 implicit naming strategy, a nested transformer and others.

如果您正在寻找一种没有额外依赖项的快速扫描方法,您可以尝试fluent-hibernate库(除了库之外,您不需要其他 jars)。除此之外,它还为 Hibernate 5 和 Hibernate 4 提供了一些有用的功能,包括实体扫描、Hibernate 5 隐式命名策略、嵌套转换器等。

Just download the library from the project page: fluent-hibernateand use EntityScanner:

只需从项目页面下载库:fluent-hibernate并使用EntityScanner

For Hibernate 4 and Hibernate 5:

对于休眠 4 和休眠 5:

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

Using a new Hibernate 5 bootstrapping API:

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

回答by Kumar Abhishek

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