How can I import the Maven shade plugin properly? - java

I am very frustrated. I've spent a long time trying to compile a Maven project into an Uber/Fat jar file using the Maven shade plugin, but I still keep getting "mvn is not recognized as an internal or external command" error in command prompt. Here are the important bits of my pom.xml:
<build>
<plugins>
<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>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>*my main class*</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
I don't know what I'm doing wrong. I am going into my project's directory using Windows Command Prompt and typed "mvn clean install" but it doesn't seem to work. I am new to Maven, I generally use Gradle. Has the plugin not loaded? Am I doing something wrong? Or am I just being stupid as always?
Any help appreciated! Thanks in advance!

For Maven to work on command line, you need to
download and unzip it to some directory
Add the bin directory in that directory to your PATH
If you have done that, you may have a type or may need to restart your system.

Related

JMH + Maven. BenchmarkList gets in wrong JAR

I've encountered a little problem with a project that I considered finished.
It includes three parts -- the main class for which the whole project was created (a quadruple-precision floating-point number with necessary arithmetic), a set of tests for it, and a benchmarking tool for it which uses JMH. Accordingly, the pom.xml is supposed to build three jar-files -- Quadruple-1.0.0.jar, Quadruple-1.0.0-tests.jar, and benchmarks.jar. And it does, but the problem is that it puts BenchmarkList in the Quadruple-1.0.0-tests.jar instead of benchmarks.jar.
Thereafter, an attempt to execute the benchmarks running the benchmarks.jar fails with the message
Exception in thread "main" java.lang.RuntimeException: ERROR: Unable to find the resource: /META-INF/BenchmarkList
at org.openjdk.jmh.runner.AbstractResourceReader.getReaders(AbstractResourceReader.java:98)
at org.openjdk.jmh.runner.BenchmarkList.find(BenchmarkList.java:124)
at org.openjdk.jmh.runner.Runner.internalRun(Runner.java:253)
at org.openjdk.jmh.runner.Runner.run(Runner.java:209)
at org.openjdk.jmh.Main.main(Main.java:71)
Below is the relevant part of the pom.xml:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<javac.target>1.8</javac.target>
<jmh.version>1.29</jmh.version>
<uberjar.name>benchmarks</uberjar.name>
<junit.jupiter.minorVersion>2.0</junit.jupiter.minorVersion>
</properties>
...
<build>
<plugins>
....
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${uberjar.name}</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
<filters>
<filter>
<!--
Shading signed JARs will fail without this.
http://stackoverflow.com/questions/999489/invalid-signature-file-when-attempting-to-run-a-jar
-->
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>test-jar</id>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
<mainClass>
com.mvohm.quadruple.test.QuadTest
</mainClass>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
...
</build>
At the same time in a neighbor folder I have a very similar project, which is actually just a previous version of the benchmarking tool, and it builds and works fine. After a number of attempts to figure out what is the reason of such a difference in their behavior, their poms became almost identical. The only difference is that the separate benchmarking project has one additional dependency (to import Quadruple), and the names of the projects are different, and there's no test subfolder in the src folder of the benchmarking project, thus the Quadruple_Benchmarks-0.0.1-SNAPSHOT-tests.jar contains nothing except MANIFEST.MF.
What may be the reason of getting BenchmarlList to the wrong jar? Generally, who is responsible for putting it in the benchmarks.jar and not in any other jar?
If any additional information turns out to be relevant and can help clarify the situation, I'm ready to promptly provide it. The complete poms (in their previous states, yet with the same behavior) are accessible at github:
https://github.com/m-vokhm/Quadruple/blob/master/pom.xml, (main project)
https://github.com/m-vokhm/QuadrupleAddendum/blob/master/QuadBenchmarks/pom.xml (old benchmarks)

How to create Jar file from Maven project in eclipse

I have a Maven project, but I am not familiar to Maven. I wanted to create an executable JAR file from this Maven project to use it in another project by eclipse. How can I do this?
To build jar From Eclipse, Right click on your maven project name then
Run as > Maven install
Right click maven project,
choose Run As-> Maven Build ....
Type package in the Goals box.
Click Run.
Command line approach:
In the root of the project (the maven project), should be a pom.xml. Go to that root and run mvn package. If this is correct, there should be a new folder with the name target in the root of the project. Inside this folder there should be the jar file.
First of all, you have to remember about security in Java. Many jars would not work in fatjars, if they got included in other projects (for example bouncycastle).
If you are doing a simple executable jar that has no libs in it, and requires all of them on classpath, default build (when packageing tag is set to jar) would be ok, and just require a proper manifest.
If you need all libs inside (fatjar), you need to configure it yourself.
There are several plugins for it, for example maven-shade-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.RSA</exclude>
<exclude>META-INF/*.INF</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>my.package.MainClass</Main-Class>
<Class-Path>.</Class-Path>
</manifestEntries>
</transformer>
</transformers>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>fat</shadedClassifierName>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
Add following into pom.xml file and Run as Maven Install. This worked for me.
pom.xml
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.pohan.App</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Now Run as Maven Install.
if you want with the terminal to do it type
mvn package
and a line before "BUILD SUCCESS" the directory of the
Install maven - https://maven.apache.org/download.cgi
Goto your project in eclipse
Run -> Maven install

Maven shade copy WEB-INF

Using maven-shade-plugin I am trying to create a project file structure as follows:
The problem is that the following pom configuration is not creating the WEB-INF directory.
<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>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<createDependencyReducedPom>true</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.my.package.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
Basically I need to copy my web.xml file, classes and lib files into a directory called WEB-INF in the root of the project.
Update: SORRY, I copied the wrong plugin from my pom into the original question!
Update: If I add the packaging from the pom declaration: <packaging>war</packaging> The WEB-INF file structure is completed as per the OQ. However, with this declaration the com directory now does not contain my packages so the main class cannot be found.
How it looks with the <packaging>war</packaging>:
How it should look:
maven-assembly plugin allows much more flexibility, it would be easily accomplished by using assembly plugin
See
assembly descriptor examples
There are lots of possible answer to achieve the desired effect with maven. However, based on the update I gave I found that adding the maven-antrun-plugin with the following solved my issue:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>move-main-class</id>
<phase>compile</phase>
<configuration>
<tasks>
<copy todir="${project.build.directory}/${project.artifactId}">
<fileset dir="${project.build.directory}/classes/">
</fileset>
</copy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>

Create runnable jar with maven 3.1 using maven-dependency-plugin doesn't create runnable jar

Using Maven 3.1
Eclipse Helios
Aspekt:
Try to create a runable jar file using maven-jar/dependency-plugins.
Problem:
After creating jar file and dependencies there are NoCLassDefFoundErrors when i try to start the jar file with command
java -jar program.jar
But the Class/File is available in ./dependency-jars folder???
I Also tried following command:
java -cp ./dependency-jars -jar program.jar
This didn't work, too.
Question:
Do you know why jvm can not find these classes? What is wrong?
pom.xml:
<build>
<finalName>program</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>dependency-jars/</classpathPrefix>
<mainClass>de.test.MainCLass</mainClass>
</manifest>
</archive>
<outputDirectory>${package-target-folder}</outputDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<executions>
<execution>
<goals>
<goal>javadoc</goal>
</goals>
<phase>package</phase>
<id>create-javadoc</id>
<configuration>
<charset>UTF-8</charset>
<outputDirectory>${package-target-folder}/docs</outputDirectory>
<reportOutputDirectory>${package-target-folder}/docs</reportOutputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${package-target-folder}/dependency-jars/</outputDirectory>
</configuration>
</execution>
<execution>
</execution>
</executions>
</plugin>
</plugins>
</build>
[UPDATE]
The created MANIFEST.MF looks like
Manifest-Version: 1.0
Built-By: ahausden
Build-Jdk: 1.7.0_25
Class-Path: dependency-jars/spring-core-4.0.0.RELEASE.jar dependency-j
ars/commons-logging-1.1.1.jar dependency-jars/spring-jdbc-4.0.0.RELEA
SE.jar dependency-jars/spring-beans-4.0.0.RELEASE.jar dependency-jars
/spring-tx-4.0.0.RELEASE.jar dependency-jars/spring-oxm-4.0.0.RELEASE
.jar dependency-jars/spring-batch-core-2.2.0.RELEASE.jar dependency-j
ars/xstream-1.3.jar dependency-jars/xpp3_min-1.1.4c.jar dependency-ja
rs/jettison-1.1.jar dependency-jars/spring-aop-3.2.0.RELEASE.jar depe
ndency-jars/spring-context-3.2.0.RELEASE.jar dependency-jars/spring-e
xpression-3.2.0.RELEASE.jar dependency-jars/spring-batch-infrastructu
re-2.2.0.RELEASE.jar dependency-jars/spring-retry-1.0.2.RELEASE.jar d
ependency-jars/spring-batch-test-2.2.0.RELEASE.jar dependency-jars/co
mmons-io-1.4.jar dependency-jars/commons-dbcp-1.2.2.jar dependency-ja
rs/commons-pool-1.3.jar dependency-jars/commons-collections-3.2.jar d
ependency-jars/spring-test-4.0.0.RELEASE.jar dependency-jars/javax.in
ject-1.jar dependency-jars/slf4j-log4j12-1.6.1.jar dependency-jars/sl
f4j-api-1.6.1.jar dependency-jars/log4j-1.2.16.jar dependency-jars/sp
ring-orm-4.0.0.RELEASE.jar dependency-jars/aopalliance-1.0.jar depend
ency-jars/mariadb-java-client-1.1.1.jar dependency-jars/hibernate-cor
e-4.3.1.Final.jar dependency-jars/jboss-logging-3.1.3.GA.jar dependen
cy-jars/jboss-logging-annotations-1.2.0.Beta1.jar dependency-jars/jbo
ss-transaction-api_1.2_spec-1.0.0.Final.jar dependency-jars/dom4j-1.6
.1.jar dependency-jars/xml-apis-1.0.b2.jar dependency-jars/hibernate-
commons-annotations-4.0.4.Final.jar dependency-jars/hibernate-jpa-2.1
-api-1.0.0.Final.jar dependency-jars/javassist-3.18.1-GA.jar dependen
cy-jars/antlr-2.7.7.jar dependency-jars/jandex-1.1.0.Final.jar depend
ency-jars/hibernate-annotations-3.5.6-Final.jar dependency-jars/hiber
nate-commons-annotations-3.2.0.Final.jar dependency-jars/hibernate-jp
a-2.0-api-1.0.0.Final.jar dependency-jars/javassist-3.12.1.GA.jar dep
endency-jars/commons-cli-1.3-20140221.042048-103.jar
Created-By: Apache Maven 3.1.0
Main-Class: de.test.MainClass
Archiver-Version: Plexus Archiver
And the last "line" is as line separator. Seems that the MANIFEST.MF file looks a little bit corrupt, doesn't it?
Not sure what's going on, but this is what my pom looks like for building a runnable jar using shade:
<build>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>schema.xsd</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>stand-alone</shadedClassifierName>
<artifactSet>
<excludes>
<exclude>org.slf4j:slf4j-api:jar:</exclude>
<exclude>org.slf4j:slf4j-log4j12:jar:</exclude>
<exclude>org.slf4j:jcl-over-slf4j:jar:</exclude>
<exclude>commons-logging:commons-logging:jar:</exclude>
<exclude>commons-logging:commons-logging-api:jar:</exclude>
</excludes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<finalName>MyFinalRunnableJarName</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>class.with.main.Method</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
</transformers>
</configuration>
</plugin>
</plugins>
</build>
The simplest solution is to use maven-assembly-plugin like this:
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<!-- NOTE: We don't need a groupId specification because the group is
org.apache.maven.plugins ...which is assumed by default.
-->
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
[...]
</project>
Try to provide entry into manifest file:
Main-Class: YourClassWithMainMethod
And also see this post. So you can make it manually and see the difference.
If dependency-jars is a directory also try:
java -cp ./dependency-jars/* -jar program.jar
I still cannot post comments, so please show what are these NoCLassDefFoundErrors.
And have you tried to do the same jar file manually from Eclipse and see the difference?
You have dependency dependency-jars/commons-cli-1.3-20140221.042048-103.jar in your manifest but you wrote you have SNAPSHOT version in directory. And there is only commons-cli:commons-cli:20040117.000000 in maven central.
#robermann please see this post (to work it should be in double quotes though)
Are you sure your java version, launched at command line, is equal or greater than that used by maven when compiling? try java -version
via command line, go to the parent dir of "dependency-jars" and run: java -jar program.jar
Ok, i solved the second/updated Problem:
I first startet to use eclipse with maven plugin to create the runable jar file. This runs in the described problems.
After all i tried to use maven 3.1 from console application and after all it works.
Seems that eclipse maven plugin has some problems.
Use this command to create jar file of any maven project.
mvn clean compile install

Build a "light" jar on multi-module project

I have a multi-module project which I assemble with the assembly plugin to a fat jar. Thank works fine so far, but now I want to build another jar that only consists of special packages of the dependencies of the uber-pom.
An example:
I have 3 deps on sub-projects and I want to have a jar with
com.mycompany.api.*,
com.mycompany.settings.*
com.mycompany.public.*
but not
com.mycompany.internal.*
These packages are distributed through the 3 deps.
Any chance to realize something like that with the assembly plugin?
Thanks,
Jan
The Shade plugin should probably be able to do something like that.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<includes>
<include>com/mycompany/api/*</include>
<include>com/mycompany/settings/*</include>
<include>com/mycompany/public/*</include>
</includes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

Categories

Resources