JPA 2.0: Adding entity classes to PersistenceUnit *from different jar* automatically
Asked Answered
I

8

38

I have a maven-built CDI-based Java SE app, which has a core module, and other modules.
Core has the persistence.xml and some entities. Modules have additional entities.

How can I add the entities to the spotlight of the persistence unit?

I have read Hibernate manual, http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/configuration.html#setup-configuration-packaging

I have also seen these SO questions

I am looking for a solution where Hibernate would scan for all loaded classes, or, would pick up some config file form the other jars (like e.g. CDI does with beans.xml).

My app does not use Spring. I don't insist on portability - I'll stick with Hibernate.

  • Is there some such solution?
  • Is there's a way to create a PU from persistence.xml and add classes to it programmatically?
  • Can I add @Entity classes to EntityManagerFactory after it was created?

Update: I found in org.​hibernate.​ejb.​Ejb3Configuration:

public Ejb3Configuration configure(String persistenceUnitName, Map integration)  

http://docs.jboss.org/hibernate/entitymanager/3.6/javadocs/

Intranuclear answered 17/6, 2011 at 2:16 Comment(1)
Maybe this could be a solution: #15026802Dottie
H
11

There are several way to solve it:

  1. As described in Do I need <class> elements in persistence.xml?, you can set hibernate.archive.autodetection property and Hibernate should be able to look up all annotated classes from classpath. However, that's not JPA spec compliant.

  2. If you are using Spring, from Spring 3.1.2 (or probably even a bit earlier), in LocalContainerEntityManagerFactoryBean, you can define packageToScan which will ask LocalContainerEntityManagerFactoryBean to scan in classpath to find all annotated classes. Again, not JPA spec compliant.

  3. I was using Maven as build tools. Years before, I have written a little plugin which will generate persistence.xml during build process. The plugin will scan from build classpath to find out all annotated classes, and list them in the generated persistence.xml. This is most tedious but the result is JPA spec compliant. One drawback (which does not apply to most people I believe) is the lookup happens in build-time, not runtime. That means if you are having an application for which entities JARs are provided only at deploy/runtime but not build time, this approach is not going to work.

Hegyera answered 7/12, 2012 at 3:55 Comment(3)
For point 3, seems someone has made something similar which is publicly avaialble: github.com/ljnelson/jpa-maven-pluginHegyera
For point 2, you need to disable the persistenceUnit that is usually configured in the LocalContainerEntityManagerFactoryBean. That is, if a persistenceUnit is specified, then Spring will ignore the packageToScan setting.Novercal
There is a more recent fork for the jpa-maven-plugin here: github.com/iSnow/jpa-maven-pluginHon
S
8

Ejb3Configuration has been removed in 4.3.0. If you don't want to create a Hibernate's Integrator, you can use the property hibernate.ejb.loaded.classes.

properties.put(org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, entities);
Persistence.createEntityManagerFactory("persistence-unit", properties);

Where entities is a List<Class> of entity classes.

Sisterhood answered 9/1, 2014 at 11:2 Comment(2)
LOADED_CLASSES setting is marked as "Internal use only" and is not defined in jar downloaded with Maven.Mayonnaise
Hey, i'm currently using this to have one persistence.xml pointing to several jar-files! Any idea why it was removed?Concretion
H
6

I have a slightly different setup where I am placing persistence.xml in the WAR file but some of its dependencies includes @Entity annotated classed to include in the persistence unit.

I have solved my problem using Maven a bit like Adrian Shum described in #3, but using the element to include the jars to be scanned for @Entity annotations.

I added a property to my-web/pom.xml for each dependency including extra entities. All my jars are part of a Maven multiproject build so for me it looks like.

<properties>
    <common.jar>common-${project.version}.jar</common.jar>
    <foo.jar>foo-${project.version}.jar</foo.jar>
</properties>

I thereafter add the following to the persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" ... >
    <persistence-unit name="primary">
        <jta-data-source>java:jboss/datasources/mysource</jta-data-source>

        <jar-file>lib/${common.jar}</jar-file>
        <jar-file>lib/${foo.jar}</jar-file>

        ...
    </persistence-unit>
</persistence>

Lastly I configure the maven-resource-plugin in web/pom.xml to replace the $expressions in persistence.xml with the properties set in the POM

<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
      <includes>
        <include>**/persistence.xml</include>
      </includes>
    </resource>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>false</filtering>
      <excludes>
        <exclude>**/persistence.xml</exclude>
      </excludes>
    </resource>
  </resources>
  ...
</build>
Hols answered 26/3, 2014 at 15:13 Comment(0)
D
3

I've experienced the same issue and unfortunately there is no easy solution, it basically looks like JPA wasn't designed to be used this way. One of solutions is to have just one persistence.xml per top-level project (application). It's kind of similar to log4j configuration. The persistence.xml has to list all classes (using <class>) or, if it's not Java SE app, jar files (using <jar-file>) that are used by the application. This way you can put entities from multiple modules (jars) into single persistence unit. The drawback is obvious: you have to list everything in one file.

EDIT: I have (possibly) found another solution that uses XML mapping files, check it out here: Multiple jars, single persistence unit solution?

Dottie answered 10/10, 2012 at 14:7 Comment(0)
J
1

You can do use this concept: https://wiki.eclipse.org/Packaging_and_Deploying_EclipseLink_JPA_Applications_(ELUG)

<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
   <persistence-unit name="mamcaPU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>mamcaPU</jta-data-source>
        <mapping-file>/META-INF/common-layer-mappings.xml</mapping-file>
    </persistence-unit>
</persistence>

common-layer-mappings.xml

<entity-mappings>   
   <entity class="vub.be.mamca.entity.Surveyactorgrouptable"></entity>
   <entity class="vub.be.mamca.entity.Userevaluationelicitationtable"></entity>
   <entity class="vub.be.mamca.entity.Userevaluationtable"></entity>
   <entity class="vub.be.mamca.entity.Usertable"></entity>
   <entity class="vub.be.mamca.entity.Userweightelicitationtable"></entity>
</entity-mappings>
Jag answered 7/1, 2017 at 10:54 Comment(0)
M
0

Possible duplicate, see my SO question.

We faced the same problem and the only way we found was to accumulate all entities in one persistence.xml for the final (web-)application.

At the same time we define separate persistence.xml files in our test resources so we can run acceptance tests per module.

Melessa answered 19/10, 2012 at 13:10 Comment(0)
B
0

I have a similar problem and solved it with Hibernate's Integrator SPI:

@Override
public void integrate(Configuration configuration,
    SessionFactoryImplementor sessionFactory,
    SessionFactoryServiceRegistry serviceRegistry) {

    configuration.addAnnotatedClass(MyEntity.class);
    configuration.buildMappings();
}

The Integrator is provided as Java service.

Becket answered 9/12, 2013 at 17:12 Comment(0)
B
-4

for JPA 2+ this does the trick

<jar-file></jar-file>

scan all jars in war for annotated @Entity classes

Botelho answered 18/9, 2014 at 9:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.