¿Cómo obtener nombres de clases dentro de un archivo jar?

112

Tengo un archivo JAR y necesito obtener el nombre de todas las clases dentro de este archivo JAR. ¿Cómo puedo hacer eso?

Lo busqué en Google y vi algo sobre JarFile o Java, ClassLoaderpero no tengo idea de cómo hacerlo.

sticksu
fuente
¿Estás usando algún IDE? Ya que se mostrará automáticamente si estás usando uno.
joey rohan
Estoy usando Eclipse, pero necesito hacer esto con código.
sticksu
@LuiggiMendoza: el posible duplicado tiene respuestas con ejemplos y recursos para la documentación. La búsqueda de uno de esos nombres de clase + ejemplo producirá varios resultados útiles.
Aiias
@Alias, el posible duplicado indica cómo encontrar y obtener un archivo de un jar, mientras que la pregunta es sobre cómo obtener los nombres de las clases dentro de un jar (posiblemente las clases en todos los paquetes dentro de él). El enlace en la respuesta de ErikKaju apunta a una posible solución usando JarInputStreamy JarEntryclases que no puedo encontrar en ninguna respuesta de su enlace referido.
Luiggi Mendoza

Respuestas:

68

Desafortunadamente, Java no proporciona una manera fácil de listar clases en el JRE "nativo". Eso le deja con un par de opciones: (a) para cualquier archivo JAR dado, puede enumerar las entradas dentro de ese archivo JAR, encontrar los .classarchivos y luego determinar qué clase Java .classrepresenta cada archivo; o (b) puede usar una biblioteca que lo haga por usted.

Opción (a): escanear archivos JAR manualmente

En esta opción, completaremos classNamescon la lista de todas las clases de Java contenidas dentro de un archivo jar en /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()));
    }
}

Opción (b): uso de bibliotecas de reflexiones especializadas

Guayaba

Guava ha tenido ClassPathdesde al menos 14.0, que he usado y me ha gustado. Una cosa buena ClassPathes que no carga las clases que encuentra, lo cual es importante cuando se busca una gran cantidad de clases.

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

Reflexiones

No he usado personalmente la biblioteca Reflections , pero parece muy apreciada. En el sitio web se proporcionan algunos ejemplos excelentes, como esta forma rápida de cargar todas las clases en un paquete proporcionado por cualquier archivo JAR, que también puede ser útil para su aplicación.

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

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

Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(SomeAnnotation.class);
sigpwned
fuente
Reflections tampoco funciona si se ejecuta desde un jar ejecutable.
Luke
Una solución de Spring que funciona desde archivos ejecutables: stackoverflow.com/a/21430849/4265610 .
Luke
1
Solo usa. jar tvf jarfile.jar. ¿Por qué estás haciendo todo esto?
Philip Rego
184

Puede utilizar la jarherramienta Java . Enumere el contenido del archivo jar en un archivo txt y podrá ver todas las clases en el jar.

jar tvf jarfile.jar

-t lista la tabla de contenido para el archivo

-v genera una salida detallada en la salida estándar

-f especificar el nombre del archivo de almacenamiento

Sanjeev Gupta
fuente
1
Gracias. Esto responde a la parte de "solo obtenga una lista de clases" del OP que no se pidió.
octopusgrabbus
9
También se puede utilizar unzip -l jarfile.jaren caso de apuro. ¡Un archivo JAR es solo un archivo zip con un manifiesto!
firmado
3
El problema es que probablemente quería obtener los archivos de clase dentro de un jar en tiempo de ejecución, dada una instancia de cargador de clases (es probable que vea qué clases se cargan dentro de ese jar específico).
Richard Duerr
19

Tal vez esté buscando un jarcomando para obtener la lista de clases en la 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

dónde,

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

O simplemente grep sobre el resultado para ver .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

Para ver el número de classes,

jar tvf launcher/target/usergrid-launcher-1.0-SNAPSHOT.jar | grep .class | wc -l
61079
prayagupd
fuente
2
esto era exactamente lo que necesitaba, incluso si el propietario de la pregunta necesitaba una solución basada en código. ¡Gracias!
providencemac
10

Este es un truco que estoy usando:

Puede usar javael autocompletado de esta manera:

java -cp path_to.jar <Tab>

Esto le dará una lista de clases disponibles para pasar como clase inicial. Por supuesto, intentar usar uno que no tiene un archivo principal no hará nada, pero puedes ver cómo se llaman javalas clases dentro del .jar.

stanm
fuente
7

Puedes usar el

jar tf example.jar
estrella solitaria
fuente
5

Puedes probar:

jar tvf jarfile.jar 

Esto será útil solo si su jar es ejecutable, es decir, en el manifiesto ha definido alguna clase como clase principal

Pallav
fuente
Agregue un ejemplo específico en un frasco de ejemplo a su respuesta.
Juru
4

El siguiente comando mostrará una lista del contenido de un archivo jar .

comando: - unzip -l jarfilename.jar.

muestra 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

Según manual de unzip

-l lista de archivos de almacenamiento (formato corto). Se imprimen los nombres, tamaños de archivo sin comprimir y fechas y horas de modificación de los archivos especificados, junto con los totales de todos los archivos especificados. Si UnZip se compiló con OS2_EAS definido, la opción -l también enumera columnas para los tamaños de los atributos extendidos (EA) de OS / 2 almacenados y las listas de control de acceso (ACL) de OS / 2. Además, se muestran el comentario del archivo zip y los comentarios del archivo individual (si los hay). Si un archivo se archivó desde un sistema de archivos de un solo caso (por ejemplo, el antiguo sistema de archivos FAT de MS-DOS) y se proporcionó la opción -L, el nombre del archivo se convierte a minúsculas y tiene el prefijo de intercalación (^).

Opster Elasticsearch Ninja
fuente
Si bien este fragmento de código es bienvenido y puede proporcionar algo de ayuda, sería mucho mejor si incluyera una explicación de cómo y por qué resuelve el problema. Recuerde que está respondiendo la pregunta para los lectores en el futuro, ¡no solo la persona que pregunta ahora! Por favor, editar su respuesta para agregar explicación y dar una indicación de lo que se aplican limitaciones y supuestos.
Toby Speight
2

Puedes probar esto:

unzip -v /your/jar.jar

Esto será útil solo si su jar es ejecutable, es decir, en el manifiesto ha definido alguna clase como clase principal

Abhimanyu Dutta
fuente
1

Utilice este script de 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

esto enumerará las clases dentro de los frascos en su directorio en la forma:

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

Salida de muestra:

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

En Windows puede usar 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
fuente
0

Descripción de la solución : Eclipse IDE se puede utilizar para esto creando un proyecto java de muestra y agregando todos los archivos jar en la ruta de construcción del proyecto

PASOS a continuación :

  1. Cree un proyecto Java de Eclipse de muestra.

  2. Todos los frascos que tienes en su Build Path

  3. CTRL + MAYÚS + T y escriba el nombre completo de la clase.

  4. Los resultados se mostrarán en la ventana con todos los frascos que tengan esa clase. Ver imagen adjunta . ingrese la descripción de la imagen aquí

Arokiadoss Asirvatham
fuente
0

Windows cmd: esto funcionaría si tiene todos los tarros en el mismo directorio y ejecuta el siguiente comando

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

Mac OS: en la terminal:

vim <your jar location>

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