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

Overview

--Maven Shade Plugin is a Maven plugin that combines dependent jar files into a single jar file. --The Maven Shade Plugin will grab the jars in the repository, but not the jars specified in the system scope (on your local filesystem). --This time, set the system scope jar files to be combined into one jar.

file organization

├── lib
│   └── my-lib-999.999.jar ← jar file that exists only locally
├── pom.xml
└── src
    └── main
        ├── java
        │   └── com
        │       └── example
        │           └── App.java
        └── resources
            └── my-app.properties ← General resource file

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.example</groupId>
  <artifactId>my-app</artifactId>
  <version>1.0</version>

  <name>my-app</name>

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

  <dependencies>

    <!--Local jar file-->
    <dependency>
      <groupId>com.example</groupId>
      <artifactId>my-lib</artifactId>
      <version>999.999</version>
      <scope>system</scope>
      <systemPath>${basedir}/lib/my-lib-999.999.jar</systemPath>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.9</version>
      <scope>compile</scope><!-- default scope -->
    </dependency>
  </dependencies>

  <build>
    <resources>
      <!--Default resource settings-->
      <resource>
        <directory>${project.basedir}/src/main/resources</directory>
      </resource>
      <!--Setting to include system scope jar file as a resource-->
      <resource>
        <directory>${project.basedir}</directory>
        <includes>
          <include>lib/*.jar</include>
        </includes>
      </resource>
    </resources>
    <plugins>
      <!--Introduced a plugin that combines dependent jar files into a single jar file-->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>3.2.1</version>
        <configuration>
          <!-- dependency-reduced-pom.Settings that do not generate xml-->
          <createDependencyReducedPom>false</createDependencyReducedPom>
        </configuration>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

Generate a jar file

Generate a jar file with the mvn package command. A warning message is displayed because there is a jar file specified in the system scope, but this time it is ignored.

$ mvn package
[INFO] Scanning for projects...
[WARNING] 
[WARNING] Some problems were encountered while building the effective model for com.example:my-app:jar:1.0
[WARNING] 'dependencies.dependency.systemPath' for com.example:my-lib:jar should not point at files within the project directory, ${basedir}/lib/my-lib-999.999.jar will be unresolvable by dependent projects @ line 27, column 19
[WARNING] 
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING] 
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.

If you check the contents of the generated jar file, it contains lib / my-lib-999.999.jar specified in the system scope. The library specified in the default compile scope is included after being expanded in the class file, while the library specified in the system scope is included as a jar file. Even if you enter it as a jar, it will be loaded properly when it works, so there is no problem.

$ jar -t -f target/my-app-1.0.jar 
META-INF/
META-INF/MANIFEST.MF
lib/
lib/my-lib-999.999.jar
my-app.properties
com/
com/example/
com/example/App.class
META-INF/maven/
META-INF/maven/com.example/
META-INF/maven/com.example/my-app/
META-INF/maven/com.example/my-app/pom.xml
META-INF/maven/com.example/my-app/pom.properties
META-INF/LICENSE
META-INF/NOTICE
META-INF/maven/com.fasterxml.jackson.core/
META-INF/maven/com.fasterxml.jackson.core/jackson-core/
META-INF/maven/com.fasterxml.jackson.core/jackson-core/pom.properties
META-INF/maven/com.fasterxml.jackson.core/jackson-core/pom.xml
META-INF/services/
META-INF/services/com.fasterxml.jackson.core.JsonFactory
com/fasterxml/
com/fasterxml/jackson/
com/fasterxml/jackson/core/
com/fasterxml/jackson/core/Base64Variant.class
com/fasterxml/jackson/core/Base64Variants.class
com/fasterxml/jackson/core/FormatFeature.class
com/fasterxml/jackson/core/FormatSchema.class
(The following is omitted)

As a side effect, the original-my-app-1.0.jar, which normally doesn't include dependent jar files, also contains system-scoped jar files. Therefore, you need to be careful when using original-*. Jar.

$ jar -t -f target/original-my-app-1.0.jar
META-INF/
META-INF/MANIFEST.MF
lib/
com/
com/example/
lib/my-lib-999.999.jar
my-app.properties
com/example/App.class
META-INF/maven/
META-INF/maven/com.example/
META-INF/maven/com.example/my-app/
META-INF/maven/com.example/my-app/pom.xml
META-INF/maven/com.example/my-app/pom.properties

System scope is not recommended in the first place

Maven – Introduction to the Dependency Mechanism

System Dependencies Important note: This is deprecated.

Reference material

Recommended Posts

Combine system-scoped jar files into one with Maven Shade Plugin
Combine system-scoped jar files into one with Maven Dependency 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