Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JRE not using classpath specified by manifest file of runnable jar

Tags:

java

manifest

First post, so sorry for my poor formatting. I have a java program that I developed in eclipse. I exported the program as a jar (myJar.jar), and then I put all of the external jars that my program depends on into a folder called lib that lives in the same location as myJar.jar. In order to set my classpath I have a manifest file with the following format:

Main-Class: exe.myMain
Class-Path: lib/jar_1.jar lib/jar_2.jar ... lib/jar_n.jar
Manifest-Version: 1.0

However, when I attempt to run the program using "java -jar myJar.jar" the classes from the jars that live in lib are not being loaded (I'm getting a ClassNotFoundException) . I used the following code in my program to print the classpath:

ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader)cl).getURLs();
for(URL url:urls){
    System.out.println(url.getFile());
}

And when I run this code the classpath is simply "myJar.jar".

I have two questions:

1.) Does the above code actually give me the classpath for the JRE at run time, or am I simply being given the address of my main class?

2.) Given the above code does indeed give me the classpath for the JRE at run time, am I doing anything wrong?

Please feel free to ask for more information, and I will happily provide what you need.

like image 642
fjimenez Avatar asked Oct 30 '22 04:10

fjimenez


1 Answers

What you are doing sounds correct.

For some reason the Class-Path entry in the manifest does not show up when inspecting the classpath (e.g. here and here; those examples use the property "java.class.path" but my testing shows that ClassLoader.getURLs() behaves the same). It should still get searched for classes though. I don't know how to obtain the true classpath that includes the Class-Path entry from the manifest.

The first thing I'd like to check is that the file META-INF/MANIFEST.MF inside myJar.jar matches the manifest that you created. You can open myJar.jar by renaming it to have a .zip file extension.

I tried to replicate your problem but the classes in lib/jar_1.jar were loaded for me, so if META-INF/MANIFEST.MF is correct I'll describe what I did in detail so you can find what we are doing differently.

Edit:

Here are the steps I used:

  1. Create a new directory called "experiment". The following steps are all to be done in that directory.

  2. Create new directories called "jar_1", "lib", and "exe"

  3. Create a file called "ClassInJar1.java" in directory "jar_1" with the following content:

    package jar_1;
    
    public class ClassInJar1 {
        public static void method() {
            System.out.println("Hello from ClassInJar1");
        }
    }
    
  4. Run javac jar_1/ClassInJar1.java

  5. Run jar cf lib/jar_1.jar jar_1/ClassInJar1.class

  6. Create a file called "myMain.java" in directory "exe" with the following content:

    package exe;
    
    import java.net.*;
    import jar_1.ClassInJar1;
    
    public class myMain {
        public static void main(String[] args) {
            ClassLoader cl = ClassLoader.getSystemClassLoader();
            URL[] urls = ((URLClassLoader) cl).getURLs();
            for (URL url : urls) {
                System.out.println(url.getFile());
            }
            ClassInJar1.method();
        }
    }
    
  7. Run javac exe/myMain.java

  8. Create a file called "manifest" in the "experiment" directory with the following content:

    Main-Class: exe.myMain
    Class-Path: lib/jar_1.jar lib/jar_2.jar
    Manifest-Version: 1.0
  1. Run jar cfm myJar.jar manifest exe/myMain.class

  2. Run java -jar myJar.jar

Output:

/.../experiment/myJar.jar
Hello from ClassInJar1
like image 121
tom Avatar answered Nov 09 '22 11:11

tom