Análisis de anotaciones Java en tiempo de ejecución


¿Cuál es la mejor manera de buscar toda la ruta de clase para una clase anotada?

Estoy haciendo una biblioteca y quiero permitir a los usuarios anotar sus clases, por lo que cuando se inicia la aplicación Web necesito escanear todo el classpath para cierta anotación.

¿Conoce una biblioteca o una instalación Java para hacer esto?

Editar: Estoy pensando en algo como la nueva funcionalidad para Java EE 5 Web Services o EJB. Anota tu clase con @WebService o @EJB y el el sistema encuentra estas clases mientras se cargan para que sean accesibles de forma remota.

Author: Andrew Tobilko, 2008-11-03

17 answers

Use org.springframework.contexto.anotación.ClassPathScanningCandidateComponentprovider

API

Un proveedor de componentes que escanea el classpath desde un paquete base. Luego aplica los filtros exclude e include a las clases resultantes para encontrar candidatos.

ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(<DO_YOU_WANT_TO_USE_DEFALT_FILTER>);

scanner.addIncludeFilter(new AnnotationTypeFilter(<TYPE_YOUR_ANNOTATION_HERE>.class));

for (BeanDefinition bd : scanner.findCandidateComponents(<TYPE_YOUR_BASE_PACKAGE_HERE>))
    System.out.println(bd.getBeanClassName());
 176
Author: Arthur Ronald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-23 17:18:18

Y otra solución es Google reflections.

Revisión rápida:

  • Spring solution es el camino a seguir si está utilizando Spring. De lo contrario es una gran dependencia.
  • Usar ASM directamente es un poco engorroso.
  • Usar Java Assist directamente también es torpe.
  • Annovention es super ligero y conveniente. Aún no hay integración maven.
  • Google reflections extrae las colecciones de Google. Indexa todo y luego es súper rápido.
 136
Author: Jonathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-04 11:23:53

(Editar: FastClasspathScanner ha sido renombrado a ClassGraph)

Intenta ClassGraph. (Descargo de responsabilidad, soy el autor). ClassGraph admite la exploración de anotaciones, ya sea en tiempo de ejecución o en tiempo de compilación, pero también mucho más. ClassGraph puede crear una representación abstracta de todo el gráfico de clases (todas las clases, anotaciones, métodos, parámetros de métodos y campos) en memoria, para todas las clases en la ruta de clases o para las clases en paquetes de lista blanca, y puede consultar ese gráfico de clases como quieras. ClassGraph soporta más mecanismos de especificación classpath y classloaders que cualquier otro escáner, y también funciona a la perfección con el nuevo sistema de módulos JPMS, por lo que si basa su código en ClassGraph, su código será portátil al máximo. Vea la API aquí.

 32
Author: Luke Hutchison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-01 04:10:36

Si desea una solución realmente ligera (sin dependencias, API simple, archivo jar de 15 kb) y muy rápida , eche un vistazo a annotation-detector que se encuentra en https://github.com/rmuller/infomas-asl

Descargo de responsabilidad: Yo soy el autor.

 19
Author: rmuller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-21 09:05:47

Puede usar Java Pluggable Annotation Processing API para escribir un procesador de anotaciones que se ejecutará durante el proceso de compilación y recopilará todas las clases anotadas y construirá el archivo de índice para su uso en tiempo de ejecución.

Esta es la forma más rápida posible de realizar el descubrimiento de clases anotado porque no necesita escanear su classpath en tiempo de ejecución, que generalmente es una operación muy lenta. También este enfoque funciona con cualquier classloader y no solo con URLClassLoaders generalmente soportados por escáneres de tiempo de ejecución.

El mecanismo anterior ya está implementado en la biblioteca ClassIndex.

Para usarlo anote su anotación personalizada con @IndexAnnotated meta-anotación. Esto creará en tiempo de compilación un archivo de índice: META-INF/annotations/com/test / YourCustomAnnotation listando todas las clases anotadas. Puede acceder al índice en tiempo de ejecución ejecutando:

ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)
 13
Author: Sławek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-19 18:36:56

Use el ServiceLoader, o implemente su propio si no está en Java 6.

Tal vez un procesador de anotación podría producir los archivos necesarios bajo META-INF/services en tiempo de compilación.

 10
Author: erickson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:24

Intenta Scannotation.

Se puede utilizar para buscar anotaciones específicas en el classpath o en el directorio lib de su aplicación web.

 6
Author: Wolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-03 23:59:29

Es posible que desee utilizar http://code.google.com/p/annovention /

 5
Author: Animesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-26 10:51:08

Ligeramente offtopic, pero la Primavera también hace algo parecido, usando , que quizás podría estudiar el código fuente de?

Spring proporciona la capacidad de detectar automáticamente clases 'estereotipadas' [...]. Para detectar automáticamente estas clases y registrar los beans correspondientes se requiere la inclusión del elemento [context: component-scan].

 3
Author: toolkit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-03 22:02:40

Con Spring también puede escribir lo siguiente usando la clase AnnotationUtils. es decir:

Class<?> clazz = AnnotationUtils.findAnnotationDeclaringClass(Target.class, null);

Para obtener más detalles y todos los métodos diferentes, consulte los documentos oficiales: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html

 3
Author: magiccrafter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-12 23:41:55

No estoy seguro de si le ayudará o no, pero podría investigar el proyecto apache commons-discovery.

Discovery project

 2
Author: Ian McLaird,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-03 17:29:04

Es demasiado tarde para responder. Yo diría que es mejor ir por las Bibliotecas como ClassPathScanningCandidateComponentprovider o como Scannotations

Pero incluso después de que alguien quiera probar algunas manos con ClassLoader, he escrito algunas por mi cuenta para imprimir las anotaciones de las clases en un paquete:

public class ElementScanner {

public void scanElements(){
    try {
    //Get the package name from configuration file
    String packageName = readConfig();

    //Load the classLoader which loads this class.
    ClassLoader classLoader = getClass().getClassLoader();

    //Change the package structure to directory structure
    String packagePath  = packageName.replace('.', '/');
    URL urls = classLoader.getResource(packagePath);

    //Get all the class files in the specified URL Path.
    File folder = new File(urls.getPath());
    File[] classes = folder.listFiles();

    int size = classes.length;
    List<Class<?>> classList = new ArrayList<Class<?>>();

    for(int i=0;i<size;i++){
        int index = classes[i].getName().indexOf(".");
        String className = classes[i].getName().substring(0, index);
        String classNamePath = packageName+"."+className;
        Class<?> repoClass;
        repoClass = Class.forName(classNamePath);
        Annotation[] annotations = repoClass.getAnnotations();
        for(int j =0;j<annotations.length;j++){
            System.out.println("Annotation in class "+repoClass.getName()+ " is "+annotations[j].annotationType().getName());
        }
        classList.add(repoClass);
    }
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

/**
 * Unmarshall the configuration file
 * @return
 */
public String readConfig(){
    try{
        URL url = getClass().getClassLoader().getResource("WEB-INF/config.xml");
        JAXBContext jContext = JAXBContext.newInstance(RepositoryConfig.class);
         Unmarshaller um =  jContext.createUnmarshaller();
         RepositoryConfig rc = (RepositoryConfig) um.unmarshal(new File(url.getFile()));
         return rc.getRepository().getPackageName();
        }catch(Exception e){
            e.printStackTrace();
        }
    return null;

}
}

Y en el archivo de configuración, pones el nombre del paquete y lo desmarcas en una clase .

 2
Author: yashpandey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-22 07:02:07

Java no tiene "Descubrimiento". La única manera que conozco es escanear el directorio que el .los archivos de clase deben estar adentro, analizar los nombres y usar eso. Horriblemente feo, tal vez hay un paquete mejor en estos días I no he mirado en unos años.

Generalmente este problema solía ser abordado mediante la inclusión de un archivo de propiedades o un .archivo xml con los nombres de clase.

Estaría interesado en escuchar una mejor respuesta también.

 1
Author: Bill K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-03 16:57:24

La API de Classloader no tiene un método "enumerar", porque la carga de clases es una actividad "bajo demanda" usually por lo general, tiene miles de clases en su classpath, solo una fracción de las cuales rt.jar solo es 48MB hoy en día!).

Así que, incluso si pudiera enumerar todas las clases, esto consumiría mucho tiempo y memoria.

El enfoque simple es listar las clases en cuestión en un archivo de configuración (xml o lo que más le convenga); si desea para hacer esto automáticamente, restringirse a un JAR o un directorio de clase.

 1
Author: mfx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-03 17:24:19

Google Reflections parece ser mucho más rápido que la Primavera. Se encontró esta solicitud de característica que se dirige a esta diferencia: http://www.opensaga.org/jira/browse/OS-738

Esta es una razón para usar Reflexiones ya que el tiempo de inicio de mi aplicación es realmente importante durante el desarrollo. Reflections también parece ser muy fácil de usar para mi caso de uso (encontrar todos los implementadores de una interfaz).

 1
Author: Martin Aubele,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-14 18:37:20

Si estás buscando una alternativa a reflections te recomiendo Panda Utilities - AnnotationsScanner. Es un escáner libre de guayaba (Guayaba tiene ~3MB, Panda Utilities tiene ~200kb) basado en el código fuente de la biblioteca reflections.

También está dedicado a búsquedas futuras. Si desea escanear varias veces las fuentes incluidas o incluso proporcionar una API, que permite a alguien escanear classpath actual, AnnotationsScannerProcess almacena en caché todas las búsquedas ClassFiles, por lo que es realmente rápida.

Ejemplo simple de AnnotationsScanner uso:

AnnotationsScanner scanner = AnnotationsScanner.createScanner()
        .includeSources(ExampleApplication.class)
        .build();

AnnotationsScannerProcess process = scanner.createWorker()
        .addDefaultProjectFilters("net.dzikoysk")
        .fetch();

Set<Class<?>> classes = process.createSelector()
        .selectTypesAnnotatedWith(AnnotationTest.class);
 1
Author: dzikoysk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-14 13:02:16

Si desea una biblioteca Scala, utilice Sclasner: https://github.com/ngocdaothanh/sclasner

 0
Author: Ngoc Dao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 06:27:29