¿Cómo puedo acceder a un campo de protección heredado de un objeto mediante la reflexión?Java reflexión - Acceso campo de protección
Respuesta
Dos cuestiones que pueda tener problemas con - el campo podrían no ser accesibles normalmente (privada), y no es de la clase que usted está viendo, pero en algún lugar en la jerarquía.
Algo como esto podría funcionar incluso con estas cuestiones:
public class SomeExample {
public static void main(String[] args) throws Exception{
Object myObj = new SomeDerivedClass(1234);
Class myClass = myObj.getClass();
Field myField = getField(myClass, "value");
myField.setAccessible(true); //required if field is not normally accessible
System.out.println("value: " + myField.get(myObj));
}
private static Field getField(Class clazz, String fieldName)
throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class superClass = clazz.getSuperclass();
if (superClass == null) {
throw e;
} else {
return getField(superClass, fieldName);
}
}
}
}
class SomeBaseClass {
private Integer value;
SomeBaseClass(Integer value) {
this.value = value;
}
}
class SomeDerivedClass extends SomeBaseClass {
SomeDerivedClass(Integer value) {
super(value);
}
}
Si hay un administrador de seguridad, esto fallaría. Necesitas concluir la llamada a setAccessible y getDeclaredField en una PriviledgedAction, y ejecutarla a través de java.security.AccessController.doPrivileged (...) – Varkhan
te amo con todo mi corazón –
Esto no funciona en Android :(Mi clase el árbol se ve así A-> B-> C y dentro de CI no puede obtener el valor de un campo protegido declarado en A. Tenga en cuenta que las tres clases están en paquetes diferentes. ¿Alguna idea de cómo evitar esto? – Moonwalker
field = myclass.getDeclaredField("myname");
field.setAccessible(true);
field.set(myinstance, newvalue);
Esto puede no funcionar si hay un administrador de seguridad que bloquea el permiso correspondiente. –
getField (String name) solo los campos públicos. – Moro
@Moro: gracias, corregí el código –
¿Usted tal vez decir a partir de un objeto diferente de un contexto que no se confía con un conjunto SecurityManager
? Eso rompería el sistema de tipos, por lo que no puedes. Desde un contexto de confianza, puede llamar al setAccessible
para anular el sistema de tipos. Idealmente, no uses el reflejo.
"Idealmente, no use reflejo". ¿Por qué? El OP está específicamente tratando de usar la reflexión ... mientras que él no dice por qué, hay muchos usos legítimos para la reflexión (especialmente en el código de prueba). –
Si bien hay usos legítimos de la reflexión, la mayoría no lo son. En particular, si te estás arrastrando por la capacidad heredada de respetar las reglas de acceso al lenguaje Java (1.0), probablemente no lo necesites. –
@Tom ... a menos que intente escribir casos de prueba JUnit específicos sin perder las reglas de acceso simplemente para el caso de prueba –
Se podría hacer algo así ...
Class clazz = Class.forName("SuperclassObject");
Field fields[] = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getName().equals("fieldImLookingFor")) {
field.set...() // ... should be the type, eg. setDouble(12.34);
}
}
También podría ser necesario cambiar la accesibilidad, como se señala en la respuesta de Maurice.
Devuelve una matriz de objetos de campo que refleja todos los campos declarados por la clase o interfaz representada por este objeto de clase. No pasó por las súper clases – Moro
¿Podría ser más específico con el problema? ¿Estás diciendo que solo obtuvo los campos en tu subclase? ¿Se ha asegurado de que al método Class.forName() se le haya pasado el nombre de la superclase y de que se haya modificado la accesibilidad, como sugirió Maurice? –
utilizar la reflexión para tener acceso a los miembros de la instancia de clase, que sean accesibles y establecer sus respectivos valores. Por supuesto, debe saber el nombre de cada miembro que desea cambiar, pero supongo que eso no será un problema.
public class ReflectionUtil {
public static Field getField(Class clazz, String fieldName) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class superClass = clazz.getSuperclass();
if (superClass == null) {
throw e;
} else {
return getField(superClass, fieldName);
}
}
}
public static void makeAccessible(Field field) {
if (!Modifier.isPublic(field.getModifiers()) ||
!Modifier.isPublic(field.getDeclaringClass().getModifiers()))
{
field.setAccessible(true);
}
}
}
public class Application {
public static void main(String[] args) throws Exception {
KalaGameState obj = new KalaGameState();
Field field = ReflectionUtil.getField(obj.getClass(), 'turn');
ReflectionUtil.makeAccessible(field);
field.setInt(obj, 666);
System.out.println("turn is " + field.get(obj));
}
}
No quería arrastrar en más bibliotecas, así que hice una que funcionaba para mí. Es una extensión de uno de los métodos de jweyrich:
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.Random;
import java.util.UUID;
public abstract class POJOFiller {
static final Random random = new Random();
public static void fillObject(Object ob) {
Class<? extends Object> clazz = ob.getClass();
do {
Field[] fields = clazz.getDeclaredFields();
fillForFields(ob, fields);
if (clazz.getSuperclass() == null) {
return;
}
clazz = clazz.getSuperclass();
} while (true);
}
private static void fillForFields(Object ob, Field[] fields) {
for (Field field : fields) {
field.setAccessible(true);
if(Modifier.isFinal(field.getModifiers())) {
continue;
}
try {
field.set(ob, generateRandomValue(field.getType()));
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
}
static Object generateRandomValue(Class<?> fieldType) {
if (fieldType.equals(String.class)) {
return UUID.randomUUID().toString();
} else if (Date.class.isAssignableFrom(fieldType)) {
return new Date(System.currentTimeMillis());
} else if (Number.class.isAssignableFrom(fieldType)) {
return random.nextInt(Byte.MAX_VALUE) + 1;
} else if (fieldType.equals(Integer.TYPE)) {
return random.nextInt();
} else if (fieldType.equals(Long.TYPE)) {
return random.nextInt();
} else if (Enum.class.isAssignableFrom(fieldType)) {
Object[] enumValues = fieldType.getEnumConstants();
return enumValues[random.nextInt(enumValues.length)];
} else if(fieldType.equals(Integer[].class)) {
return new Integer[] {random.nextInt(), random.nextInt()};
}
else {
throw new IllegalArgumentException("Cannot generate for " + fieldType);
}
}
}
Un método utilidad genérica para ejecutar cualquier getter en este o cualquier superclase.
Adaptado de Marius's respuesta.
public static Object RunGetter(String fieldname, Object o){
Object result = null;
boolean found = false;
//Search this and all superclasses:
for (Class<?> clas = o.getClass(); clas != null; clas = clas.getSuperclass()){
if(found){
break;
}
//Find the correct method:
for (Method method : clas.getDeclaredMethods()){
if(found){
break;
}
//Method found:
if ((method.getName().startsWith("get")) && (method.getName().length() == (fieldname.length() + 3))){
if (method.getName().toLowerCase().endsWith(fieldname.toLowerCase())){
try{
result = method.invoke(o); //Invoke Getter:
found = true;
} catch (IllegalAccessException | InvocationTargetException ex){
Logger.getLogger("").log(Level.SEVERE, "Could not determine method: " + method.getName(), ex);
}
}
}
}
}
return result;
}
Espero que sea útil para alguien.
Si se acaba de entrar el campo de protección
Field protectedfield = Myclazz.class.getSuperclass().getDeclaredField("num");
Si está utilizando Eclipse Ctrl +espacio aparecerá una lista de métodos cuando se escribe un "" después del objeto
Utilice FieldUtils.writeField(object, "fieldname", value, true)
o readField(object, "fieldname", true)
desde Apache Commons lang3.
Si se utiliza la primavera, ReflectionTestUtils proporciona algunas herramientas útiles que ayudan a cabo aquí con un mínimo esfuerzo.
Por ejemplo, para obtener un valor de campo protegida que se sabe que es un int
:
int theIntValue = (int)ReflectionTestUtils.getField(theClass, "theProtectedIntField");
O, alternativamente, para establecer el valor de este campo:
ReflectionTestUtils.setField(theClass, "theProtectedIntField", theIntValue);
- 1. valor Conjunto de campo de objeto por reflexión en Java
- 2. Android: cambiar definitiva campo utilizando Java reflexión estática privada
- 3. Protección de un servidor web Linux para acceso público
- 4. Interceptar el acceso de campo de objetos Java en Rhino
- 5. Protección JKS
- 6. Conseguir el campo "longitud" en una matriz de Java utilizando la reflexión
- 7. Pregunta de reflexión de Java
- 8. C# acceso protegido campo
- 9. Acceso última variable estática por medio de la reflexión
- 10. método Java para asignar valores de campo de objeto con la reflexión
- 11. asp.net protección de medios
- 12. sincronizar el acceso a un campo estático
- 13. Framework de reflexión de Java y seguridad
- 14. Adecuación de la reflexión de Java
- 15. Obtener el tipo de un campo en Haxe (reflexión API)
- 16. ¿Los modificadores de acceso también afectan la reflexión?
- 17. Modificadores de reflexión y acceso en una propiedad
- 18. JSON - Campo de acceso llamado '*' asterisco
- 19. R: valores del campo de acceso
- 20. Acceso al campo de la clase externa
- 21. Reflexión que no encontró el campo protegido del tipo anidado
- 22. C# Reflexión: Finding atributos en un campo miembro
- 23. Protección de archivos jar de Java para la distribución
- 24. Reflexión del método seguro en Java
- 25. Java Reflexión con los tipos primitivos
- 26. Java gama reflexión: isArray vs instanceof
- 27. paquete frente a protección protegida con reflejo de Java
- 28. Buscar la vía de acceso de clase Java mínima necesaria
- 29. Acceso al campo de identidad de incremento automático después de insertar SQL en Java
- 30. Acceso de campo privado de Java posible al tener una referencia?
La pregunta sería mejor si usted indicó lo que probaste (exactamente) y lo que sucedió (exactamente). –