Come ottenere i nomi delle classi all'interno di un file jar?


112

Ho un file JAR e ho bisogno di ottenere il nome di tutte le classi all'interno di questo file JAR. Come lo posso fare?

Ho cercato su Google e ClassLoaderho visto qualcosa su JarFile o Java ma non ho idea di come farlo.


Stai usando un IDE? Poiché verrà visualizzato automaticamente se ne stai usando uno.
joey rohan

Sto usando Eclipse, ma devo farlo con il codice.
sticksu

@LuiggiMendoza - Il potenziale duplicato ha risposte con esempi e risorse per la documentazione. La ricerca di uno di quei nomi di classe + esempio produrrà diversi risultati utili.
Aiias

@Alias ​​il possibile duplicato afferma come trovare e ottenere un file da un jar, mentre la domanda è ottenere i nomi delle classi all'interno di un jar (possibilmente le classi in tutti i pacchetti al suo interno). Il collegamento nella risposta di ErikKaju punta a una possibile soluzione utilizzando JarInputStreame JarEntryclassi che non riesco a trovare in nessuna risposta del tuo link indicato.
Luiggi Mendoza

Risposte:


68

Sfortunatamente, Java non fornisce un modo semplice per elencare le classi nel JRE "nativo". Ciò ti lascia con un paio di opzioni: (a) per ogni dato file JAR, puoi elencare le voci all'interno di quel file JAR, trovare i .classfile e quindi determinare quale classe Java ciascuno.class rappresenta file; o (b) puoi usare una libreria che fa questo per te.

Opzione (a): scansione manuale dei file JAR

In questa opzione, riempiremo classNamescon l'elenco di tutte le classi Java contenute in un file jar in /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()));
    }
}

Opzione (b): utilizzo di librerie di riflessioni specializzate

Guaiava

Guava ha ClassPathalmeno 14.0, che ho usato e mi è piaciuto. Una cosa bella ClassPathè che non carica le classi che trova, il che è importante quando si esegue la scansione di un gran numero di classi.

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

Riflessi

Non ho usato personalmente la libreria Reflections , ma mi sembra molto apprezzata. Alcuni ottimi esempi sono forniti sul sito web come questo modo rapido per caricare tutte le classi in un pacchetto fornito da qualsiasi file JAR, che può anche essere utile per la tua applicazione.

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

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

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

Reflections non funziona neanche se eseguito da un jar eseguibile.
Luca

Una soluzione Spring che funziona da jar eseguibili: stackoverflow.com/a/21430849/4265610 .
Luca

1
Basta usare. jar tvf jarfile.jar. Perché stai facendo tutto questo per.
Philip Rego

184

Puoi usare lo jarstrumento Java . Elenca il contenuto del file jar in un file txt e puoi vedere tutte le classi nel jar.

jar tvf jarfile.jar

-t elenca il sommario per l'archivio

-v genera un output dettagliato sullo standard output

-f specifica il nome del file di archivio


1
Grazie. Questo risponde alla parte "ottieni solo un elenco di classe" dell'OP che non è stata richiesta.
octopusgrabbus

9
Puoi anche usare unzip -l jarfile.jarin un pizzico. Un file JAR è solo un file zip con un manifest!
firmato

3
Il problema è che probabilmente voleva ottenere i file di classe all'interno di un jar in fase di esecuzione, data un'istanza del classloader (probabilmente per vedere quali classi sono caricate all'interno di quel jar specifico).
Richard Duerr

19

Forse stai cercando il jarcomando per ottenere l'elenco delle classi nel terminale,

$ 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

dove,

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

Oppure, basta grep sopra il risultato per vedere .classsolo 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

Per vedere il numero di classes,

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

2
questo era esattamente ciò di cui avevo bisogno, anche se il proprietario della domanda aveva bisogno di una soluzione basata sul codice. Grazie!
Provvidencemac

10

Questo è un trucco che sto usando:

Puoi utilizzare javail completamento automatico di in questo modo:

java -cp path_to.jar <Tab>

Questo ti darà un elenco di classi disponibili per passare come classe iniziale. Ovviamente, provare a usarne uno che non ha un file principale non farà nulla, ma puoi vedere cosa javapensa che le classi all'interno del file .jarsiano chiamate.



5

Puoi provare:

jar tvf jarfile.jar 

Questo sarà utile solo se il tuo jar è eseguibile, cioè nel manifest hai definito una classe come classe principale


Aggiungi un esempio specifico su un vaso di esempio alla tua risposta.
Juru

4

Il comando seguente elencherà il contenuto di un file jar .

comando: - unzip -l jarfilename.jar.

campione 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

Secondo il manuale di unzip

-l elenca i file di archivio (formato breve). Vengono stampati i nomi, le dimensioni dei file non compressi e le date e le ore di modifica dei file specificati, insieme ai totali per tutti i file specificati. Se UnZip è stato compilato con OS2_EAS definito, l'opzione -l elenca anche le colonne per le dimensioni degli attributi estesi OS / 2 (EA) e degli ACL (access control list) OS / 2 memorizzati. Inoltre, vengono visualizzati il ​​commento del file zip e i commenti dei singoli file (se presenti). Se un file è stato archiviato da un file system a caso singolo (ad esempio, il vecchio file system FAT di MS-DOS) e è stata fornita l'opzione -L, il nome del file viene convertito in minuscolo e viene preceduto da un accento circonflesso (^).


Sebbene questo frammento di codice sia il benvenuto e possa fornire qualche aiuto, sarebbe notevolmente migliorato se includesse una spiegazione di come e perché questo risolve il problema. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo alla persona che lo chiede ora! Si prega di modificare la risposta di aggiungere una spiegazione, e dare un'indicazione di ciò si applicano le limitazioni e le assunzioni.
Toby Speight

2

Puoi provare questo:

unzip -v /your/jar.jar

Questo sarà utile solo se il tuo jar è eseguibile, cioè nel manifest hai definito una classe come classe principale


1

Usa questo 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

questo elencherà le classi all'interno di jars nella tua directory nel modulo:

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

Output di esempio:

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

In Windows puoi usare 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

Descrizione della soluzione : è possibile utilizzare l'IDE Eclipse creando un progetto java di esempio e aggiungendo tutti i jar nel percorso di compilazione del progetto

FASI di seguito :

  1. Crea un progetto Java Eclipse di esempio.

  2. Tutti i vasi che hai nel suo percorso di costruzione

  3. CTRL + MAIUSC + T e digitare il nome completo della classe.

  4. I risultati verranno visualizzati nella finestra con tutti i vasi con quella classe. Vedi foto allegata. inserisci qui la descrizione dell'immagine


0

windows cmd: questo funzionerebbe se avessi tutti i file jar nella stessa directory ed eseguissi il comando seguente

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

0

Mac OS: sul terminale:

vim <your jar location>

after jar gets opened, press / and pass your class name and hit enter
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.