2012-03-27 22 views
8

Tengo una cadena con algún valor. Quiero iterar sobre todas las clases en un paquete llamando a un método específico, y si el valor devuelto por el método es igual al valor en mi Cadena, cree un objeto de esa clase.¿Es posible iterar sobre todas las clases dentro de un paquete con Reflection?

Quiero hacer esto de una manera dinámica, así que si agrego una clase en este paquete, estará automáticamente en la iteración.

¿Es posible hacer esto? Si no, ¿hay una manera de hacer lo que quiero?


Esperaba algo así como.

for(Class clazz: SomeClass.listClasses("org.package")){ 
    //code here 
} 
+0

¿Qué significa "agregar una clase en este paquete"? ¿Cómo se obtiene en el classpath del proceso java? –

+0

@Jeffrey Estaba leyendo sobre Reflection y creo que esta es la única forma, pero no sé nada sobre Reflection. Intenté de una "manera normal" agregar una verificación para cada clase que tengo en ese paquete, pero no quiero de esta manera porque no es expansible. –

+0

@MiserableVariable En tiempo de desarrollo, agrego una nueva clase en el paquete (todas las clases extienden una clase abstracta llamada Documento). –

Respuesta

8

No, esto no es posible de una manera totalmente confiable; sin embargo, puede ser práctico implementarlo en muchos casos.

Debido a la flexibilidad de los cargadores de clase Java, las clases definidas en un paquete particular pueden no conocerse en tiempo de ejecución (por ejemplo, considerar un cargador de clases especial que define las clases sobre la marcha, quizás cargándolas de la red, o compilándolos ad-hoc). Como tal, no existe una API Java estándar que le permita enumerar las clases en un paquete.

En términos prácticos, sin embargo, podría hacer algunos trucos buscando en la ruta de clases para todos los archivos de clase y JAR, creando una colección de nombres de clase totalmente calificados, y buscándolos como desee. Esta estrategia funcionaría bien si está seguro de que ningún cargador de clases activo se comportará como se describe en el párrafo anterior. Por ejemplo (pseudocódigo de Java):

Map<String, Set<String>> classesInPackage = new HashMap(); 
for (String entry : eachClasspathEntry()) { 
    if (isClassFile(entry)) { 
    String packageName = getPackageName(entry); 
    if (!classesInPackage.containsKey(packageName)) { 
     classesInPackage.put(packageName, new HashSet<String>()); 
    } 
    classesInPackage.get(packageName).add(getClassName(entry)); 
    } else if (isJarOrZipFile(entry)) { 
    // Do the same for each JAR/ZIP file entry... 
    } 
} 
classesInPackage.get("com.foo.bar"); // => Set<String> of each class... 
+0

Pero un cargador de clases personalizado podría, al menos en teoría. –

+0

@MiserableVariable: imagine que escribí un cargador de clases personalizado que implementa el método 'defineClass (String)' devolviendo el bytecode para una clase que define una clase vacía por el nombre de clase proporcionado. Este es un cargador de clases totalmente válido y no hay una forma (práctica) de enumerar cada clase que podría definir. – maerics

+0

Sí, en general, el problema no se puede resolver. Pero es diferente para una situación específica estrecha: podría querer verificar todos los archivos .class en un nombre de carpeta 'plugins' y crear una instancia en cada clase que tenga un método' register'. –

1

Sí, pero no como una solución de caso general. Deberá empaquetar su código e invocar la JVM de manera específica. Específicamente, deberá crear un agente de instrumentación y llamar al java.lang.instrument.Instrumentation.getAllLoadedClasses().

El paquete documentation for java.lang.instrument tiene muchos detalles sobre cómo crear y crear instancias de un agente.

+0

No quiere solo clases cargadas, pero (presumiblemente) cualquier archivo de clase nuevo cayó en una carpeta en classpath –

+0

@MiserableVariable No sé si está claro, pero las clases que quiero cargar están definidas en Tiempo de desarrollo, no en Runtime. –

2

Puedo pensar en dos formas de resolver lo que creo que es tu problema, aunque ninguna de las dos opciones realmente itera sobre todas las clases en un paquete.

Una es crear un archivo separado que enumere las clases en las que se debe llamar a ese método específico. Esto es bastante fácil de implementar. Es posible que tenga algo de trabajo creando el archivo, pero que podría ser automático.

La segunda opción es buscar archivos .class en algún lugar conocido, por ejemplo, una sola carpeta o un conjunto de carpetas, y adivinar cuál sería el nombre de clase y cargarlo. Si se trata de un proceso de desarrollo simple, los archivos de clase de un único paquete probablemente estén en un único directorio.

Cuestiones relacionadas