23

We are developing a web application with Spring, Hibernate and Maven in a very modular fashion. There are core projects defining data access and view specific stuff, then there are modules defining logic and entities (@Entity) and then there's the web app defining controller and view.

Now we have a security module defining security entities like account and role and we have a prototype module defining some example entities like customer and order. Both have a PersistenceUnit defined inside a persistence.xml which is pretty much empty except for the PersistenceUnit name, as all database configuration is done in the web app with a datasource.xml. The web app is supposed to load both jars as maven dependencies.

Both projects will build fine, autocscanning all entities and creating them for their respective unit tests. They will also get loaded inside the web app successfully if added individually.

However, as soon as both are loaded at the same time, the second one will override the PersistenceUnit of the first one and thus create an IllegalArgumentException : Not an entity for all entities from the first one. If both projects have a different persistence unit, loading the web app will throw another exception saying that no single default persistence unit defined.

So.. how can I get all @Entity annotated classes to load up in my web app without having to define them all inside the persistence.xml (like here) but rather via component scan? This seems like an idea, though I don't know how to use and test it...

I think we either have to merge all PersistenceUnits inside the web app or load all Entities programmatically. Defining them hard-coded inside the persistence.xml is not an option for us.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Pete
  • 10,720
  • 25
  • 94
  • 139
  • concerning the first answer: As far as I know, Spring already scans for the annotaded classes and adds them to the `PersistenceUnit`. The problem is, that I have to name all `PersistenceUnits` the same which will result in them overriding each other. So I'm looking for a way to merge all PersistenceUnits into one in my web app. Don't know if [this][1] (bottom) would do, though I have no idea where to register a `MergingPersistenceUnitPostProcessor` [1]: http://forum.springsource.org/showthread.php?61763-Problems-with-JPA-and-multiple-persistence-units – Pete Sep 16 '11 at 10:33

5 Answers5

5

Since the question seems to still get attention, I'll post our latest solution to the problem.

We are now auto-scanning all packages instead of using persistence.xml files anywhere.

In our datasource.xml we added the line

<property name="packagesToScan" value="our.basepackage" />

Almost complete datasource.xml:

<!-- Bean definition here -->

<bean id="ourDataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <!-- define connection properties -->       
</bean>


<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="ourDataSource" />
    <property name="packagesToScan" value="our.basepackage" />
    <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>

</bean>

<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" />

Pete
  • 10,720
  • 25
  • 94
  • 139
  • But this won't help unless you start your application. You won't be able to generate static metamodel using this config. – kboom Apr 22 '14 at 13:37
4

We use a similar module layout, but we place the persistence context in the war-part of our application and inject the entitymanager into the DAOs of the modules. Except for unit testing, the modules don't have a PU. We did this because we were afraid, that a transaction spanning multiple modules could cause trouble.

In the DAO

@PersistenceContext
private EntityManager em;

In the persistance.xml you need to enlist all entities with the elements.

<persistence-unit name="myPU">
    <class>com.Entity1</class>      
<class>com.Entity2</class>

etc.

DwB
  • 37,124
  • 11
  • 56
  • 82
stacker
  • 68,052
  • 28
  • 140
  • 210
  • 1
    I see.. I tried that approach and it does work. But doesn't it feel quite cumbersome to always have to update that persistence.xml file (plus the unit test persistence.xml files)? Is there no dynamic way to load it all automatically? – Pete Sep 16 '11 at 11:34
  • 2
    Theoretically there is a runtime auto-scan feature (depends on JPA provider? I am not sure) but I found that not always working. In my company, I wrote a Maven plugin, which run in the war project when building, to automatically generate persistence.xml base on all classes annotated @Entity in the classpath. – Adrian Shum Sep 19 '11 at 11:17
  • Good idea, that's at least somewhat automated and it would be able to supply the latest persistence.xml prior to unit test execution. Can you post some pointer to the key elements of your plugin? Haven't done this before... (I can already think of a second use case for this, namely creating query types for queryDSL, since the latest plugin seems to be broken) – Pete Sep 19 '11 at 12:25
  • I wonder if the the reference implementation and standards have been updated so that we don't have to explicitly list the entities. – Archimedes Trajano Jan 18 '14 at 02:28
  • @ArchimedesTrajano they are, and JPA actually has always been like this. If it doesn't work, it just means that you didn't follow the rules (packaging, ...). – ymajoros Feb 20 '17 at 09:14
3

The classes will be in the class loader.

This so answer Scanning Java annotations at runtime.

Is that what you want? To scan for @Entity annotated and add them to a PersistenceUnit?

Regards.

Community
  • 1
  • 1
ssedano
  • 8,322
  • 9
  • 60
  • 98
3

Well, we' re having a similar problem on our development cycle. If your referencing entities are in another -ejb.jar file (that's our case) you can bind these entities with

<jar-file>relativePathToYourJar/dependent-entities-ejb.jar</jar-file>

tag. Notice that you should also include a persistence.xml under dependent-entities-ejb.jar's META-INF folder. Further information could be found here.

tugcem
  • 1,078
  • 3
  • 14
  • 25
0

I've made a solution like tugcem, but because I am using Maven I would hate to have the jar version numbers in my persistence.xml. The solution I came up with is described here: JPA 2.0: Adding entity classes to PersistenceUnit *from different jar* automatically

Jesper Tejlgaard
  • 827
  • 10
  • 16