I would like to generate a jar containing package 'com.x' and a class (let's say, Utils.class) from another package 'com.y'. I am able to bundle the complete package com.y in the shaded jar but I only want the one class. It doesn't seem to work with I have below. I have also tried by providing the path to the class: com/bar/cli/pol/Utils.class without any luck.
<dependencies>
<dependency>
<groupId>com.x</groupId>
<artifactId>foo</artifactId>
</dependency>
<dependency>
<groupId>com.y</groupId>
<artifactId>bar</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>com.x:foo</include>
<include>com.y:bar:**/Utils.class</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I got this working by doing the following:
<configuration>
<finalName>myshadedjar</finalName>
<artifactSet>
<includes>
<include>com.x:foo</include>
<include>com.y:bar</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>com.y:bar</artifact>
<includes>
<include>com/bar/cli/pol/Utils.class</include>
</includes>
</filter>
</filters>
Related
Each time I run maven package to produce an updated jar, it creates an "original" jar file, as well as the updated one.
This is particularly an issue for me due to the fact that I'm running the compiled jar automatically, and they're both trying to start.
All I want created is the ${project.artifactId}-${project.version}-shaded.jar file produced, and not the "original" one. Is there a way to have it just overwrite without making a backup (I'm assuming that's what it's doing)?
How can I solve this?
Here is my pom:
<groupId>com.spiromarshes</groupId>
<artifactId>LiveDebugTest</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>LiveDebugTest</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<defaultGoal>clean package</defaultGoal>
<plugins>
<plugin>
<version>3.6.1</version>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<outputDirectory>${dir}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<repositories>
<repository>
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
</repository>
<repository>
<id>sonatype</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
Solved by using <outputFile>${dir}/${project.artifactId}.jar</outputFile> under the configuration section for maven-shade-plugin.
Full example, for context:
<plugin>
<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>
</execution>
</executions>
<configuration>
<outputFile>${dir}/${project.artifactId}.jar</outputFile>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/MANIFEST.MF</exclude>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</plugin>
The original Maven intended file name for the package includes the version number.
There is a shade-plugin configuration that not only prevents the "original"-prefixed file name, but also achieves the original Maven package name.
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<finalName>${project.artifactId}-${project.version}</finalName>
.. ..
.. more shade configuration ..
.. ..
</configuration>
</execution>
</executions>
</plugin>
I am a newbie when it comes to Maven, and so really struggling to solve the following problem because a colleague with real knowledge in this area has moved onto fresh pastures. Would really appreciate pointers to where I might be going wrong; I realise there must be lots of questions on StackOverflow about Maven & Eclipse classpaths, but having searched some of them, I need to ask in my own terms because of my lack of experience - sorry.
Some files are attached which I hope will be enough to form the equivalent of an SSCCE in pure Maven POM terms. The Java itself is irrelevant and subject to obvious confidentiality, but I can provide more info if needed.
So I have a small Maven project providing my own API for a third-party software protection dongle (DinKey, from Microcosm). The project is called dinkeypro with half a dozen of my classes which reference the manufacturer's class that reads/writes the dongle, namely DinkeyPro.class. This class is held inside DinkeyPro.JAR, which I reference as a dependency using a SystemPath and, as you can see from the following POM, I've tried two different SystemPath specs. Just for reference, note that the manufacturer requires the package structure for the class file to be:
uk/microcosm/dinkeydongle/DinkeyPro.class
Here is the POM for dinkeypro, with irrelevant dependencies removed for brevity/readability:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xyz</groupId>
<artifactId>dinkeypro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>DinkeyPro API</name>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>dinkeyjar</groupId>
<artifactId>dinkeyjar</artifactId>
<scope>system</scope>
<version>1.0</version>
<!--<systemPath>${basedir}\src\main\resources\DinkeyPro.jar</systemPath>-->
<systemPath>C:\Dev\core_dinkeypro\src\main\resources\DinkeyPro.jar</systemPath>
</dependency>
</dependencies>
</project>
Access to the dongle API is required from two other Maven projects, 'client' and 'server'. They both appear to specify the exact same Maven dependency on dinkeypro (see POMs below) although, admittedly, client and server are structured differently in terms of folders (server uses the more recognisable src/main/java paradigm but the client does not, and I'm wondering if this is the source of the problem.
What happens is that the client project runs and successfully reads the dongle via my API, whilst the server throws:
Exception in thread "main" java.lang.NoClassDefFoundError: uk/microcosm/dinkeydongle/DinkeyPro
at com.xyz.dinkeypro.SoftwareProtectionReadOnlyAgent.isProtectionDevicePresent(SoftwareProtectionReadOnlyAgent.java:73)
at com.xyz.soft.ServerApp.initialize(ServerApp.java:1200)
at com.xyz.soft.ServerApp.main(ServerApp.java:310)
Caused by: java.lang.ClassNotFoundException: uk.microcosm.dinkeydongle.DinkeyPro
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 3 more
Here is the POM for client, which runs OK:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xyz.soft</groupId>
<artifactId>client</artifactId>
<version>0.5.0-SNAPSHOT</version>
<name>client</name>
<description>client</description>
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target</outputDirectory>
<resources>
<resource>
<directory>${basedir}/target-resource</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>${basedir}/target-resource</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</resource>
</resources>
<delimiters>
<delimiter>${*}</delimiter>
</delimiters>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>client</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.xyz.client.ClientApp</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.xyz</groupId>
<artifactId>dinkeypro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
Here is the POM for the server which has the classpath problem:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xyz.soft</groupId>
<artifactId>server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>server</name>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>additional-target-resources</id>
<phase>pre-integration-test</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<includeEmptyDirs>true</includeEmptyDirs>
<outputDirectory>${basedir}/target</outputDirectory>
<resources>
<resource>
<directory>${basedir}/target-resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>${basedir}/target-resources</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/*.properties</exclude>
</excludes>
</resource>
</resources>
<delimiters>
<delimiter>${*}</delimiter>
</delimiters>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<id>run</id>
<phase>integration-test</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.xyz.server.ServerApp</mainClass>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>ebmsCore</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.xyz.server.ServerApp</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.xyz</groupId>
<artifactId>dinkeypro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
I've examined the content of both the built client and server JAR files. They both contain DinkeyPro.JAR at the root of their own JAR, and both can navigate from the root to com.xyz.dinkeypro.
So, confusion reigns. Can anyone shed any light on what I've done wrong ? As you can see, I am valiantly trying to keep with Maven, simply so that future changes to dinkeypro API can just roll through to client and server (and any other projects that may need it one day...). However, if this gets to be too much of a minefield, I may just have to place a copy of DinkeyPro.JAR in the resources folder of the server project so that I can move on.
Many thanks
I am trying to create a deploy-able jar which using Apache's commons-lang3. However my AWS cluster where my Hadoop is does not contain this library so I get a classNotFoundException. I figured I needed to manually add that dependency in but I am having issues working with the maven shade plugin (I was recommended to use this) My current pom file looks like this :
<dependency>
<groupId>org.apache.pig</groupId>
<artifactId>pig</artifactId>
<version>0.12.0-cdh5.2.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifact>org.apache.commons:commons-lang3</artifact>
<includes>
<include>org/apache/commons/commons-lang3/3.4/*</include>
</includes>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
I want a completely normal jar with the addition of the commons-lang3 library embedded inside. Is there something I am doing incorrectly?
To include whitelisted jars you need to do the following:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>org.apache.commons:commons-lang3</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Using maven-shade-plugin, is there a way to exclude a dependency (which is not provided) and all its transitive dependencies?
For example :
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>some-artifact</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
... other dependencies
</dependencies>
and 1)
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<artifactSet>
<includes>
<include>*:*</include>
</includes>
<excludes>
<exclude>com.example:some-artifact</exclude>
</excludes>
</artifactSet>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
or 2)
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<artifactSet>
<includes>
<include>*:*</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>com.example:some-artifact</artifact>
<excludes>
<exclude>**</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Those don't work.
All the transitive dependencies of com.example:some-artifact are added to the final jar.
Note that I don't want to set the scope of com.example:some-artifact to provided.
Run "shade" from within a profile, and mark your dependency as provided only in that profile. For example:
<profiles>
<profile>
<id>shadeProfile</id>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>some-artifact</artifactId>
<version>1.23</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedClassifierName>shaded</shadedClassifierName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
When you run mvn -PshadeProfile package it will treat your dependency as provided (and thus omit its dependencies), and it will use the classifier "shaded" so you can use this as a dependency in other modules.
I tried following configuration, and it worked for me also:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>client-${artifactId}</finalName>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*</exclude>
</excludes>
</filter>
</filters>
<artifactSet>
<excludes>
<exclude>org.apache.jmeter:*</exclude>
<exclude>com.fasterxml.jackson.core:jackson-databind:*</exclude>
<exclude>com.fasterxml.jackson.module:jackson-module-scala_2.11:*</exclude>
</excludes>
</artifactSet>
</configuration>
</plugin>
You must take in mind that by default all dependencies COMPILE will be included. But if you set artifacts in artifactSet includes, only those will be considered and the rest will be excluded (dependencies and its transitive dependencies)
Sometimes it's easier include only the dependencies you need than exclude all the rest.
Maven's assembly plugin enables the creation of a big jar including all dependencies with descriptorRef jar-with-dependencies.
How can one exclude some of these dependencies? It seems like it does not have such a configuration? Is there another solution?
Add the <scope>provided</scope> to the dependencies you don't want included in the jar-with-dependencies, e.g.
<dependency>
<groupId>storm</groupId>
<artifactId>storm</artifactId>
<version>0.6.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
You should use the excludes option available in dependencySet.
Follow below.:
Example in your pom.xml:
...
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.3</version>
<configuration>
<finalName>../final/${project.artifactId}</finalName>
<archive>
<manifest>
<addClasspath>false</addClasspath>
<mainClass>com.entrerprise.App</mainClass>
</manifest>
</archive>
<descriptors>
<descriptor>src/main/resources/jar-with-deps-with-exclude.xml</descriptor>
</descriptors>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
...
Now in your new file jar-with-deps-with-exclude.xml (where dependencySet lives):
<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
<id>jar-with-dependencies-and-exclude-classes</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
<excludes>
<exclude>junit:junit</exclude>
<exclude>commons-cli:commons-cli</exclude>
<exclude>org.apache.maven.wagon:wagon-ssh</exclude>
</excludes>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<outputDirectory>/</outputDirectory>
<directory>${project.build.outputDirectory}</directory>
</fileSet>
</fileSets>
</assembly>
That's all.
This example indicates one way to do this:
<dependencySets>
<dependencySet>
....
<excludes>
<exclude>commons-lang:commons-lang</exclude>
<exclude>log4j:log4j</exclude>
</excludes>
</dependencySet>
....
</dependencySets>
Essentially we would use the excludes option available in dependencySet.
See also: https://maven.apache.org/plugins/maven-assembly-plugin/assembly-component.html
Another alternative is to switch to the much more feature rich maven-shade-plugin which can do this without any external assembly files or marking as "provided" (which may not be what you want as it forces users to have that dependency in their pom). Here is an example:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<artifactSet>
<excludes>
<exclude><group-id>:<artifact-id>:<classifier></exclude>
<exclude>org.apache.logging.log4j:log4j-core</exclude>
</excludes>
</artifactSet>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
https://maven.apache.org/plugins/maven-shade-plugin/index.html
Note that this wont make a jar-with-dependencies but rather an original-jar... and then just the regular output jar. This plugin even lets you filter out specific classes.