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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With