Есть ли инструмент, чтобы обнаружить, существует ли один и тот же класс в нескольких банках в пути к классам? - PullRequest
19 голосов
/ 26 сентября 2008

Если в вашем пути к классам есть две банки, содержащие разные версии одного и того же класса, порядок пути к классам становится критическим.

Я ищу инструмент, который может обнаружить и пометить такие потенциальные конфликты в заданном пути к классам или в наборе папок.

Конечно, скрипт, который запускается:

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

с некоторой умной сортировкой / uniq / diff / grep / awk позже имеет потенциал, но мне было интересно, если кто-нибудь знает какие-либо существующие решения.

Ответы [ 7 ]

9 голосов
/ 23 декабря 2010

Похоже, jarfish будет делать то, что вы хотите, с его командой "dupes".

6 голосов
/ 24 декабря 2010

Инструмент Tattletale от JBoss является другим кандидатом: «Найдите, если класс / пакет находится в нескольких файлах JAR»

4 голосов
/ 26 сентября 2008

Я думаю, было бы не сложно написать инструмент для себя.

Вы можете получить записи classpath с помощью System.getProperty ("java.class.path");

А затем пройдитесь по банкам, почтовым индексам или каталогам, перечисленным там, соберите всю информацию о классах и найдите те, которые могут вызвать проблемы.

Это задание займет максимум 1 или 2 дня. Затем вы можете загрузить этот класс прямо в ваше приложение и сгенерировать отчет.

Вероятно, свойство java.class.path не будет отображать все классы, если вы работаете в какой-либо инфраструктуре со сложной пользовательской загрузкой классов (например, однажды я видел приложение, которое загружает классы из LDAP), но оно, безусловно, будет работать для большинства случаи.

Вот инструмент, который вы могли бы найти полезным, я сам никогда не использовал его, но попробуйте и дайте нам знать результат.

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

Если вы собираетесь создать свой собственный инструмент, вот код, который я использую для того же сценария оболочки, опубликованного ранее, но который я использую на своем компьютере с Windows. Он работает быстрее, когда есть множество файлов jar.

Вы можете использовать его и изменить, чтобы вместо рекурсивного обхода каталога прочитать путь к классу и сравнить атрибут времени .class.

Существует класс Command, который вы можете подклассировать, если это необходимо, я думал в опции -execute "find"

Это мой собственный код, поэтому он не был предназначен для "производства готов", просто чтобы сделать работу.

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

Надеюсь, это поможет.

3 голосов
/ 26 сентября 2008

Classpath Helper - это плагин Eclipse, который немного помогает.

1 голос
/ 06 мая 2016

Если вам не нравится скачивать и устанавливать вещи, вы можете использовать эту однострочную команду, чтобы найти конфликты jar со стандартными инструментами gnu. Это элементарно, но вы можете расширить его, как пожелаете.

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

(если у вас много баночек, он немного медленный)

Пояснение: Он перечисляет все файлы во всех банках, greps для файлов классов, находит дубликаты, затем greps оригинальных банок, чтобы увидеть, где они появились. Это можно сделать более эффективным с помощью более сложного сценария.

1 голос
/ 26 сентября 2008
0 голосов
/ 30 сентября 2008

jarclassfinder - это еще одна опция плагина Eclipse

...