Как получить имена классов внутри 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.