One supposedly standard way to solve this is to use the jar-file tag in persistence.xml. But it doesn't solve the problem because you have to use absolute URLs, which is not workable for production.
I found the solution in this post, which was to override persistence unit processing. In addition to the following code, I had to set up my Spring configuration in a particular way to make it all work properly:
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
/**
* This merges all JPA entities from multiple jars. To use it, all entities must
* be listed in their respective persistence.xml files using the <class> tag.
*
* @see http://forum.springsource.org/showthread.php?t=61763
*/
public class MergingPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor
{
Map<String, List<String>> puiClasses = new HashMap<String, List<String>>();
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui)
{
List<String> classes = puiClasses.get(pui.getPersistenceUnitName());
if (classes == null)
{
classes = new ArrayList<String>();
puiClasses.put(pui.getPersistenceUnitName(), classes);
}
pui.getManagedClassNames().addAll(classes);
final List<String> names = pui.getManagedClassNames();
classes.addAll(pui.getManagedClassNames());
}
}
To use it, I found that this only works if do all of the following:
- All your entities need to be mentioned in your persistence.xml files. Normally you don't have to do this is if you set up entity scanning in your Spring config
- All your persistence units use the same name, and furthermore it has to be the default name, namely "default"
- You have to use a particular entity manager factory, namely LocalContainerEntityManagerFactoryBean
- You have to have define your persistence provider in persistence.xml, in our case org.hibernate.ejb.HibernatePersistence
- Each persistence.xml file needs a unique name, because they are enumerated in the application context.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- Entities have to be enumerated here for MergingPersistenceUnitPostProcessor -->
<class>com.my.Foo</class>
...
Here is an excerpt from my application context. The whole point is that I can now have as many persistence.xml files as I like, in different jar files:
<bean id="pum"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>classpath*:META-INF/persistence1.xml</value>
<value>classpath*:META-INF/persistence2.xml</value>
</list>
</property>
<property name="persistenceUnitPostProcessors">
<bean class="com.my.MergingPersistenceUnitPostProcessor"/>
</property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="pum"/>
</bean>
3 comments:
Try adding exclude-unlisted-classes set to true to the persistence-unit section.
You can have a look here: http://java.sun.com/xml/ns/persistence for an explanation...
Dan, thanks for the comment. However, I don't think you mean it as an alternative to the merging; it's just a way of avoiding having to enumerate the entity classes in persistence.xml.
I was planning on building our domain model in a modular way with multiple Maven modules. Hopefully this will come in very handy!
Post a Comment