É possível encontrar todas as classes ou interfaces em um determinado pacote? (Olhando rapidamente para Package
, por exemplo , pareceria não.)
java
reflection
packages
Jonik
fonte
fonte
Respostas:
Devido à natureza dinâmica dos carregadores de classes, isso não é possível. Os carregadores de classes não precisam informar à VM quais classes ela pode oferecer; em vez disso, são apenas solicitações de classe recebidas e precisam retornar uma classe ou lançar uma exceção.
No entanto, se você escrever seus próprios carregadores de classe ou examinar os caminhos de classe e seus jars, é possível encontrar essas informações. Isso ocorrerá através de operações do sistema de arquivos e não de reflexão. Pode até haver bibliotecas que podem ajudá-lo a fazer isso.
Se houver classes geradas ou entregues remotamente, você não poderá descobrir essas classes.
Em vez disso, o método normal é registrar em algum lugar as classes às quais você precisa acessar em um arquivo ou referenciá-las em uma classe diferente. Ou apenas use a convenção quando se trata de nomear.
Adendo: A Biblioteca de Reflexões permitirá que você procure classes no caminho de classe atual. Pode ser usado para obter todas as classes em um pacote:
fonte
Você provavelmente deveria dar uma olhada na biblioteca de código-fonte do Reflections . Com ele, você pode facilmente alcançar o que deseja.
Primeiro, configure o índice de reflexões (é um pouco confuso, pois a pesquisa de todas as classes está desativada por padrão):
Em seguida, você pode consultar todos os objetos em um determinado pacote:
fonte
.addUrls(ClasspathHelper.forJavaClassPath())
invés do acima os resolveu para mim. Menos código também!O Google Guava 14 inclui uma nova classe
ClassPath
com três métodos para procurar classes de nível superior:getTopLevelClasses()
getTopLevelClasses(String packageName)
getTopLevelClassesRecursive(String packageName)
Veja os
ClassPath
javadocs para mais informações.fonte
ClassPath
é marcado com@Beta
, por isso pode não ser uma boa idéia para alguns ...Você pode usar este método 1 que usa o
ClassLoader
.__________
1 Esse método foi obtido originalmente em http://snippets.dzone.com/posts/show/4831 , que foi arquivado pelo Internet Archive, como vinculado agora. O snippet também está disponível em https://dzone.com/articles/get-all-classes-within-package .
fonte
%20
, mas onew File()
construtor tratou isso como um sinal de porcentagem literal dois zero. Corrigi-o alterando adirs.add(...)
linha para o seguinte:dirs.add(new File(resource.toURI()));
Isso também significava que eu tinha que adicionarURISyntaxException
à cláusula throws degetClasses
Primavera
Este exemplo é para o Spring 4, mas você pode encontrar o scanner de caminho de classe em versões anteriores.
Google Guava
Nota: Na versão 14, a API ainda está marcada como @Beta , portanto, tenha cuidado no código de produção.
fonte
ClassPath
classe no Guava também está marcada com@Beta
: "As APIs marcadas com a anotação @Beta no nível da classe ou do método estão sujeitas a alterações. Elas podem ser modificadas de qualquer forma ou mesmo removidas em qualquer release principal. Se o seu código é uma biblioteca em si (ou seja, é usada no CLASSPATH de usuários fora de seu próprio controle), você não deve usar APIs beta, a menos que as reembalegetAllClasses()
método pode ser usado.Olá. Eu sempre tive alguns problemas com as soluções acima (e em outros sites).
Eu, como desenvolvedor, estou programando um complemento para uma API. A API impede o uso de bibliotecas externas ou ferramentas de terceiros. A instalação também consiste em uma mistura de código em arquivos jar ou zip e arquivos de classe localizados diretamente em alguns diretórios. Portanto, meu código precisava funcionar em todas as configurações. Depois de muita pesquisa, criei um método que funcionará em pelo menos 95% de todas as configurações possíveis.
O código a seguir é basicamente o método de exagero que sempre funcionará.
O código:
Esse código verifica um determinado pacote para todas as classes incluídas nele. Ele funcionará apenas para todas as classes na atual
ClassLoader
.Esses três métodos fornecem a capacidade de encontrar todas as classes em um determinado pacote.
Você o usa assim:
A explicação:
O método primeiro obtém o atual
ClassLoader
. Em seguida, ele busca todos os recursos que contêm o referido pacote e itera essesURL
s. Em seguida, cria umURLConnection
e determina que tipo de URl temos. Pode ser um diretório (FileURLConnection
) ou um diretório dentro de um arquivo jar ou zip (JarURLConnection
). Dependendo do tipo de conexão, temos dois métodos diferentes que serão chamados.Primeiro vamos ver o que acontece se for um
FileURLConnection
.Ele primeiro verifica se o arquivo passado existe e é um diretório. Se for esse o caso, verifica se é um arquivo de classe. Nesse caso, um
Class
objeto será criado e colocado noArrayList
. Se não é um arquivo de classe, mas é um diretório, simplesmente iteramos nele e fazemos a mesma coisa. Todos os outros casos / arquivos serão ignorados.Se o
URLConnection
é,JarURLConnection
o outro método auxiliar privado será chamado. Esse método itera sobre todas as entradas no arquivo zip / jar. Se uma entrada for um arquivo de classe e estiver dentro do pacote, umClass
objeto será criado e armazenado noArrayList
.Depois que todos os recursos foram analisados, o método principal retorna o
ArrayList
conteúdo de todas as classes no pacote fornecido, que os atuaisClassLoader
conhecem.Se o processo falhar a qualquer momento
ClassNotFoundException
, será lançado um contendo informações detalhadas sobre a causa exata.fonte
sun.net.www.protocol.file.FileURLConnection
, o que gera um aviso em tempo de compilação ("warning: sun.net.www.protocol.file.FileURLConnection é API proprietária da Sun e pode ser removido em uma versão futura"). Existe uma alternativa ao uso dessa classe ou o aviso pode ser suprimido usando anotações?if ( ... instanceof JarURLConnecton) { ... } else { // Asume that the Connection is valid and points to a File }
É o que eu fiz no meu código para procurar JPA anotada aulasSem usar nenhuma biblioteca extra:
fonte
upackage
énull
... :(String pack = getPackage().getName();
, precisará adicionarpack = pack.replaceAll("[.]", "/");
Em geral, os carregadores de classes não permitem a varredura em todas as classes no caminho de classe. Mas geralmente o único carregador de classes usado é o UrlClassLoader, do qual podemos recuperar a lista de diretórios e arquivos jar (consulte getURLs ) e abri-los um por um para listar as classes disponíveis. Essa abordagem, chamada de rastreamento de caminho de classe, é implementada no Scannotation and Reflections .
Outra abordagem é usar a API do Java Pluggable Annotation Processing para gravar o processador de anotações que coletará todas as classes anotadas em tempo de compilação e criará o arquivo de índice para uso em tempo de execução. Este mecanismo é implementado na biblioteca ClassIndex :
Observe que nenhuma configuração adicional é necessária, pois a verificação é totalmente automatizada, graças ao compilador Java que descobre automaticamente todos os processadores encontrados no caminho de classe.
fonte
O mecanismo mais robusto para listar todas as classes em um determinado pacote atualmente é o ClassGraph , porque ele lida com a maior variedade possível de mecanismos de especificação de caminho de classe , incluindo o novo sistema de módulo JPMS. (Eu sou o autor.)
fonte
Aqui está como eu faço isso. Examino todas as subpastas (subpacotes) e não tento carregar classes anônimas:
fonte
Eu montei um projeto simples do github que resolve esse problema:
https://github.com/ddopson/java-class-enumerator
Ele deve funcionar para AMBOS os caminhos de classe baseados em arquivo E para arquivos jar.
Se você executar 'make' depois de verificar o projeto, ele será impresso:
Veja também minha outra resposta
fonte
Sim, usando poucas APIs que você pode, aqui está como eu gosto de fazê-lo, enfrentou esse problema que eu estava usando o hibernate core e tive que encontrar classes que foram anotadas com uma certa anotação.
Crie uma anotação personalizada usando a qual você marcará quais classes deseja selecionar.
Em seguida, marque sua classe com ela como
Crie esta classe de utilitário que possui o seguinte método
Chame o método allFoundClassesAnnotatedWithEntityToBeScanned () para obter um conjunto de classes encontrado.
Você precisará das bibliotecas fornecidas abaixo
fonte
Você precisa procurar todas as entradas do carregador de classes no caminho da classe:
Se a entrada for diretório, basta procurar no subdiretório direito:
Se a entrada é o arquivo e é jar, inspecione as entradas ZIP dele:
Agora, depois de ter todos os nomes de classe dentro do pacote, você pode tentar carregá-los com reflexão e analisar se eles são classes ou interfaces, etc.
fonte
Eu tenho tentado usar a biblioteca Reflections, mas tive alguns problemas usando-a, e havia muitos jarros que eu deveria incluir apenas para simplesmente obter as classes em um pacote.
Vou postar uma solução que encontrei nesta pergunta duplicada: Como obter todos os nomes de classes em um pacote?
A resposta foi escrita por sp00m ; Eu adicionei algumas correções para fazê-lo funcionar:
Para usá-lo, basta chamar o método find conforme sp00n mencionado neste exemplo: Adicionei a criação de instâncias das classes, se necessário.
fonte
Acabei de escrever uma classe util, que inclui métodos de teste, você pode verificar ~
IteratePackageUtil.java:
fonte
A solução de Aleksander Blomskøld não funcionou para mim em testes parametrizados
@RunWith(Parameterized.class)
ao usar o Maven. Os testes foram nomeados corretamente e também onde foram encontrados, mas não executados:Um problema semelhante foi relatado aqui .
No meu caso,
@Parameters
está criando instâncias de cada classe em um pacote. Os testes funcionaram bem quando executados localmente no IDE. No entanto, ao executar o Maven, nenhuma classe foi encontrada com a solução de Aleksander Blomskøld.Eu fiz funcionar com o seguinte trecho, inspirado no comentário de David Pärsson sobre a resposta de Aleksander Blomskøld:
fonte
Que tal isso:
Você pode sobrecarregar a função:
Se você precisar testá-lo:
Se o seu IDE não tiver um auxiliar de importação:
Funciona:
do seu IDE
para um arquivo JAR
sem dependências externas
fonte
Quase todas as respostas que usa
Reflections
ou lê arquivos de classe do sistema de arquivos. Se você tentar ler classes do sistema de arquivos, poderá ocorrer erros ao compactar seu aplicativo como JAR ou outro. Além disso, você pode não querer usar uma biblioteca separada para esse fim.Aqui está outra abordagem que é java puro e não depende do sistema de arquivos.
O Java 8 não é obrigatório . Você pode usar loops em vez de fluxos. E você pode testá-lo assim
fonte
ToolProvider.getSystemJavaCompiler()
, esse código não verifica pacotes aninhados.Desde que você não esteja usando nenhum carregador de classe dinâmico, é possível pesquisar o caminho de classe e, para cada entrada, pesquisar o diretório ou arquivo JAR.
fonte
Vale a pena mencionar
Se você deseja ter uma lista de todas as classes em algum pacote, pode usar
Reflection
da seguinte maneira:Isso criará uma lista de classes que mais tarde você poderá usá-las como desejar.
fonte
É muito possível, mas sem bibliotecas adicionais, como
Reflections
é difícil ...É difícil porque você não possui um instrumento completo para obter o nome da classe.
E eu pego o código da minha
ClassFinder
classe:fonte
Com base na resposta de @ Staale e em uma tentativa de não confiar em bibliotecas de terceiros, eu implementaria a abordagem do Sistema de Arquivos inspecionando a localização física do primeiro pacote com:
fonte
Se você deseja apenas carregar um grupo de classes relacionadas, o Spring pode ajudá-lo.
O Spring pode instanciar uma lista ou mapa de todas as classes que implementam uma determinada interface em uma linha de código. A lista ou mapa conterá instâncias de todas as classes que implementam essa interface.
Dito isso, como alternativa ao carregamento da lista de classes do sistema de arquivos, basta implementar a mesma interface em todas as classes que você deseja carregar, independentemente do pacote e usar o Spring para fornecer instâncias de todas elas. Dessa forma, você pode carregar (e instanciar) todas as classes que desejar, independentemente do pacote em que elas estejam.
Por outro lado, se você deseja tê-los todos em um pacote, basta fazer com que todas as classes nesse pacote implementem uma determinada interface.
fonte
java simples: FindAllClassesUsingPlainJavaReflectionTest.java
PS: para simplificar clichês para lidar com erros, etc, estou usando aqui
vavr
elombok
bibliotecasoutras implementações podem ser encontradas no meu repositório GitHub daggerok / java-reflexão-encontrar-anotado-classes-ou métodos
fonte
Não consegui encontrar um trabalho curto para algo tão simples. Então aqui está, eu mesmo fiz isso depois de me meter um pouco:
fonte
Se você estiver em Spring-land, poderá usar
PathMatchingResourcePatternResolver
;fonte
Não é possível, pois todas as classes no pacote podem não ser carregadas, enquanto você sempre conhece o pacote de uma classe.
fonte