annotations ejemplo - Escaneando anotaciones de Java en tiempo de ejecución




crear spring (15)

Si está buscando una alternativa a las reflexiones, me gustaría recomendar Panda Utilities - AnnotationsScanner . Es un escáner sin guayaba (Guava tiene ~ 3MB, Panda Utilities tiene ~ 200kb) basado en el código fuente de la biblioteca de reflexiones.

También se dedica a búsquedas basadas en el futuro. Si desea escanear varias veces las fuentes incluidas o incluso proporcionar una API, lo que permite a alguien escanear la ruta de ClassFiles actual, AnnotationsScannerProcess almacena en caché todos los ClassFiles obtenidos, por lo que es realmente rápido.

Ejemplo simple del uso de AnnotationsScanner :

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

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

Set<Class<?>> classes = process.createSelector()
        .selectTypesAnnotatedWith(AnnotationTest.class);

¿Cuál es la mejor manera de buscar el classpath completo para una clase anotada?

Estoy haciendo una biblioteca y quiero permitir que los usuarios anoten sus clases, así que cuando la aplicación web se inicie, necesito escanear toda la ruta de clase para una anotación determinada.

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

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


Y otra solución es reflexiones de Google .

Revisión rápida:

  • La solución Spring 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 es demasiado pesado también.
  • Annovention es super ligero y conveniente. No hay integración de maven todavía.
  • Las reflexiones de Google atraen a las colecciones de Google. Indexa todo y luego es super rapido.

Un poco fuera de lugar, pero Spring también hace algo similar, usando <context:component-scan> , del cual quizás podrías estudiar el código fuente de?

Spring proporciona la capacidad de detectar automáticamente clases "estereotipadas" [...]. Para autodetectar estas clases y registrar los beans correspondientes se requiere la inclusión del [contexto: componente-elemento de escaneo].


Puede encontrar clases con cualquier anotación dada con ClassGraph , así como buscar otros criterios de interés, por ejemplo, clases que implementan una interfaz determinada. (Descargo de responsabilidad, soy el autor de ClassGraph). ClassGraph puede generar una representación abstracta de la clase completa (todas las clases, anotaciones, métodos, parámetros de método y campos) en la memoria, para todas las clases en el classpath o para las clases en en la lista blanca, y puede consultar ese gráfico de clase como lo desee. ClassGraph admite más mecanismos de especificación de ruta de clase y cargadores de clases 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. Vea la API aquí.


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

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


No estoy seguro de si te ayudará o no, pero podrías ver el proyecto de descubrimiento de apache commons.

proyecto de descubrimiento


Java no tiene "Discovery". La única forma que conozco es escanear el directorio en el que deberían estar los archivos .class, analizar los nombres y usarlos. Horriblemente feo, tal vez haya un paquete mejor en estos días, no lo he visto en algunos años.

Por lo general, este problema solía resolverse al incluir un archivo de propiedades o un archivo .xml con los nombres de clase en él.

También me interesaría escuchar una mejor respuesta.


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

Esta es la forma más rápida posible de realizar el descubrimiento de clases anotadas porque no necesita escanear su classpath en tiempo de ejecución, lo que generalmente es una operación muy lenta. Además, este enfoque funciona con cualquier cargador de clases 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 el momento de la compilación un archivo de índice: META-INF / annotations / com / test / YourCustomAnnotation que enumera todas las clases anotadas. Puede acceder al índice en tiempo de ejecución ejecutando:

ClassIndex.getAnnotated(com.test.YourCustomAnnotation.class)

Trate de Scannotation .

Se puede utilizar para buscar anotaciones específicas en el classpath o en su directorio de aplicaciones web.



Google Reflections parece ser mucho más rápido que Spring. Encontré esta solicitud de función que aborda esta diferencia: http://www.opensaga.org/jira/browse/OS-738

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


La API del Cargador de clases no tiene un método de "enumeración", porque la carga de clases es una actividad "a pedido". Por lo general, tiene miles de clases en su ruta de clase, solo una fracción de las cuales será necesaria (rt.jar solo es 48MB hoy en día!).

Entonces, incluso si pudieras enumerar todas las clases, esto consumiría mucho tiempo y memoria.

El enfoque simple es enumerar las clases en cuestión en un archivo de configuración (xml o lo que sea más conveniente para usted); Si desea hacer esto automáticamente, limítese a un JAR o un directorio de clase.


Utilice org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider

API

Un proveedor de componentes que escanea el classpath desde un paquete base. Luego aplica excluir e incluir filtros 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());


JSR305 y FindBugs son creados por la misma persona. Ambos están mal mantenidos, pero son tan estándar como son y son compatibles con todas las IDE principales. La buena noticia es que funcionan bien como están.

Aquí se explica cómo aplicar @Nonnull a todas las clases, métodos y campos de forma predeterminada. Consulte https://.com/a/13319541/14731 y https://.com/a/9256595/14731

  1. Definir @NotNullByDefault
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.annotation.Nonnull;
import javax.annotation.meta.TypeQualifierDefault;


    /**
     * This annotation can be applied to a package, class or method to indicate that the class fields,
     * method return types and parameters in that element are not null by default unless there is: <ul>
     * <li>An explicit nullness annotation <li>The method overrides a method in a superclass (in which
     * case the annotation of the corresponding parameter in the superclass applies) <li> there is a
     * default parameter annotation applied to a more tightly nested element. </ul>
     * <p/>
     * @see https://.com/a/9256595/14731
     */
    @Documented
    @Nonnull
    @TypeQualifierDefault(
    {
        ElementType.ANNOTATION_TYPE,
        ElementType.CONSTRUCTOR,
        ElementType.FIELD,
        ElementType.LOCAL_VARIABLE,
        ElementType.METHOD,
        ElementType.PACKAGE,
        ElementType.PARAMETER,
        ElementType.TYPE
    })
    @Retention(RetentionPolicy.RUNTIME)
    public @interface NotNullByDefault
    {
    }

2. Agregue la anotación a cada paquete: package-info.java

@NotNullByDefault
package com.example.foo;

ACTUALIZACIÓN : A partir del 12 de diciembre de 2012, JSR 305 aparece como "Inactivo". Según la documentación:

Un JSR que fue votado como "inactivo" por el Comité Ejecutivo, o uno que ha llegado al final de su vida natural.

Parece que JSR-308 está convirtiendo en JDK 8 y aunque JSR no define @NotNull, el Checkers Framework acompaña sí lo hace. En el momento de escribir este artículo, el complemento de Maven no se puede utilizar debido a este error: https://github.com/typetools/checker-framework/issues/183





java annotations classloader