Para acceder a los campos privados, debe obtenerlos de los campos declarados de la clase y luego hacerlos accesibles:
Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException
EDITAR : como ha comentado aperkins , tanto acceder al campo, configurarlo como accesible y recuperar el valor puede arrojar Exception
s, aunque las únicas excepciones marcadas de las que debe tener en cuenta se comentaron anteriormente.
Se NoSuchFieldException
generaría si solicitara un campo con un nombre que no correspondiera a un campo declarado.
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
Se IllegalAccessException
generaría si el campo no fuera accesible (por ejemplo, si es privado y no se ha hecho accesible al perder la f.setAccessible(true)
línea).
Los RuntimeException
s que se pueden lanzar son SecurityException
s (si las JVM SecurityManager
no le permitirán cambiar la accesibilidad de un campo), o IllegalArgumentException
s, si intenta acceder al campo en un objeto que no es del tipo de clase del campo:
f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
getDeclaredField()
no encuentra campos si están definidos en clases principales: también debe iterar hacia arriba a través de la jerarquía de clases principales, llamandogetDeclaredField()
a cada uno, hasta que encuentre una coincidencia (después de lo cual puede llamarsetAccessible(true)
), o llegueObject
.private
campos. Impide el acceso accidental.Pruebe
FieldUtils
desde apache commons-lang3:fuente
La reflexión no es la única forma de resolver su problema (que es acceder a la funcionalidad / comportamiento privado de una clase / componente)
Una solución alternativa es extraer la clase del .jar, descompilarla usando (por ejemplo) Jode o Jad , cambiar el campo (o agregar un descriptor de acceso) y recompilarlo contra el .jar original. Luego coloque el nuevo .class delante del
.jar
en el classpath, o vuelva a insertarlo en el.jar
. (la utilidad jar le permite extraer y reinsertar en un .jar existente)Como se señala a continuación, esto resuelve el problema más amplio de acceder / cambiar el estado privado en lugar de simplemente acceder / cambiar un campo.
Esto requiere que
.jar
no se firme, por supuesto.fuente
Otra opción que aún no se ha mencionado: usar Groovy . Groovy le permite acceder a variables de instancia privadas como efecto secundario del diseño del lenguaje. Ya sea que tenga o no un captador para el campo, simplemente puede usar
fuente
Usando Reflection in Java puede acceder a todos los
private/public
campos y métodos de una clase a otra. Pero según la documentación de Oracle en los inconvenientes de la sección , recomendaron que:"Dado que la reflexión permite que el código realice operaciones que serían ilegales en el código no reflectante, como acceder a campos y métodos privados, el uso de la reflexión puede provocar efectos secundarios inesperados, que pueden hacer que el código sea disfuncional y destruir la portabilidad. Código reflectante rompe las abstracciones y, por lo tanto, puede cambiar el comportamiento con las actualizaciones de la plataforma "
a continuación se muestran los ajustes de código para demostrar los conceptos básicos de Reflection
Reflexión1.java
Reflection2.java
Espero que ayude.
fuente
Como menciona oxbow_lakes, puede usar la reflexión para sortear las restricciones de acceso (suponiendo que su SecurityManager lo permita).
Dicho esto, si esta clase está tan mal diseñada que te hace recurrir a tal piratería informática, tal vez deberías buscar una alternativa. Seguro que este pequeño truco podría ahorrarte unas horas ahora, pero ¿cuánto te costará en el futuro?
fuente
Utilice el marco de optimización Soot Java para modificar directamente el código de bytes. http://www.sable.mcgill.ca/soot/
Soot está completamente escrito en Java y funciona con nuevas versiones de Java.
fuente
Debes hacer lo siguiente:
fuente
Si usa Spring, ReflectionTestUtils proporciona algunas herramientas útiles que ayudan aquí con un mínimo esfuerzo. Se describe como "para uso en escenarios de prueba de unidad e integración" . También hay una clase similar llamada ReflectionUtils, pero se describe como "Solo para uso interno" . Consulte esta respuesta para obtener una interpretación de lo que esto significa.
Para abordar el ejemplo publicado:
fuente
ReflectionTestUtils
como en mi experiencia, solo he necesitado hacer este tipo de cosas en una situación de prueba).Solo una nota adicional sobre la reflexión: he observado en algunos casos especiales, cuando existen varias clases con el mismo nombre en diferentes paquetes, esa reflexión tal como se usa en la respuesta superior puede fallar al elegir la clase correcta del objeto. Entonces, si sabe cuál es el paquete.clase del objeto, entonces es mejor acceder a sus valores de campo privado de la siguiente manera:
(Esta es la clase de ejemplo que no funcionaba para mí)
fuente
Puede usar Manifold's @JailBreak para una reflexión directa y segura de Java:
@JailBreak
desbloquea lafoo
variable local en el compilador para acceder directamente a todos los miembros deFoo
la jerarquía.Del mismo modo, puede usar el método de extensión jailbreak () para un uso único:
A través del
jailbreak()
método, puede acceder a cualquier miembro deFoo
la jerarquía.En ambos casos, el compilador resuelve el acceso de campo para que escriba de forma segura, como si fuera un campo público, mientras que Manifold genera un código de reflexión eficiente para usted bajo el capó.
Descubre más sobre Colector .
fuente
Es bastante fácil con la herramienta XrayInterface . Simplemente defina los captadores / establecedores que faltan, por ejemplo
y haz una radiografía de tu pobre proyecto diseñado:
Internamente esto se basa en la reflexión.
fuente
Intente solucionar el problema para el caso, la clase de la que desea establecer / obtener datos es una de sus propias clases.
Solo crea un
public setter(Field f, Object value)
ypublic Object getter(Field f)
para eso. Incluso puede hacer algunas comprobaciones de seguridad por su cuenta dentro de estas funciones miembro. Por ejemplo, para el setter:Por supuesto, ahora usted tiene que averiguar la
java.lang.reflect.Field
desString
antes del fraguado del valor del campo.Utilizo esta técnica en un ResultSet-to-and-from-model-mapper genérico.
fuente