How to have maven-assembly-plugin respect the excl

2019-02-07 03:46发布

问题:

TL;DR

When some (specific) transitive dependencies are excluded in the POM file but the assembly descriptor is set to fetch all dependencies, the excluded dependencies will be included in assembly. How can I prevent this?

A bit of background

Some dependencies may be tricky to handle because their groupIds and artifactIds change at almost each version (in my case, bouncycastle).

I am retrieving several versions of bouncycastle (138, 1.38, 1.45 and 1.50). My purpose is to eliminate all versions other than 1.50. To be precise, I have one dependency (let's call it some.perfectly.done:job) which imports 1.50 and one other (how.many.castles:do-you-need) which imports all others. They are corporate dependencies, so giving you real groupId:artifactId wouldn't help you for testing.

pom.xml

My dependencies are declared as follows:

<dependency>
    <groupId>some.perfectly.done</groupId>
    <artifactId>job</artifactId>
</dependency>
<dependency>
    <groupId>how.many.castles</groupId>
    <artifactId>do-you-need</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.bouncycastle</groupId>
            <artifactId>*</artifactId>
        </exclusion>
        <exclusion>
            <groupId>bouncycastle</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>

assembly.xml

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
    <id>bin</id>
    <formats>
        <format>zip</format>
    </formats>

    <!-- Adds dependencies to zip package under lib directory -->
    <dependencySets>
        <dependencySet>
            <useProjectArtifact>false</useProjectArtifact>
            <useTransitiveFiltering>true</useTransitiveFiltering>
            <outputDirectory>lib</outputDirectory>
                        <outputFileNameMapping>${artifact.groupId}.${artifact.artifactId}-${artifact.version}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
            <unpack>false</unpack>
        </dependencySet>
    </dependencySets>
    <!-- ... -->
</assembly>

What I get

$ ls *bouncycastle*
bouncycastle.bcmail-jdk14-138.jar       org.bouncycastle.bcmail-jdk15on-1.50.jar  org.bouncycastle.bcprov-jdk15-1.45.jar
bouncycastle.bcprov-jdk14-138.jar       org.bouncycastle.bcpkix-jdk15on-1.50.jar  org.bouncycastle.bcprov-jdk15on-1.50.jar
org.bouncycastle.bcmail-jdk14-1.38.jar  org.bouncycastle.bcprov-jdk14-1.38.jar    org.bouncycastle.bctsp-jdk14-1.38.jar

What I expect (and need)

$ ls *bouncycastle*
org.bouncycastle.bcmail-jdk15on-1.50.jar  org.bouncycastle.bcpkix-jdk15on-1.50.jar  org.bouncycastle.bcprov-jdk15on-1.50.jar

Some possible leads to build upon

The real value in an answer here would be to find a real, generic solution. I am not looking to solve my case, I'd like to find a solution for all people with a similar case.

As such, I'd like to avoid some solutions which would work but are really related to a particular case and often requires to duplicate the POM's logic into the assembly descriptor.

These are however leads that may help if nothing better can be found.

Reproduce the exclusion pattern inside the assembly descriptor

Obviously. In my own case though, quite impractical, except by the intelligent use of includes/excludes. This is not a practical solution.

Make several dependency sets

Note that I am aware this question has already been asked, but the only attempt at an answer is unsatisfactory for my case:

If you have such thing you need to define two dependencySet entries one which include the logback [with useTransitiveDependencies=false] and other.

(by khmarbaise)

Use maven-dependency-plugin

On the same question as above, an approach which I might use if no question is asked has been proposed: first use dependency:copy-dependencies to copy my correct dependencies to a temporary directory, then assemble my zip from this directory.

As a workaround, this is probably the most valid solution, as being generic and not duplicating the logic from the POM in the assembly descriptor, though this makes the build longer.

Side question: Why?

Why does the maven-assembly-plugin behave this way? I did not find any reference to this in the documentation. Is it desired behavior, or is it a (known/unknown) bug?

回答1:

Use the maven-dependency-plugin

Though not the ultimate solution I am looking for, this may help people who are in an emergency.

pom.xml

In your POM, define the following property (adapt the path to your preferences):

<properties>
    <!-- ... -->
    <assembly.lib.directory>${project.build.directory}/lib</assembly.lib.directory>
    <!-- ... -->
</properties>

In the <build/> section:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${assembly.lib.directory}</outputDirectory>
                        <overWriteReleases>false</overWriteReleases>
                        <overWriteSnapshots>false</overWriteSnapshots>
                        <overWriteIfNewer>true</overWriteIfNewer>
                        <prependGroupId>true</prependGroupId>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptors>
                    <descriptor>src/main/assembly/assembly.xml</descriptor>
                </descriptors>
            </configuration>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

assembly.xml

The idea is replacing the dependencySet with a fileSet:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
    <id>bin</id>
    <formats>
        <format>zip</format>
    </formats>

    <!-- Adds dependencies to zip package under lib directory -->
    <fileSets>
        <fileSet>
            <directory>${assembly.lib.directory}</directory>
            <outputDirectory>lib</outputDirectory>
        </fileSet>

        <!-- ... -->
    </fileSets>
</assembly>

Edit: as highlighted by user716401, it is better to execute the dependencies:copy-dependencies in prepare-package phase to ensure it runs before assembly:single.



回答2:

Just facing the same issue right now, it appears that Maven assembly plugin does not honor exclusions using wildcards (*), see MASSEMBLY-762, MASSEMBLY-861 or MASSEMBLY-675. From the last JIRA issue, the problem will be solved in version 3.1.1 of the plugin (see commit). At the moment of writing, the 3.1.1 version is not released : 3.1.0 is the latest version.

Hopefully, the problem can be solved with previous versions.

To do so, just declare the right excluded artifacts instead of *, and it works properly. It can be painful to list all excluded dependencies, but at least I think it is a better solution than the accepted one (less tweaking of Maven phases), especially on multi-modules project with cross dependencies (my case). Moreover, by doing so, you have more control about the dependencies.

Hope that helps, waiting the 3.1.1 version! :)



回答3:

I had the same issue with a spring maven project. Looking at the pom.xml file I had the following two bouncycastle dependencies.

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.50</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.50</version>
</dependency>

I was able to remove bcprov-jdk15on dependency block safely as nothing seemed to be dependent on it since a subsequent build was successful, however, the issue was still present. So I ran the following maven command after updating the dependency plugin version to 2.10 in the pom.xml file from 2.6 that did not work.

mvn dependency:tree -Dverbose -Dincludes=bouncycastle

This gave the output:

[INFO] ------------------------------------------------------------------------
[INFO] Building dhtexasAdmin 1.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.10:tree (default-cli) @ dhtexasAdmin ---
[WARNING] Using Maven 2 dependency tree to get verbose output, 
[INFO] com.dhtexasadmin:dhtexasAdmin:war:1.0
[INFO] \- org.xhtmlrenderer:core-renderer:jar:R8pre2:compile
[INFO]    \- com.lowagie:itext:jar:2.1.0:compile
[INFO]       +- bouncycastle:bcmail-jdk14:jar:136:compile
[INFO]       \- bouncycastle:bcprov-jdk14:jar:136:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.324 s
[INFO] Finished at: 2017-04-21T16:58:52+01:00
[INFO] Final Memory: 16M/39M
[INFO] ------------------------------------------------------------------------

So I had to add an exclusion for the bcprov-jdk14 in the xhtmlrenderer section as below, following the example Maven Dependency Exclusions

<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>core-renderer</artifactId>
    <version>R8pre2</version>
    <exclusions>
        <exclusion>
            <artifactId>bcprov-jdk14</artifactId>
            <groupId>bouncycastle</groupId>
        </exclusion>
    </exclusions>
</dependency>

After which a mvn clean followed by mvn package did the trick.