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?
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.
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 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>
$ 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
$ ls *bouncycastle*
org.bouncycastle.bcmail-jdk15on-1.50.jar org.bouncycastle.bcpkix-jdk15on-1.50.jar org.bouncycastle.bcprov-jdk15on-1.50.jar
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.
Obviously. In my own case though, quite impractical, except by the intelligent use of includes
/excludes
. This is not a practical solution.
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)
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.
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?
Open the dependency POM and find the transitive dependency you want to exclude. Copy groupId and artifactId . In your project POM, underneath your active dependency, enter exclusions and using code completion paste the copied info of the dependency you want to exclude.
Multiple transitive dependencies can be excluded by using the <exclusion> tag for each of the dependency you want to exclude and placing all these exclusion tags inside the <exclusions> tag in pom. xml. You will need to mention the group id and artifact id of the dependency you wish to exclude in the exclusion tag.
In the build section you can define plugins for which you need to build the artifacts in your project.
Conclusion – By using the <scope>provided</scope> for a dependency you can globally exclude the dependency from getting packaged in the application lib instead it's loaded by the server classloader thus avoiding any LinkageError or ClassCastExceptions from arising due to jar conflicts.
Version 3.1.1
of the maven-assembly-plugin
have been released Jan 01, 2019. It solves the JIRA issues mentioned in my answer below (kept for history or for users that cannot upgrade the plugin). With this version, maven-assembly-plugin
now honors wildcards in dependencies exclusions. Simply upgrade the plugin.
maven-assembly-plugin
version <= 3.1.0It appears that Maven assembly plugin (version <= 3.1.0) 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 version <= 3.1.0.
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! :)
maven-dependency-plugin
Though not the ultimate solution I am looking for, this may help people who are in an emergency.
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>
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With