Hibernate Mapping Package
Asked Answered
E

6

46

I'm using Hibernate Annotations.

In all my model classes I annotate like this:

@Entity
@Table
public class SomeModelClass {
//
}

My hibernate.cfg.xml is

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

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

Eardrop answered 11/9, 2009 at 20:47 Comment(1)
It's worth commenting that the <mapping package="com.fooPackage/> entry is for configuring meta-data defined on the package itself, not for classes in that package.Maze
C
18

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 AnnotationSessionFactoryBean and do something like:

@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 AnnotationConfiguration via addAnnotatedClass() method.

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

Chrysoprase answered 11/9, 2009 at 21:0 Comment(1)
Wow Chss, It is the first time i have seen ClassPathScanningCandidateComponentProvider. Very good.Panorama
I
11

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 packagesToScan part:

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

Intricacy answered 9/8, 2011 at 7:50 Comment(1)
<property name="packagesToScan" value="test.package"/> This worked for me too.. Thanks for your answer...Adulterant
C
11

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:

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

Crossruff answered 14/10, 2014 at 3:3 Comment(1)
Keep in mind, that this way of configuration doesn't work for Hibernate 5. It should be changed.Merchandise
A
1

If you do not want to use spring or any other library, you can achieve that like this. Same approach as luke's but without Reflections library

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;
    }
}
Analogize answered 28/9, 2015 at 18:52 Comment(0)
M
1

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.

Using fluent-hibernate

If you are looking for a quick scanning approach without additional dependencies, you can try fluent-hibernate library (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.

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

For Hibernate 4 and Hibernate 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:

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();
Merchandise answered 20/5, 2016 at 10:52 Comment(0)
R
-3
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");
Recrystallize answered 21/1, 2017 at 18:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.