Как найти 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. И да, это ПЛАГИН ЗАТМЕНИЯ!
Скачайте и сохраните плагин в любом месте на вашем компьютере.
Плагин содержит следующие файлы:
- Временная папка
- Файл jad.exe
- Плагин *net.sf.jadclipse_3.3.0.jar* JAR
- Readme
Выполните следующие шаги:
- Скопируйте плагин JAR в папку плагинов папки eclipse
- Открытое затмение. Перейти к окну >> Настройки >> Java >> JADClipse >> Путь к декомпилятору.
- Дайте путь jad.exe
- Перезапустите 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. Хотя это не дает прямого ответа на вопрос, но не повредит:)
Надеюсь это поможет