We are building ear-files with a large number of jars. Some of them contain persistence.xml files defining persistence units which reference other jars with
<jar-file>other.jar</jar-file>
Now we plan to use Maven in the future and jar names now contain version numbers. This is a huge problem for the mechanism described above: Instead of other.jar
, we need to specify other-1.2.3.jar
. But the correct version number cannot be known when the jar is built because in the construction of the ear, the dependency mediation could replace other-1.2.3.jar
with other-2.3.4.jar
so that my reference in the persistence.xml of the jar becomes invalid.
So my question is: How can I manage the persistence.xml files properly in Maven when building a large ear file?
EDIT:
Let me try to construct a small examples to make my point clearer:
Let us have first-ejb-1.0.0.jar
depending on other-1.2.3.jar
and second-ejb-1.0.0.jar
depending on other-2.3.4.jar
. Both first-ejb-1.0.0.jar
and second-ejb-1.0.0.jar
contain a persistence.xml with a <jar-file>
entry. first-ejb-1.0.0.jar
points to other-1.2.3.jar
and second-ejb-1.0.0.jar
points to other-2.3.4.jar
. So far, so good.
Now I build an ear from first-ejb-1.0.0.jar
and second-ejb-1.0.0.jar
. The dependencies are resolved, but only one of the other-*.jar
can be included in the ear. Say, our dependency mediation chooses other-2.3.4.jar
. Then first-ejb-1.0.0.jar
has a dead <jar-file>
entry, pointing to a non-existent jar.
The maven-ear-plugin
has a property fileNameMapping
by which you can specify the file name mapping to use for all dependencies included in the EAR file. The following values are valid standard
, no-version
, full
, no-version-for-ejb
. The standard
means the filename is the artifactId incl. the version of the artifact. The no-version
means the files is only the artifactId without the version. The full
means the filename is the groupId+artifactId+version of the artifact. The no-version-for-ejb
means the filename is the artifactId without the version in case of EJB type.
So specifying the ear plugin as follows:
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.10.1</version>
<configuration>
<fileNameMapping>no-version</fileNameMapping>
</configuration>
</plugin>
might do the trick for you.
Alternative 2: Externalize persistence.xml
An alternative approach could be to externalize the persistence.xml
. The most straight forward approach would be to create a jar containing the persistence.xml
and put it into the lib folder of the ear:
EAR +
|- lib +
| |- core-module.jar
| \- persistence-module.jar +
| \- META-INF +
| \- persistence.xml
|- ejb1-module.jar
\- ejb2-module.jar
EJB modules may be either jar archives or exploded directories. In the setup as above the persistence.xml
would look like:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="my-persistence-unit">
<!-- Note: it's relative to `persistence-module.jar` file location in EAR -->
<jar-file>../ejb1-module.jar</jar-file>
<jar-file>../ejb2-module.jar</jar-file>
....
</persistence-unit>
</persistence>
A persistence unit that is defined at the level of the EAR is generally visible to all components in the application. However, if a persistence unit of the same name is defined by an EJB-JAR, WAR, or application jar file within the EAR, the persistence unit of that name defined at EAR level will not be visible to the components defined by that EJB-JAR, WAR, or application jar file unless the persistence unit reference uses the persistence unit name #
syntax to specify a path name to disambiguate the reference. When the #
syntax is used, the path name is relative to the referencing application component jar file. For example, the syntax ../lib/persistenceUnitRoot.jar#myPersistenceUnit
refers to a persistence unit whose name, as specified in the name element of the persistence.xml
file, is myPersistenceUnit
and for which the relative path name of the root of the persistence unit is ../lib/persistenceUnitRoot.jar
.
The persistence unit can be specified by annotating the entityManager with @PersistenceContext(unitName = "../lib/persistenceUnitRoot.jar#myPersistenceUnit")
.
So, like you said yourself, by the time you are building EAR, your artifact is built, the jar-file
is already defined and cannot be changed. There are, therefore, two options:
jar-file
must be a specific version - do not allow other versions to be used jar-file
can be any version - exclude version from jar name 1. Strict version
You can force Maven to consider only a specific version of dependency by using single-version range :
<dependency>
<groupId>my.company</groupId>
<artifactId>persistence</artifactId>
<!-- require specifically this version -->
<version>[1.0.2]</version>
</dependency>
2. Exclude version from jar name
You can add jars to EAR with any name, even without version :
<build>
<plugins>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.10.1</version>
<configuration>
<modules>
<ejbModule>
<groupId>my.company</groupId>
<artifactId>persistence</artifactId>
<!-- rename artifact in ear -->
<bundleFileName>persistence.jar</bundleFileName>
</ejbModule>
</modules>
</configuration>
</plugin>
</plugins>
</build>
Since you have a EAR project and an Other project, I assume you have a parent project.
I'm not entirely sure what you mean by
But the correct version number cannot be known when the jar is built because in the construction of the ear, the dependency mediation could replace other-1.2.3.jar with other-2.3.4.jar
I understand that other does not know its version until ear is built (but why?). You can do the following: in the parent project, define a variable to hold the actual final version.
<properties>
<my.final.version>...</my.final.version>
</properties>
Obviously, my.final.version should be set with your actual expected value. Then, Change persistence.xml to this:
<jar-file>other-${my.final.version}.jar</jar-file>
Then, in other 's pom.xml, add this:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
Enabling filtering tells maven to replace variables.
You may wish to fine tune the filtering if you don't want to do filtering on all resources (for performance or what ever other reason). Look for the tag includes under .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.