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>
Related
I have a legacy code (which suppose to be 100% working) without any documentation. This code consists of several separate services which do some tasks (like working with RabbitMQ, inserting some records into Postgres DB, and so on).
Each and every service in its pom.xml in maven-shade-plugin configuration has resourses folder being excluded from the resulting jar. Like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin-version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>log4j2.xml</exclude>
<exclude>application.properties</exclude>
<exclude>update.sql</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
As a result, when I try to run any of such jars (with java -jar any_of_my_jars.jar) - they fail, cuz they need application.properties and all other resources to run.
So the question is: it should be I'm missing something. I either should run them in some other way, or I should deploy them somewhere. Can someone plz explain to me how such jars can be used to be working jars?
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:
I've imported Lucene sources and built successfully.
But when I'm trying to use any of Lucene classes, I get
A SPI class of type org.apache.lucene.codecs.Codec with name 'Lucene410' does not exist
The current classpath supports the following names: []
I tried to get path to classes by
String path = Lucene410Codec.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
And got right path, so there is no problem with wrong jar-file.
The problem was that I've missed META-INF folder while imported project.
I've manually added META-INF/services folder and it's contents - codecs files (which I took from lucene.core.jar) to sources and configured right build path.
add something to resources in eclipse
Now I can work with Lucene.
For the ones who is facing such issue I have another solution which seems decent. Main reason for such issue to occur is that some JAR files (Lucene in this case) providing implementations of some interfaces ship with 'META-DATA/service' directory. This directory then maps interfaces to their implementation classes for lookup by the service locator. So the solution will be to relocate the class names of these implementation classes and merge multiple implementations of the same interface into one service entry.
Maven's shade plugin provides a resource transformer called ServiceResourceTransformer which does such relocation. So in practice I would define the plugin as follows:
<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>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>main.class.of.your.app.MainClass</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
I have a package org.myapp.mypackage with some ruby files (*.rb) and I need to include them in the generated build jar in the same package along with the java class files.
How do I tell my friend Maven to do this?
Note : No, I cannot copy to anywhere else, but thanks for suggesting. :)
You can modify the resources section of the <build> bit of the POM:
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<filtering>false</filtering>
<directory>src/main/java</directory>
<includes>
<include>*.rb</include>
</includes>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
</resources>
Or, the other answer (create the same package structure in src/main/resources) will also work.
Not sure if i understood the problem correctly, but if your Ruby files are packaged by maven and
declared as a dependency, you can use the shade plugin to include the
contents into the resulting jar file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>org.myapp.mypackage:mypackage</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>org.myapp.mypackage:mypackage</artifact>
<includes>
<include>org/my/package/*.rb</include>
</includes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
Put them in the correct directory (src/main/resources in general) and
they should be bundled into the Jar properly. To put you *.rb files create the same dir structure under the src/main/resources folder.
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).