
franco krueger
Tengo una clase mal diseñada en un tercero JAR
y necesito acceder a uno de sus privado campos. Por ejemplo, ¿por qué debería elegir un campo privado si es necesario?
class IWasDesignedPoorly {
private Hashtable stuffIWant;
}
IWasDesignedPoorly obj = ...;
¿Cómo puedo usar la reflexión para obtener el valor de stuffIWant
?

oxbow_lakes
Para acceder a los campos privados, debe obtenerlos de la clase declarado campos y luego hacerlos accesibles:
Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException
EDITAR: como ha sido comentado por aperkinstanto acceder al campo, configurarlo como accesible y recuperar el valor puede arrojar Exception
s, aunque el único comprobado las excepciones que debe tener en cuenta se comentan anteriormente.
los NoSuchFieldException
se arrojaría si solicita un campo con un nombre que no corresponde a un campo declarado.
obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException
los IllegalAccessException
se lanzaría si el campo no fuera accesible (por ejemplo, si es privado y no se ha hecho accesible al perder el f.setAccessible(true)
línea.
los RuntimeException
s que se pueden lanzar son SecurityException
s (si la JVM SecurityManager
no le permitirá 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
Tratar FieldUtils
de apache commons-lang3:
FieldUtils.readField(object, fieldName, true);

Brian Agnew
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 (digamos) Jode o Jad, cambie el campo (o agregue un descriptor de acceso) y vuelva a compilarlo contra el .jar original. Luego coloque la nueva .class delante de la .jar
en el classpath, o reinsértelo en el .jar
. (la utilidad jar le permite extraer y volver a insertar en un .jar existente)
Como se indica 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 la .jar
sin firmar, por supuesto.

lucas
Otra opción que aún no se ha mencionado: usar maravilloso. Groovy te permite acceder a variables de instancias privadas como un efecto secundario del diseño del lenguaje. Ya sea que tenga o no un captador para el campo, puede usar
def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()

simiente
Utilizando el Reflexión en Java puedes acceder a todos los private/public
campos y métodos de una clase a otra. Pero según el Oráculo documentación en la sección inconvenientes recomendaron que:
“Dado que la reflexión permite que el código realice operaciones que serían ilegales en el código no reflexivo, como acceder a campos y métodos privados, el uso de la reflexión puede generar efectos secundarios inesperados, lo que puede hacer que el código sea disfuncional y puede destruir la portabilidad. Código reflexivo rompe las abstracciones y, por lo tanto, puede cambiar el comportamiento con las actualizaciones de la plataforma”
aquí están las siguientes instantáneas de código para demostrar los conceptos básicos de Reflexión
Reflexión1.java
public class Reflection1{
private int i = 10;
public void methoda()
{
System.out.println("method1");
}
public void methodb()
{
System.out.println("method2");
}
public void methodc()
{
System.out.println("method3");
}
}
Reflexión2.java
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflection2{
public static void main(String ar[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
Method[] mthd = Reflection1.class.getMethods(); // for axis the methods
Field[] fld = Reflection1.class.getDeclaredFields(); // for axis the fields
// Loop for get all the methods in class
for(Method mthd1:mthd)
{
System.out.println("method :"+mthd1.getName());
System.out.println("parametes :"+mthd1.getReturnType());
}
// Loop for get all the Field in class
for(Field fld1:fld)
{
fld1.setAccessible(true);
System.out.println("field :"+fld1.getName());
System.out.println("type :"+fld1.getType());
System.out.println("value :"+fld1.getInt(new Reflaction1()));
}
}
}
Espero que ayude

Laurence Gonsalves
Como menciona oxbow_lakes, puede usar la reflexión para evitar 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, tal vez deberías buscar una alternativa. Seguro que este pequeño truco podría ahorrarte algunas horas ahora, pero ¿cuánto te costará en el futuro?

pcpratts
Utilice el marco de optimización de Soot Java para modificar directamente el código de bytes.
http://www.sable.mcgill.ca/hollín/
Soot está completamente escrito en Java y funciona con nuevas versiones de Java.