Pure Danger Tech


A rare classloader problem

18 Jun 2007

This is an odd and esoteric problem, but I’ll post it here in case anyone ever comes up against it. I mentioned in my previous post some of the issues you can run into using post-delegation classloaders.

Post-delegation classloaders protect a chunk of code (at runtime) from the dependencies of their parent classloader. In other words, they allow you to insert your own version of libraries, effectively hiding the version in the parent. However, I recently ran into an issue where this is not enough. In this case, the post-delegation classloader needed to also mimic the non-existence of a class in the parent classloader!

In this case, I had a parent classloader with library X, version 1. And I had a post-delegation classloader hosting a plugin with library X, version 2. As normally happens, the main code can using X1 and the plugin can use X2 without any conflict (as long as classes from X are not passed through the plugin interface). However, I found there was code deep in X2 that was checking for the existence of a particular optional library Y. It turns out that X1 was using Y, so when X2 checked for the existence of Y it was not found, but it then used parent delegation and DID find Y in X1. At that point, X2 had incorrectly filled an optional dependency based on the existence of a library in the parent.

This is kind of tricky to fix. I actually ended up fixing it by getting rid of the need for X1 and Y in the parent classloader, but that won’t always be possible. The fix is to tell your post-delegation classloader a set of classes where it should NOT do parent delegation. This is a dangerous thing so you want to do this on as few classes as possible. In my case, I could tell from instrumenting my classloader that the library was looking for the existence of a particular XML parser class. So, one way to fix this problem was to instruct my classloader to not use parent delegation for that particular class.

As I said, this is dangerous as you may theoretically run into other libraries that may actually need that class from the parent and you have broken them. It also requires you to hard-code class names as strings in your code, which we know is a design smell. So, consider this technique a last resort. I have never done this in production code, but it’s been a helpful hack to assist in tracking down problems and finding better alternative solutions.