Search code examples
mavenexecutable-jarmaven-assembly-pluginmaven-shade-pluginfatjar

Maven assembly : ignore signed dependencies


I am posting this issue because I am currently working on Maven to build fat jars. All of our projects are plugins, so our goal is to get all dependencies from MANIFEST.MF files in order to build fat jars.
The first problem is some of our dependencies are in the system scope (com.google.guava for instance), and as we build intermediate jars which are then required by further project, they are in the provided scope. So I decided to avoid the shade-plugin, as scopes do not seem configurable with it.
I chose to work with maven-assembly as it seemed to be the most expressive way to handle our builds, with the following custom assembly file to collect dependencies from all scopes :

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
    <id>jar-with-dependencies</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>provided</scope>
        </dependencySet>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>system</scope>
        </dependencySet>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <unpack>true</unpack>
            <scope>runtime</scope>
        </dependencySet>
    </dependencySets>
</assembly>

I had to set unpack to true because we need on executable jar, and it also seemed impossible to deal easily with "jar-in-jar" loading when using maven-assembly (if you have any solution for that, I'm interested too).
The problem I have is that for a specific project where we require bundle org.apache.commons.lang;bundle-version="2.6.0" in one of our MANIFEST.MF files, and it leads somehow to the exception :

Execution make-assembly of goal org.apache.maven.plugins:maven-assembly-plugin:3.3.0:single failed: invalid SHA1 signature file digest for org/apache/commons/lang/math/JVMRandom.class

When I investigated, I found in the dependency a signed manifest file + ECLIPSE_.RSA & ECLIPSE_.SF, so I tried to exclude at least those files when unpacking with :

...
            <unpackOptions>
                <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                </excludes>
            </unpackOptions>
...

for each tag, but I still got the same error.
In the end, I am kind of stuck about what I should do. Ignore the dependency (which will cause errors when running the final jar) ? Find a way to ignore such errors ?
Thanks for reading by the way.


Solution

  • Well after further investigation, here is a short summary.
    Tycho stores the external dependencies in the system scope, and the module dependencies in the provided scope, so if you want executable jars, you need to find a plugin that captures these.
    Here is the plugins I tested :

    1. Maven-assembly

    This plugin seemed adapted to tycho as it is configurable to capture all the dependencies you need (as described in the question).
    But it does not provide any JAR in JAR support, so either you can unpack all dependencies but you might have some dependency conflicts, or you can keep all dependencies packed but you will need to write your own JAR in JAR ClassLoader (as Capsule or One Jar, except they are not updated anymore).

    2. Maven-shade

    This plugin apparently provides such JAR in JAR support, but it only works in the runtime scope, and I could not find a way to change this default scope, so I also had to move on.

    3. Maven-capsule

    This plugin works, but in some cases, I need to have redundant dependencies in some pom.xml files, and capsule has not been updated for five years so it seems like a bad idea to depend on it.

    4. Maven-bundle

    This plugin requires to add .bnd files, so it does not answer my need for a MANIFEST-first plugin.

    5. Spring-boot-maven

    It is the only plugin that made it work almost instantaneously. It repackages a bundle and all its dependencies & provides a custom ClassLoader to make it executable. You can include system scope in the plugin's options, it is often updated, and it has its own precise documentation.
    The only strange thing is that when repackaging, it takes all dependencies in the classpath/MANIFEST.MF files & suffixes them with .jar, which can lead to .jar.jar files if jar files are directly included in the classpath, as well as package-lib/ folders.

    Hope this will help further maven users !