configure Maven Shade minimizeJar to include class files - java

I am trying to minimize the UberJar's size by using Maven Shade Plugin's minimizeJar. It looks like minimizeJar only includes classes that are statically imported in the code (I suspect this because I see LogFactory.class in uber jar at org\apache\commons\logging\ but no classes of the impl package are included, hence throwing java.lang.ClassNotFoundException: org.apache.commons.logging.impl.LogFactoryImpl when I run the uber-jar).
Is there any way I can tell Maven's Shade plugin to include specified packages into the final jar no matter what the minimizeJar suggests?
Here the pom snippet of what I am trying:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>org/apache/commons/logging/**</include>
</includes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.myproject.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>

This functionality has been added to version 1.6 of the maven-shade-plugin (just released). minimizeJar will now not remove classes that have been specifically included with filters. Note that including some of an artifact's classes in a filter will exclude non-specified classes for that artifact, so be sure to include all the classes that you need.
Here's an example plugin config:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>log4j:log4j</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>

I am using the 2.0 version of the Maven Shade Plugin and still I am not able to include classes after "minimizing" the JAR.
As a workaround the only thing that comes to my mind is to create references to the needed classes to avoid the minimization code to get rid of them. ie:
/*
* This block prevents the Maven Shade plugin to remove the specified classes
*/
static {
#SuppressWarnings ("unused") Class<?>[] classes = new Class<?>[] {
JButton.class,
JMenu.class,
JMenuBar.class,
JMenuItem.class
};
}
I hope Maven developers implement a way to handle this situation (which I guess is very common).

Related

Maven Shade Plugin does not include needed classes from dependancy

In a project, I use as a dependancy an artifact which is in the same groupId than this project.
The dependancy is well imported and used in my IDE, but when I compile the jar, no classes from the dependancy are copied inside the final jar. So I get exceptions at runtime...
Why ???
The dependancy POM head :
<groupId>com.example.things</groupId>
<artifactId>project-foo</artifactId>
My project POM head :
<groupId>com.example.things</groupId>
<artifactId>project-bar</artifactId>
My project POM section to declare dependancy :
<dependency>
<groupId>com.example.things</groupId>
<artifactId>example-foo</artifactId>
<version>1.2.345-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
My project POM Maven Shade Section :
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<artifactSet>
<includes>
<include>com.example.things:project-foo</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
Thanks for helping, it seems I do something wrong...

Including some dependencies in my compiled jar

Hello people of stackoverflow, on my working project I have 5 dependencies.
I'm working on a project which doesn't contain any main method.
What I would like to do is including 2 (HikariCP and slf4j) out of my 5 dependencies in the final jar, but I don't figure how to do this, it's always adding all of them.
Edit: I'm using eclipse
Using Maven
You can use the maven-shade-plugin to generate a fat-jar (or uber-jar). It will package all your dependencies inside the jar:
<build>
<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>
<finalName>YOUR_JAR_FINAL_NAME</finalName>
</configuration>
</plugin>
</plugins>
</build>
Documentation related to the maven-shade-plugin can be found in here
UPDATE: As you want to include just a few dependencies inside of it, you can check the Selecting contents for Uber JAR section:
You can use the include or exclude tag to select which content will be provided to the jar, you can find some examples from the docs below:
Excluding
<configuration>
<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>
</configuration>
Including and excluding
<configuration>
<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>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
UPDATE 2: For a runnable jar file, you can follow this section of the documentation related to Executable Jars
In Eclipse
You can use the Package required libraries into generated JAR option, the downside of it is that you can't really select which dependencies do you want to include into to, since it is assessing all the required libs for you project.
I believe if you really want to remove some stuff, you would need to use Maven to package, or remove manually the dependencies you don't like from the generated jar, generating a custom jar with your own hands:

How to create a jar without meta-inf folder in maven?

If I wanted to create a jar file without META-INF nonsense using jar utility I can pass the -M switch, which will:
-M do not create a manifest file for the entries
Note that this is a feature of the jar utility. If I use it, I will get a jar without the META-INF folder and included MANIFEST, basically just an archive of type jar with whatever files/directories I put in it.
How do I do this with the maven-jar-plugin? I need to do this to conform to another process. (They expect a jar with very specific file/folder layout and I cannot have a META-INF folder at the root of the jar file.)
I've got the configuration to create the jar file just right and I don't want to mess with another plugin...
In maven-jar-plugin there is no option to disable creation of manifest folder, but you can disable the maven descriptor directory like this :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
<manifest>
<addClasspath>false</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
If absolutely you want to delete the META-INF folder you can use maven-shade-plugin like this :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
You can use maven-shade-plugin to achieve the desired effect:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>${project.groupId}:${project.artifactId}</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
The configuration filters out the META-INF directory and includes only the current project so that dependencies are not attached.

Maven Get Specific Classes

Is there a way that I can get maven to only include specific .class files when importing dependencies into uber jar (shade). I'm looking for a way to get files that contain "Client" in their name to be pulled out of the dependency jars and added to the final jar. Any help would be wonderful.
You should be able to use the maven-dependency-plugin like this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId><!--dependency groupId--></groupId>
<artifactId><!--dependency artifactId--></artifactId>
<version><!--depedency version--></version>
<includes>**/*Client*.java</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you are using the Maven Shade Plugin, you can a filter, which will allow you to filter which artifacts get shaded, but as well as which classes to exclude or include.
Here's the example they provide:
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>org/junit/**</include>
</includes>
<excludes>
<exclude>org/junit/experimental/**</exclude>
</excludes>
</filter>
</filters>

Minimize an Uber Jar correctly, Using Shade-Plugin

I am using the Maven-Shade-Plugin to create a runnable Uber-jar.
According to the last frame on this page, the size of the jar can be minimized by using:
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
But this feature does not take into consideration the classes that are declared in the log4j.properties file. Hence, e.g. org.apache.log4j.appender.TimeAndSizeRollingAppender is not included in the Uber-jar, even though it’s declared in the log4j.properties file.
I believe I will face the same problem with Spring. If my code only refers to interface A and my Spring file contains an instantiation of class B that implements A, then B might not be added to the jar, since it’s not in the code.
How can I solve this problem?
This functionality has been added to version 1.6 of the maven-shade-plugin (just released). minimizeJar will now not remove classes that have been specifically included with filters. Note that including some of an artifact's classes in a filter will exclude non-specified classes for that artifact, so be sure to include all the classes that you need.
Here's an example plugin config:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>log4j:log4j</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>commons-logging:commons-logging</artifact>
<includes>
<include>**</include>
</includes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
To only include specific classes, add them as includes using path slashes in the class name in a filter (again, non-included classes will be automatically excluded).
<filter>
<artifact>org.yourorg:your-artifact</artifact>
<includes>
<include>org/yourorg/yourartifact/api/*</include>
<include>org/yourorg/yourartifact/util/*</include>
</includes>
</filter>

Categories