Class JarClassLoader Download version 41
History

Description
The class loader to load classes, native libraries and resources from the top JAR and from JARs inside the top JAR. The top JAR very often is referred as an executable, standalone or uber JAR. The class loader looks through the hierarchy of JARs and allows nested JARs. The class loader delegates class loading to the parent class loader and successfully loads classes, native libraries and resources when it works not in a JAR environment. The initial revision was published in September 2007.

This class loader gives you an option to deploy your application in a single deployment JAR. This means that all third party libraries in JARs (even signed JARs), native libraries and resources could be put into this single deployment JAR in their original state. Access to any resource in this single deployment JAR is transparent. All JARs with all nested JARs and all native libraries in the deployment JAR are considered to be added to the application classpath regardless of their names and locations in the deployment JAR.

The class loader is a single class ~1300 lines (including ~500 lines of comments and instructions in JavaDoc).

There are multiple benefits of using this class loader to deliver Java application in a single JAR:

  • Simplifies deployment. Only a single JAR is deployed.
  • Obfuscates dependencies. All dependent JARs are hidden into a single deployment JAR.
  • Simplifies application support. Reduces risk of lost, replaced or misused dependent JARs.
  • Simplifies classpath. All dependent JARs in deployment JAR are considered in the classpath.
  • Simplifies native libraries loading. All native libraries in deployment JAR are considered in the native libraries path.
  • Eliminates native libraries loading issues. Reduces risk of lost, replaced or misused native libraries.
  • Simplifies resources loading. All resources in deployment JAR are considered in the classpath.
  • Convenient in development stage. Transparent loading classes, native libraries and resources from a JAR or file system.
  • Allows multiple entry points (applications). The JAR may contain multiple classes with main() method and multiple applets.
  • Allows shaded class loading. You may override any class or resource replacing the original class or resource in the dependent JAR.
    See details in Shaded class loading section.
  • Supports WebStart / JNLP. WebStart works out of the box.
    See details in WebStart / JNLP section.
  • Supports extension JCE providers. The deployment JAR may contain JCE extension provider JAR.
    (for example: Bouncy Castle)
  • Java applets. Any level of complexity for Java applets with dependent JARs, native libraries and resources packed into a single JAR.
    See details in Java Applet section.
  • Small footprint. JARs content is enumerated but do not stored in memory. Not used entries in JARs do not consume memory.

The class loader could be used without any special knowledge of Java class loading and without customizing or learning its internals. It works for you out of the box. Instructions for how to use this class loader are in How to use the JarClassLoader section and in the class JavaDoc. See also discussion Using JARs. It is is very simple to use in comparison to other available JAR class loaders. It does not require JAR manifest or system environment modifications, special application build, strict JAR structure or any kind of properties or settings. Just add this class loader and adjusted trivial Launcher class to your application. The Launcher class has only 12 lines of code.

This class loader resolves feature request Bug 4648386 posted in March 2002 against JDK 1.2 which is still not resolved in JDK-7. It had multiple votes and was listed in a Sun's Top 25 RFE's (broken link). The link is broken because it was not transfered to Oracle. For some reasons Sun and later Oracle ignored this request.

The class loader was tested with Java 5 and Java 6 on WinXP and Linux platforms.

Similar products
There are many free JAR class loaders available on the web.

  • Classworlds (also here) The package is titled advanced classloader framework. The version 1.0 R3 was published in 2003. The final release is not available. The package consists of 17 files with a total size of ~3600 lines. It does not support loading native libraries. It also requires an external configuration file. There are no clear instructions for how to use the package.
  • UberJAR Based on Classworlds package. Requires configuration file and strict directory structure. Does not support native libraries. Documentation is minimal.
  • Meta Jar Utilities The version 1.7.1 was published in 2002. The package consists of 6 files with a total size of ~2200 lines. The package does not support loading native libraries. There are two class loaders in the package. These class loaders have code that is duplicate and commented out. Instructions are not clear as to how and when the class loaders should be used.
  • One-JAR The version 0.97 RC5 was published in 2010. The package consists of 6 core files with a total size of ~2200 lines. This is the most mature product in comparison with others. The package supports loading native libraries. The web site contains too many confusing JARs to download: appgen, sdk, example, dll, ant-task, boot. Nested JARs are not supported. Does not allow shaded class loading. Memory hog, all JARs content is stored in memory even for not used resources. The class loader requires a strictly specified root JAR structure. The class loader is controlled by MANIFEST.MF attributes. The package is over-engineered.
  • Embedded jar classloader in under 100 lines Published in October 2008. It is essentially a simplified version of our JarClassLoader. The class loader is controlled by MANIFEST.MF attribute. It cannot load native libraries and external LookAndFeel classes. Documentation is minimal.
  • Eclipse 3.4 JDT: Runnable JAR export wizard Specific to Eclipse. Combines all classes into a single JAR file. Does not work with signed JARs and native libraries.
  • Fat Jar Eclipse Plug-In Specific to Eclipse. Integrates One-JAR.
  • (JCL) Jar Class Loader Contains ~3500 lines of code in 25 files. Requires xml configuration file. Supports Spring. Does not support native libraries. Uses Log4j. Documentation is missing.
  • Maven Shade Plugin Combines all JARs content into a single JAR which may lead to conflicts. No special class loader is required. Configuration with Maven knowledge might be required. Does not work with signed JARs and native libraries. Nicely documented, there a many resources on a web including tutorials, for example here.
  • JarJar Utility that repackages classes from multiple JARs into a single one. No special class loader is required.
None of these class loaders are perfect or easy to use. The summary of the main issues in majority of them:
  • Requirement to specify main JAR entry in the MANIFEST.MF or configuration file. This complicates the use and eliminates option to have multiple entry points in a JAR.
  • Requirement to have strict directories structure.
  • Native libraries are not supported.
  • Dependency on other software, e.g. Eclipse, Log4j.
  • Missing or not sufficient documentation.

How to use the JarClassLoader
Follow these steps:

1. Create your main root JAR. Put in it all classes, resources, native libraries and other JARs required by your application in any location (directory path). JARs could be nested, i.e. you may have JARs in other JARs with any level of nesting. JarClassLoader ignores location of JARs and native libraries in the main root JAR. This gives you an option to organize main root JAR directory structure content.

2. Add class com.jdotsoft.jarloader.JarClassLoader to the main root JAR.

3. Create a launcher class using the following template and add it to the main root JAR. You could have multiple launcher classes in the JAR to start different applications from the same root JAR.

package com.mycompany;
import com.jdotsoft.jarloader.JarClassLoader;

public class MyAppLauncher {

  public static void main(String[] args) {
    JarClassLoader jcl = new JarClassLoader();
    try {
      jcl.invokeMain("com.mycompany.MyApp", args);
    } catch (Throwable e) {
      e.printStackTrace();
    }
  } // main()

} // class MyAppLauncher
Update the package declaration in the example above and rename the class. Update the parameter in the method JarClassLoader.invokeMain() with package + classname of your application main class. Pick any name for the package and class name for the launcher and your main class.

4. Start your application using the launcher class com.mycompany.MyAppLauncher.main() created in the previous step with one of the following commands:

    (1) java -cp MyApp.jar com.mycompany.MyAppLauncher Hello World
    (2) java -jar MyApp.jar Hello World

The command #2 is available if you have the following entry in the manifest file:
    Main-Class: com.mycompany.MyAppLauncher

Any parameters in the examples of command lines given above like Hello World are optional and passed to your class com.mycompany.MyApp.main() method by JarClassLoader.

Using the launcher class is transparent in application development stages when all resources are not yet packed into a single JAR. The JarClassLoader checks its location: JAR or file system. If JarClassLoader finds that it is loaded from a file system it passes all control to the system class loader. The system class loader than loads classes from a classpath and handles native libraries accordingly.

Using Maven to build executable JAR
You do not need special Maven plugins to make an executable JAR with JarClassLoader. The standard Maven plugins will do the job.

Follow these steps:

1. Complete steps in section How to use the JarClassLoader.

2. Add the following <build> section into your project pom-file, just copy / paste. Minimal customization and significance of bold elements is discussed below. In most cases you will need to modify only red value.

<project . . .>
  . . .
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.7.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <id>copy</id>
            <phase>prepare-package</phase>
            <goals>
              <goal>copy-dependencies</goal>
            </goals>
            <configuration>
              <excludeArtifactIds>junit</excludeArtifactIds>
              <outputDirectory>${project.build.directory}/classes</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.1.0</version>
        <configuration>
          <archive>
            <manifest>
              <mainClass>com.mycompany.MyAppLauncher</mainClass>
              <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

maven-compiler-plugin provides an option to override default Java compiler version. Most probably you already have this plugin declared in your pom-file. The default Maven settings is Java 1.3 compiler. The value 1.8 overrides it to required by your project Java compiler version.

maven-dependency-plugin executed before packaging, see prepare-package key value.
JUnit JAR is excluded from the packaging, see junit key value. The plugin copies all dependent JARs into the
    [PROJECT_HOME]/target/classes
directory because Maven defines the default value ${project.build.directory} as [PROJECT_HOME]/target directory.

maven-jar-plugin does actual packaging from [PROJECT_HOME]/target/classes directory.
Update the Launcher class name com.mycompany.MyAppLauncher with actual class name. You may remove the entry
    <mainClass>. . .</mainClass>
altogether if JAR manifest should not contain the main class name.

Logging
Class loader has flexible logging controlled by system properties. Developer could specify different logging level and different logging areas. The log could be redirected to a file. See details in the class JavaDoc.

The default logging level is ERROR without any output in normal conditions.

Shaded class loading
In many cases developer has to fix a bug in some class or replace resources in the third party JAR used in the project. Examples of such replacements could be Java class, JavaScript file, or hard coded template in dependent JAR. The JarClassLoader allows this replacement with shaded class loading. The techniques is very simple. The replacement class or resource should be placed into the root JAR. The JarClassLoader scans the root JAR first and then dependent JARs. The requested class or resource is loaded from the root JAR if found there and further scanning in dependent JARs is not performed.

Multiple JARs may contain identical classes. Some classes in JAR-A may be shaded by classes with same names in JAR-B. The class loader may give an answer what classes are actually loaded and what classes are shaded. This information is logged at WARN log level:

    -DJarClassLoader.logger.level=WARN

WebStart / JNLP
The JarClassLoader supports WebStart / JNLP. Follow these steps to create WebStart / JNLP application in a single JAR:

The implementation is based on idea published by our user. See WebStart / JNLP demo in the Demo section.

Java Applet
The JarClassLoader works transparently for applets as well. Follow these steps to create Java applet in a single JAR:

The applet's launcher class core functionality is similar to plain Java application launcher discussed in How to use the JarClassLoader section. The applet's launcher implements standard Applet.init(), Applet.start(), Applet.stop() and Applet.destroy() methods to pass browser's calls to underlying com.mycompany.MyApplet applet implementation.

package com.mycompany;
import com.jdotsoft.jarloader.JarClassLoader;
import javax.swing.JApplet;

public class MyAppletLauncher extends JApplet {

  private JarClassLoader jcl;

  @Override
  public void init() {
    jcl = new JarClassLoader();
    try {
      jcl.initApplet("com.mycompany.MyApplet", this);
    } catch (Throwable e) {
      e.printStackTrace();
    }
  }

  @Override
  public void start() {
    jcl.startApplet();
  }

  @Override
  public void stop() {
    jcl.stopApplet();
  }

  @Override
  public void destroy() {
    jcl.destroyApplet();
  }

} // class MyAppletLauncher
Update the package declaration in the example above and rename the Java applet class.

See Java applet demo in the Demo section.

Temporary files
Class loader extracts inner JARs and native libraries into temporary files, see design discussion in Design constraints and known limitations section. All inner JARs are always extracted into temporary files. Native libraries are extracted into temporary files only on request to load them.

Temporary files are created by java.io.File.createTempFile() and marked with a flag deleteOnExit(). As a result they are deleted by the system on application shutdown when all temporary files are closed. The application shutdown event is intercepted by Runtime.addShutdownHook().

Temporary files with JARs are not deleted on Windows platform if some resources (other than classes) are loaded from them using getResourceAsStream(). Temporary files with native libraries are never deleted on Windows platform. Attempt to explicitly delete these temporary files on shutdown by calling File.delete() fails because VM does not release these files' handles. See Bug 4171239: "This occurs only on Win32, which does not allow a file to be deleted until all streams on it have been closed."

As a result some temporary files may remain hanging in the file system after the application shutdown. The class loader uses a workaround preserving list with failed to delete temporary files in configuration file .JarClassLoader saved in the [user.home] directory. The example configuration file location:

    [Win7]  C:\Users\username\.JarClassLoader
    [WinXP] C:\Documents and Settings\username\.JarClassLoader
    [Unix]  /export/home/username/.JarClassLoader
             -or-  /home/username/.JarClassLoader

The configuration file is not created if all temporary files are deleted. Temporary files listed in the configuration files are deleted on the next application run. It's recommended periodically manually check the directory with temporary files and delete them if they are present. These files could accumulate if application process was killed. The example location for temporary files:
    [Win7]  C:\Users\username\AppData\Local\Temp\JarClassLoader
    [WinXP] C:\Documents and Settings\username\Local Settings\Temp\JarClassLoader
    [Unix]  /var/tmp/JarClassLoader

The default temporary files location could be changed by modifying java.io.tmpdir system property:
    -Djava.io.tmpdir=<your-temp-dir> (in command line)
    System.setProperty("java.io.tmpdir", "<your-temp-dir>"); // in Launcher before new JarClassLoader()

Design constraints and known limitations
See also JarClassLoader class JavaDoc and comments for details how the class loader works.

  The system class loader scans classpath in a well defined order - the order directories and JARs are declared in a classpath. The result is predictable: some resource which exists in multiple places will be always loaded from a directory or JAR which is declared earlier in a classpath.

JarClassLoader loads some class, resource, or native library which has identical path and present in multiple JARs from unpredictable JAR in a top JAR. The JarClassLoader does not have any specific scanning order thus making loading unpredictable.

  Using temporary files for loading JARs could be avoided if one of the following constructors is available in Java API:

    java.util.jar.JarFile(java.io.InputStream)
    java.util.jar.JarFile(java.util.jar.JarEntry)
    java.io.File(java.util.jar.JarEntry)

Alternative to temporary files is Protocol Handlers with all JARs content stored in memory. Protocol Handlers are registered using java.protocol.handler.pkgs System property. This approach is taken by One-JAR. It resolves issue with temporary JAR files deletion but consumes large memory to store all inner JARs in memory. The number of JARs and their size in current applications could be significant. It is not reasonable to store the whole JAR in memory while only a few classes maybe actually needed from it.

  Using temporary files for loading native libraries could be avoided if java.lang.ClassLoader class and VM have an option to load native library from a stream. Currently VM loads native libraries using method String findLibrary(String) where String parameter is an absolute path to the native library. For example, on Windows platform the absolute path to native library Native.dll in the main root JAR is defined as

    jar:file:/C:/.../MyApp.jar!/lib/Native.dll

This absolute path URL does not work for loading native libraries and it is not defined at all for nested resources.

  The packages and JARs sealing is not supported.

  Shaded class loading discussed in a section might expose Java vulnerability. System class loader does not allow replacing system Java classes available in rt.jar with custom replica. Current JarClassLoader implementation allows loading any class from an application JAR, even a system class, before passing class loading request to a system class loader. Fortunately the security exception is thrown for attempt to shade a class in a system package, for example java.lang.String:

java.lang.SecurityException: Prohibited package name: java.lang
    at java.lang.ClassLoader.preDefineClass(Unknown Source)
    at java.lang.ClassLoader.defineClassCond(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at com.jdotsoft.jarloader.JarClassLoader.findJarClass(JarClassLoader.java:523)
    at com.jdotsoft.jarloader.JarClassLoader.loadClass(JarClassLoader.java:812)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
    at java.lang.Class.getMethod0(Unknown Source)
    at java.lang.Class.getMethod(Unknown Source)
    at com.jdotsoft.jarloader.JarClassLoader.invokeMain(JarClassLoader.java:728)
    at com.jdotsoft.jarloader.test.LauncherTestConsole.main(LauncherTestConsole.java:18)
However, not all classes and resources in rt.jar are protected. For example, classes in org.w3c.dom package in rt.jar could be replaced without any warning. This could be considered a feature and could be used for some cases.

Demo
You could view JarClassLoader in action in the demo. The demo is packed into a single JAR file JarClassLoaderDemo.jar available for download. You can build this JAR yourself using Eclipse project available in Download section.

The same demo could be executed in multiple fashions:

  • Using command line (console version). Download or build demo JAR and execute command
        java -jar JarClassLoaderDemo.jar Hello World
    

  • Using command line (GUI version). Download or build demo JAR and execute command
        java -cp JarClassLoaderDemo.jar com.jdotsoft.jarloader.test.LauncherTestGUI Hello World
    

  • Using WebStart / JNLP. Click here to launch demo GUI version using WebStart.
    This demo is a self-signed application and thus is untrusted. See details here and here how to add http://jdotsoft.com to Exceptions Site List.

  • Using Java Applet. Click here to launch demo GUI version as a Java Applet.
    Firefox users: sometimes applet popup page remains blank. This could be result of conflicting installed JREs or latest Firefox version did not pickup Java plugin. To resolve the problem close Firefox, unstall all (!) JREs, install the single one and restart Firefox.

    The Java applet demo could be also started as a plain Java application. Download JarClassLoaderDemo.jar or build it from the Eclipse project and execute command
        java -cp JarClassLoaderDemo.jar com.jdotsoft.jarloader.test.LauncherTestApplet Hello World
    

The JarClassLoaderDemo.jar used for all demos has the following content:

root
  - com\jdotsoft\jarloader\JarClassLoader.class

  - com\jdotsoft\jarloader\test\TestConsole.class
  - com\jdotsoft\jarloader\test\TestGUI.class
  - com\jdotsoft\jarloader\test\TestApplet.class

  - com\jdotsoft\jarloader\test\LauncherTestConsole.class
  - com\jdotsoft\jarloader\test\LauncherTestGUI.class
  - com\jdotsoft\jarloader\test\LauncherTestApplet.class

  - com\jdotsoft\jarloader\test\ClassForName.class
  - com\jdotsoft\jarloader\test\HelloTopJar.class
  - com\jdotsoft\jarloader\test\NativeCode.class
  - com\jdotsoft\jarloader\test\PrintFile.class

  - resources\TopText.txt
  - libNative.so
  - Native.dll
  - substance-lite.jar
      - ...multiple classes and resources...
  - lib\InnerJar.jar
      - com\jdotsoft\jarloader\test\HelloInnerJar.class
      - resources\HelloInner.txt
The actual demo test code resides in TestConsole class. The main() method in this class should be used to start the demo in an exploded environment (make sure that resources are in a classpath).

The TestConsole demo should be started from a JAR using LauncherTestConsole launcher.

The similar pair TestGUI and LauncherTestGUI exist for the GUI demo. This demo is a simple JFrame application with TestConsole output. External look-and-feel in substance-lite.jar from http://java.net/projects/substance is added for this demo and should be tested visually.

The similar pair TestApplet and LauncherTestApplet exist for the applet demo. This demo is an applet wrapper around TestGUI code.

Native libraries Native.dll and libNative.so are built for the Windows and Unix platforms. Sorry, no Mac native library in the demo.

Be aware of the following security concerns when launching the demo:

  • Temporary files will be created on your file system by JarClassLoader.
  • Demo has a native library method call.
The JarClassLoaderDemo.jar is signed to allow access to your file system (to create temporary files) and execute native calls. The JarClassLoaderDemo.jlnp for the WebStart / JNLP demo file has the following:
  <security>
    <all-permissions/>
  </security>

The native library has the following code:

#include "com_jdotsoft_jarloader_test_NativeCode.h"

JNIEXPORT jstring JNICALL
  Java_com_jdotsoft_jarloader_test_NativeCode_getString(JNIEnv *env, jobject ob)
{
  return (*env)->NewStringUTF(env, "String from native code");
}

Download
Click here to view the class source, here to download Eclipse project with demo and unit tests.

License
This Java class is licensed under GNU General Public License version 3 as published by the Free Software Foundation. Commercial license is available.

Comments


Posted by Troy on April 10, 2008, 11:49 PM

It works! Thanks again.

Posted by Gianfranco on July 4, 2008, 1:13 AM

I must say this is so much simpler then OneJAR.

Posted by Martin on September 15, 2008, 5:13 am

I tried to use your class in combination with SUNs WebService development kit. I get a class not found exception for the class com.sun.xml.ws.spi.ProviderImpl. When I try to load this class explicitly by Class.forName I get no error. So I guess your class works fine but in my special case the system classloader tries to load this class and can't find it. Any suggestions?

Admin: Fixed in v1.28

Posted by maple story mesos on June 29, 2009, 10:03 pm

This is exactly the post I needed to see!

Posted by Ted P. on August 22, 2009, 7:13 am

Thanks for the work you've put into this ClassLoader, it's much easier to use than trying to figure out the instructions for OneJAR or one of the other solutions out there.

Posted by Brent B. on February 18, 2010, 9:31 am

Your product seems to work great -- many thanks for making this available!

Posted by Michael S. on September 10, 2010, 5:10 pm

Eureka and yay! Got it working in a few minutes. I was skeptical at first, but JarClassLoader *was* easier to get going than OneJAR. Thanks!!

Posted by Paul C. on January 15, 2011, 1:15 am

I've just been trying out the JarClassLoader class (v1.28), which is fantastic I must say. Thanks for a great product.

Posted by Rammohan Akula on February 24, 2011, 5:04 pm

In case if you are seeing ClassNotFoundException while trying to launch your jar using java web start (JNLP), you can resolve it by loading from cached resources in public JarClassLoader(ClassLoader parent) constructor. It can be done using javax.jnlp.BasicService and javax.jnlp.DownloadService2. You need to add [JDK_HOME]/sample/jnlp/servlet/jnlp.jar to your project class path.

Admin: WebStart / JNLP support is available since v1.36

Posted by Stefano M. on March 1, 2011, 10:55 am

What about using this ClassLoader in java applets?
How can I put dll's inside the applet and then load them through JarClassLoader?
I use a signed jar. There are no main() method to run! How does it work?

Admin: Java applets support is available since v1.36

Posted by Eric on June 23, 2011, 1:51 am

I have successfully created an applet with a native library (written in C++) with JarClassLoader and it works just fine! (:
The "only" thing I had to do was to inherit the Applet class into the launcher-class, create a public void init() method, and run the same procedure as in the main() method in the init() method.
I've got a question though. Is it possible to invoke another method than main(), later in the program? I mean, after you've invoked the main() method.

Admin: Java applets support is available since v1.36

Posted by Jon Barrilleaux on August 24, 2011, 8:33 pm

To Rammohan Akula,
Could you post the code to allow use of JarClassLoader with JNLP? Thanks.

Posted by Rammohan Akula on August 25, 2011, 9:36 pm

To Jon,
I've sent required files to Admin. He will post working copy soon.

Admin: WebStart / JNLP support is available since v1.36

Posted by Jon Barrilleaux on August 26, 2011, 4:32 pm

Thanks Rammohan. I managed to get it to work using a different approach mentioned at http://jsomt.blogspot.com/2010/10/improving-jarclassloader.html. It uses JarURLConnection to access the jar file. I added a second constructor to JarClassLoader.JarFileInfo that takes a JarFile (returned by JarURLConnection) instead of a File. I've tested in on a webserver via JNLP, and via jar using "java -jar...".

A big thanks to JDotSoft for providing JarClassLoader!

Posted by Frank on September 19, 2011, 12:01 pm

Great! Thanks!
I had a bit trouble on Mac OS X with the native library. (NativeCode: Library "Native": java.lang.UnsatisfiedLinkError: no Native in java.library.path)
The reason for me was the ending of the native lib filename.
CXX on Mac OS X compiled my native lib with a default ending ".dylib" but JNI wants: ".jnilib"
After renaming the native lib to: "libNative.jnilib" it worked for me.

Posted by Lars B. on October 19, 2011, 8:16 am

The JCL works great, it was the only one that worked out of the box:
- JCL: I could get this to work within 15 min
- maven-shade-plugin has the problem that you lose resources with the same name in different jarfiles
- Classworlds/UberJar is too old
So thanks for the JCL!

Posted by Ignatios Souvatzis on January 6, 2012, 5:17 am

Hm, sounds interesting ... but can I have multiple versions of a native library for different architectures?

Admin: Yes, you can have multiple versions of native libraries for different architectures. Check the demo application.

Posted by Mário on January 19, 2012, 7:07 am

Can I do this?
    System.setProperty("java.library.path", "PdfSigner.jar!resources/nativelib-windows-x86");
    java.lang.reflect.Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
    fieldSysPath.setAccessible(true);
    fieldSysPath.set(null, null);
    System.loadLibrary("myNativeLibrary");
I'm using JarClassLoader like in the instructions, but the myNativeLibrary.dll is never loaded from inside my PdfSigner.jar file.
What I'm doing wrong?

Admin: Remove all code and leave the last line as System.loadLibrary("myNativeLibrary")
The JarClassLoader considers ALL native libraries in a top JAR and in inner JARs to be in java.library.path
Native library path in a JAR does not matter. Native library could be in a JAR's root or in any JAR's location, see demo.

Posted by Mário on January 20, 2012, 4:04 am

Hello, got it to work using the dll inside the root of the JAR, loading it first from 'resources' in a JNLP file, and then when I call System.loadLibrary("myNativeLibrary"); it just works.
Thanks.

Posted by Will on April 22, 2012, 2:10 am

How can I pass a variable from MyAppletLauncher to MyApplet?
For example, I am able to execute javascript within MyAppletLauncher like this:
netscape.javascript.JSObject.getWindow(this).eval("alert('test');");
But I can't figure out how to reference the MyAppletLauncher instance from within MyApplet methods. Thanks.

Admin: MyAppletLauncher should not add or modify applet parameters. You should provide parameters in applet tag on html page.

Posted by Ashish Kataria on July 2, 2012, 8:48 am

Will it work for Linux too?
Will it load the native library in java.io.tempdir for Ubuntu Linux like it's doing for Windows?

Admin: JarClassLoader works for any OS, check the demo application. Native library path in the JAR does not matter, see my reply above for the comment on January 19, 2012.

Posted by phaniram on August 24, 2012, 1:03 pm

I tried the same way as told in tutorial, but I have UnsatisfiedLinkError. Native libraries and etc. are packed as required, but still it says that my abc native library is not in java.library.path
I tried using System.loadLibrary("abc"); but the problem remains. Are there any settings I might've missed?

Admin: The first thing to debug this kind of problem would be to examine main JAR content in a tool like WinZip. Make sure that JAR has the following entries:
- JarClassLoader.class in a path com\jdotsoft\jarloader
- your application classes and JARs
- myAbc.dll (as an example) in any path; this native library is for Windows and should be loaded in a code as System.loadLibrary("myAbc");

Posted by SubaruWRC on October 6, 2012, 6:35 pm

Is there any possibility this library could be re-licensed under a BSD or otherwise commercially-friendly license?

Admin: One time fee for unlimited use in a single commercial product is a JCL share of the product revenue. JCL is free for non-commercial products.

Posted by Mattias Willman on November 22, 2012, 5:37 pm

I'm trying to add Bouncy Castle to our Main.jar file but we end up with:
java.lang.SecurityException: JCE cannot authenticate the provider BC
java.util.jar.JarException: file:/D:/Main.jar has unsigned entries - lib/xyz.jar

When JCE verifies the crypto provider they go via the getCodebase() method in the ProtectionDomain and it returns the Main.jar as the code base, which contains unsigned entries, as well as the Bouncy Castle jar. What do I miss? Or is it not possible to have it in Main.jar?

Admin: Bouncy Castle and any other extension JCE providers are supported in v1.38
Mattias, thanks for your input!

Posted by Nasra on September 12, 2013, 11:10 pm

Good to see real expertise on display. Your contribution is most welcome.

Posted by Anton Hack on October 31, 2013, 12:53 pm

All my jdbc connectors under one /lib directory in the main jar file. That is a really useful peace of software. Many Thanks!

Posted by Rob Ratcliff on November 20, 2013, 8:05 pm

Would this classloader be a good candidate to manage plug-ins where all the jar files for that plug-in were bundled in one jar or directory and could have different versions of a third party library in each plug-in? (Basically a subset of OSGI functionality where each plug-in's didn't need to share classes with each other.) If not, do you know of a light weight solution out there?

Admin: The JCL seems to be a good candidate to bundle required JARs into a single plug-in JAR. There could be issues if plug-in is not executed in its own JVM.

Posted by Richard Tingstad on December 10, 2015, 5:13 am

Thank you for this file (especially Bouncy Castle support).

I ran into a problem when using Spring (OXM, 4.0.5) on Windows, because JarClassLoader findResource(str) returns URL
jar:file:C:\Users\\AppData\Local\Temp\JarClassLoader\example.jar.123.tmp!/my-schema.xsd
Spring tries to convert to URI and gets a URISyntaxException because of \

When modifying \s to /s my app works.
Maybe JarClassLoader should behave like ClassLoader.getResource(str) and return (jar:)file:/C:/path/...

Admin: Java is not consistent using back or forward slash in file path. Thanks for pointing out issue how JCL handles it. This will be addressed in future JCL versions.

Posted by bianbian.org on April 20, 2016, 11:30 pm

Mac with JDK7/8 looks for the native libraries with the .dylib extension.

Admin: Thanks BianBian. The v1.39 updated with JavaDoc for method findJarNativeEntry().

Posted by Alexander Kriegisch on July 20, 2018, 5:12 am

I think it would be nice if the JarClassLoader class itself was available as a Maven dependency on Central. Copying the source code into my project is kinda ugly.

Admin: Reasons why JCL is not in Maven:
• the JCL a single class, it makes no sense to pack it as a JAR for Maven, it's simple to add it to your project explicitly
• less declarations in your already overcrowded pom
• adding it to GitHub and Maven repository is not an option because of supporting and versioning issues
• and the main obstacle: system class loader cannot load JarClassLoader class if it in its own JAR inside the main JAR; JarClassLoader class must be loaded by system class loader from the root of the main JAR

Posted by Günter Albrecht on April 3, 2019, 8:27 am

Thanks for your JarClassLoader. I decided to use it because we must use signed BC libs in an executable jar. So I dropped the OneJar approach.
I encountered a problem with the com/ibm/oti/vm/BootstrapClassLoader which is resolved now. The reason was a Maven dependency to com.sun.xml.stream:sjsxp:1.0.2 which interferes silently with the xml.jar from IBM SDK.

Posted by Ananya on December 30, 2019, 3:54 pm

Does the JCL have Gradle support?

Admin: JCL is not supported by Gradle and Maven. See my answer above on July 20, 2018.

Posted by Jason on February 18, 2020, 5:49 am

Any thoughts about using this for building a single jar for Alexa skill with Amazon lambda?
I need to avoid exploding a resource jar that contains tens of thousands of small resource files, put this resource jar in the large jar, and can still load resource files from the resource jar inside the single jar for the skill.

Admin: The JCL seems to be a good candidate to keep multiple resources in a single JAR.

Leave a comment


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

Submit Comment