JAR's inside a JAR + custom ClassLoader

K

Karsten Wutzke

Hi all!

I want to bundle my app in one JAR file. In the lib sub dir of the
JAR, there should be all JAR's that the application depends on, here
bcel-5.2.jar (plus several others).

Since adding the JAR's to the manifest's Class-Path entry didn't work,
I tried my luck with a URLClassLoader. The code itself is too easy. I
have no real idea of how to tell the runtime when and how to use that
class loader. I read the class loader docs which explained the
delegation model.

So I did:

URL urlLib1 = RuntimeConfig.class.getResource("/lib/bcel-5.2.jar");

URLClassLoader cllLibs = new URLClassLoader(new URL[]{urlLib1});

I expected the class loader to become a child of the bootstrap class
loader.

The problem is: I don't really know where to put the above code.
Currently it is in my "config" class. However, the class loader
doesn't seem to be put into the delegation hierarchy, otherwise the
classloader would find the classes from the bcel JAR. I checked the
URL and JAR location inside my JAR, they seem to be correct.

As soon as one of the classes get referenced, here
org.apache.bcel.generic.Type, the (main) thread stops with a
NoClassDefFoundException.

Does anyone know what I am doing wrong? How do I make it work?

TIA
Karsten
 
T

Tom Hawtin

Karsten said:
I want to bundle my app in one JAR file. In the lib sub dir of the
JAR, there should be all JAR's that the application depends on, here
bcel-5.2.jar (plus several others).

You are probably better off unjarring the jars and jarring the lot together.
Since adding the JAR's to the manifest's Class-Path entry didn't work,
I tried my luck with a URLClassLoader. The code itself is too easy. I
have no real idea of how to tell the runtime when and how to use that
class loader. I read the class loader docs which explained the
delegation model.

So I did:

URL urlLib1 = RuntimeConfig.class.getResource("/lib/bcel-5.2.jar");

URLClassLoader cllLibs = new URLClassLoader(new URL[]{urlLib1});

I expected the class loader to become a child of the bootstrap class
loader.

If you use the constructor that doesn't specify the parent, then you get
the system class loader as parent. This is what the API docs mean by
"the default delegation parent ClassLoader". Why they use such an obtuse
phrase, I don't know. If you want the bootstrap class loader to be the
direct parent, add ", null".
The problem is: I don't really know where to put the above code.
Currently it is in my "config" class. However, the class loader
doesn't seem to be put into the delegation hierarchy, otherwise the
classloader would find the classes from the bcel JAR. I checked the
URL and JAR location inside my JAR, they seem to be correct.

The delegation happens the other way around. A class loader delegates to
its parent. So your class loader delegates to the system (and hence
boot) class loader, not the other way around. You need to specify your
class loader to load a class from it, for instance using
Class.forName(String,boolean,ClassLoader).

If you want to link your own code to that, then you either need another
class loader that delegates to your "cllLibs" class loader, or make one
class loader to load it all (other than your initial code to create the
class loader and kick off the app).

Tom Hawtin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top