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




crear annotations en java (12)

¿Es demasiado tarde para responder? Yo diría que es mejor ir por bibliotecas como ClassPathScanningCandidateComponentProvider o como Scannotation

Pero incluso después de que alguien quiera probarlo con classLoader, he escrito algunos 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 eliminas a una clase.

¿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.



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).


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.


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

proyecto de descubrimiento


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í.


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

Descargo de responsabilidad: yo soy el autor.



Trate de Scannotation .

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


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].


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());

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.




classloader