Leveraging Java "1.6.0_24" on Windows XP, I performed some quick tests to determine if a JAR's manifest (META-INF/MANIFEST.MF) Class-Path attribute could reference a directory, thereby automatically picking up any contained classes/jars within that directory.
The result... INTERESTING..
My directory tree contents were as follows:
   
/test      
/test/test.jar       
/test/lib       
/test/lib/abc.jar
the "test.jar" found in the top level "test" directory contained a single file entry:     
META-INF/MANIFEST.MF
the "abc.jar" found in the "lib" directory contained a single file entry; a class named "Testing" :-
public class Testing      
{       
  public static void main(String args[])       
  {       
    System.out.println("found me");       
  }       
}
   
To prove our Testing class can be located, we set test.jar's MANIFEST.MF contents initially to:
Manifest-Version: 1.0      
Class-Path: lib/abc.jar       
Created-By: 1.6.0_24 (Sun Microsystems Inc.)
(Note, following the Created-By: ... line, there are two newlines.)
Invoking the following java command line, we see the Testing class was successfully triggered:
C:\test>java -cp test.jar Testing      
found me
   
I did some additional testing with relative and absolute paths in the MANIFEST.MF, the results of which were:
works:  Class-Path: ./lib/abc.jar      
works:  Class-Path: /C:/test/lib/abc.jar      
works:  Class-Path: \C:\test\lib\abc.jar      
fails:  Class-Path: C:\test\lib\abc.jar
   
Next, I altered the MANIFEST.MF contents to:
Manifest-Version: 1.0      
Class-Path: lib/       
Created-By: 1.6.0_24 (Sun Microsystems Inc.)
and re-issued the java command:
C:\test>java -cp test.jar Testing      
Exception in thread "main" java.lang.NoClassDefFoundError: Testing       
Caused by: java.lang.ClassNotFoundException: Testing       
        at java.net.URLClassLoader$1.run(Unknown Source)       
        at java.security.AccessController.doPrivileged(Native Method)       
        at java.net.URLClassLoader.findClass(Unknown Source)       
        at java.lang.ClassLoader.loadClass(Unknown Source)       
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)       
        at java.lang.ClassLoader.loadClass(Unknown Source)       
Could not find the main class: Testing.  Program will exit.
Thus, it appeared jar files in the lib directory would not be automatically included in the classpath.    
To be overly thorough, I decided to run some additional tests, the results of which were:
fails:  Class-Path: lib      
fails:  Class-Path: lib/      
fails:  Class-Path: ./lib      
fails:  Class-Path: ./lib/      
fails:  Class-Path: \C:\test\lib\      
fails:  Class-Path: \C:\test\lib      
fails:  Class-Path: /C:/test/lib/      
fails:  Class-Path: /C:/test/lib
At this point, I was of the opinion that a directory specified as part of a manifest Class-Path attribute/directive would simply be ignored.
WRONG!
I decided to extract (and subsequently delete) abc.jar. The contents of my directory tree were thus:
/test      
/test/test.jar       
/test/lib       
/test/lib/Testing.class
   
I set the MANIFEST.MF contents to:
Manifest-Version: 1.0      
Class-Path: lib/       
Created-By: 1.6.0_24 (Sun Microsystems Inc.)
   
and re-issued the java command:
C:\test>java -cp test.jar Testing      
found me
SUCCESS. It had located the class. What was even more interesting came out in the subsequent tests I performed:
fails:  Class-Path: lib      
fails:  Class-Path: ./lib      
fails:  Class-Path: \C:\test\lib      
fails:  Class-Path: /C:/test/lib      
works:  Class-Path: lib/      
works:  Class-Path: ./lib/      
works:  Class-Path: \C:\test\lib\      
works:  Class-Path: /C:/test/lib/
Hence, if an explicit directory name is provided as part of the Class-Path attribute, it must have a trailing slash in order to be recognized!
If a directory entry ends with "." or ".." no trailing slash is required. For example, if test.jar was moved to /test/lib, and had its MANIFEST.MF Class-Path set to ../.. , then Testing.class would be found if it resided in "/".
As a final test, and just to be doubly certain that relative paths specified in a MANIFEST.MF are in no way influenced by the java invoking end-user's working directory, I ran the following:
(with MANIFEST.MF Class-Path set to lib/ and lib containing Testing.class)
C:\>java -cp test\test.jar Testing      
found me       
 
 
Thanks ... This was helpful. I ran into this issue from another angle.
ReplyDeleteI had in my MANIFEST.MF:
Class-Path: ./somejar.jar ./some_directory
and this loaded somejar.jar as well as classes found under some_directory. Note that some_directory does not need the traling slash.
but when I changed to:
Class-Path: ./some_directory
The classes under some_directory no longer loaded.
Finally, with help from your blog post:
Class-Path: ./some_directory/
Works like a charm! So, it seems the trailing slash is definitely needed when a directory is specified by itself.
Thanks,
-- Craig
Thanks, I have been struggling with this all morning. Big help!
ReplyDeleteThis is very useful.
ReplyDeleteThanks!