Classloader issues - How to determine which library versions (jar-files) are loaded

21,850

Solution 1

If you happen to be using JBoss, there is an MBean (the class loader repository iirc) where you can ask for all classloaders that have loaded a certain class.

If all else fails, there's always java -verbose:class which will print the location of the jar for every class file that is being loaded.

Solution 2

If you've got appropriate versions info in a jar manifest, there are methods to retrieve and test the version. No need to manually read the manifest.

java.lang.Package.getImplementationVersion() and getSpecificationVersion() and isCompatibleWith() sound like they'd do what you're looking for.

You can get the Package with this.getClass().getPackage() among other ways.

The javadoc for java.lang.Package doesn't give the specific manifest attribute names for these attributes. A quick google search turned it up at http://java.sun.com/docs/books/tutorial/deployment/jar/packageman.html

Solution 3

In the current version of Java, library versioning is a rather wooly term that relies on the JAR being packaged correctly with a useful manifest. Even then, it's a lot of work for the running application to gather this information together in a useful way. The JVm runtime gives you no help whatsoever.

I think your best bet is to enforce this at build time, using dependency management tools like Ivy or Maven to fetch the correct versions of everything.

Interestingly, Java 7 will likely include a proper module versioning framework for precisely this sort of thing. Not that that helps you right at this moment,

Solution 4

I don't think there is a good way to check that. And I'm not sure you want to do that. What you need to do is get familiar with your app-server's class loading architecture, and understand how that works.

A simplified explanation of how it works is: an EJB or a web-app will first look for a class or a resource in libraries declared in its own module (ejb-jar or war). if the class is not found there, the class loader forwards the request to the its parent class loader which is either a declared dependency (usualy an ejb) or the the application class loader which is responsible to load libraries and resources declared in the ear package. If the class or the resource is still not found the request is forwarded to the app server which will look in its own classpath.

This being said, you should remember that a Java EE module (web-app, ejb) will always load classes from a jar that is in the nearest scope. For example if you package log4j v1 in the war file, log4j v2 at ear level and you put log4j v3 in your app-server's class path, the module will use the jar in its own module. take that away and it'll use the one at ear level. take that out and it will use the one in the app-server's classpath. Things get more tricky when you have complex dependencies between modules.

Best is to put application global libraries at ear level.

Share:
21,850
Johan Pelgrim
Author by

Johan Pelgrim

I'm an Independent Android Developer and doing full-time Android development since 2012. I have an Enterprise Java background (SCJP, SCWCD, SCBCD). I've been programming since 1995 and still love this profession with a passion! If I'm not behind my Macbook Pro I like to spend time with my wife and 3 kids, family and friends, read a good book (novel or work related), watch a good movie or play the piano or guitar.

Updated on October 17, 2021

Comments

  • Johan Pelgrim
    Johan Pelgrim over 2 years

    I've just solved another *I-though-I-was-using-this-version-of-a-library-but-apparently-my-app-server-has-already-loaded-an-older-version-of-this-library-*issue (sigh).

    Does anybody know a good way to verify (or monitor) whether your application has access to all the appropriate jar-files, or loaded class-versions?

    Thanks in advance!

    [P.S. A very good reason to start using the OSGi module architecture in my view!]

    Update: This article helped as well! It gave me insight which classes JBoss' classloader loaded by writing it to a log file.