是否有工具可以发现类路径中的多个jar中是否存在相同的类?

时间:2020-03-06 14:44:55  来源:igfitidea点击:

如果类路径中有两个jar,其中包含同一个类的不同版本,则类路径的顺序就很重要。

我正在寻找一种工具,该工具可以检测和标记给定的类路径或者文件夹集中的此类潜在冲突。

当然可以启动一个脚本:

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

稍后再使用一些巧妙的sort / uniq / diff / grep / awk很有潜力,但是我想知道是否有人知道任何现有的解决方案。

解决方案

Classpath Helper是一个Eclipse插件,可以提供一些帮助。

尝试jwhich或者jcfind

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

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

我认为为自己编写工具并不难。

我们可以使用System.getProperty(" java.class.path");获得类路径条目。

然后浏览那里列出的jar,zip或者目录,收集有关类的所有信息,并找出可能引起麻烦的信息。

此任务最多需要1或者2天。然后,我们可以直接在应用程序中加载此类,并生成报告。

如果我们在具有复杂的自定义类加载的某些基础结构中运行(例如,我曾经见过一个从LDAP加载类的应用程序),则java.class.path属性可能不会显示所有类。

这是一个我们可能会发现有用的工具,我从来没有亲自使用过,但请尝试一下,让我们知道结果。

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

如果要创建自己的工具,这是我以前发布的相同Shell脚本所使用的代码,但是我在Windows计算机上使用了该代码。当有大量的jar文件时,它运行得更快。

我们可以使用它并对其进行修改,因此不必递归地遍历目录,读取类路径并比较.class time属性。

有一个Command类可以根据需要进行子类化,我在想" find"的-execute选项

这是我自己的代码,因此并不是为了进行生产而准备的,只是为了完成工作。

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 ){}
        }
    }
}

我希望这有帮助。

jarclassfinder是另一个eclipse插件选项

看起来jarfish可以通过其" dupes"命令执行我们想要的操作。

JBoss的Tattletale工具是另一个候选者:"如果一个类/程序包位于多个JAR文件中,则发现"