¿Es posible encontrar todas las clases o interfaces en un paquete dado? (Mirando rápidamente, por ejemplo Package
, parecería que no).
java
reflection
packages
Jonik
fuente
fuente
Respuestas:
Debido a la naturaleza dinámica de los cargadores de clases, esto no es posible. Los cargadores de clases no están obligados a decirle a la VM qué clases puede proporcionar, sino que simplemente reciben solicitudes de clases y tienen que devolver una clase o lanzar una excepción.
Sin embargo, si escribe sus propios cargadores de clases, o examina los classpaths y sus frascos, es posible encontrar esta información. Sin embargo, esto será a través de las operaciones del sistema de archivos, y no a través de la reflexión. Incluso puede haber bibliotecas que pueden ayudarlo a hacer esto.
Si hay clases que se generan o se entregan de forma remota, no podrá descubrir esas clases.
El método normal consiste en registrar en algún lugar las clases a las que necesita acceder en un archivo, o hacer referencia a ellas en una clase diferente. O simplemente use la convención cuando se trata de nombrar.
Anexo: La Biblioteca Reflections le permitirá buscar clases en el classpath actual. Se puede usar para obtener todas las clases en un paquete:
fuente
Probablemente deberías echar un vistazo a la biblioteca de Reflexiones de código abierto . Con él puedes lograr fácilmente lo que quieres.
Primero, configure el índice de reflexiones (es un poco desordenado ya que la búsqueda de todas las clases está deshabilitada de forma predeterminada):
Luego puede consultar todos los objetos en un paquete dado:
fuente
.addUrls(ClasspathHelper.forJavaClassPath())
lugar de lo anterior los resolvió por mí. ¡Menos código también!Google Guava 14 incluye una nueva clase
ClassPath
con tres métodos para buscar clases de nivel superior:getTopLevelClasses()
getTopLevelClasses(String packageName)
getTopLevelClassesRecursive(String packageName)
Vea los
ClassPath
javadocs para más información.fuente
ClassPath
está etiquetado con@Beta
, por lo que podría no ser una buena idea para algunos ...Puede usar este método 1 que usa el
ClassLoader
.__________
1 Este método fue tomado originalmente de http://snippets.dzone.com/posts/show/4831 , que fue archivado por el Archivo de Internet, como se vincula ahora. El fragmento también está disponible en https://dzone.com/articles/get-all-classes-within-package .
fuente
%20
, pero elnew File()
constructor lo trató como un signo de porcentaje literal dos cero. Lo arreglé cambiando ladirs.add(...)
línea a esto:dirs.add(new File(resource.toURI()));
Esto también significaba que tenía que agregarURISyntaxException
a la cláusula de tiros degetClasses
Primavera
Este ejemplo es para Spring 4, pero también puede encontrar el escáner classpath en versiones anteriores.
Google guayaba
Nota: En la versión 14, la API todavía está marcada como @Beta , así que tenga cuidado con el código de producción.
fuente
ClassPath
clase en Guava también está marcada con@Beta
: "Las API marcadas con la anotación @Beta a nivel de clase o método están sujetas a cambios. Se pueden modificar de cualquier manera, o incluso eliminar, en cualquier versión principal. Si su código es una biblioteca en sí misma (es decir, se usa en CLASSPATH de usuarios que están fuera de su propio control), no debe usar las API beta, a menos que las vuelva agetAllClasses()
se puede usar el método.Hola. Siempre he tenido algunos problemas con las soluciones anteriores (y en otros sitios).
Yo, como desarrollador, estoy programando un complemento para una API. La API evita el uso de bibliotecas externas o herramientas de terceros. La configuración también consiste en una mezcla de código en archivos jar o zip y archivos de clase ubicados directamente en algunos directorios. Por lo tanto, mi código tenía que poder funcionar en cada configuración. Después de mucha investigación, he encontrado un método que funcionará en al menos el 95% de todas las configuraciones posibles.
El siguiente código es básicamente el método overkill que siempre funcionará.
El código:
Este código escanea un paquete dado para todas las clases que están incluidas en él. Solo funcionará para todas las clases en la corriente
ClassLoader
.Estos tres métodos le brindan la capacidad de encontrar todas las clases en un paquete dado.
Lo usas así:
La explicación:
El método primero obtiene la corriente
ClassLoader
. Luego recupera todos los recursos que contienen dicho paquete e itera estosURL
s. Luego creaURLConnection
ay determina qué tipo de URL tenemos. Puede ser un directorio (FileURLConnection
) o un directorio dentro de un archivo jar o zip (JarURLConnection
). Dependiendo de qué tipo de conexión tenemos, se llamarán dos métodos diferentes.Primero veamos qué sucede si es a
FileURLConnection
.Primero verifica si el archivo pasado existe y es un directorio. Si ese es el caso, verifica si se trata de un archivo de clase. Si es así
Class
, se creará un objeto y se colocará en elArrayList
. Si no es un archivo de clase sino un directorio, simplemente lo iteramos y hacemos lo mismo. Todos los demás casos / archivos serán ignorados.Si
URLConnection
es unJarURLConnection
, se llamará al otro método auxiliar privado. Este método itera sobre todas las entradas en el archivo zip / jar. Si una entrada es un archivo de clase y está dentro del paqueteClass
, se creará un objeto y se almacenará en elArrayList
.Después de analizar todos los recursos, (el método principal) devuelve el
ArrayList
contenido de todas las clases en el paquete dado, que el actualClassLoader
conoce.Si el proceso falla en algún momento
ClassNotFoundException
, se lanzará un mensaje con información detallada sobre la causa exacta.fuente
sun.net.www.protocol.file.FileURLConnection
, lo que genera una advertencia en tiempo de compilación ("advertencia: sun.net.www.protocol.file.FileURLConnection es la API propiedad de Sun y puede eliminarse en una versión futura"). ¿Existe alguna alternativa para usar esa clase, o se puede suprimir la advertencia mediante anotaciones?if ( ... instanceof JarURLConnecton) { ... } else { // Asume that the Connection is valid and points to a File }
es lo que hice en mi código para buscar clases anotadas JPASin usar ninguna biblioteca adicional:
fuente
upackage
esnull
... :(String pack = getPackage().getName();
, entonces debe agregarpack = pack.replaceAll("[.]", "/");
En general, los cargadores de clases no permiten escanear todas las clases en el classpath. Pero, por lo general, el único cargador de clases utilizado es UrlClassLoader, del cual podemos recuperar la lista de directorios y archivos jar (consulte getURL ) y abrirlos uno por uno para enumerar las clases disponibles. Este enfoque, llamado exploración de ruta de clase, se implementa en Scannotation and Reflections .
Otro enfoque es utilizar la API de procesamiento de anotación conectable de Java para escribir un procesador de anotación que recopilará todas las clases anotadas en tiempo de compilación y creará el archivo de índice para uso en tiempo de ejecución. Este mecanismo se implementa en la biblioteca ClassIndex :
Tenga en cuenta que no se necesita ninguna configuración adicional ya que el escaneo está completamente automatizado gracias al compilador Java que descubre automáticamente cualquier procesador encontrado en el classpath.
fuente
El mecanismo más robusto para enumerar todas las clases en un paquete dado es actualmente ClassGraph , porque maneja la gama más amplia posible de mecanismos de especificación de classpath , incluido el nuevo sistema de módulos JPMS. (Soy el autor)
fuente
Así es como lo hago. Escaneo todas las subcarpetas (subpaquetes) y no intento cargar clases anónimas:
fuente
Creé un proyecto simple de github que resuelve este problema:
https://github.com/ddopson/java-class-enumerator
Debería funcionar para AMBOS classpaths basados en archivos Y para archivos jar.
Si ejecuta 'make' después de revisar el proyecto, lo imprimirá:
Ver también mi otra respuesta
fuente
Sí, usando pocas API, puede hacerlo, así es como me gusta hacerlo, enfrenté este problema que estaba usando hibernate core y tuve que encontrar clases que estaban anotadas con una cierta anotación.
Haga de estas una anotación personalizada con la que marcará las clases que desea que se seleccionen.
Luego marca tu clase con ella como
Haga esta clase de utilidad que tiene el siguiente método
Llame al método allFoundClassesAnnotatedWithEntityToBeScanned () para obtener un conjunto de clases encontrado.
Necesitarás libs dados a continuación
fuente
Debe buscar cada entrada del cargador de clases en la ruta de clase:
Si la entrada es el directorio, simplemente busque en el subdirectorio correcto:
Si la entrada es el archivo y es jar, inspeccione las entradas ZIP del mismo:
Ahora, una vez que tenga todos los nombres de clase dentro del paquete, puede intentar cargarlos con reflexión y analizar si son clases o interfaces, etc.
fuente
He estado tratando de usar la biblioteca Reflections, pero tuve algunos problemas para usarla, y había demasiados frascos que debería incluir solo para obtener las clases en un paquete.
Publicaré una solución que encontré en esta pregunta duplicada: ¿Cómo obtener todos los nombres de clases en un paquete?
La respuesta fue escrita por sp00m ; He agregado algunas correcciones para que funcione:
Para usarlo, simplemente llame al método find como sp00n mencionado en este ejemplo: he agregado la creación de instancias de las clases si es necesario.
fuente
Acabo de escribir una clase util, que incluye métodos de prueba, puedes tener un cheque ~
IteratePackageUtil.java:
fuente
La solución de Aleksander Blomskøld no me funcionó para las pruebas parametrizadas
@RunWith(Parameterized.class)
al usar Maven. Las pruebas se nombraron correctamente y también se encontraron pero no se ejecutaron:Un problema similar se ha informado aquí .
En mi caso
@Parameters
es crear instancias de cada clase en un paquete. Las pruebas funcionaron bien cuando se ejecutan localmente en el IDE. Sin embargo, al ejecutar Maven no se encontraron clases con la solución de Aleksander Blomskøld.Lo hice funcionar con el siguiente recorte que se inspiró en el comentario de David Pärsson sobre la respuesta de Aleksander Blomskøld:
fuente
¿Qué hay de esto?
Luego puede sobrecargar la función:
Si necesita probarlo:
Si su IDE no tiene ayuda de importación:
Funciona:
de tu IDE
para un archivo JAR
sin dependencias externas
fuente
Casi todas las respuestas usan
Reflections
o leen archivos de clase del sistema de archivos. Si intenta leer clases del sistema de archivos, puede recibir errores cuando empaqueta su aplicación como JAR u otro. Además, es posible que no desee utilizar una biblioteca separada para ese propósito.Aquí hay otro enfoque que es puro Java y no depende del sistema de archivos.
Java 8 no es imprescindible . Puede usar para bucles en lugar de secuencias. Y puedes probarlo así
fuente
ToolProvider.getSystemJavaCompiler()
, este código no escanea paquetes anidados.Siempre que no esté utilizando cargadores de clases dinámicos, puede buscar el classpath y para cada entrada buscar el directorio o el archivo JAR.
fuente
Vale la pena mencionar
Si desea tener una lista de todas las clases en algún paquete, puede usar
Reflection
la siguiente manera:Esto creará una lista de clases que luego podrá usar como desee.
fuente
Es muy posible, pero sin bibliotecas adicionales como si
Reflections
fuera difícil ...Es difícil porque no tienes un instrumento completo para obtener el nombre de la clase.
Y tomo el código de mi
ClassFinder
clase:fuente
Basado en la respuesta de @ Staale , y en un intento de no confiar en bibliotecas de terceros, implementaría el enfoque del Sistema de archivos al inspeccionar la ubicación física del primer paquete con:
fuente
Si simplemente está buscando cargar un grupo de clases relacionadas, entonces Spring puede ayudarlo.
Spring puede crear una instancia de una lista o mapa de todas las clases que implementan una interfaz determinada en una línea de código. La lista o mapa contendrá instancias de todas las clases que implementan esa interfaz.
Dicho esto, como alternativa a cargar la lista de clases fuera del sistema de archivos, simplemente implemente la misma interfaz en todas las clases que desee cargar, independientemente del paquete y use Spring para proporcionarle instancias de todas ellas. De esa manera, puede cargar (e instanciar) todas las clases que desee, independientemente del paquete en el que se encuentren.
Por otro lado, si desea tenerlos todos en un paquete, simplemente haga que todas las clases de ese paquete implementen una interfaz determinada.
fuente
plain java: FindAllClassesUsingPlainJavaReflectionTest.java
PD: para simplificar las repeticiones para el manejo de errores, etc., estoy usando aquí
vavr
ylombok
bibliotecasse pueden encontrar otras implementaciones en mi repositorio daggerok / java-reflection-find-annotated-classes-or-method de GitHub
fuente
No pude encontrar un trabajo corto cortado por algo tan simple. Así que aquí está, lo hice yo mismo después de jugar un rato:
fuente
Si estás en Spring-land puedes usar
PathMatchingResourcePatternResolver
;fuente
No es posible, ya que es posible que no se carguen todas las clases del paquete, mientras que siempre conoce el paquete de una clase.
fuente