Reference jars inside a jar
Asked Answered
D

7

60

I have a jar whose content looks as shown below,

enter image description here

Below is my manifest file

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.7.0_06-b24 (Oracle Corporation)
Main-Class: org.sai.com.DerbyDemo
Class-Path: derby.jar derbyclient.jar derbynet.jar derbytools.jar

When i try to run the jar, it has thrown a ClassNotFoundExcception meaning it isn't referencing the jars inside the outer jar.

In the Class-Path attribute, how can I reference jars (derby.jar, etc) inside the actual jar?

Diecious answered 10/9, 2012 at 18:5 Comment(1)
possible duplicate of Classpath including JAR within a JAREmirate
N
40

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 of Class-Path. Trying to use jar: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.

Nomenclature answered 10/9, 2012 at 18:36 Comment(0)
M
24

You can't. From the official tutorial:

By using the Class-Path header in the manifest, you can avoid having to specify a long -classpath flag when invoking Java to run the your application.

Note: The Class-Path header points to classes or JAR files on the local network, not JAR files within the JAR file or classes accessible over internet protocols. To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes. For example, if MyJar.jar contains another JAR file called MyUtils.jar, you cannot use the Class-Path header in MyJar.jar's manifest to load classes in MyUtils.jar into the class path.

Megrim answered 10/9, 2012 at 18:37 Comment(0)
X
17

In Eclipse you have option to export executable jar. enter image description here You have an option to package all project related jars into generated jar and in this way eclipse add custom class loader which will refer to you integrated jars within new jar.

enter image description here

Xanthe answered 7/7, 2015 at 13:16 Comment(4)
@Xanthe How did you create the launch configuration MainActivity-asc_validation? In my case, I have an Android application which I am using it as a jar file. This jar file in turn refers multiple other jar files. So I was trying to use this option. However I am stuck at this point. I am not able to get the android configuration into launch configuration.Dosage
Excellent! This works perfectly and I don't understand why it is not better documented! Thank you very much Vogash!Rinehart
Really works. I was doing all kind of command line monkey business, and didn't know eclipse has it... Thx for sharingGrieg
For this to work, it's critical that you choose 'Runnable JAR file' (as shown in the screenshot above) during the Export and not 'JAR file'.Tala
A
6

Default implementations of the classloader cannot load from a jar-within-a-jar: in order to do so, the entire 'sub-jar' would have to be loaded into memory, which defeats the random-access benefits of the jar format (reference pending - I'll make an edit once I find the documentation supporting this).

I recommend using a program such as JarSplice to bundle everything for you into one clean executable jar.

Edit: Couldn't find the source reference, but here's an un-resolved RFE off the Sun website describing this exact 'problem': https://bugs.java.com/bugdatabase/view_bug?bug_id=4648386

Also, you could 'test' that your program works by placing the library jar files in a \lib sub-directory of your classes directory, then running from the command line. In other words, with the following directory structure:

classes/org/sai/com/DerbyDemo.class
classes/org/sai/com/OtherClassFiles.class
classes/lib/derby.jar
classes/lib/derbyclient.jar

From the command line, navigate to the above-mentioned 'classes' directory, and type:

java -cp .:lib/* org.sai.com.DerbyDemo
Alexi answered 10/9, 2012 at 18:44 Comment(0)
P
4

if you do not want to create a custom class loader. You can read the jar file stream. And transfer it to a File object. Then you can get the url of the File. Send it to the URLClassLoader, you can load the jar file as you want. sample:

InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("example"+ ".jar");
final File tempFile = File.createTempFile("temp", ".jar");
tempFile.deleteOnExit();  // you can delete the temp file or not
try (FileOutputStream out = new FileOutputStream(tempFile)) {
    IOUtils.copy(resourceAsStream, out);
}
IOUtils.closeQuietly(resourceAsStream);
URL url = tempFile.toURI().toURL();
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{url});
urlClassLoader.loadClass()
...
Placia answered 6/8, 2019 at 9:0 Comment(0)
J
2

Add the jar files to your library(if using netbeans) and modify your manifest's file classpath as follows:

Class-Path: lib/derby.jar lib/derbyclient.jar lib/derbynet.jar lib/derbytools.jar

a similar answer exists here

Jaguarundi answered 7/12, 2013 at 12:52 Comment(0)
B
-1

in eclipse, right click project, select RunAs -> Run Configuration and save your run configuration, this will be used when you next export as Runnable JARs

Bobinette answered 20/4, 2017 at 5:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.