Para acessar campos particulares, você precisa obtê-los dos campos declarados da classe e torná-los acessíveis:
Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException
EDIT : como comentado por aperkins , acessando o campo, configurando-o como acessível e recuperando o valor pode gerar Exception
s, embora as únicas exceções verificadas das quais você precisa estar ciente sejam comentadas acima.
A NoSuchFieldException
seria lançada se você pediu um campo por um nome que não corresponde a um campo declarado.
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
A IllegalAccessException
seria lançada se o campo não era acessível (por exemplo, se é privado e não foi tornado acessível via perdendo a f.setAccessible(true)
linha.
Os RuntimeException
s que podem ser lançados são SecurityException
s (se as JVMs SecurityManager
não permitirem alterar a acessibilidade de um campo) ou IllegalArgumentException
s, se você tentar acessar o campo em um objeto que não seja do tipo da classe do campo:
f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
getDeclaredField()
não encontra campos se eles estiverem definidos nas classes pai - você também deve percorrer a hierarquia da classe pai, chamandogetDeclaredField()
cada um, até encontrar uma correspondência (após a qual você pode chamarsetAccessible(true)
) ou alcançarObject
.private
campos. Isso impede o acesso acidental.Tente
FieldUtils
do apache commons-lang3:fonte
A reflexão não é a única maneira de resolver seu problema (que é acessar a funcionalidade / comportamento privado de uma classe / componente)
Uma solução alternativa é extrair a classe do .jar, descompilar usando (digamos) Jode ou Jad , alterar o campo (ou adicionar um acessador) e recompilar no arquivo .jar original. Em seguida, coloque o novo .class à frente do
.jar
no caminho de classe ou reinsira-o no.jar
. (o utilitário jar permite extrair e reinserir em um arquivo .jar existente)Conforme observado abaixo, isso resolve a questão mais ampla de acessar / alterar o estado privado, em vez de simplesmente acessar / alterar um campo.
Isso requer que
.jar
não seja assinado, é claro.fonte
Uma outra opção que ainda não foi mencionada: use o Groovy . O Groovy permite acessar variáveis de instância privadas como efeito colateral do design do idioma. Independentemente de você ter um getter para o campo, basta usar
fonte
Usando o Reflection in Java, você pode acessar todos os
private/public
campos e métodos de uma classe para outra. Mas, conforme a documentação do Oracle nas desvantagens da seção, eles recomendaram que:"Como a reflexão permite que o código execute operações que seriam ilegais no código não-reflexivo, como acessar campos e métodos privados, o uso da reflexão pode resultar em efeitos colaterais inesperados, que podem tornar o código disfuncional e destruir a portabilidade. Código reflexivo quebra abstrações e, portanto, pode alterar o comportamento com atualizações da plataforma "
aqui está o código snapts para demonstrar os conceitos básicos de reflexão
Reflection1.java
Reflection2.java
Espero que ajude.
fonte
Como oxbow_lakes menciona, você pode usar a reflexão para contornar as restrições de acesso (supondo que o SecurityManager permita).
Dito isto, se essa classe é tão mal projetada que faz com que você recorra a tal hackery, talvez você deva procurar uma alternativa. Claro que esse pequeno truque pode economizar algumas horas agora, mas quanto vai custar no futuro?
fonte
Use a estrutura Soot Java Optimization para modificar diretamente o bytecode. http://www.sable.mcgill.ca/soot/
A fuligem é completamente escrita em Java e funciona com novas versões do Java.
fonte
Você precisa fazer o seguinte:
fonte
Se você estiver usando o Spring, o ReflectionTestUtils fornece algumas ferramentas úteis que ajudam aqui com o mínimo esforço. É descrito como "para uso em cenários de teste de unidade e integração" . Há também uma classe semelhante chamada ReflectionUtils, mas é descrita como "Somente para uso interno" - veja esta resposta para uma interpretação do que isso significa.
Para abordar o exemplo postado:
fonte
ReflectionTestUtils
como na minha experiência, eu só precisei fazer esse tipo de coisa em uma situação de teste.) #Apenas uma observação adicional sobre reflexão: observei em alguns casos especiais, quando várias classes com o mesmo nome existem em pacotes diferentes, que a reflexão usada na resposta superior pode não conseguir escolher a classe correta do objeto. Portanto, se você souber qual é o package.class do objeto, é melhor acessar seus valores de campo privado da seguinte maneira:
(Esta é a classe de exemplo que não estava funcionando para mim)
fonte
Você pode usar o @JailBreak do Manifold para refletir Java diretamente e com segurança de tipo:
@JailBreak
desbloqueia afoo
variável local no compilador para acesso direto a todos os membros naFoo
hierarquia.Da mesma forma, você pode usar o método de extensão jailbreak () para uso único:
Através do
jailbreak()
método, você pode acessar qualquer membro daFoo
hierarquia.Nos dois casos, o compilador resolve o acesso ao campo para você digitar com segurança, como se fosse um campo público, enquanto o Manifold gera um código de reflexão eficiente para você.
Descubra mais sobre o coletor .
fonte
É bastante fácil com a ferramenta XrayInterface . Basta definir os getters / setters ausentes, por exemplo
e xray seu projeto mal projetado:
Internamente, isso depende de reflexão.
fonte
Tente solucionar o problema do caso, cuja classe você deseja definir / obter dados é uma de suas próprias classes.
Basta criar um
public setter(Field f, Object value)
epublic Object getter(Field f)
para isso. Você pode até fazer alguma verificação de segurança por conta própria dentro dessas funções de membro. Por exemplo, para o levantador:Claro, agora você tem que descobrir o
java.lang.reflect.Field
parasString
antes de definir o valor campo.Eu uso essa técnica em um ResultSet genérico para o mapeador de modelo.
fonte