Creating Skinny Modules

This is a bit like skinny WARs, but taken to the next level and applied to EAR modules of type:

Starting with version 3.2.0, the Maven EAR Plugin supports referencing external JARs packaged within the EAR via the Class-Path setting in EAR module MANIFEST.MF.

You need to change the EAR project's pom.xml to package those JARs in the EAR and to use the skinnyModules parameter.

Note: In this example we package all JARs into a libs/ directory within the EAR. This is just to distinguish between Java EE modules (which will be packaged in the root of the EAR) and Java libraries (which are packaged in libs/). Also, we use non-standard outputFileNameMapping to shorten names of files packaged in EAR and to keep them close to the names used in local repository for a better readability.

<project>
  ...
  <dependencies>
    <!-- This is the JAR we want to share -->
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>shared-jar</artifactId>
      <version>1.0.0</version>
    </dependency>
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>war</artifactId>
      <version>1.0.0</version>
      <type>war</type>
    </dependency>
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>rar</artifactId>
      <version>1.0.0</version>
      <type>rar</type>
    </dependency>
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>sar</artifactId>
      <version>1.0.0</version>
      <type>sar</type>
    </dependency>
  </dependencies>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-ear-plugin</artifactId>
        <version>3.3.0</version>
        <configuration>
          <outputFileNameMapping>@{artifactId}@-@{version}@@{dashClassifier?}@.@{extension}@</outputFileNameMapping>
          <defaultLibBundleDir>libs/</defaultLibBundleDir>
          <skinnyModules>true</skinnyModules>
        </configuration>
      </plugin>
    </plugins>
  </build>
  ...
</project>

Your EAR will contain something like this:

 .
 |-- META-INF
 |   `-- application.xml
 |-- libs
 |   `-- shared-jar-1.0.0.jar
 |-- war-1.0.0.war
 |-- sar-1.0.0.sar
 `-- rar-1.0.0.rar

If you look inside the copies of war-1.0.0.war, rar-1.0.0.ear and sar-1.0.0.sar, that are packaged within the EAR, you will see that they no longer contain WEB-INF/lib/shared-jar-1.0.0.jar, shared-jar-1.0.0.jar and lib/shared-jar-1.0.0.jar files respectively.

Also, if you inspect the MANIFEST.MF of WAR, SAR and HAR modules of EAR you will notice that the Class-Path entry has been modified or added, if it was missing, and now has a reference to libs/shared-jar-1.0.0.jar.

If an archive representing the EAR module has non-standard location of libraries, then this location can be configured using the libDirectory property.

Here is example for SAR which contains libraries at the root of the archive (refer to sarModule for description of libDirectory property):

<project>
  ....
  <dependencies>
    <!-- This is the JAR we want to share -->
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>shared-jar</artifactId>
      <version>1.0.0</version>
    </dependency>
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>war</artifactId>
      <version>1.0.0</version>
      <type>war</type>
    </dependency>
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>rar</artifactId>
      <version>1.0.0</version>
      <type>rar</type>
    </dependency>
    <!-- SAR having shared-jar-1.0.0.jar at the root -->
    <dependency>
      <groupId>com.acme</groupId>
      <artifactId>sar</artifactId>
      <version>1.0.0</version>
      <type>sar</type>
    </dependency>
  </dependencies>
  ...
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-ear-plugin</artifactId>
        <version>3.3.0</version>
        <configuration>
          <outputFileNameMapping>@{artifactId}@-@{version}@@{dashClassifier?}@.@{extension}@</outputFileNameMapping>
          <defaultLibBundleDir>libs/</defaultLibBundleDir>
          <skinnyModules>true</skinnyModules>
          <modules>
            <sarModule>
              <groupId>com.acme</groupId>
              <artifactId>sar</artifactId>
              <libDirectory>/</libDirectory>
            </sarModule>
          </modules>
        </configuration>
      </plugin>
    </plugins>
  </build>
  ...
</project>