Access to Private Inherited Fields via Reflection in Java

Access to private inherited fields via reflection in Java

In fact i use a complex type hierachy so you solution is not complete.
I need to make a recursive call to get all the private inherited fields.
Here is my solution

 /**
* Return the set of fields declared at all level of class hierachy
*/
public static List<Field> getAllFields(Class<?> clazz) {
return getAllFieldsRec(clazz, new ArrayList<>());
}

private static List<Field> getAllFieldsRec(Class<?> clazz, List<Field> list) {
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null) {
getAllFieldsRec(superClazz, list);
}
list.addAll(Arrays.asList(clazz.getDeclaredFields()));
return list;
}

Get all fields (even private and inherited) from class

obj = obj.getClass().getSuperclass().cast(obj);

This line does not do what you expect it to do. Casting an Object does not actually change it, it just tells the compiler to treat it as something else.

E.g. you can cast a List to a Collection, but it will still remain a List.

However, looping up through the super classes to access fields works fine without casting:

Class<?> current = yourClass;
while(current.getSuperclass()!=null){ // we don't want to process Object.class
// do something with current's fields
current = current.getSuperclass();
}

BTW, if you have access to the Spring Framework, there is a handy method for looping through the fields of a class and all super classes:

ReflectionUtils.doWithFields(baseClass, FieldCallback)
(also see this previous answer of mine: Access to private inherited fields via reflection in Java)

Set private field value with reflection

To access a private field you need to set Field::setAccessible to true. You can pull the field off the super class. This code works:

Class<?> clazz = Child.class;
Object cc = clazz.newInstance();

Field f1 = cc.getClass().getSuperclass().getDeclaredField("a_field");
f1.setAccessible(true);
f1.set(cc, "reflecting on life");
String str1 = (String) f1.get(cc);
System.out.println("field: " + str1);

Why is it allowed to access Java private fields via reflection?

Private is intended to prevent accidental misuse, not as a security mechanism. If you choose to bypass it then you can do so at your own risk and the assumption you know what you are doing.

Java: Accessing private field via reflection (behaviour)

Is there any limitation?

Yes - you need several JVM permissions (most notably accessDeclaredMembers and suppressAccessChecks, marked with big, bold warnings in the docs) for this to work; if your JVM's security profile is somewhat strict (say, the much-maligned applets), your code will not work because these permissions will not be available.

Does it get changed forever?

Yes, as long as your program keeps on running the fields will remain accessible (as long as you keep on using the same Field instance where you changed access permissions).

Is it bad?

Not necessarily. It allows java code to serialize and de-serialize objects with private fields, it allows complex mocking that may simplify testing, it allows you to peek into places you would not otherwise be able to peek into. However, since it breaks expectations, you should use it sparingly and make sure that users know that you require the extra permissions and "are looking under the hood". The docs (see above) state quite clearly that this is considered risky, and that it should only be allowed if you know what you are doing.

Get all private fields using reflection

It is possible to obtain all fields with the method getDeclaredFields() of Class. Then you have to check the modifier of each fields to find the private ones:

List<Field> privateFields = new ArrayList<>();
Field[] allFields = SomeClass.class.getDeclaredFields();
for (Field field : allFields) {
if (Modifier.isPrivate(field.getModifiers())) {
privateFields.add(field);
}
}

Note that getDeclaredFields() will not return inherited fields.

Eventually, you get the type of the fields with the method Field.getType().

How to access field inherited from an abstract class with Reflection?

Use Class.getField() rather than Class.getDeclaredField(). getDeclaredField() only considers the fields declared by the type of the object on which the method is invoked, while getField() recursively ascends the tree of supertypes looking for a match.

C#: Accessing Inherited Private Instance Members Through Reflection

As Lee stated, you can do this with recursion.

private static void FindFields(ICollection<FieldInfo> fields, Type t) {
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

foreach (var field in t.GetFields(flags)) {
// Ignore inherited fields.
if (field.DeclaringType == t)
fields.Add(field);
}

var baseType = t.BaseType;
if (baseType != null)
FindFields(fields, baseType);
}

public static void Main() {
var fields = new Collection<FieldInfo>();
FindFields(fields, typeof(B));
foreach (FieldInfo fi in fields)
Console.WriteLine(fi.DeclaringType.Name + " - " + fi.Name);
}

Retrieving the inherited attribute names/values using Java Reflection

no, you need to write it yourself. It is a simple recursive method called on Class.getSuperClass():

public static List<Field> getAllFields(List<Field> fields, Class<?> type) {
fields.addAll(Arrays.asList(type.getDeclaredFields()));

if (type.getSuperclass() != null) {
getAllFields(fields, type.getSuperclass());
}

return fields;
}

@Test
public void getLinkedListFields() {
System.out.println(getAllFields(new LinkedList<Field>(), LinkedList.class));
}


Related Topics



Leave a reply



Submit