The first module example-project is a spring project that contains a JPA entity + a service class and a DAO class for this entity. (I configure this entity inside an orm.xml file + the persistence unit inside a persist.xml file).
The second module example-project-boot is a simple spring-boot project that calls the service class of the first module.
Please find below the codebase of this project (you can also find it here).
When I run this project with IntelliJ or Eclipse, everything works as expected.
When I package this same project as a fat jar, then I try to run it, I am getting an
and this method is returning /Users/mabbas/example-project-parent/example-project-boot/target/example-project-boot-0.0.1-SNAPSHOT.jar
/Users/mabbas/example-project-parent/example-project-boot/target/example-project-boot-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/example-project.jar (the root of persist.xml is example-project and not example-project-boot).
Because of this result, I think that the entity defined inside example-project.jar is never loaded and then the exception is thrown.
I have first created a spring-boot issue here, but it seems that this problem is more about spring-orm than spring-boot.
That setup is super unusual, have you considered migrating it (i.e. let Spring Boot creates the datasource rather than doing everything yourself? or configure things at least in one place?). Looking at the code you are creating the entity manager in one module and the persistence unit in another. Yet the persistence unit is linked so you have an inverse dependency from a configuration standpoint.
The URL that is computed is actually correct (remember, it is a default URL that we compute as a fallback because JPA requires one). I've tried to force the use of orm.xml by adding the following to your java configuration but didn't manage to start your application.
I completely agree with you; it is super unusual. But unfortunately, in my real project, I have a dependency on three legacy JARs, each of them declares a persistent unit, and those JARs cannot be modified.
I made a test by intercepting the call, in my IDE, to method
it resolves the problem. This is why I was thinking about a bug in determinePersistenceUnitRootUrl.
As a workaround to this problem, and instead of building a fat jar, i can extract all the dependencies of my project to a 'lib' directory and point the classpath to this directory when running the application. It resolves my problem but of course, it is not the perfect solution.
Understood. Just to confirm, the behaviour of determinePersistenceUnitRootUrl is correct but won't work in a Spring Boot app. I am actually surprised that setting the path to mapping resources doesn't work either. Perhaps Juergen Hoeller can chime in here?
I have a very similar setup as Mohamad, in my case using EclipseLink.
The persistence.xml is in an inner jar of the spring-boot fat jar, configured with exclude-unlisted-classes to false.
When spring configures the PersistenceUnitInfo it uses PersistenceUnitReader.determinePersistenceUnitRootUrl which gives as a root URL the fat jar (and not the inner jar containing the persistence.xm).
When EclipseLink tries to load it's entities through classpath scanning, it's not going to get down to inner jars but will only consider classes from the fat jar.
In turn, entities present in the inner jar that holds the persistence.xml file are not seen.
I tested to change the root url returned by PersistenceUnitReader.determinePersistenceUnitRootUrl to point to the inner jar and it fixes the issue.
@snicoll if you confirm that it is the correct behavior, may be I should open an issue in EclipseLink project ?
It's quite misleading because it works well inside IDE's but fails when running as a spring boot fat jar.