Is there a tool to discover if the same class exists in multiple jars in the classpath?

Looks like jarfish will do what you want with its "dupes" command.


The Tattletale tool from JBoss is another candidate: "Spot if a class/package is located in multiple JAR files"


I think it wouldn't be too hard to write a tool for your self.

You can get the classpath entries with System.getProperty("java.class.path");

And then walk through the jars, zips, or directories listed there and collect all the information about the classes and findout those that might cause trouble.

This task would take 1 or 2 days at most. Then you can load this class directly in your application and generate a report.

Probably java.class.path property wont's show all the classes if you run in some infrastructure with complex custom class loading ( for instance I once saw an app that load the classes from the LDAP ) but it would certainly work for most of the cases.

Heres a tool you might find useful, I've never use it my self, but give it a try and let us know the result.

http://www.jgoodies.com/freeware/jpathreport/features.html

If you are going to create your own tool, here is the code I use for the same shell script posted before, but that I use on my Windows machine. It runs faster when there are tons of jar files.

You can use it and modify it so instead of recursively walk a directory, read the class path and compare the .class time attribute.

There is a Command class you can subclass if needed, I was thinking in the -execute option of "find"

This my own code, so it was not intended to be "production ready", just to do the work.

import java.io.*;
import java.util.zip.*;


public class ListZipContent{
    public static void main( String [] args ) throws IOException {
        System.out.println( "start " + new java.util.Date() );
        String pattern = args.length == 1 ? args[0] : "OracleDriver.class";// Guess which class I was looking for :) 
        File file = new File(".");
        FileFilter fileFilter = new FileFilter(){
            public boolean accept( File file ){
                return file.isDirectory() || file.getName().endsWith( "jar" );
            }
        };
        Command command = new Command( pattern );
        executeRecursively( command, file, fileFilter );
        System.out.println( "finish  " + new java.util.Date() );
    }
    private static void executeRecursively( Command command, File dir , FileFilter filter ) throws IOException {
        if( !dir.isDirectory() ){
            System.out.println( "not a directory " + dir );
            return;
        }
        for( File file : dir.listFiles( filter ) ){
            if( file.isDirectory()){
                executeRecursively( command,file , filter );
            }else{
                command.executeOn( file );
            }
        }
    }
}
class Command {

    private String pattern;
    public Command( String pattern ){
        this.pattern = pattern;
    }

    public void executeOn( File file ) throws IOException {
        if( pattern == null ) { 
            System.out.println( "Pattern is null ");
            return;
        }

        String fileName = file.getName();
        boolean jarNameAlreadyPrinted = false;

        ZipInputStream zis = null;
        try{
            zis = new ZipInputStream( new FileInputStream( file ) );

            ZipEntry ze;
            while(( ze = zis.getNextEntry() ) != null ) {
                if( ze.getName().endsWith( pattern )){
                    if( !jarNameAlreadyPrinted ){
                        System.out.println("Contents of: " + file.getCanonicalPath()  );
                        jarNameAlreadyPrinted = true;
                    }
                    System.out.println( "    " + ze.getName() );
                }
                zis.closeEntry();
            }
        }finally{
            if( zis != null ) try {
                zis.close();
            }catch( Throwable t ){}
        }
    }
}

I hope this helps.