Find a way out of the ClassLoader maze

System, current, context? Which ClassLoader should you use?

1 2 Page 2
Page 2 of 2
public class DefaultClassLoadStrategy implements IClassLoadStrategy
{
    public ClassLoader getClassLoader (final ClassLoadContext ctx)
    {
        final ClassLoader callerLoader = ctx.getCallerClass ().getClassLoader ();
        final ClassLoader contextLoader = Thread.currentThread ().getContextClassLoader ();
        
        ClassLoader result;
        
        // If 'callerLoader' and 'contextLoader' are in a parent-child
        // relationship, always choose the child:
        
        if (isChild (contextLoader, callerLoader))
            result = callerLoader;
        else if (isChild (callerLoader, contextLoader))
            result = contextLoader;
        else
        {
            // This else branch could be merged into the previous one,
            // but I show it here to emphasize the ambiguous case:
            result = contextLoader;
        }
        
        final ClassLoader systemLoader = ClassLoader.getSystemClassLoader ();
        
        // Precaution for when deployed as a bootstrap or extension class:
        if (isChild (result, systemLoader))
            result = systemLoader;
        
        return result;
    }
    
    ... more methods ...
} // End of class

The logic above should be easy to follow. If the caller's current and context classloaders are in a parent-child relationship, I always choose the child. The set of resources visible to a child loader is normally a superset of classes visible to its parent, so this feels like the right decision as long as everybody plays by J2SE delegation rules.

It is when the current and the context classloaders are siblings that the right decision is impossible. Ideally, no Java runtime should ever create this ambiguity. When it happens, my code chooses the context loader: a decision based on personal experience of when things work correctly most of the time. Feel free to change that code branch to suit your taste. It is possible that the context loader is a better choice for framework components, and the current loader is better for business logic.

Finally, a simple check ensures that the selected classloader is not a parent of the system classloader. This is a good thing to do if you are developing code that might be deployed as an extension library.

Note that I intentionally do not look at the name of resources or classes that will be loaded. If nothing else, the experience with Java XML APIs becoming part of the J2SE core should have taught you that filtering by class names is a bad idea. Nor do I trial load classes to see which classloader succeeds first. Examining classloader parent-child relationships is a fundamentally better and more predictable approach.

Although Java resource loading remains an esoteric topic, J2SE relies on various load strategies more and more with every major platform upgrade. Java will be in serious trouble if this area is not given some significantly better design considerations. Whether you agree or not, I would appreciate your feedback and any interesting pointers from your personal design experience.

Vladimir Roubtsov has programmed in a variety of languages for more than 13 years, including Java since 1995. Currently, he develops enterprise software as a senior engineer for Trilogy in Austin, Texas.

Learn more about this topic

1 2 Page 2
Page 2 of 2