¿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.


¿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);

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


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

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.



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


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 (^).


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


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 "/", ".")
    }
}

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í


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")

0

Mac OS: en la terminal:

vim <your jar location>

after jar gets opened, press / and pass your class name and hit enter
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.