Maven build appears to be overwriting classes when creating jar-with-dependencies - java

I'm using maven to build a jar-with-dependencies jar. One of the vendor jar files in the project has similarly named classes with different case. For example aM.class and am.class.
When the build creates the "jar-with-dependencies" jar file, only aM.class is present. am.class appears to have been overwritten or skipped. The same thing happens for every similarly named classes files.
We have a couple work-arounds, but I'm curious why the maven build is behaving this way. Thanks
My pom:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.mytest.MyTest</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>
<dependencies>
<dependency>
<groupId>com.bloomberglp</groupId>
<artifactId>blpapi3</artifactId>
<version>3.10.1</version>
</dependency>
</dependencies>

Same class conflict issue will happen with maven-assembly-plugin, this plugin extracts all dependency jars into raw classes, and group it together.It works in project with less dependencies only, for large project with many dependencies, it will cause Java class name conflict issue, check here.
Better way to use maven-shade-plugin if you have many jars with potentially could conflict. You can also you relocating feature in shade plugin to explicitly avoid conflicts

Related

Create a single jar containing dependencies and Javadoc with Maven

I'm trying to create a jar file with both Javadoc and dependencies that I can use in another project.
I can use mvn package with the following pom.xml plugins:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
</configuration>
<version>2.7</version>
<executions>
<execution>
<id>attach-javadoc</id>
<phase>prepare-package</phase>
<goals>
<goal>javadoc</goal>
</goals>
<configuration>
<destDir>docs</destDir>
<reportOutputDirectory>${project.build.directory}/classes/</reportOutputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
This creates a Javadoc as well as add the Javadoc and the dependencies to a single jar. However, the Javadoc doesn't actually seem to work as when I hover over the Classes and Methods in Eclipse it says This element neither has attached source nor attached Javadoc and hence no Javadoc could be found.
When I export the jar using the eclipse exporter I can get the Javadoc to work but because my jar is not runnable I can't package it with my dependencies and so it doesn't actually work.
If anyone has any idea how I can get this to work, tell me why my understanding is flawed or can point me in the right direction I will be very appreciative.
Don't do that. Your library jar does not get to have opinions about which dependency versions to include and how. Let Maven do its job and pull them in transitively in the client projects. (Publish the Maven artifacts if that's the problem; it looks like you're trying to do this part manually.)
Also don't include Javadoc; it's not necessary at runtime and bulks up the deployment package unnecessarily.
Overall, when there's a Standard Way of doing things, it's usually there for a reason and best to go along with it, if for no other reason than that's what everyone you interact with expects.

Packaging ONLY the necessary Classes from Dependencies

How can I use the maven shade or assembly plugin to automatically determine which classes are needed from the dependency jars, and copy ONLY these classes into the build. So far I have had no luck getting it to automatically find which classes will be necessary for my build.
I can use minimizeJar and include and exclude tags to specify which classes get added but what I really want it to do is something like this:
Copy all of the imports of all of my classes into the jar, and copy all of their imports, and all of their import's imports and so on.
Am I thinking about the problem all wrong? How can I get maven to automatically minimize the jar size depending on which imports are used? (please don't just say this maven plugin) because I am already at a dead end, I need an example of what to add to my pom to accomplish these tasks.
ProGuard can remove unused classes and even more.
ProGuard is a free Java class file shrinker, optimizer, obfuscator, and preverifier. It detects and removes unused classes, fields, methods, and attributes. It optimizes bytecode and removes unused instructions. It renames the remaining classes, fields, and methods using short meaningless names.
First, you should package a jar with dependencies. It can be easily done with maven-assembly-plugin:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.4</version>
<configuration>
<archive>
<manifest>
<mainClass>com.test.HelloWorld</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>
Then configure proguard to optimize generated jar. For maven projects, use proguard-maven-plugin:
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<version>2.0.10</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>proguard</goal></goals>
</execution>
</executions>
<configuration>
<injar>${project.build.finalName}-jar-with-dependencies.jar</injar>
<outjar>${project.build.finalName}-small.jar</outjar>
<outputDirectory>${project.build.directory}</outputDirectory>
<options>
<option>-dontobfuscate</option>
<option>-dontwarn com.google.**</option>
<option>-keep public class com.test.HelloWorld {public static void main(java.lang.String[]);}</option>
</options>
<libs>
<lib>${java.home}/lib/rt.jar</lib>
</libs>
</configuration>
</plugin>
After these steps run
mvn clean install
and check target/<artifact name>-small.jar - it should contain only classes that are actually used in runtime.
Please note that there might be some issues if your code or your dependencies use reflection.

Maven not adding all dependencies to jar

I've a simple program build in IntelliJ and using maven that uses the dependency io.netty. I've added to my POM file:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.0.Beta1</version>
</dependency>
In order to compile and get a jar file I usually do:
Clean
Compile
Package
However I noticed that the dependency is not added to the jar, neither existing in the target folder (Or in any of it's sub folders) or added to the resources folder like usually happens.
In order to have the io.netty library to be added to the jar I have tried:
Setting the scope to provided and to compile.
Re-importing the pom file.
Deleting io.netty folder in the .m2/repository/ folder.
I have several other libraries linked including:
mysql-connector-java
slf4j-simple
trove4j
Thanks for reading.
For some odd reason I had changed my maven configuration a while ago. While I had not added any new libraries, the old ones still had their classes laying around therefor still being added to the jar.
I solved this issue by changing the build in my pom to:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.domain.Program</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Used as reference: http://mkyong.com/maven/create-a-fat-jar-file-maven-assembly-plugin/
Maven doesn't package all dependencies into a jar by default. You can use the assembly plugin to build a "jar with dependencies, as seen here:
How can I create an executable JAR with dependencies using Maven?

How to make jar of jars using maven [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Including dependencies in a jar with Maven
I am beginner in maven and would like to build a jar containing dependency jars in it using maven. But, I could not do so. Kindly help me about it.
If you're trying to create a single jar that contains your application and it's required libraries, there are two ways (that I know of) to do that. The first is One-Jar, which uses a special classloader to allow the nesting of jars. The second is UberJar, (or Shade), which explodes the included libraries and puts all the classes in the top-level jar.
I should also mention that UberJar and Shade are plugins for Maven1 and Maven2 respectively. As mentioned below, you can also use the assembly plugin (which in reality is much more powerful, but much harder to properly configure).
Use shade plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
You would to include the following in your pom.xml file.
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>MainClass with the packages</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>

Problems running executable jar with dependencies

Hey so I have been working on a project that I want to be able to run as an executable jar from the command line. I have been able to create the jar with dependencies using Mavens assembly:single command. My pom looks like this.
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.3</version>
<configuration>
<archive>
<manifest>
<mainClass>org.openmetadata.main.OmadUpdate</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
The build is successful and creates the jar omad-update-0.0.1-SNAPSHOT-jar-with-dependencies.jar. I go to my projects target folder in the command line and type
java -jar omad-update-0.0.1-SNAPSHOT-jar-with-dependencies.jar
I have also tried
java -cp omad-update-0.0.1-SNAPSHOT-jar-with-dependencies.jar org.openmetadata.main.OmadUpdate
Unfortunately in each case I am given a java.lang.NoClassDefFoundError: org/openmetadata/main/OmadUpdate. I am confused because I know my main class is in the package org.openmetadata.main and yet it is not found. I find this especially confusing because in my pom I specify that class as my main class. I have tried changing the name of the main class to src.main.java.org.openmetadata.main.OmadUpdate and simply OmadUpdate as well but neither seems to have an effect. Thanks for any help in advance.
I do not see a Class-Path entry in the manifest above, but your very long filename mentions dependencies. If there are jars within this jar file that your program is dependent on, you must enumerate them in the Class-Path section. See Adding Classes to the JAR File's Classpath for more details.
Another option might be to use the onejar-maven-plugin. Unfortunately the usage page is a bit scarce, but the plugin does what is supposed to when configured correctly.
I finally have been able to get this to work by adding the following code to my pom.
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.3</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>org.openmetadata.omadupdate.OmadUpdate</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Without the executions tag in the pom along with its children only the maven dependencies will be added to the jar and the classes from the project itself will not be added.

Categories

Resources