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

时间:2021-02-10 09:16:34

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

如果类路径中有两个包含同一类的不同版本的jar,则类路径顺序变得至关重要。

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.

有一些聪明的排序/ uniq / diff / grep / awk以后有潜力,但我想知道是否有人知道任何现有的解决方案。

7 个解决方案

#1


6  

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

来自JBoss的Tattletale工具是另一个候选者:“如果一个类/包位于多个JAR文件中,则会发现”

#2


8  

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

看起来像jarfish将通过其“dupes”命令执行您想要的操作。

#3


4  

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");

您可以使用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.

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

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.

如果你在一些具有复杂自定义类加载的基础结构中运行,可能java.class.path属性不会显示所有类(例如我曾经看过一个从LDAP加载类的应用程序),但它肯定适用于大多数情况。

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.

如果您要创建自己的工具,这里是我用于之前发布的相同shell脚本的代码,但是我在Windows机器上使用的代码。当有大量的jar文件时,它运行得更快。

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

您可以使用它并对其进行修改,而不是递归地遍历目录,读取类路径并比较.class时间属性。

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

如果需要,你可以子类化一个Command类,我在思考“find”的-execute选项

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.

我希望这有帮助。

#4


3  

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

Classpath Helper是一个Eclipse插件,可以帮助一点点。

#5


1  

Try jwhich or jcfind

试试jwhich或jcfind

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

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

#6


1  

If you dislike downloading and installing stuff you can use this one line command to find jar conflicts with standard gnu tools. It is rudimentary but you can expand it as you will.

如果您不喜欢下载和安装内容,可以使用这一行命令查找与标准gnu工具的jar冲突。这是基本的,但你可以随意扩展它。

ls *.jar | xargs -n1 -iFILE unzip -l FILE | grep class | sed "s,.* ,," | tr "/" "." | sort | uniq -d | xargs -n1 -iCLASS grep -l CLASS *.jar | sort -u

(it is a bit slow to run if you have a lot of jars)

(如果你有很多罐子,它运行有点慢)

Explanation: It lists all the files in all the jars, greps for class files, finds dupes, then greps the original jars to see where they appeared. It could be made more efficient with a more complicated script.

说明:它列出了所有jar中的所有文件,类文件的greps,查找dupes,然后greps原始jar以查看它们出现的位置。使用更复杂的脚本可以提高效率。

#7


0  

jarclassfinder is another eclipse plugin option

jarclassfinder是另一个eclipse插件选项

#1


6  

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

来自JBoss的Tattletale工具是另一个候选者:“如果一个类/包位于多个JAR文件中,则会发现”

#2


8  

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

看起来像jarfish将通过其“dupes”命令执行您想要的操作。

#3


4  

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");

您可以使用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.

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

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.

如果你在一些具有复杂自定义类加载的基础结构中运行,可能java.class.path属性不会显示所有类(例如我曾经看过一个从LDAP加载类的应用程序),但它肯定适用于大多数情况。

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.

如果您要创建自己的工具,这里是我用于之前发布的相同shell脚本的代码,但是我在Windows机器上使用的代码。当有大量的jar文件时,它运行得更快。

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

您可以使用它并对其进行修改,而不是递归地遍历目录,读取类路径并比较.class时间属性。

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

如果需要,你可以子类化一个Command类,我在思考“find”的-execute选项

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.

我希望这有帮助。

#4


3  

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

Classpath Helper是一个Eclipse插件,可以帮助一点点。

#5


1  

Try jwhich or jcfind

试试jwhich或jcfind

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

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

#6


1  

If you dislike downloading and installing stuff you can use this one line command to find jar conflicts with standard gnu tools. It is rudimentary but you can expand it as you will.

如果您不喜欢下载和安装内容,可以使用这一行命令查找与标准gnu工具的jar冲突。这是基本的,但你可以随意扩展它。

ls *.jar | xargs -n1 -iFILE unzip -l FILE | grep class | sed "s,.* ,," | tr "/" "." | sort | uniq -d | xargs -n1 -iCLASS grep -l CLASS *.jar | sort -u

(it is a bit slow to run if you have a lot of jars)

(如果你有很多罐子,它运行有点慢)

Explanation: It lists all the files in all the jars, greps for class files, finds dupes, then greps the original jars to see where they appeared. It could be made more efficient with a more complicated script.

说明:它列出了所有jar中的所有文件,类文件的greps,查找dupes,然后greps原始jar以查看它们出现的位置。使用更复杂的脚本可以提高效率。

#7


0  

jarclassfinder is another eclipse plugin option

jarclassfinder是另一个eclipse插件选项