Is it possible to create an uber jar containing the project classes and the project dependencies as jars with a custom manifest file?
Actually, I didn't check what the maven-shade-plugin
is doing exactly (or any other plugin) as maven 2 has everything built-in to create a megajar or uberjar. You just have to use the maven-assembly-plugin with the predefined jar-with-dependencies
descriptor.
Just add this snippet to your pom.xml
to customize the manifest:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>my.package.to.my.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
And the following command will generate your uberjar:
mvn assembly:assembly -DdescriptorId=jar-with-dependencies
But, again, the default behavior of this descriptor is to unpack dependencies (like the maven-shade-plugin). To be honest, I don't get why this is a problem but, if this is really not what you want, you can use your own custom assembly descriptor.
To do so, first, create your assembly descriptor, let's say src/assembly/uberjar.xml
, with the following content:
<assembly>
<id>uberjar</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<unpack>false</unpack>
<scope>runtime</scope>
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
Then, configure the maven-assembly-plugin to use this descriptor and to add the dependencies to the Class-Path
entry of the manifest:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/assembly/uberjar.xml</descriptor>
</descriptors>
<archive>
<manifest>
<mainClass>my.package.to.my.MainClass</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
<!--
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
-->
</plugin>
Finally run mvn assembly:assembly
to produce your uberjar.
Optionally, uncomment the executions
element to bind the assembly plugin on the package
phase (and have the assembly produced as part of the normal build).
How can I create an executable/runnable JAR with dependencies using Maven?
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
and you run it with
mvn clean compile assembly:single
Compile goal should be added before assembly:single or otherwise the code on your own project is not included.
See more details in comments.
Commonly this goal is tied to a build phase to execute automatically. This ensures the JAR is built when executing mvn install
or performing a deployment/release.
<build>
<plugins>
<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>
</build>
Including dependencies in a jar with Maven
You can do this using the maven-assembly plugin with the "jar-with-dependencies" descriptor. Here's the relevant chunk from one of our pom.xml's that does this:
<build>
<plugins>
<!-- any other plugins -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
Generate jar file in Maven with dependencies and tests
My solution is to build an archive (zip or other formats) that contains your classes in a jar, the dependencies jars, a folder with runtime configuration files and scripts to launch the application. The scope is to have a run ready application just by unzipping the archive.
The built archive content is:
artifactId-version.zip:
<artifactId folder>
├─ config
| ├─ log4j2.xml
├─ lib
| ├─ <all dependencies jars>
├─ leanft.cmd
├─ leanft.sh
└─ artifactId-version.jar
You should tailor the solution based on what/if you need configuration files. You don't need the META-INF folders with MANIFEST.MF files because will be generated automatically by maven plugin.
Project structure
<maven_module_root>
├─ src
| ├─ main
| | ├─ assembly
| | | ├─ leanft-assembly.xml
| | ├─ java
| | | ├─ <your classes content>
| | ├─ resources
| | | ├─ log4j2.xml
| | | ├─ <your runtime configuration files>
| | ├─ scripts
| | | ├─ leanft.cmd
| | | ├─ leanft.sh
│ └───test
├─ pom.xml
The project structure is similar with your current structure with two additional folders:
- assembly: in this folder is the leanft-assembly.xml to customize the maven-assembly-plugin.
- scripts: in this folder are the launcher scripts for your application. This is necessary it if you need to have runtime configuration files available for edit. In my example, the resources/log4j2.xml will be in a config file so the user can edit this file without touching any jar/archive.
Assembly descriptor
The solution is based on maven assembly plugin with custom configuration. I recommend to get familiar with it, starting with descriptor assembly descriptor
Your leanft-assembly.xml could look like:
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>dist</id>
<formats>
<!-- <format>tar.gz</format> -->
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<baseDirectory>${project.artifactId}</baseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>${project.artifactId}-${project.version}.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.directory}/lib</directory>
<outputDirectory>/lib</outputDirectory>
<includes>
<include>*.*</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/config</outputDirectory>
<includes>
<include>log4j2.xml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/main/scripts</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>leanft.*</include>
</includes>
</fileSet>
</fileSets>
</assembly>
Maven pom
Finally, the pom.xml make use of 3 plugins:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>test.LeanFTest</mainClass>
</manifest>
</archive>
<excludes>
<exclude>log4j2.xml</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/leanft-assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>
I will explain the usage of maven plugins:
- maven-dependency-plugin: copy all dependencies at package phase in a lib folder under the target folder.
- maven-jar-plugin:
- archive: generate manifest file, define in manifest all dependencies from the lib folder and what is the main class so you can run the application also with "java -jar"
- excludes: don't include the log4j2.xml file in the module jar because will be in config folder available at runtime from outside jar.
- maven-assembly-plugin: create at package phase a zip file that contains your distribution. The archive is placed in target folder. The descriptor tag reference your assembly configuration file leanft-assembly.xml.
Script
The script to launch the application call java with predefined parameters, the main line from script being:
%JAVA_HOME%\bin\java %JVM_ARGS% -cp %SCRIPT_DIR%\*;%SCRIPT_DIR%\config\ test.LeanFTest
Maven 3 uber jar how to embed a jar within a jar?
I think the uber jar is the wrong route. Instead to accomplish your goal of hiding methods from the DatabaseLibrary but make them accessible to your Logic I would declare your methods as "protected" which limits its visibility to the package level. Given that you would make sure that any classes that needed to talk between jars were within the same package (though in seperate jars). This will force a 3rd party vendor only to use the public methods that are available to them.
- DatabaseLibrary
|- com.mycompany
|- DatabaseClass
-LogicLibrary
|- com.mycompany
|- LogicClass
public class DatabaseClass{
protected void doSomething(){
}
}
public class LogicClass{
public void doSomething(){
DatabaseClass dbClass = new DatabaseClass();
dbClass.doSomething();
}
}
Now you're 3rd party vendor will only see LogicClass.doSomething()
See also: http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
Classpath including JAR within a JAR
If you're trying to create a single jar that contains your application and its 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).
Using Gradle to build a JAR with dependencies
I posted a solution in JIRA against Gradle:
// Include dependent libraries in archive.
mainClassName = "com.company.application.Main"
jar {
manifest {
attributes "Main-Class": "$mainClassName"
}
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
}
Note that mainClassName
must appear BEFORE jar {
.
Multiple entry points (main classes) inside jar's top level
I found a solution here Spring Boot - How to specify an alternate start-class? (Multiple Entry Points). Ended up using -Dloader.main
property when launching jar.
Command line looks like these: java -jar -Dloader.main=<main_class> ./final.jar
Related Topics
Differencebetween @Inject and @Autowired in Spring Framework? Which One to Use Under What Condition
Singleton with Arguments in Java
Is a Java Array of Primitives Stored in Stack or Heap
How to Print Formatted Bigdecimal Values
How to Reference Another Property in Java.Util.Properties
Eclipse: Attach Source/Javadoc to a Library via a Local Property
Executors.Newcachedthreadpool() Versus Executors.Newfixedthreadpool()
Leiningen - How to Add Dependencies for Local Jars
Static Fields on a Null Reference in Java
Randomly Select an Item from a List
Why Use a Reentrantlock If One Can Use Synchronized(This)
Good Reasons to Prohibit Inheritance in Java
How to Redirect to Login Page When Session Is Expired in Java Web Application
What Is the --Release Flag in the Java 9 Compiler
Synchronizing on an Integer Value
Adding Image to Jbutton with Foreground Label
How to Dockerize Maven Project? and How Many Ways to Accomplish It