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).
Reference jars inside a jar
You will need a custom class loader for this, have a look at One Jar.
One-JAR lets you package a Java application together with its dependency Jars into a single executable Jar file.
It has an ant task which can simplify the building of it as well.
REFERENCE (from background)
Most developers reasonably assume that putting a dependency Jar file into their own Jar file, and adding a Class-Path attribute to the META-INF/MANIFEST will do the trick:
jarname.jar
| /META-INF
| | MANIFEST.MF
| | Main-Class: com.mydomain.mypackage.Main
| | Class-Path: commons-logging.jar
| /com/mydomain/mypackage
| | Main.class
| commons-logging.jar
Unfortunately this is does not work. The Java
Launcher$AppClassLoader
does not know how to load classes from a Jar inside a Jar with this kind ofClass-Path
. Trying to usejar:file:jarname.jar!/commons-logging.jar
also leads down a dead-end. This approach will only work if you install (i.e. scatter) the supporting Jar files into the directory where the jarname.jar file is installed.
Call java -jar MyFile.jar with additional classpath option
You use either -jar
or -cp
, you can't combine the two. If you want to put additional JARs on the classpath then you should either put them in the main JAR's manifest and then use java -jar
or you put the full classpath (including the main JAR and its dependencies) in -cp
and name the main class explicitly on the command line
java -cp 'MyProgram.jar:libs/*' main.Main
(I'm using the dir/*
syntax that tells the java
command to add all .jar
files from a particular directory to the classpath. Note that the *
must be protected from expansion by the shell, which is why I've used single quotes.)
You mention that you're using Ant so for the alternative manifest approach, you can use ant's <manifestclasspath>
task after copying the dependencies but before building the JAR.
<manifestclasspath property="myprogram.manifest.classpath" jarfile="MyProgram.jar">
<classpath>
<fileset dir="libs" includes="*.jar" />
</classpath>
</manifestclasspath>
<jar destfile="MyProgram.jar" basedir="classes">
<manifest>
<attribute name="Main-Class" value="main.Main" />
<attribute name="Class-Path" value="${myprogram.manifest.classpath}" />
</manifest>
</jar>
With this in place, java -jar MyProgram.jar
will work correctly, and will include all the libs
JAR files on the classpath as well.
Run a JAR file from the command line and specify classpath
When you specify -jar
then the -cp
parameter will be ignored.
From the documentation:
When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.
You also cannot "include" needed jar files into another jar file (you would need to extract their contents and put the .class files into your jar file)
You have two options:
- include all jar files from the
lib
directory into the manifest (you can use relative paths there) - Specify everything (including your jar) on the commandline using
-cp
:java -cp MyJar.jar:lib/* com.somepackage.subpackage.Main
Creating a JAR file which contains other library files
I think you can try it like this;
Here is a simple example for you question. First, we assume we have a project directory like D:\javademo
. In this working directory we then create a main class HelloWorld.java and thtat contains our other JAR files, like commons-lang.jar
. Now, we must archive our main classes HelloWorld and commons-lang.jar into test.jar file.
First we must edit our manifest file so that we can specify our class-path and main-class
like this:
Manifest-Version: 1.0
Created-By: tony example
Class-Path: test.jar commons-lang.jar
Main-Class: org.tony.java.HelloWorld
We named this file test.mf
. Now we use the jar
command to generate our JAR file like this:
jar -cvfm test.jar test.mf -C ./ .
Then it will generate the JAR file test.jar
. You can use this command to run this main class using java command:
java -jar test.jar
That is my solution. I hope it give you something helpful...
Related Topics
Getting the Name of the Currently Executing Method
How to Get Rid of Accents and Convert a Whole String to Regular Letters
Is Java.Sql.Timestamp Timezone Specific
How to Format a Number in Java
How to Convert Json to a Hashmap Using Gson
How to Take a Screenshot Using Java and Save It to Some Sort of Image
What's the Difference Between Instant and Localdatetime
Number of Lines in a File in Java
Generationtype.Auto VS Generationtype.Identity in Hibernate
Http Url Address Encoding in Java
How to Tell Gradle to Use Specific Jdk Version
How to Check If a String Contains Another String in a Case Insensitive Manner in Java
In Arrayblockingqueue, Why Copy Final Member Field into Local Final Variable
Finalize() Called on Strongly Reachable Objects in Java 8
How to Find a Java Memory Leak
What Components Are MVC in Jsf MVC Framework