Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically loading Entity classes with JPA 2.0?

Tags:

With Hibernate you can load your Entity classes as:

sessionFactory = new AnnotationConfiguration()                     .addPackage("test.animals")                     .addAnnotatedClass(Flight.class)                     .addAnnotatedClass(Sky.class)                     .addAnnotatedClass(Person.class)                     .addAnnotatedClass(Dog.class); 

Is there a way to do the same thing - programmatically loading your Entity classes - in a JPA 2.0 compliant way?

The reason for this question is because I'd like to dynamically load my Entity classes, thus not necessarily programmatically.

like image 530
wen Avatar asked May 15 '10 02:05

wen


1 Answers

With the help of Spring I did this in a JPA compliant way.

My "persistence.xml" looks empty, with no entities listed within the <persistence-unit> element.

I then wrote a class that implemented PersistenceUnitPostProcessor like so:

import java.util.Set; import javax.persistence.Entity; import javax.persistence.MappedSuperclass; import org.reflections.Reflections; import org.reflections.scanners.TypeAnnotationsScanner; import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo; import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;  public class ReflectionsPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {      private String reflectionsRoot;     private Logger log = LoggerFactory.getLogger(ReflectionsPersistenceUnitPostProcessor.class);      @Override     public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {             Reflections r = new Reflections(this.reflectionsRoot, new TypeAnnotationsScanner());             Set<String> entityClasses = r.getStore().getTypesAnnotatedWith(Entity.class.getName());             Set<String> mappedSuperClasses = r.getStore().getTypesAnnotatedWith(MappedSuperclass.class.getName());              for (String clzz : mappedSuperClasses)             {                     pui.addManagedClassName(clzz);             }               for (String clzz : entityClasses)             {                     pui.addManagedClassName(clzz);             }      }      public String getReflectionsRoot() {             return reflectionsRoot;     }      public void setReflectionsRoot(String reflectionsRoot) {             this.reflectionsRoot = reflectionsRoot;     } } 

Then I adjusted my spring context xml like this:

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">             <property name="dataSource" ref="dataSource" />             <property name="jpaVendorAdapter">                     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">                             <property name="showSql" value="false" />                             <property name="generateDdl" value="true" />                             <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />                     </bean>             </property>             <property name="persistenceUnitName" value="GenericPersistenceUnit"/>             <property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>             <property name="persistenceUnitPostProcessors">                     <list>                             <bean class="com.austinmichael.core.repository.ReflectionsPersistenceUnitPostProcessor">                                     <property name="reflectionsRoot" value="com.austinmichael"/>                             </bean>                     </list>             </property>     </bean> 

Note the registration of the ReflectionsPersistenceUnitPostProcessor in the persistenceUnitPostProcessors setting.

And that's it. Every class with a JPA Entity or MappedSuperclass annotation on the classpath is added to the classpath. I had to give reflections the prefix of a package name to scan through which is why com.austinmichael is there at all. You could register a second ReflectionsPersistenceUnitPostProcessor with a different package name prefix if you want if your entities don't share a common package name prefix.

But, this is now JPAVendor agnostic.

like image 67
Carl Horton Avatar answered Oct 05 '22 23:10

Carl Horton