views:

664

answers:

4

If you have two jars in your classpath that contain different versions of the same class, the classpath order becomes critical.

I am looking for a tool that can detect and flag such potential conflicts in a given classpath or set of folders.

Certainly a script that starts:

classes=`mktemp`
for i in `find . -name "*.jar"`
do
    echo "File: $i" > $classes
    jar tf $i > $classes
    ...
done

with some clever sort/uniq/diff/grep/awk later on has potential, but I was wondering if anyone knows of any existing solutions.

+3  A: 

Classpath Helper is an Eclipse plug-in that helps a little bit.

jeffContext
+1  A: 

Try jwhich or jcfind

http://javaclassfind.wiki.sourceforge.net/

http://which4j.dev.java.net/

skaffman
These both appear to do the opposite of what I want: they find a given class in a set of jars. I want to find conflicting classes in a given classpath or set of jars.
David Citron
In what way is that the opposite? They list which JARs a given class can be found, and if there's multiple matches, they list them all - that's your conflict listing.
skaffman
But I want to discover every instance of some class appearing in multiple jars. I would have to run whichj for every class in my CLASSPATH and search for duplicates (sort|uniq|diff) -- just a slower version of my brute-force proposal in the question.
David Citron
+2  A: 

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.

OscarRyz
A: 

jarclassfinder is another eclipse plugin option

s_t_e_v_e
The product's description says that it's a "plug-in utility for finding Java Archive (JAR) files containing a given class for the Java build path of a project." This is the opposite of what I need. I need to know if the same class is in two jars, NOT which jar a given class is in.
David Citron
It will detect that a given class is in multiple jars, but it won't find all cases of classes in multiple jars.
s_t_e_v_e