Как найти JAR-файл, содержащий определение класса?

Какой ваш любимый инструмент, плагин, скрипт, чтобы найти java-класс в куче jar-файлов?

Очень часто я наследую код, который жалуется на несуществующий класс, и это только потому, что файл jar не включен в classpath. Но в каком файле (ах) jar находится класс? У меня может не быть JAR (поэтому мне нужно искать в Интернете), или добавление JAR в путь к классам может создать проблему с дублированием определения класса.

Очевидно, я бы предпочел плагин Eclipse, но я открыт для любого программного обеспечения, которое работает с Windows.

Я знаю... Windows - это не мой выбор, но с этим я и должен работать.

Спасибо!

Луис

PS Спасибо за ваши ответы. Изучив некоторые ответы, я понял, что должен был лучше объяснить свой сценарий. У нас была библиотека загруженных или созданных JAR-файлов, но иногда класс был где-то онлайн.

17 ответов

(Это улучшение по сравнению со сценарием, который был у меня в предыдущих версиях ответа, поскольку он дает гораздо более чистый вывод по цене некоторых awk особое / безобразное цитирование.)

Я построил скрипт (findinjars) который делает именно это.

#!/usr/bin/env bash
if [[ ($# -ne 1) && ($# -ne 2) ]]
then
    echo "usage is $0 <grep pattern to look for in 'jar tvf' output> [<top-of-dir-tree> or, if missing, current dir]"
else
    THING_TO_LOOKFOR="$1"
    DIR=${2:-.}
    if [ ! -d $DIR ]; then
        echo "directory [$DIR] does not exist";
        exit 1;
    fi
    find "$DIR" -iname \*.jar | while read f ; do (jar tf $f | awk '{print "'"$f"'" "  " $0}' | grep -i "$THING_TO_LOOKFOR") ; done
fi

затем вы можете вызвать его с помощью:

$findinjars a.b.c.d.Class [directoryTreeRoot or, if missing, current dir]

или просто

$findinjars partOfClassName [directoryTreeRoot or, if missing, current dir]

Точечные символы в полностью определенном имени класса будут интерпретироваться в смысле регулярного выражения "любой символ", но это не имеет большого значения, поскольку это эвристическая утилита (поэтому она также нечувствительна к регистру). Обычно я не беспокоюсь о полном имени класса, а просто набираю его часть.

В тех же строках, что и в ответе BalusC (я пока не могу оставлять комментарии и ссылаться на 2 URL-адреса, нет репутации:(), вы можете найти банку благодаря этим двум механизмам поиска банок: - http://www.jarfinder.com/ - findjar

Более простая команда. Вам не нужно использовать 'while-do', используйте '&&' для печати имени файла, если 'grep' находит класс.

find . -name '*.jar' -print0 |  xargs -0 -I '{}' sh -c 'jar tf {} | grep Hello.class &&  echo {}'

Я обычно использую Bash для этого: grep -lr "ClassName" . Хитрость в том, что имена никак не кодируются. Вы можете открыть файл JAR в текстовом редакторе, и вы увидите их. (Вы даже можете включить имя пакета в поисковый запрос.)

Я подозреваю, что есть также несколько оконных эквивалентов.

Я сталкивался с одной и той же проблемой бесчисленное количество раз, поэтому я написал небольшой инструмент, чтобы найти их.

Простая командная строка: findclass MyClass -classpath...

Он ищет каталоги, файлы jar, zip, war и ear для вашего класса. Я написал это несколько лет назад и использую это все время. Я думал, что другие могут найти это полезным, поэтому я загрузил на GitHub.

Его можно бесплатно загрузить по адресу: https://github.com/eurozulu/Findclass/tree/master/dist

Если вы хотите посмотреть на источник, он находится на том же сайте: https://github.com/eurozulu/Findclass/tree/master

Если вам это нравится, просто дайте мне знать, чтобы дать мне это теплое удобное чувство:)

Я использую Jarscan. Это исполняемый файл jar, который может рекурсивно искать всю структуру папок для jar-файлов, которые содержат искомый класс. Он ищет по имени класса, имени пакета или регулярному выражению.

Grepj - это утилита командной строки для поиска классов в файлах jar.

Вы можете запустить утилиту как grepj package.Class my1.jar my2.war my3.ear

Область поиска

  • Классы в фляге
  • Классы внутри вложенных артефактов, таких как банки в файлах ear и war
  • WEB-INF/classes также ищется.

Может быть предоставлено несколько файлов jar, ear, war.

Я написал программу для этого: https://github.com/javalite/jar-explorer Он также декомпилирует существующий байт-код, чтобы показать вам интерфейсы, методы, суперклассы, покажет содержимое других ресурсов - текст, изображения, HTML, так далее.

Очень часто я наследую код, который жалуется на несуществующий класс, и это только потому, что файл jar не включен в classpath.

Если его нет в пути к классам, то, скорее всего, у вас нет самого файла JAR. Поиск через встроенную Eclipse Ctrl+Shift+T функция не очень поможет. Обычно вы можете использовать имя пакета, чтобы "угадать", откуда вы можете получить JAR-файл в Интернете. Например org.apache.commons.lang.XXX класс доступен на http://commons.apache.org/lang.

Для неочевидных я сам использую http://grepcode.com/, механизм поиска исходного кода JAR.

Использовать этот:

public class Main {

    private static final String SEARCH_PATH = "C:\\workspace\\RPLaunch";
    private static String CLASS_FILE_TO_FIND =
            "javax.ejb.SessionBean";
    private static List<String> foundIn = new LinkedList<String>();

    /**
     * @param args the first argument is the path of the file to search in. The second may be the
     *        class file to find.
     */
    public static void main(String[] args) {
        File start;
        new Scanner(args[0]);
        if (args.length > 0) {
            start = new File(args[0]);
            if (args.length > 1) {
                CLASS_FILE_TO_FIND = args[1];
            }
        } else {
            start = new File(SEARCH_PATH);
        }
        if (!CLASS_FILE_TO_FIND.endsWith(".class")) {
            CLASS_FILE_TO_FIND = CLASS_FILE_TO_FIND.replace('.', '/') + ".class";
        }
        search(start);
        System.out.println("------RESULTS------");
        for (String s : foundIn) {
            System.out.println(s);
        }
    }

    private static void search(File start) {
        try {
            final FileFilter filter = new FileFilter() {
                public boolean accept(File pathname) {
                    return pathname.getName().endsWith(".jar") || pathname.isDirectory();
                }
            };
            for (File f : start.listFiles(filter)) {
                if (f.isDirectory()) {
                    search(f);
                } else {
                    searchJar(f);
                }
            }
        } catch (Exception e) {
            System.err.println("Error at: " + start.getPath() + " " + e.getMessage());
        }
    }

    private static void searchJar(File f) {
        try {
            System.out.println("Searching: " + f.getPath());
            JarFile jar = new JarFile(f);
            ZipEntry e = jar.getEntry(CLASS_FILE_TO_FIND);
            if (e == null) {
                e = jar.getJarEntry(CLASS_FILE_TO_FIND);
            }
            if (e != null) {
                foundIn.add(f.getPath());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Лучший и самый простой способ - использовать JAD Decompiler. И да, это ПЛАГИН ЗАТМЕНИЯ!

Скачайте и сохраните плагин в любом месте на вашем компьютере.

Плагин содержит следующие файлы:

  1. Временная папка
  2. Файл jad.exe
  3. Плагин *net.sf.jadclipse_3.3.0.jar* JAR
  4. Readme

Выполните следующие шаги:

  1. Скопируйте плагин JAR в папку плагинов папки eclipse
  2. Открытое затмение. Перейти к окну >> Настройки >> Java >> JADClipse >> Путь к декомпилятору.
  3. Дайте путь jad.exe
  4. Перезапустите Eclipse

Теперь выберите любой класс и нажмите F3.

Файл.class автоматически декомпилируется и отображает содержимое!

Недавно я создал инструмент для поиска классов, пакетов и библиотек. Вы можете попробовать это http://javasearch.buggybread.com/. Нажмите на платформу, и она поможет вам найти информацию о зависимостях ( jar, pom).

Для х в $(найти. -name '*.jar') распаковать -l $x | grep WCCResponseImpl сделано

@ Никита Рыбак: AstroGrep для Windows - наш друг: http://astrogrep.sourceforge.net/

Вы всегда можете добавить справочную библиотеку в ваш проект в Eclipse, а затем в Package Browser, просто разверните пакеты в файле JAR, пока не найдете нужный класс.

Я пробовал некоторые из этих команд Unix, но они ошибались по разным причинам. Вот сценарий Perl, который я написал. Он специально разработан для запуска на Cygwin с использованием версии Perl для Cygwin.

#!/bin/perl

# This program searches recursively for a given class in .jar files contained in or below
# directories given as command-line arguments. See subroutine printUsageAndExit for details,
# or just run it with -h command-line argument.
#
# It is specfically designed to run on Windows via Cygwin, with Cygwin's version of Perl,
# though it could easily be modified to run elsewhere.

use strict;
use File::Find;
use Getopt::Std;

sub processCommandLineArguments (\$\@);
sub checkCommandLineArguments;

my $className;
my @startingDirectories;

&checkCommandLineArguments;
&processCommandLineArguments (\$className, \@startingDirectories );

my %options;
$options{wanted} = \&processFoundFile;
$options{no_chdir} = 1;
$options{follow} = 1; # So that $File::Find::fullname will be populated.
$options{follow_skip} = 2; # So it won't die if it encounters the same thing twice.

&find ( \%options, @startingDirectories );  # find comes from "use File::Find".

sub processFoundFile{
    # This routine is called by File::Find.
    #
    #  $File::Find::dir is the current directory name,
    #  $_ is the current filename within that directory
    #  $File::Find::name is the complete pathname to the file.

    my $jarFileName = $_;

    return unless /\.jar$/;

    my $fullFileName = $File::Find::fullname; # set by File::Find only when $options{follow} == 1

    # Windowize filename:
    $fullFileName = qx{cygpath --windows $fullFileName 2>&1};
    chomp $fullFileName;
    $fullFileName = '"' . $fullFileName . '"';

    my @results = qx{jar -tf $fullFileName 2>&1};

    local $/ = "\r\n";  # So that this Unix-based Perl can read output from Windows based jar command.

    for my $result ( @results )
    {
        chomp $result;

        if ( $result =~ /\b(\w+)\.((java)|(class))$/ )
        {
            my $classNameFound = $1;

            if ($classNameFound eq $className)
            {
                print $jarFileName, "\n";
                return;
            }
        }
    }
}

sub processCommandLineArguments (\$\@){

    my $refClassName = shift;
    my $refStartingDirectories = shift;

    $$refClassName = '';

    # parse @ARGV
    while (@ARGV){
        my $arg = shift @ARGV;

        if ($arg =~ /\Q-c/){
            $$refClassName = shift @ARGV;
        }elsif ($arg =~ /\Q-directories/){

            while ($ARGV[0] =~ m{^/(\w+/?)+\b}){
                my $directory = shift @ARGV;
                die "Can't find $directory $!" if ! -e $directory;
                push @$refStartingDirectories, $directory;
            }
        }
    }

    die "Must give -c class_name argument $!" if $$refClassName eq "";

    push @$refStartingDirectories, '.' if scalar (@$refStartingDirectories ) == 0;
}

sub checkCommandLineArguments
{
    {
        # getopts butchers @ARGV, so have to use it on a local version.
        local @ARGV = @ARGV;

        our $opt_h;
        &getopts('hc'); # Have to specify all options given or getopts will die.

        &printUsageAndExit if $opt_h;
    }

    my $className;

    {
        # getopts butchers @ARGV, so have to use it on a local version.
        local @ARGV = @ARGV;

        while (@ARGV){
            my $arg = shift @ARGV;

            if ($arg =~ /\Q-c/){
                $className = shift @ARGV;

                &printUsageAndExit if $className =~ /^\s*$/ ;

                return;
            }
        }
    }

    &printUsageAndExit;
}

sub printUsageAndExit
{
    print "Usage:\n\n";
    print "$0 -c class_name_to_search_for [ -directories startingDirectory1 startingDirectory2 ...]\n\n";
    print "Example:\n\n";
    print "findJarContainingClass.pl -c ApplicationMaster -directories /home/lylez/Hadoop/hadoop-2.x/hadoop-2.2.0/share/hadoop/yarn/sources /home/lylez/Hadoop/hadoop-2.x/hadoop-2.2.0/share/hadoop/yarn\n\n";

    exit;
}

Просто хотел упомянуть здесь, что третьи стороны могут искать какое-то конкретное имя файла в jarfinder. Хотя это не дает прямого ответа на вопрос, но не повредит:)

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

Другие вопросы по тегам