简体   繁体   中英

Version number in jar name - how to handle persistence.xml?

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:

  1. jar-file must be a specific version - do not allow other versions to be used
  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM