Duplicate :
|
|
Duplicate :
|
|
Duplicate :
|
|
Relates :
|
|
Relates :
|
Name: jl125535 Date: 03/06/2002 FULL PRODUCT VERSION : java version "1.4.0-rc" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-rc-b91) Java HotSpot(TM) Client VM (build 1.4.0-rc-b91, mixed mode) FULL OPERATING SYSTEM VERSION : Microsoft Windows 2000 [Version 5.00.2195] ADDITIONAL OPERATING SYSTEMS : Any O/S that supports the Java platform. A DESCRIPTION OF THE PROBLEM : Executable JAR files are a good and relatively simple way of deploying Java applications. When the JAR file contains a "Main-Class:" attribute, it becomes possible to launch the application by double-clicking on the file's icon (if supported by the client OS) or from the command line, as follows: java -jar some_app.jar or, where there are multiple entry-points (not just one main class): java -cp some_app.jar com.mycompany.MyMainClass However, there is a limitation with this approach. If the application contained within the JAR file depends upon other external JAR files, there is no straightforward way of bundling these files within the "main" JAR file. According to the JAR specifications, there is a Class-Path: attribute that can be specified in JAR manifest files. However, such paths can only be resolved relative to the URL from which the JAR file was loaded. For example, if the JAR file was loaded from "C:\java\apps\appli.jar", and the Class-Path: references "lib/other.jar", the class loader will look in "C:\java\apps\lib\" for "other.jar". It won't look at the JAR file entry "lib/other.jar". This example uses "file://" URLs, but the same sort of approach also applies to HTTP URLs, etc. As far as I aware, and based on my own attempts, there's no way to specify a Class-Path that makes the class loader look in embedded jar files. See the preceeding paragraph for a description. I suggest perhaps allow the Class-Path attribute to recognise by some path prefix or special URL protocol ("jar://", "self://"?) that the path refers to the inside of the JAR file. Alternatively, a new attribute could be added, such as "Jar-Internal-Class-Path:", specifically for finding classes (and, for that matter, any other resources that can be retrieved via getResource()). I prefer the second approach personally, as it avoids protocol conflicts, and is easier to understand and resolve. This should be recursive (embedded JARs should be recursively search for other embedded JARs). STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : 1. Create a JAR file, "test.jar", containing some classes. 2. Create another class that refers to classes contained within "test.jar". This should ideally be an executable class, i.e.: it should contain a "main()" method. 3. Create another JAR file, "main.jar", including the class created in step 2 and the JAR file from step 1. Set the Main-Class: attribute to refer to the class from step 2. 4. Try running the "main.jar", from a location that does not contain the other jar file (from step 1) or class file (from step 2); if these files are in the same folder as "main.jar" when you run it, then classes can be loaded from the current folder -- it won't need to look in the jar file (you may therefore wish to place "main.jar" in some other arbitrary folder before running it). It should complain that the class from step 2 cannot be found. 5. Try step 3 with various different settings for the Class- Path: attribute in the META-INF/MANIFEST.MF file. EXPECTED VERSUS ACTUAL BEHAVIOR : I would like the classes from the embedded JAR file to become accessible. Instead, I get error messages as shown below (example). ERROR MESSAGES/STACK TRACES THAT OCCUR : Exception in thread "main" java.lang.NoClassDefFoundError: B at A.main(A.java:3) This bug can be reproduced always. CUSTOMER WORKAROUND : 1./ Ask the end-user to manually install the required external libraries himself, either as an "extension" for the JVM or in a specific location. This is not desirable, as it makes the deployment process more complicated; depending on the type of end user, this may be quite offputting (non- trivial). 2./ Deploy the application as an archive (such as a ZIP file), and ask the user to decompress it. The main class is decompressed into a user-specified folder, and the external libraries are placed in the same folder or some subfolder. This allows Class-Path: to resolve, but is an additional step that could be eliminated by enhancing Java. Furthermore, this requires that the user has the appropriate decompression software. 3./ Possibly writing a custom classloader... if possible, this is a relatively time-consuming and complicated approach for the developer (not so much writing the classloader, as in understanding class visibility etc between different classloaders, which can often be confusing -- and it would be nice to maintain a high-level relatively abstract approach to software development in Java, instead of forcing developers to worry about "plumbing"). Additionally, this may require granting certain security permissions (not sure about that though). This may be one means of implementing the enhancement, but I would prefer that this is integrated into the standard APIs and class- loading behaviour, and is transparent for the developer. 4./ Decompress all external JAR, then merge the contents of these JAR files into the main JAR file. If the "reverse domain name" convention for classes is respected, this should work for class files from different JAR files, but may cause conflicts for resources such as "conf/gui.conf", "i18n/text_en.properties", "images/splas h.png" in some cases where common names are used. Furthermore, there may be conflicts between different manifest files and it becomes difficult to include signed or sealed code correctly. (Review ID: 139046) ======================================================================
|