Maven: How to exclude an artifact from fat-jar? - maven

I know about the <exclusions> attribute that is placed inside a <dependency> to exclude specific artifacts from a dependency but the problem with this is that one has to find out all the dependencies that might have the artifact that is desired to be excluded and then one by one exclude that artifact from all those dependencies. Isn't there a simpler way of specifying in the pom that a certain artifact should not end up in the fat-jar no matter what dependency is trying to include it?

I found the answer here and here
Use artifactSet exclusions:
<artifactSet>
<excludes>
<exclude>classworlds:classworlds</exclude>
<exclude>junit:junit</exclude>
<exclude>jmock:*</exclude>
<exclude>*:xml-apis</exclude>
<exclude>org.apache.maven:lib:tests</exclude>
<exclude>log4j:log4j:jar:</exclude>
</excludes>
</artifactSet>
and also use filters to exclude classes:
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>junit/framework/**</include>
<include>org/junit/**</include>
</includes>
<excludes>
<exclude>org/junit/experimental/**</exclude>
<exclude>org/junit/runners/**</exclude>
</excludes>
</filter>

Related

Maven shade plugin does not exclude an artifact

I need to exclude the log4j artifact from the shade plug-in to avoid the log4j vulnerability, however, the exclude tag under artifactSet does not seem to work. Any suggestion to fix this?
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
~~
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude>*:log4j-core:jar</exclude>
</excludes>
</artifactSet>
~~~
I keep getting below error:
Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:3.2.4:shade (default) on project : Execution default of goal org.apache.maven.plugins:maven-shade-plugin:3.2.4:shade failed: Plugin org.apache.maven.plugins:maven-shade-plugin:3.2.4 or one of its dependencies could not be resolved: Could not find artifact org.apache.logging.log4j:log4j-core:jar:2.13.0
I meet the same problem, and finally solved by maven-shade-plugin config. In your case, you want to exclude log4j-core, your filter config must put outside of artifactSet as below.
find log4j-core class path prefix, for example org/slf4j/;
put this class path prefix in filter exclude rule, run cmd mvn package
use vim your-target.jar to check exclude success or not, you will find that org/slf4j has gone.
for more exclude info, pls see https://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>org/slf4j/**</exclude>
</excludes>
</filter>

outputFileNameMapping and exclude problem with maven-assembly-plugin (3.1.0)

I have a multi-module maven project with two separate "main" projects (projectA and projectB) from which I would like to build a zip file (incl. all dependencies).
One of the dependencies "subProjectC" I would like to exclude. This is the relevant portion of assembly.xml:
<moduleSets>
<moduleSet>
<!-- Enable access to all projects in the current multimodule build! -->
<useAllReactorProjects>true</useAllReactorProjects>
<includes>
<include>${project.groupId}:projectA</include>
<include>${project.groupId}:projectB</include>
</includes>
<excludes>
<exclude>${project.groupId}:subProjectC</exclude>
</excludes>
<binaries>
<outputFileNameMapping>${module.artifactId}.${module.extension}</outputFileNameMapping>
<outputDirectory>project-root/lib</outputDirectory>
<unpack>false</unpack>
</binaries>
</moduleSet>
</moduleSets>
subProjectC turns up in the zip file nevertheless.
Also, all dependencies show up with their full version, e.g. projectA-0.0.1-SNAPSHOT.jar, although the outputFileNameMapping should have prevented this...
What am I doing wrong?
Ok, it seems "outputFileNameMapping" only affects those artifacts that are specified in the "includes" list...

Exclude all but some artifacts with Maven shade

Is there a way to create a fat jar with Maven that only contains some but not all dependency artifacts?
More concretely, I want to have two executions of shade: one that includes com.acme:* and one that includes all else. The point is to have two jars -- one with all my code and one with all the 3rd party deps. The latter is easy:
<artifactSet>
<excludes>
<exclude>com.acme:*</exclude>
</excludes>
</artifactSet>
But the former isn't. Because exclusions are processed after inclusions and everything is included by default, the following would not work:
<artifactSet>
<excludes>
<exclude>*:*</exclude>
</excludes>
<includes>
<include>com.acme:*</include>
</includes>
</artifactSet>
Any Maven mavens out there? (sorry but I had to)

Maven dynamically exclude class with same name from different dependencies

There are two classes com.package.A, one coming from
<dependency>
<groupId>com.package</groupId>
<artifactId>art1</artifactId>
</dependency>
and one coming from
<dependency>
<groupId>com.package</groupId>
<artifactId>art2</artifactId>
</dependency>
Notice that the artifact ids are different.
For different Maven profiles, I want to exclude one version and just keep the other version. I am using the Shade Plugin.
With the maven-shade-plugin, it is possible to exclude certain class for specific dependencies. This is configured with the help of the filters property:
Archive Filters to be used. Allows you to specify an artifact in the form of a composite identifier as used by artifactSet and a set of include/exclude file patterns for filtering which contents of the archive are added to the shaded jar.
In your case, to exclude the class com.package.A from the dependency art2, you can have:
<filters>
<filter>
<artifact>com.package:art2</artifact>
<excludes>
<exclude>com/package/A.class</exclude>
</excludes>
</filter>
</filters>
To make this dynamic, i.e. select at build-time which com.package.A class you want to keep, you don't need to use a profile. You can use a Maven property that will hold the artifact id of the dependency to filter. In your properties, add
<properties>
<shade.exclude.artifactId>art2</shade.exclude.artifactId>
</properties>
The shade.exclude.artifactId property will hold the artifact id of the dependency to filter. By default, this configuration would select art2. Then, in the <filter> configuration of the Shade Plugin, you can use <artifact>com.package:${shade.exclude.artifactId}</artifact>.
Here's a full configuration of this in action:
<build>
<plugins>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<id>shade</id>
<goals>
<goal>shade</goal>
</goals>
<phase>package</phase>
<configuration>
<filters>
<filter>
<artifact>com.package:${shade.exclude.artifactId}</artifact>
<excludes>
<exclude>com/package/A.class</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<shade.exclude.artifactId>art2</shade.exclude.artifactId>
</properties>
Running mvn clean package will create an uber jar with the A.class from art1 since the one from art2 was excluded. And then, running mvn clean package -Dshade.exclude.artifactId=art1 will keep this time A.class from the dependency art2 since the one from art1 was excluded.

In Maven how to exclude resources from the generated jar?

When I create an executable jar with dependencies (using this guide), all properties files are packaged into that jar too. How to stop it from happening? Thanks.
UPDATE: I tried to exclude them using the Maven resources plugin, but then my application won't find the properties files when I run it in Eclipse (right click on the module -> Run As -> Java Application)
UPDATE: Thanks for your useful answers. I think I'd better spend time to learn Maven, for now I just choose the simplest solution.
To exclude any file from a jar / target directory you can use the <excludes> tag in your pom.xml file.
In the next example, all files with .properties extension will not be included:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>*.properties</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
</build>
By convention, the directory src/main/resources contains the resources that will be used by the application. So Maven will include them in the final JAR.
Thus in your application, you will access them using the getResourceAsStream() method, as the resources are loaded in the classpath.
If you need to have them outside your application, do not store them in src/main/resources as they will be bundled by Maven. Of course, you can exclude them (using the link given by chkal) but it is better to create another directory (for example src/main/external-resources) in order to keep the conventions regarding the src/main/resources directory.
In the latter case, you will have to deliver the resources independently as your JAR file (this can be achieved by using the Assembly plugin). If you need to access them in your Eclipse environment, go to the Properties of your project, then in Java Build Path in Sources tab, add the folder (for example src/main/external-resources). Eclipse will then add this directory in the classpath.
This calls exactly for the using the Maven JAR Plugin
For example, if you want to exclude everything under src/test/resources/ from the final jar, put this:
<build>
<plugins>
<!-- configure JAR build -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<excludes>
<exclude>src/test/resources/**</exclude>
</excludes>
</configuration>
</plugin>
...
Files under src/test/resources/ will still be available on class-path, they just won't be in resulting JAR.
Put those properties files in src/test/resources. Files in src/test/resources are available within Eclipse automatically via eclipse:eclipse but will not be included in the packaged JAR by Maven.
Exclude specific pattern of file during creation of maven jar using maven-jar-plugin.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3</version>
<configuration>
<excludes>
<exclude>**/*.properties</exclude>
<exclude>**/*.xml</exclude>
<exclude>**/*.exe</exclude>
<exclude>**/*.java</exclude>
<exclude>**/*.xls</exclude>
</excludes>
</configuration>
</plugin>
Do you mean to property files located in src/main/resources? Then you should exclude them using the maven-resource-plugin. See the following page for details:
http://maven.apache.org/plugins/maven-resources-plugin/examples/include-exclude.html
Another possibility is to use the Maven Shade Plugin, e.g. to exclude a logging properties file used only locally in your IDE:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin-version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>log4j2.xml</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
This will however exclude the files from every artifact, so it might not be feasible in every situation.
When I create an executable jar with dependencies (using this guide), all properties files are packaged into that jar too. How to stop it from happening? Thanks.
Properties files from where? Your main jar? Dependencies?
In the former case, putting resources under src/test/resources as suggested is probably the most straight forward and simplest option.
In the later case, you'll have to create a custom assembly descriptor with special excludes/exclude in the unpackOptions.
here is another solution to exclude all files in resources folder, the final configuration looks like:
<build>
<!-- exclude all files in resources-->
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>**/**</exclude>
</excludes>
<filtering>false</filtering>
</resource>
</resources>
<!-- other configurations/plugins in the pom.xml-->
</build>
or we can use includes to only package some file or folder.
But this method has a side effect. IDE will also exclude the resource files in target/classes folder. maven-jar-plugin only affect jar file.
I found a better solution to execludes resourses folder using maven-jar-plugin, here we use includes:
<build>
<plugins>
<!-- configure JAR build -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<includes>
<include>**/*.class</include>
</includes>
</configuration>
</plugin>
...

Resources