Como obter nomes de classes dentro de um arquivo jar?

112

Eu tenho um arquivo JAR e preciso obter o nome de todas as classes dentro desse arquivo JAR. Como eu posso fazer isso?

Pesquisei no Google e vi algo sobre JarFile ou Java, ClassLoadermas não tenho ideia de como fazer isso.

Sticku
fonte
Você está usando algum IDE? Porque ele será exibido automaticamente se você estiver usando um.
joey rohan
Estou usando o Eclipse, mas preciso fazer isso com código.
Sticku
@LuiggiMendoza - A possível duplicata possui respostas com exemplos, bem como recursos para documentação. Procurar por um desses nomes de classe + exemplo produzirá vários resultados úteis.
Aiias
@Alias, a possível duplicata afirma como encontrar e obter um arquivo de um jar, enquanto a questão é sobre como obter os nomes das classes dentro de um jar (possivelmente as classes em todos os pacotes dentro dele). O link na resposta do ErikKaju aponta para uma possível solução usando JarInputStreame JarEntryclasses que não consigo encontrar em nenhuma resposta do seu referido link.
Luiggi Mendoza

Respostas:

68

Infelizmente, o Java não fornece uma maneira fácil de listar classes no JRE "nativo". Isso deixa você com algumas opções: (a) para qualquer arquivo JAR fornecido, você pode listar as entradas dentro desse arquivo JAR, localizar os .classarquivos e determinar qual classe Java cada .classarquivo representa; ou (b) você pode usar uma biblioteca que faça isso para você.

Opção (a): Verificar arquivos JAR manualmente

Nesta opção, preencheremos classNamescom a lista de todas as classes Java contidas em um arquivo jar em /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()));
    }
}

Opção (b): Usando bibliotecas de reflexões especializadas

Goiaba

A goiaba tem ClassPathdesde pelo menos 14.0, que usei e gostei. Uma coisa boa ClassPathé que ele não carrega as classes que encontra, o que é importante quando você está procurando por um grande número de classes.

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

Reflexões

Eu não usei pessoalmente a biblioteca Reflections , mas parece bem quista. Alguns ótimos exemplos são fornecidos no site, como esta maneira rápida de carregar todas as classes em um pacote fornecido por qualquer arquivo JAR, que também pode ser útil para seu aplicativo.

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

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

Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(SomeAnnotation.class);
assinado
fonte
O Reflections também não funciona se executado a partir de um jar executável.
Lucas
Uma solução Spring trabalhando com jars executáveis: stackoverflow.com/a/21430849/4265610 .
Lucas
1
Apenas use. jar tvf jarfile.jar. Por que você está fazendo tudo isso.
Philip Rego
184

Você pode usar a jarferramenta Java . Liste o conteúdo do arquivo jar em um arquivo txt e você poderá ver todas as classes do jar.

jar tvf jarfile.jar

-t lista o índice do arquivo

-v gera saída detalhada na saída padrão

-f especificar o nome do arquivo

Sanjeev Gupta
fonte
1
Obrigado. Isso responde à parte "basta obter uma lista de classes" do OP que não foi solicitada.
octopusgrabbus
9
Você também pode usar unzip -l jarfile.jarem uma pitada. Um arquivo JAR é apenas um arquivo zip com um manifesto!
assinado
3
O problema é que ele provavelmente queria obter os arquivos de classe dentro de um jar em tempo de execução, dada uma instância do carregador de classe (provavelmente para ver quais classes são carregadas dentro desse jar específico).
Richard Duerr
19

Talvez você esteja procurando um jarcomando para obter a lista de classes no terminal,

$ 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

Onde,

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

Ou apenas grep acima do resultado para ver .classapenas os

$ 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

Para ver o número de classes,

jar tvf launcher/target/usergrid-launcher-1.0-SNAPSHOT.jar | grep .class | wc -l
61079
prayagupd
fonte
2
isso era exatamente o que eu precisava, mesmo que o proprietário da pergunta precisasse de uma solução baseada em código. Obrigado!
providencemac
10

Este é um hack que estou usando:

Você pode usar javao preenchimento automático de assim:

java -cp path_to.jar <Tab>

Isso lhe dará uma lista de classes disponíveis para passar como a classe inicial. Claro, tentar usar um que não tenha o arquivo principal não fará nada, mas você pode ver o que javapensa que as classes dentro do .jarsão chamadas.

stanm
fonte
7

Você pode usar o

jar tf example.jar
estrela Solitária
fonte
5

Podes tentar:

jar tvf jarfile.jar 

Isso será útil apenas se o seu jar for executável, ou seja, no manifesto, você definiu alguma classe como classe principal

Pallav
fonte
Adicione algum exemplo específico em um jarro de exemplo à sua resposta.
Juru,
4

O comando abaixo listará o conteúdo de um arquivo jar .

comando: - unzip -l jarfilename.jar.

amostra o / p: -

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

De acordo com o manual de unzip

-l lista os arquivos compactados (formato curto). Os nomes, tamanhos de arquivo não compactados e datas e horas de modificação dos arquivos especificados são impressos, junto com os totais de todos os arquivos especificados. Se o UnZip foi compilado com OS2_EAS definido, a opção -l também lista colunas para os tamanhos de atributos estendidos (EAs) do OS / 2 armazenados e listas de controle de acesso (ACLs) do OS / 2. Além disso, o comentário do zipfile e os comentários individuais do arquivo (se houver) são exibidos. Se um arquivo foi arquivado de um sistema de arquivos de caso único (por exemplo, o antigo sistema de arquivos FAT do MS-DOS) e a opção -L foi fornecida, o nome do arquivo é convertido para minúsculas e é prefixado com um acento circunflexo (^).

Opster Elasticsearch Ninja
fonte
Embora este trecho de código seja bem-vindo e possa fornecer alguma ajuda, seria muito melhor se incluísse uma explicação de como e por que isso resolve o problema. Lembre-se de que você está respondendo às perguntas para os leitores no futuro, não apenas para a pessoa que está perguntando agora! Por favor edite sua resposta para adicionar explicação, e dar uma indicação do que limitações e premissas se aplicam.
Toby Speight
2

Você pode tentar isto:

unzip -v /your/jar.jar

Isso será útil apenas se o seu jar for executável, ou seja, no manifesto, você definiu alguma classe como classe principal

Abhimanyu Dutta
fonte
1

Use este script 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

isso irá listar as classes dentro de jars em seu diretório na forma:

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

Saída de amostra:

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

No Windows, você pode usar o 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 "/", ".")
    }
}
ESPRIELLA_GREGORIO QUINTERO_DE
fonte
0

Descrição da solução : Eclipse IDE pode ser usado para isso criando um projeto java de amostra e adicionando todos os jars no caminho de construção do projeto

PASSOS abaixo :

  1. Crie um projeto Eclipse Java de amostra.

  2. Todos os frascos que você tem em seu caminho de construção

  3. CTRL + SHIFT + T e digite o nome completo da classe.

  4. Os resultados serão exibidos na janela com todos os frascos dessa classe. Veja a foto em anexo. insira a descrição da imagem aqui

Arokiadoss Asirvatham
fonte
0

windows cmd: isso funcionaria se você tivesse todos os jars no mesmo diretório e execute o comando abaixo

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

Mac OS: No Terminal:

vim <your jar location>

after jar gets opened, press / and pass your class name and hit enter
Rajiv Singh
fonte