We have a Java application, which is run locally from the command line (ie using 'java'). Included in the application is the Java Help 2.0 jar. Some of our customers have an issue where an exception is thrown, which is a parse error from the Java Help help set file. I think the reason for this is that they have Java Help 1.0 installed as an extension (ie in the ire/lib/ext directory), which is trying to parse the Java Help 2.0 file.
I'm trying to find a way to stop the class loader using this extension jar, rather than the one bundled with the app. It appears that versioning of extensions is quite OK with applets (using the manifest of the applet), or with Java Web Start (using the version attribute of a jar file in the JNLP file). However, I'm at a loss of how to achieve this with a straightforward local application - a simple test always loads the jar file in the extension directory, rather than one of the class path, regardless of version. I can stop all extensions being loaded, by clearing the ext.dirs property, but that then means no extensions will be loaded, and I need the JCE one.
Does anyone have any ideas on how to work around this? I guess implementing a new class loader would work, but this seems very complex for such a simple requirement! Another option would be rebuilding Java Help with a different package namesake, but again...
There's a classloader which looks only at the extensions directory, and there's the classloader you're familiar with which looks at the classpath. And the former classloader is the parent of the latter.
But you seem to be contemplating a classloader which looks at some hard-coded part of the extensions directory. You could write such a thing (although that would be an act of desperation), but its parent would be the classpath classloader. This means that classes which are loaded in the normal way from the classpath wouldn't look at your new classloader when they needed a class. They would continue in the normal way to delegate to their parent, which checks the extensions directory, and then search the classpath.
So doing that doesn't gain you anything. You would have to somehow insert your new classloader between the regular extensions classloader and the standard classpath classloader. And you would have to program it to not delegate to its parent, the extensions classloader. The latter is doable but I have no idea how to finagle the former.
I've been burned three times in the past by undesired side-effects of putting jars in the extensions directory. So as far as I'm concerned, the extensions directory is poison. I just don't ever put anything in there because it's going to come back and bite me later. As it has you.
Yes, my thought was to replace the system class loader, sitting below the extensions one, and change the behaviour so that it tries to load from its own class path, and if the class isn't found then delegates to the parent (so the opposite of the normal behaviour). Sounds like it would work in theory, but I'm not sure that it is worth the complexity.
My understanding from the link, and the associated documentation, is that enforcing the version in the manifest only works for applets, not for applications run locally. I can't say I really understand why this would be the case (or rather, why this would be desirable), but having tried a simple test, it does appear that the version is ignored for applications. (The test: the application requests a specific extension version in the manifest, which is present in it's classpath, but there is also an earlier version of the extension in the extensions directory, then the one is the extensions directory is the only one that gets loaded).
Is my understanding and test wrong? If this is supposed to work correctly, then that would definitely make life easier!
The extensions mechanism is for extensions, and extensions go in the lib/ext directory. You are breaking the rules by providing an extension and not putting it there. I suspect if you do that properly it will pick up the correct version.
It doesn't work. If two versions of the same extension are in the ext directory, then a Java application appears to use the one which is enumerated first by the extension class loader (the first of the two jars found). The version in the manifest appears to make no difference.