Java: obtenga una lista de todas las clases cargadas en la JVM

Me gustaría obtener una lista de todas las clases que pertenecen a un determinado paquete, así como a todos sus hijos. Las clases pueden o no estar ya cargadas en la JVM.

No es una solución programática, pero puedes ejecutar

java -verbose:class .... 

y la JVM arrojará lo que está cargando y desde dónde.

 [Opened /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Opened /usr/java/j2sdk1.4.1/jre/lib/sunrsasign.jar] [Opened /usr/java/j2sdk1.4.1/jre/lib/jsse.jar] [Opened /usr/java/j2sdk1.4.1/jre/lib/jce.jar] [Opened /usr/java/j2sdk1.4.1/jre/lib/charsets.jar] [Loaded java.lang.Object from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Loaded java.io.Serializable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Loaded java.lang.Comparable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Loaded java.lang.CharSequence from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] [Loaded java.lang.String from /usr/java/j2sdk1.4.1/jre/lib/rt.jar] 

Mira aquí para más detalles.

utilizando la biblioteca Reflections , es fácil como:

 Reflections reflections = new Reflections("my.pkg", new SubTypesScanner(false)); 

Eso analizaría todas las clases en la URL / s que contiene el paquete my.pkg.

  • el parámetro falso significa – no excluye la clase Object, que está excluida por defecto.
  • en algunos escenarios (contenedores diferentes) puede pasar el classLoader así como también un parámetro.

Entonces, obtener todas las clases es obtener todos los subtipos de Objeto de forma transitiva:

 Set allClasses = reflections.getStore().getSubTypesOf(Object.class.getName()); 

(La forma ordinaria de reflections.getSubTypesOf(Object.class) provocaría la carga de todas las clases en PermGen y probablemente lanzaría OutOfMemoryError. No desea hacerlo …)

Si desea obtener todos los subtipos directos de Objeto (o cualquier otro tipo), sin obtener todos sus subtipos transitivos de una vez, use esto:

 Collection directSubtypes = reflections.getStore().get(SubTypesScanner.class).get(Object.class.getName()); 

Hay varias respuestas a esta pregunta, en parte debido a una pregunta ambigua: el título está hablando de clases cargadas por la JVM, mientras que el contenido de la pregunta dice “puede o no ser cargado por la JVM”.

Suponiendo que OP necesita clases cargadas por la JVM por un cargador de clases determinado, y solo esas clases, también mi necesidad, hay una solución ( elaborada aquí ) que dice lo siguiente:

 import java.net.URL; import java.util.Enumeration; import java.util.Iterator; import java.util.Vector; public class CPTest { private static Iterator list(ClassLoader CL) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Class CL_class = CL.getClass(); while (CL_class != java.lang.ClassLoader.class) { CL_class = CL_class.getSuperclass(); } java.lang.reflect.Field ClassLoader_classes_field = CL_class .getDeclaredField("classes"); ClassLoader_classes_field.setAccessible(true); Vector classes = (Vector) ClassLoader_classes_field.get(CL); return classes.iterator(); } public static void main(String args[]) throws Exception { ClassLoader myCL = Thread.currentThread().getContextClassLoader(); while (myCL != null) { System.out.println("ClassLoader: " + myCL); for (Iterator iter = list(myCL); iter.hasNext();) { System.out.println("\t" + iter.next()); } myCL = myCL.getParent(); } } } 

Una de las mejores cosas es que puedes elegir un cargador de clases arbitrario que quieras verificar. Sin embargo, es probable que se rompa en caso de que las partes internas de la clase del cargador de clases cambien, por lo que se debe utilizar como una herramienta de diagnóstico única.

Un enfoque alternativo a los descritos anteriormente sería crear un agente externo usando java.lang.instrument para descubrir qué clases están cargadas y ejecutar su progtwig con el -javaagent :

 import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.security.ProtectionDomain; public class SimpleTransformer implements ClassFileTransformer { public SimpleTransformer() { super(); } public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException { System.out.println("Loading class: " + className); return bytes; } } 

Este enfoque tiene el beneficio adicional de proporcionarle información sobre qué ClassLoader cargó una clase determinada.

También te sugiero que escribas un agente -javagent , pero usa el método getAllLoadedClasses en lugar de transformar cualquier clase.

Para sincronizar con su código de cliente (código Java normal), cree un socket y comuníquese con el agente a través de él. Luego puede activar un método de “enumerar todas las clases” cuando lo necesite.

Una forma, si ya conoce la ruta del nivel superior del paquete, es usar OpenPojo

 final List pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null); 

Luego puede repasar la lista y realizar cualquier funcionalidad que desee.

Es posible que pueda obtener una lista de las clases que se cargan a través del cargador de clases, pero esto no incluiría las clases que aún no ha cargado pero que están en su classpath.

Para obtener TODAS las clases en su classpath, tiene que hacer algo como su segunda solución. Si realmente desea clases que actualmente están “cargadas” (en otras palabras, las clases a las que ya hizo referencia, accedió o creó instancias), debe refinar su pregunta para indicar esto.

Ejecute su código en una JVM JRockit, luego use JRCMD print_class_summary

Esto generará todas las clases cargadas, una en cada línea.

Bueno, lo que hice fue simplemente enumerar todos los archivos en el classpath. Puede que no sea una solución gloriosa, pero funciona de manera confiable y me da todo lo que quiero, y más.

Este progtwig imprimirá todas las clases con su ruta física. el uso puede simplemente copiar esto a cualquier JSP si necesita analizar la carga de la clase desde cualquier servidor web / de aplicaciones.

 import java.lang.reflect.Field; import java.util.Vector; public class TestMain { public static void main(String[] args) { Field f; try { f = ClassLoader.class.getDeclaredField("classes"); f.setAccessible(true); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Vector classes = (Vector) f.get(classLoader); for(Class cls : classes){ java.net.URL location = cls.getResource('/' + cls.getName().replace('.', '/') + ".class"); System.out.println("

"+location +"

"); } } catch (Exception e) { e.printStackTrace(); } } }