2

I want to use one class and two JPA persistence units and as such to be able to store data in different tables (or even databases) and different definitions.

According to the JPA2.2 specification this should be possible but I experience weird behaviour. I'm using payara which uses eclipselink.

For a complete description and a reproducer see this github project.

I hope someone can help me.

thehpi
  • 5,683
  • 4
  • 17
  • 24
  • Seems you are using the same entity class files in two different packages - JPA generally packages them all in one jar, so you'd have one persistence.xml with two persistence units defined within it. This seems that you might have weaving turned on as it is running in a server, and the requirements for these two might conflict if the apps using them are not given different classloaders. Try turning off weaving using a persistence property https://www.eclipse.org/eclipselink/documentation/2.4/concepts/app_dev007.htm in one or both persistence units and see. – Chris Jan 18 '22 at 16:00
  • According to the jpa2.2 spec different persistence units can contain the same class. Also these classes can be located in different jars. Even orm.xml can be located and used from different jars. I already tried turning off weaving without success – thehpi Jan 22 '22 at 11:04
  • Not sure your point - are you trying to find a solution? If so, I was trying to help. Otherwise, if it is just spec question - you misinterpreted the point of it only stating 1 orm.xml file can be used. The intent is that only 1 set of mappings is defined - you have two persistence units with two very different and conflicting sets of mappings for the same class, forcing a conflict in how the class must be enhanced for JPA support. What you have is exactly the same as having two different orm.xml files – Chris Jan 23 '22 at 17:20
  • Your help is of course appreciated. It is not a spec question, I'm trying to use one class and store data into different tables. So you are saying that JPA will create one set of mappings so what I'm doing won't work. But I don't think that is the case. I just created a branch 'working-version' in my github project where I changed the orm.xml such that the fields are the same but the table and column names are different, also some transient fields are now basic fields. This version works fine. So maybe changing the primary key is not supported. Could not find this in the spec though. – thehpi Jan 26 '22 at 23:16
  • I am only guessing as I haven't debugged your code, but Change tracking might be getting confused as both use the same change tracking mechanisms woven into the entity, and it isn't incompatible on the 'other' persistence unit. Turning off weaving (or some combination of weaving options, like using deferred change tracking) in one persistence unit would *possibly* allow it to function using an instance you move between persistence units. This is might explain why the tables/column name differences are picked up, but not the values. – Chris Jan 27 '22 at 16:05
  • Try turning off change tracking in one or both persistence units. Another thing to try would be to have one uber persistence unit that maps everything, and then you config it to deploy first - but never use it. This would ensure the entities are woven to cover all fields in a way that might be usable for any other persistence units down stream. That is assuming weaving is the issue (but it has to be, as I have used non-woven classes elsewhere with no issues). – Chris Jan 27 '22 at 16:07
  • I thought I already tested turning off weaving without success but now indeed it works when I turn it off. I have to turn it off in service1. Only in service2 won't work. So weaving is persistence unit dependent but because there is only one class this will produce conflicts. Sounds logical. I don't understand your comment about the uber persistence unit because if weaving is dependent on the persistence unit (and as such also the orm.xml) then I cannot create one persistence unit for both because the whole idea is to have to different table layouts. Or I don't understand your comment. – thehpi Jan 28 '22 at 15:23
  • I tried static weaving in the service1 and service2 module and I can see that it creates new adapted classes for Foo and Bar. The classes are different when attributes are `@Transient` or have `@Id`. So this explains why problem and also why it works with weaving disabled. Thanks for your help @Cris – thehpi Jan 28 '22 at 16:10
  • The one uber persistence unit is just a way to have everything that requires weaving, woven. No transients etc, so that all properties that might have a mapping in one or the other runtime persistence units, has a mapping and gets woven for the 'uber' one - a superset of everything in the other persistence unit. Loading/deploying it first would then ensure the class is woven in way that *might* work for both other persistence units, and let you get the performance benefits from weaving. Its not a simple endeavour, but I believe I remember it being done successfully in the past. – Chris Jan 28 '22 at 16:50

1 Answers1

2

The reason why this does not work is eclipselink weaving. What this does is manipulate the bytecode of entity classes to extend them with functionality so provide all kinds of optimizations.

The problem however is that the resulting 'woven' classes depend on the definitions as defined in the persistence.xml and orm.xml.

This means in my case, because I have two different persistence.xml/orm.xml combinations, I would need two Foo.class and Bar.class files which reflect the different functionality. Of course this won't work.

The solution is to turn off weaving and this can be done using a property in the persistence.xml

<property name="eclipselink.weaving" value="off"/>

If you want to see the actual 'woven' classes you can use static weaving. This can be done using this property

<property name="eclipselink.weaving" value="static"/>

and this maven plugin

<plugin>
    <groupId>de.empulse.eclipselink</groupId>
    <artifactId>staticweave-maven-plugin</artifactId>
    <version>1.0.0</version>
    <executions>
      <execution>
        <phase>process-classes</phase>
        <goals>
          <goal>weave</goal>
        </goals>
        <configuration>
          <persistenceXMLLocation>META-INF/persistence.xml</persistenceXMLLocation>
          <logLevel>FINE</logLevel>
        </configuration>
      </execution>
    </executions>
    <dependencies>
      <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa</artifactId>
        <version>2.7.7.payara-p3</version>
      </dependency>
    </dependencies>
  </plugin>

When you then build the project you can decompile the classes in the jar to see what is happening.

Thanks you Cris for pointing me to eclipselink weaving.

thehpi
  • 5,683
  • 4
  • 17
  • 24