2
votes

I am developing a software with an automated update function, which works even when the user has no write permission to the installation folder. For that, the application analyses the classpath and checks whether there are newer JAR files for the entries in the classpath in a separate user directory. In that case the application generates a revised classpath and starts a new VM with that classpath.

My problem arises when the java default class loader changes the order of the JAR files by inserting libraries, which are mentioned in a manifest file.

I will give you a simplified example, which lacks a lot of details and does not make sense for a real update scenario, but it will explain my problem. So let's assume I am not allowed to change the contents of main.jar.

I start the application with

java -jar main.jar

main.jar has a proper MANIFEST file, which contains the Main-Class and a Class-Path, referencing the additional libraries c.jar and d.jar.

So the complete Class-Path during runtime would be:

main.jar, c.jar, d.jar

The order is important, since main.jar overrides classes from c.jar. Now the application finds out that there are updates available, which require the additional libraries a.jar and b.jar.

So the application now calculates the new classpath:

main.jar, a.jar, b.jar, c.jar, d.jar

Again, the order is important, since a.jar overrides classes from d.jar. Now the application starts a new VM with an explicit classpath:

java -cp main.jar:a.jar:b.jar:c.jar:d.jar <Main-Class>

Unfortunately, java alters the class-path by inserting the libraries, referenced by the MANIFEST of main.jar, at the position of main.jar. So the effective classpath would be:

main.jar, c.jar, d.jar, a.jar, b.jar, c.jar, d.jar
--------  ------------  --------------------------
   CP       MANIFEST                CP  

With that order, c.jar now has a higher priority than a.jar. And the overriding classes from a.jar will not get loaded.

The obvious solution to this problem would be to provide a main.jar without a manifest. But this would lead to other problems, I would like to avoid.

My question is: Is there a way to disable the behaviour of java to include the referenced JAR files from a MANIFEST while searching the classpath?

1
Interesting. I always thought that Class-Path attribute was ignored when -jar was not used. - Mathieu Fortin
What if you just call java -cp a.jar:b.jar:main.jar:c.jar:d.jar <Main-Class> ? - Mathieu Fortin

1 Answers

0
votes

Just a quick and untested idea. If you are able to dynamically load your updated jars at runtime, instead of specifying them at the command line, you could create a URLClassLoader for these jars and explicitly load your classes using that custom class loader:

URL[] jarurls = new URL[]{jar1,jar2,...};
URLClassLoader customCL= new URLClassLoader (jarurls, getClass().getClassLoader());
Class clazz = Class.forName ("com.blablabla.MyClass1", true, customCL);
MyClass1 instance = (MyClass1)clazz.newInstance();

You could load every jar which resides in your user folder into that class loader. When instantiating a class you would prioritize your custom class loader and failover on the default one.

This certainly adds a complexities/risks to your design since classes would now need to be instantiated by reflection.