I've looked through every entry related to Java reflection I can find and none seem to address the situation I'm dealing with. I have a class A with a static nested class in it, B. Class A also has as one of its fields, an array of type B, called bArray. I need to access this field from outside the class as well as the private members of the elements of bArray. I have been able to get the static nested class using getDeclaredClasses and I would normally get the private field bArray with getDeclaredFields and setAccessible but I can't seem to put it all together to be able to iterate through bArray from outside the class.
Here is an example class structure that I'm working with.
public class A {
private A.B[] bArray = new A.B[16];
private static class B {
private int theX;
private int theY;
B(int x, int y) {
this.theX = x;
this.theY = y;
}
// More methods of A.B not included
}
}
I ultimately need to get at bArray and its fields theX and theY from outside of class A.
I cannot use the names of the classes like Class.forName("classname") because the code all gets run through an obfuscator and the names all change except the ones in strings of course. I can use the field order (index) but not the name due to obfuscation. I've managed to pick out all of the fields, methods and whatnot that I need except this private static nested array field.
This is the direction I've tried. The first 3 lines of this seem to do what I want but the 4th says ABArray cannot be resolved:
A myA = new A();
Class AB = stealNamedInnerClass(A.class);
Class ABArray = Array.newInstance(AB, 0).getClass();
ABArray myABArray = (ABArray)stealAndGetField(myA, ABArray);
These are the utility functions I'm referencing:
public static Field stealField(Class typeOfClass, Class typeOfField)
{
Field[] fields = typeOfClass.getDeclaredFields();
for (Field f : fields) {
if (f.getType().equals(typeOfField)) {
try {
f.setAccessible(true);
return f;
} catch (Exception e) {
break; // Throw the Exception
}
}
}
throw new RuntimeException("Couldn't steal Field of type \"" + typeOfField + "\" from class \"" + typeOfClass + "\" !");
}
public static Object stealAndGetField(Object object, Class typeOfField)
{
Class typeOfObject;
if (object instanceof Class) { // User asked for static field:
typeOfObject = (Class)object;
object = null;
} else {
typeOfObject = object.getClass();
}
try {
Field f = stealField(typeOfObject, typeOfField);
return f.get(object);
} catch (Exception e) {
throw new RuntimeException("Couldn't get Field of type \"" + typeOfField + "\" from object \"" + object + "\" !");
}
}
public static Class stealNamedInnerClass(Class clazz)
{
Class innerClazz = null;
Class[] innerClazzes = clazz.getDeclaredClasses();
if (innerClazzes != null) {
for (Class inner : innerClazzes) {
if (!inner.isAnonymousClass())
return inner;
}
}
return null;
}
Class
instances are not types in the sense of the Java programming language. They are just objects. So you can’t dobecause
ABArray
is just an object of typeClass
, not a type. If it were a type, it wouldn’t help anyway as the type you are trying to use is not accessible from that code. Which is what your attempt is all about, you are trying to access aprivate
class which is not possible using normal Java language constructs. But you can just useObject[]
asA.B[]
is a subclass ofObject[]
:Note that processing the elements as
Object
is no problem as you will (and can) access them via reflection only and the reflection methods takeObject
as input anyway. Of course, you will lose compile-time type safety and detect mistakes at runtime only but that’s an unavoidable limitation of reflection.Yes, you can simply iterate over your bArray:
When you are testing it, make sure your array is fully initialized (i.e. contains non-null values).