Using JARs

There are many resources on the web for how to use JARs. Usually they are focused on default JARs features. The class JarClassLoader provides new features that may change the way a developer uses JARs.

JAR files are used to deploy Java application. For example, you have completed development of some very complex MyApp application. Most probably you will generate MyApp.jar with all your Java classes required by your application resources. Where do you keep other dependent required resources?

To JAR or not to JAR?
The general approach to answer this question should be the following: put everything you are not exposing to your user in a JAR. In other words, leave out of a JAR only those files that are allowed to be modified by a user. Examples of files to be kept out of the JAR are

  • log4j.properties - the logger properties file. This file (or similar files) is included in your application distribution if you are using Log4J package for logging. In many cases users are allowed to modify this file if different level of logging are required.
  • MyApp.properties - the application properties file. In many cases this file is allowed to be modified by user. Move this file (if it exist) into JAR if you do not allow a user to modify it.

How to deal with dependent JARs in conventional deployment
In conventional deployment without the use of the JarClassLoader you have the following options:

  • Leave dependent JARs outside of the main root MyApp.jar and refer them via classpath. This approach exposes dependencies of your application, clutters the distribution package and adds a chance for your application to fail if these JARs are missing or replaced.
  • Add JARs content into your main root JAR. This can be done by adding the following line (example for Log4J) into your Ant script while generating main root JAR:
        <zipfileset src="log4j.jar"/>
    

    This technique cannot be used for signed JARs or for third party JARs with special licenses. For example Java Help uses signed JARs. In addition, your application Java Help content and control files could be packaged into your main JAR as well.

How to deal with dependent JARs using JarClassLoader
Very simple: just add third party JARs directly into your main root JAR. The location of these JARs in the main root JAR does not matter. You could put them into any folder, for example lib folder or even into another JAR (nested JAR). Any JAR in the main root JAR is considered to be in the classpath of the main application.

The JarClassLoader allows to have nested JARs, i.e to have JARs in the JAR. This is very convenient for projects with complex dependencies. For example, Hibernate distribution has about 20 JAR files. It includes JARs and license files. You could safely put all of them into a single JAR for nice encapsulation and add this single JAR into your main root JAR.

How to deal with native libraries in conventional deployment
In conventional deployment without use of the JarClassLoader you actually do not have any options. You must know exact the location of the native library and provide this location to the VM via java.library.path system properties entry, or environment variable, or by putting the native library into some system default location.

Having native libraries in your distribution package exposes dependencies of your application, clutters the distribution package, and adds the possibility for your application to fail if these native libraries are missing or replaced.

Problems with loading native libraries are very common and difficult to debug. The VM complains with java.lang.UnsatisfiedLinkError which does not give any clue as to what may cause this problem. You could do very little while supporting your customers online with this kind of problem. Your support ends up with a try this or try that approach.

How to deal with native libraries using JarClassLoader
Very simple: just put native libraries directly into your main root JAR. The native library could be in the Windows or *nix format and will be loaded appropriately on a proper platform. The location of these native libraries in the main root JAR does not matter. You could put them into any folder, for example lib folder or even into another JAR (nested JAR). Any native library in the main root JAR is considered to be in the native libraries path of the main application and will be loaded by the class loader. This design approach guarantees that you will not have any problems with loading native libraries.

How to load other resources
Loading resources from a JAR or a file system with JarClassLoader or system class loader is identical. Here are some examples:

Loading an image

ImageIcon img = null;
URL url = getClass().getClassLoader().getResource("MyApp.gif");
if (url != null) {
    img = new ImageIcon(url);
}

Reading a file

String fileName = "resource/Sample.txt";
try {
    InputStream is = getClass().getClassLoader().getResourceAsStream(fileName);
    if (is == null) {
        throw new FileNotFoundException(fileName);
    }
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    for (int i = 1; ; i++) {
        String s = br.readLine();
        if (s == null) {
            break;
        }
        System.out.println("Line-" + i + ": " + s);
    }
} catch(IOException e) {
    System.out.println("Cannot read file '" + fileName + "':" + e);
}

Leave a comment


  CAPTCHA Image
  Allowed tags: <b> <i> <code>
We record your IP address 44.211.24.175 (located here) and will report abuse of this form to authorities.

Submit Comment