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.
Related
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.
I am new to java and currently doing a java project. This is the instruction on how to submit the project. Could anyone tell me how to do this in either intelliJ or eclipse?
Please submit a Java Archive (jar file containing all java classes you have written). Your jar file should
contain:
a) Contain source code for all classes
b) Contain executable (byte code) for all classes
This question has been already answered here multiple times.
Since you also need to include the sources, you will have to change the resource patterns so that .java files are also copied to the compiler output and are therefore included in the .jar file.
By default .java files are excluded from copying, so you need to remove !?*.java; pattern that excludes them:
!?*.java;!?*.form;!?*.class;!?*.groovy;!?*.scala;!?*.flex;!?*.kt;!?*.clj;!?*.aj
becomes
!?*.form;!?*.class;!?*.groovy;!?*.scala;!?*.flex;!?*.kt;!?*.clj;!?*.aj
Don't forget to change it back for your real world applications.
If you need a sample project for IntelliJ IDEA, you can download it from my another answer. It shows a more complicated example where additional dependent jars are included into the project using different ways (single jar and multiple jars).
If you you are using eclipse you can follow one of the below ways as per your requirements.
To Export the project you are working as jar:
1) Right Click on the project you are working > Select Export from context menu.
2) Select Java > JAR File
3) Select the project to export as JAR. Enter the name for the generating jar file and then click on finish.
If you are using Maven do following configurations to the pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.xxxxx.xxxxx</mainClass>
</manifest>
</archive>
<outputDirectory>C:\tmp</outputDirectory>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<outputDirectory>C:\tmp</outputDirectory>
</configuration>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
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
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>
i am creating a standalone java application with maven, and i am including the dependencies in the jar file with maven-dependecy-plugin as follows:
<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>${project.build.directory}/classes/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>theMainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>create-my-bundle</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
this includes the dependencies in the generated jar file in a lib folder, and the jar runs and works fine, but the issue is in the other generated jar file appname-1.0-jar-with-dependencies.jar.
ISSUE: i am not sure if it's an issue or not, but i noticed in target folder in the generated appname-1.0-jar-with-dependencies.jar, that it contains duplicate application files like:
all sql,property files,xml files exists twice.
all java classes .class file exists twice.
there are lots of overview.html and license.txt files related to the dependencies.
i am not sure if that's feels right or not, also i need someone to clarify for me what is the importance of this generated jar file, since i am not familiar with this plugin.
please advise, thanks.
Since you have mentioned jar-with-dependencies, I assume you are using maven assembly plugin to assemble your project artifacts along with the dependant jars into a single jar.
I suspect that your project artifacts are getting into the jar-with-dependencies twice - due to a property useProjectArtifact of dependencySet which is true, by default. You can set this property to true in your assembly descriptor and see if it addresses your issue.
In the specific case above, maven dependency plugin does not seem to be doing anything useful. maven assembly plugin automatically packages all its dependencies into a single distribution as per configuration.
But do note classpath issues if you create an executable jar-with-dependencies. You may want to create a zip or tar.gz instead.
The configuration used above is the default and does not allow for customization. You may want to use an assembly descriptor file, where you can set the property mentioned earlier or other options.