Pergunta

O que é a melhor maneira de pesquisar todo o caminho de classe para uma classe anotada?

Estou fazendo uma biblioteca e eu quero permitir que os usuários para anotar suas aulas, por isso, quando o aplicativo da Web começa Eu preciso fazer a varredura de todo o classpath com certeza anotação.

Você sabe uma biblioteca ou uma instalação de Java para fazer isso?

Edit: Eu estou pensando em algo como a nova funcionalidade para Java EE 5 Web Services ou EJB do. Você anotar sua classe com @WebService ou @EJB e o sistema encontrar essas classes durante o carregamento para que eles sejam acessíveis remotamente.

Foi útil?

Solução

Use org.springframework .context.annotation.ClassPathScanningCandidateComponentProvider

API

Um provedor de componente que verifica o classpath de um pacote base. Em seguida, aplica excluir e incluir filtros para as classes 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());

Outras dicas

E outra solução é Google reflexões .

revisão rápida:

  • solução Primavera é o caminho a percorrer se você está usando Spring. Caso contrário, é uma grande dependência.
  • Usar ASM diretamente é um pouco complicado.
  • Usando Java Assist diretamente é desajeitado também.
  • Annovention é super leve e conveniente. Sem integração Maven ainda.
  • reflexões puxa Google em coleções do Google. Índices tudo e, em seguida, é super rápido.

Você pode encontrar classes com qualquer anotação com ClassGraph , bem como a procura de outros critérios de interesse , por exemplo classes que implementam uma determinada interface. (Disclaimer: Eu sou o autor de ClassGraph.) ClassGraph pode construir uma representação abstrata de todo o gráfico de classe (todas as classes, anotações, métodos, parâmetros de métodos e campos) na memória, para todas as classes no classpath, ou para as aulas em pacotes na lista de autorizações, e você pode consultar esse gráfico classe como quiser. ClassGraph suporta mais mecanismos de especificação classpath e classloaders do que qualquer outro scanner, e também funciona perfeitamente com o novo sistema de módulos JPMS, por isso, se você basear seu código em ClassGraph, seu código será maximamente portátil. Veja a API aqui.

Se você quiser realmente um peso leve (sem dependências, simples API, 15 kb arquivo jar) e muito rápido solução, dê uma olhada annotation-detector encontrada em https://github.com/rmuller/infomas-asl

Disclaimer:. Eu sou o autor

Você pode usar a API Java Pluggable Anotação de processamento para o processador de escrita anotação que será executado durante o processo de compilação e irá recolher todas as classes anotadas e construir o arquivo de índice para uso de tempo de execução.

Esta é a maneira mais rápida possível para fazer a descoberta classe anotada porque você não precisa analisar o seu classpath em tempo de execução, que normalmente é uma operação muito lenta. Também esta abordagem funciona com qualquer carregador de classe e não apenas com URLClassLoaders geralmente apoiados por scanners de tempo de execução.

O mecanismo acima já está implementado em ClassIndex biblioteca.

Para usá-lo anotar sua anotação personalizado com @IndexAnnotated meta-anotação. Isto irá criar em tempo de compilação um arquivo de índice: META-INF / anotações / com / test / YourCustomAnnotation listando todas as classes anotadas. Você pode acccess o índice em tempo de execução, executando:

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

Tente Scannotation .

Ele pode ser usado para procurar o classpath ou seu diretório lib aplicação web para anotações específicas.

Com Primavera você também pode simplesmente escrever o seguinte usando a classe AnnotationUtils. ou seja:.

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

Para mais detalhes e todos os métodos diferentes verificar documentos oficiais: https: // docs. spring.io/spring/docs/current/javadoc-api/org/springframework/core/annotation/AnnotationUtils.html

Um pouco offtopic, mas Primavera também faz algo semelhante, usando , que talvez pudesse estudar o código fonte de

Spring fornece a capacidade de detectar automaticamente 'estereotipada' classes [...]. Para detectar automaticamente essas classes e registrar os grãos correspondentes exige a inclusão da [contexto: elemento componente-scan].

É tarde demais para responder. Eu diria, a sua melhor ir de Bibliotecas como ClassPathScanningCandidateComponentProvider ou como Scannotations

Mas mesmo depois de alguém quiser tentar algumas mãos sobre ele com carregador de classe, eu escrevi alguns em meu próprio para imprimir as anotações de aulas em um pacote:

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;

}
}

E no arquivo de configuração, você coloca o nome do pacote e desempacotar-lo a uma classe.

O Classloader API não tem um método "enumerar", porque a classe de carga é uma atividade "on-demand" - que geralmente têm milhares de aulas no seu classpath, apenas uma fração do que nunca vai ser necessário (o rt.jar sozinho é 48MB hoje em dia!).

Assim, mesmo se você pode enumerar todas as classes, isso seria muito tempo e consome memória.

A abordagem simples é listar as classes envolvidas em um arquivo de configuração XML (ou que ternos sua fantasia); se você quiser fazer isso automaticamente, restringir-se a um JAR ou um diretório de classe.

Eu não tenho certeza se ele vai ajudá-lo ou não, mas você pode olhar para o projeto Apache commons-descoberta.

projeto descoberta

Reflexões parece ser muito mais rápido do que da Primavera. Encontrado esta solicitação recurso que Endereços esta diferença: http://www.opensaga.org/jira/ Navegar / OS-738

Esta é uma razão para usar Reflexões como tempo de inicialização do meu aplicativo é realmente importante durante o desenvolvimento. Reflexões também parece ser muito fácil de usar para o meu caso de uso (encontrar todos os implementadores de uma interface).

Se você está procurando uma alternativa para reflexões eu gostaria de recomendar Panda Utilities - AnnotationsScanner . É uma goiaba-free (Goiaba tem ~ 3MB, Panda Utilities tem ~ 200kb) do scanner baseado no código fonte da biblioteca reflexões.

Ele também é dedicado para pesquisas baseadas em futuras. Se você gostaria de digitalizar várias vezes incluído fontes ou até mesmo fornecer uma API, que permite que alguém a digitalização classpath atual, AnnotationsScannerProcess armazena todos ClassFiles buscado, por isso é muito rápido.

Um exemplo simples do uso 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);

Google Reflexão se você quer descobrir as interfaces também.

Spring ClassPathScanningCandidateComponentProvider não está descobrindo interfaces.

Spring tem algo chamado uma classe AnnotatedTypeScanner.
Essa classe usa internamente

ClassPathScanningCandidateComponentProvider

Essa classe tem o código para a digitalização real dos classpath recursos. Ele faz isso usando os metadados classe disponível em tempo de execução.

Um pode simplesmente estender esta classe ou usar a mesma classe para digitalização. Abaixo está a definição construtor.

/**
     * Creates a new {@link AnnotatedTypeScanner} for the given annotation types.
     * 
     * @param considerInterfaces whether to consider interfaces as well.
     * @param annotationTypes the annotations to scan for.
     */
    public AnnotatedTypeScanner(boolean considerInterfaces, Class<? extends Annotation>... annotationTypes) {

        this.annotationTypess = Arrays.asList(annotationTypes);
        this.considerInterfaces = considerInterfaces;
    }

Se você quiser uma biblioteca Scala, use Sclasner: https://github.com/ngocdaothanh/sclasner

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top