DEV Community

Vincent A. Cicirello
Vincent A. Cicirello

Posted on

How to Use the Maven Shade Plugin if Your Project Uses Java Platform Module System

The Apache Maven Shade Plugin is perhaps the easiest way to produce a jar-with-dependencies, a single jar file containing everything your Java application needs to run, including all of its dependencies. These are sometimes also referred to as "uber jars" or "fat jars." There are some issues that may arise though if you are not careful in how you configure it. For example, if your project uses Java Platform Module System (JPMS) modules, then if you are not careful you may end up with a jar-with-dependencies that doesn't function for those who wish to consume it in their projects.

My intention in this post is not to encourage the use of such uber jars. Ideally, consumers of your library should use a tool for dependency management, such as build tools like Maven (or Gradle) that handles importing transitive dependencies. However, for those that don't use a dependency management tool, offering them a jar-with-dependencies provides a convenient option to ensure that they download everything they need. Another scenario where I see a potential benefit is for applications, where distributing your application as a single jar file simplifies things for your users.

Table of Contents: The remainder of this post is organized as follows:

Basic Configuration

This is not a general tutorial on Maven. I'm assuming that you know the basics of configuring your Maven pom.xml. Here is a minimal example of configuring the Maven Shade Plugin to build a jar-with-dependencies during the package phase. Someplace inside of <build><plugins> and </plugins></build> insert the following:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.3.0</version>
    <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <shadedClassifierName>jar-with-dependencies</shadedClassifierName>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>
Enter fullscreen mode Exit fullscreen mode

Now whenever you run mvn package or any other command that includes the package phase, in addition to the regular jar, you will get a jar-with-dependencies.

Configuration if You Use JPMS Modules

First, be aware that if your project uses JPMS modules that the resulting jar-with-dependencies will only be usable on the classpath. In fact, to get it to work, we need to filter out the module-info.class of our library, as well as the module-info.class of every dependency. Why? There is a one-to-one mapping of JPMS module to jar file. The JPMS specification doesn't allow a single jar to contain multiple JPMS modules. If we attempt to use the configuration in the previous section above, our jar-with-dependencies will include one module-info.class file, either from our library (or application) or from one of its dependencies. We'll essentially end up with whichever module-info.class is the last that the Maven Shade Plugin attempts to include.

The problem with having an arbitrarily chosen module-info.class is that it controls what Java packages are exported from the module, as well as what Java packages are required by the module. To deal with this, we need to configure the Maven Shade Plugin to exclude all of the module-info.class files. The Maven Shade Plugin provides a filtering feature that we can use to accomplish this. So adjust the configuration to use a filter to exclude the module-info.class file from all artifacts that you are combining into the jar-with-dependencies with the following.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.3.0</version>
    <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <shadedClassifierName>jar-with-dependencies</shadedClassifierName>
        <filters>
            <filter>
                <artifact>*:*</artifact>
                <excludes>
                    <exclude>module-info.class</exclude>
                </excludes>
            </filter>
        </filters>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>
Enter fullscreen mode Exit fullscreen mode

With the above, the jar-with-dependencies can be used by consumers of our library on the classpath in a non-JPMS project. The regular jar file is not affected by this, and will continue to include the module-info.class that defines our JPMS module, enabling appropriate use within JPMS projects.

Live Example

To see a live example, you can consult the pom.xml of one of my projects. Here is the GitHub repository:

GitHub logo cicirello / Chips-n-Salsa

A Java library of Customizable, Hybridizable, Iterative, Parallel, Stochastic, and Self-Adaptive Local Search Algorithms

Chips-n-Salsa - A Java library of customizable, hybridizable, iterative, parallel, stochastic, and self-adaptive local search algorithms

Chips-n-Salsa Mentioned in Awesome Machine Learning

Copyright (C) 2002-2022 Vincent A. Cicirello.

Website: https://chips-n-salsa.cicirello.org/

API documentation: https://chips-n-salsa.cicirello.org/api/

Publications About the Library DOI
Packages and Releases Maven Central GitHub release (latest by date) JitPack
Build Status build docs CodeQL
JaCoCo Test Coverage coverage branches coverage
Security Snyk security score Snyk Known Vulnerabilities
DOI DOI
License GitHub
Support GitHub Sponsors Liberapay Ko-Fi

How to Cite

If you use this library in your research, please cite the following paper:

Cicirello, V. A., (2020). Chips-n-Salsa: A Java Library of Customizable, Hybridizable, Iterative, Parallel, Stochastic, and Self-Adaptive Local Search Algorithms. Journal of Open Source Software, 5(52), 2448, https://doi.org/10.21105/joss.02448 .

Overview

Chips-n-Salsa is a Java library of customizable, hybridizable, iterative, parallel, stochastic, and self-adaptive local search algorithms. The library includes implementations of several stochastic local search algorithms, including simulated annealing, hill climbers, as well as constructive search algorithms such as stochastic sampling. Chips-n-Salsa now also includes genetic algorithms as well as evolutionary algorithms more generally. The library very extensively supports simulated annealing. It includes several classes for representing solutions to a variety of optimization problems. For…

Where You Can Find Me

Follow me here on DEV:

Follow me on GitHub:

GitHub logo cicirello / cicirello

My GitHub Profile

Vincent A Cicirello

Vincent A. Cicirello

Sites where you can find me or my work
Web and social media Personal Website LinkedIn DEV Profile
Software development Github Maven Central PyPI Docker Hub
Publications Google Scholar ORCID DBLP ACM Digital Library IEEE Xplore ResearchGate arXiv

My bibliometrics

My GitHub Activity

If you want to generate the equivalent to the above for your own GitHub profile, check out the cicirello/user-statistician GitHub Action.




Or visit my website:

Vincent A. Cicirello - Professor of Computer Science

Vincent A. Cicirello - Professor of Computer Science at Stockton University - is a researcher in artificial intelligence, evolutionary computation, swarm intelligence, and computational intelligence, with a Ph.D. in Robotics from Carnegie Mellon University. He is an ACM Senior Member, IEEE Senior Member, AAAI Life Member, EAI Distinguished Member, and SIAM Member.

favicon cicirello.org

Top comments (0)