Как получить имена классов внутри jar файла?


112

У меня есть файл JAR, и мне нужно получить имена всех классов внутри этого файла JAR. Как я могу это сделать?

Я погуглил и увидел кое-что о JarFile или Java, ClassLoaderно понятия не имею, как это сделать.


Вы используете какую-либо IDE? Поскольку она будет отображаться автоматически, если вы ее используете.
— Джои Рохан

Я использую Eclipse, но мне нужно сделать это с помощью кода.
— sticksu

@LuiggiMendoza - у потенциального дубликата есть ответы с примерами, а также ресурсы для документации. Поиск одного из этих имен классов + пример даст несколько полезных результатов.
— Aiias

@Alias ​​возможный дубликат указывает, как найти и получить файл из банки, в то время как вопрос заключается в получении имен классов внутри банки (возможно, классов во всех пакетах внутри нее). Ссылка в пунктах ответа ErikKaju к возможному решению с использованием JarInputStreamи JarEntryклассов , которые я не могу найти в любом ответе вашей упомянутой ссылки.
— Луиджи Мендоса

Ответы:


68

К сожалению, Java не предоставляет простой способ перечисления классов в «родной» JRE. Это оставляет вам несколько вариантов: (а) для любого заданного файла JAR вы можете перечислить записи внутри этого файла JAR, найти .classфайлы, а затем определить, какой класс Java представляет каждый .classфайл; или (б) вы можете использовать библиотеку, которая сделает это за вас.

Вариант (а): сканирование файлов JAR вручную

В этом варианте мы заполним classNamesсписок всех классов Java, содержащихся в файле jar по адресу /path/to/jar/file.jar.

List<String> classNames = new ArrayList<String>();
ZipInputStream zip = new ZipInputStream(new FileInputStream("/path/to/jar/file.jar"));
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
    if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
        // This ZipEntry represents a class. Now, what class does it represent?
        String className = entry.getName().replace('/', '.'); // including ".class"
        classNames.add(className.substring(0, className.length() - ".class".length()));
    }
}

Вариант (б): Использование специализированных библиотек отражений

гуайява

У Guava было ClassPathпо крайней мере 14.0, что я использовал и любил. Приятно то, ClassPathчто он не загружает найденные классы, что важно, когда вы сканируете большое количество классов.

ClassPath cp=ClassPath.from(Thread.currentThread().getContextClassLoader());
for(ClassPath.ClassInfo info : cp.getTopLevelClassesRecurusive("my.package.name")) {
    // Do stuff with classes here...
}

Размышления

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

Reflections reflections = new Reflections("my.project.prefix");

Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);

Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(SomeAnnotation.class);

Отражения также не работают, если запускаются из исполняемого файла jar.
— Люк

Решение Spring, работающее с исполняемыми jar-файлами: stackoverflow.com/a/21430849/4265610 .
— Люк

1
Просто используйте. jar tvf jarfile.jar. Зачем ты все это делаешь.
— Филип Рего

184

Вы можете использовать jarинструмент Java . Перечислите содержимое jar-файла в txt-файле, и вы увидите все классы в jar-файле.

jar tvf jarfile.jar

-t перечислить оглавление для архива

-v генерировать подробный вывод на стандартный вывод

-f указать имя файла архива


1
Спасибо. Это отвечает на часть OP «просто получить список классов», о которой не спрашивали.
— octopusgrabbus

9
Вы также можете использовать unzip -l jarfile.jarв крайнем случае. Файл JAR - это просто zip-файл с манифестом!
— подписано

3
Проблема в том, что он, вероятно, хотел получить файлы классов внутри банки во время выполнения, учитывая экземпляр загрузчика классов (вероятно, чтобы увидеть, какие классы загружены внутри этой конкретной банки).
— Ричард Дюрр

19

Возможно, вы ищете jarкоманду для получения списка классов в терминале,

$ jar tf ~/.m2/repository/org/apache/spark/spark-assembly/1.2.0-SNAPSHOT/spark-assembly-1.2.0-SNAPSHOT-hadoop1.0.4.jar 
META-INF/
META-INF/MANIFEST.MF
org/
org/apache/
org/apache/spark/
org/apache/spark/unused/
org/apache/spark/unused/UnusedStubClass.class
META-INF/maven/
META-INF/maven/org.spark-project.spark/
META-INF/maven/org.spark-project.spark/unused/
META-INF/maven/org.spark-project.spark/unused/pom.xml
META-INF/maven/org.spark-project.spark/unused/pom.properties
META-INF/NOTICE

где,

-t  list table of contents for archive
-f  specify archive file name

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

$ jar tf ~/.m2/repository/org/apache/spark/spark-assembly/1.2.0-SNAPSHOT/spark-assembly-1.2.0-SNAPSHOT-hadoop1.0.4.jar | grep .class
org/apache/spark/unused/UnusedStubClass.class

Чтобы увидеть количество classes,

jar tvf launcher/target/usergrid-launcher-1.0-SNAPSHOT.jar | grep .class | wc -l
61079

2
это было именно то, что мне нужно, даже если владельцу вопроса требовалось решение на основе кода. Спасибо!
— Provisionncemac

10

Вот что я использую:

Вы можете использовать javaавтозаполнение следующим образом:

java -cp path_to.jar <Tab>

Это даст вам список классов, доступных для передачи в качестве начального класса. Конечно, попытка использовать тот, у которого нет основного файла, ничего не даст, но вы можете увидеть, что javaдумают, что классы внутри класса .jarвызываются.



6

Можешь попробовать:

jar tvf jarfile.jar 

Это будет полезно, только если ваша банка является исполняемой, то есть в манифесте вы определили какой-то класс как основной класс


Добавьте к своему ответу конкретный пример из баночки с образцом.
— Juru 08

4

Команда ниже отобразит содержимое файла jar .

команда: - unzip -l jarfilename.jar.

образец о / п: -

Archive: hello-world.jar Length Date Time Name --------- ---------- ----- ---- 43161 10-18-2017 15:44 hello-world/com/ami/so/search/So.class 20531 10-18-2017 15:44 hello-world/com/ami/so/util/SoUtil.class --------- ------- 63692 2 files

Согласно руководству unzip

-l список файлов архива (короткий формат). Распечатываются имена, размеры несжатых файлов, даты и время изменения указанных файлов, а также итоговые данные для всех указанных файлов. Если UnZip был скомпилирован с определением OS2_EAS, опция -l также перечисляет столбцы для размеров сохраненных расширенных атрибутов OS / 2 (EAs) и списков управления доступом (ACL) OS / 2. Кроме того, отображаются комментарии к zip-файлу и отдельные комментарии к файлу (если есть). Если файл был заархивирован из файловой системы с одним регистром (например, из старой файловой системы MS-DOS FAT) и был задан параметр -L, имя файла преобразуется в нижний регистр и начинается с символа вставки (^).


Хотя этот фрагмент кода приветствуется и может оказать некоторую помощь, его можно было бы значительно улучшить, если бы он включал объяснение того, как и почему это решает проблему. Помните, что вы отвечаете на вопрос для будущих читателей, а не только для человека, который задает его сейчас! Пожалуйста , измените свой ответ , чтобы добавить объяснение, и дать указание о том , что применять ограничения и допущения.
— Тоби Спейт

2

Вы можете попробовать это:

unzip -v /your/jar.jar

Это будет полезно, только если ваша банка является исполняемой, то есть в манифесте вы определили какой-то класс как основной класс


1

Используйте этот сценарий bash:

#!/bin/bash

for VARIABLE in *.jar
do
   jar -tf $VARIABLE |grep "\.class"|awk -v arch=$VARIABLE '{print arch ":" $4}'|sed 's/\//./g'|sed 's/\.\.//g'|sed 's/\.class//g'
done

это перечислит классы внутри jar-файлов в вашем каталоге в форме:

file1.jar:fullyqualifiedclassName
file1.jar:fullyqualifiedclassName
file1.jar:fullyqualifiedclassName
file1.jar:fullyqualifiedclassName
file2.jar:fullyqualifiedclassName
file2.jar:fullyqualifiedclassName
file2.jar:fullyqualifiedclassName

Пример вывода:

commons-io.jar:org.apache.commons.io.ByteOrderMark
commons-io.jar:org.apache.commons.io.Charsets
commons-io.jar:org.apache.commons.io.comparator.AbstractFileComparator
commons-io.jar:org.apache.commons.io.comparator.CompositeFileComparator
commons-io.jar:org.apache.commons.io.comparator.DefaultFileComparator
commons-io.jar:org.apache.commons.io.comparator.DirectoryFileComparator
commons-io.jar:org.apache.commons.io.comparator.ExtensionFileComparator
commons-io.jar:org.apache.commons.io.comparator.LastModifiedFileComparator

В Windows вы можете использовать PowerShell:

Get-ChildItem -File -Filter *.jar |
ForEach-Object{
    $filename = $_.Name
    Write-Host $filename
    $classes = jar -tf $_.Name |Select-String -Pattern '.class' -CaseSensitive -SimpleMatch
    ForEach($line in $classes) {
       write-host $filename":"(($line -replace "\.class", "") -replace "/", ".")
    }
}

0

Описание решения : для этого можно использовать среду Eclipse IDE, создав образец java-проекта и добавив все jar-файлы в путь сборки проекта.

ШАГИ ниже :

  1. Создайте образец проекта Eclipse Java.

  2. Все банки, которые у вас есть в пути сборки

  3. CTRL + SHIFT + T и введите полное имя класса.

  4. Результаты будут отображаться в окне со всеми банками, имеющими этот класс. См. Прикрепленное изображение. введите описание изображения здесь


0

windows cmd: это будет работать, если у вас есть все банки te в одном каталоге и выполните следующую команду

for /r %i in (*) do ( jar tvf %i | find /I "search_string")

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.