[JAVA] Combine system-scoped jar files into one with Maven Dependency Plugin

Overview

--Assuming a situation where the dependent JAR file is placed locally and \ <scope > system \ </ scope > is specified in pom.xml --Set the JAR file created by the mvn package command to contain all the class files in the dependent JAR files. --This environment: Apache Maven 3.6.2

Method

Set as follows in Maven Dependency Plugin.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <phase>prepare-package</phase>
      <goals>
        <goal>unpack-dependencies</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/classes</outputDirectory>
        <includeArtifactIds>ajd4jp,jdom</includeArtifactIds>
      </configuration>
    </execution>
  </executions>
</plugin>

When mvn package is executed with this setting, class files etc. are expanded from dependent JAR files such as libraries and copied to the directory specified by outputDirectory before creating the JAR file. When you create a JAR file, the class files that were in the dependent JAR files are also combined into one JAR file.

Illustration

Prepare pom.xml file.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>sample</artifactId>
  <packaging>jar</packaging>
  <version>1.0.0</version>
  <name>sample</name>

  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
      <!-- Apache Maven Dependency Plugin -->
      <!-- https://maven.apache.org/plugins/maven-dependency-plugin/ -->
      <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-dependency-plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <phase>prepare-package</phase>
            <goals>
              <goal>unpack-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/classes</outputDirectory>
              <includeArtifactIds>ajd4jp,jdom</includeArtifactIds>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>

    <dependency>
      <groupId>ajd4jp</groupId>
      <artifactId>ajd4jp</artifactId>
      <version>1.4.6.2019</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/lib/ajd4jp-1.4.6.2019.jar</systemPath>
    </dependency>

    <dependency>
      <groupId>jdom</groupId>
      <artifactId>jdom</artifactId>
      <version>1.1.3</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/lib/jdom-1.1.3.jar</systemPath>
    </dependency>

  </dependencies>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

</project>

Create a JAR file with the mvn package command.

$ mvn package

If you expand the created target / sample.jar, you can see that it contains the class files that were included in the jar file of the specified library.

$ unzip target/sample.jar
Archive:  target/sample.jar
   creating: META-INF/
  inflating: META-INF/MANIFEST.MF    
   creating: orrery/
   creating: iso/
   creating: org/
   creating: org/jdom/
   creating: org/jdom/xpath/
   creating: org/jdom/input/
   creating: org/jdom/output/
   creating: org/jdom/adapters/
   creating: org/jdom/filter/
   creating: org/jdom/transform/
   creating: ajd4jp/
   creating: ajd4jp/orrery/
   creating: ajd4jp/orrery/tool/
   creating: ajd4jp/iso/
   creating: ajd4jp/util/
   creating: ajd4jp/format/
   creating: format/
   creating: com/
   creating: com/example/
  inflating: orrery/package-info.class  
  inflating: Copyright.txt           
  inflating: iso/package-info.class  
  inflating: org/jdom/IllegalAddException.class  
  inflating: org/jdom/DefaultJDOMFactory.class  
  inflating: org/jdom/EntityRef.class  
(Omission)

Combine with Maven Assembly Plugin

By introducing Maven Assembly Plugin, not only JAR files with system scope but also dependent JAR files in the repository can be collected together.

Prepare pom.xml file.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>sample</artifactId>
  <packaging>jar</packaging>
  <version>1.0.0</version>
  <name>sample</name>

  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
      <!-- Apache Maven Dependency Plugin -->
      <!-- https://maven.apache.org/plugins/maven-dependency-plugin/ -->
      <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-dependency-plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <phase>prepare-package</phase>
            <goals>
              <goal>unpack-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/classes</outputDirectory>
              <includeArtifactIds>ajd4jp,jdom</includeArtifactIds>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <!-- Apache Maven Assembly Plugin -->
      <!-- http://maven.apache.org/plugins/maven-assembly-plugin/ -->
      <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-assembly-plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <mainClass>com.example.App</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>

    <dependency>
      <groupId>ajd4jp</groupId>
      <artifactId>ajd4jp</artifactId>
      <version>1.4.6.2019</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/lib/ajd4jp-1.4.6.2019.jar</systemPath>
    </dependency>

    <dependency>
      <groupId>jdom</groupId>
      <artifactId>jdom</artifactId>
      <version>1.1.3</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/lib/jdom-1.1.3.jar</systemPath>
    </dependency>

    <dependency>
      <groupId>org.twitter4j</groupId>
      <artifactId>twitter4j-core</artifactId>
      <version>4.0.7</version>
      <scope>compile</scope>
    </dependency>

  </dependencies>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

</project>

Create a JAR file with the mvn package command.

$ mvn package

If you expand the created target / sample-jar-with-dependencies.jar, you can see that it contains the class files included in the jar file of the library specified in the system scope and compile scope.

$ unzip target/sample-jar-with-dependencies.jar 
Archive:  target/sample-jar-with-dependencies.jar
  inflating: META-INF/MANIFEST.MF    
   creating: twitter4j/
   creating: twitter4j/util/
   creating: twitter4j/util/function/
   creating: twitter4j/auth/
   creating: twitter4j/management/
   creating: twitter4j/json/
   creating: twitter4j/api/
   creating: twitter4j/conf/
   creating: META-INF/maven/
   creating: META-INF/maven/org.twitter4j/
   creating: META-INF/maven/org.twitter4j/twitter4j-core/
   creating: orrery/
   creating: iso/
   creating: org/
   creating: org/jdom/
   creating: org/jdom/xpath/
   creating: org/jdom/input/
   creating: org/jdom/output/
   creating: org/jdom/adapters/
   creating: org/jdom/filter/
   creating: org/jdom/transform/
   creating: ajd4jp/
   creating: ajd4jp/orrery/
   creating: ajd4jp/orrery/tool/
   creating: ajd4jp/iso/
   creating: ajd4jp/util/
   creating: ajd4jp/format/
   creating: format/
   creating: com/
   creating: com/example/
   creating: META-INF/maven/com.example/
   creating: META-INF/maven/com.example/sample/
  inflating: META-INF/LICENSE.txt    
  inflating: twitter4j/JULLoggerFactory.class  
  inflating: twitter4j/SymbolEntity.class  
  inflating: twitter4j/MediaEntity.class  
  inflating: twitter4j/TwitterBase.class  
  inflating: twitter4j/Dispatcher.class  
  inflating: twitter4j/HttpClientBase.class  
(Omission)

Reference material

Recommended Posts

Combine system-scoped jar files into one with Maven Dependency Plugin
Combine system-scoped jar files into one with Maven Shade Plugin
Build Jar files in plugin folder with one click in IntelliJ
Getting started with Gradle (until you create a Java project and combine external libraries into one executable JAR)
Getting started with Maven (until you create a Java project and combine external libraries into a single executable JAR)
Automate integration testing with Maven Failsafe plugin