java reflection class
Java: obtenga una lista de todas las clases cargadas en la JVM (10)
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.
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.
Ejecute su código en una JVM JRockit, luego use JRCMD <PID> print_class_summary
Esto generará todas las clases cargadas, una en cada línea.
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.
Este programa 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<Class> classes = (Vector<Class>) f.get(classLoader);
for(Class cls : classes){
java.net.URL location = cls.getResource(''/'' + cls.getName().replace(''.'',
''/'') + ".class");
System.out.println("<p>"+location +"<p/>");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
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.
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 here para más detalles.
También te sugiero que escribas un agente -javagent
, pero usa el método getAllLoadedClasses 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.
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 programa 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.
Una forma, si ya conoce la ruta del nivel superior del paquete, es usar OpenPojo
final List<PojoClass> pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null);
Luego puede repasar la lista y realizar cualquier funcionalidad que desee.
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<String> 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<String> directSubtypes =
reflections.getStore().get(SubTypesScanner.class).get(Object.class.getName());