It seems that the Android application class loader allows to reflectively acquire a reference to the public static
field of a package-private class even from a different package (than the one the aforementioned class is defined in), while Sun JDK classloader for example doesn't.
More concretely, given the following class definition:
package org.example.a
class PackagePrivateClass {
public static final Parcelable.Creator<PackagePrivateClass> CREATOR = generateCreator();
}
And the following code in a separate package:
package org.example.b
public class TestClass {
public void testMethod() {
final Class classRef = Class.forName("org.example.a.PackagePrivateClass");
final Field creatorFieldRef = classRef.getField("CREATOR");
creatorFieldRef.get(null); // throws here (unless on Android)
}
}
When executed on Sun JVM it throws an IllegalAccessException
on the last line:
java.lang.IllegalAccessException: Class org.example.b.TestClass can not access a member of class org.example.a.PackagePrivateClass with modifiers "public static final"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
...
However, when run on an Android device (5.1 Lollipop FWIW) it executes without throwing and creatorFieldRef.get(null)
actually returns a valid reference to the CREATOR
field.
My question is : why is it the case ? Is it a bug or a feature of the Android classloader ?? (or, if applicable, what did I get wrong in my example ?)
This class loader is used to load classes and resources from a search path of URLs referring to both JAR files and directories. A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class.
We can use newInstance() method on the constructor object to instantiate a new instance of the class. Since we use reflection when we don't have the classes information at compile time, we can assign it to Object and then further use reflection to access it's fields and invoke it's methods.
Since Java enforces the most restrictive access, we have to explicitly declare packages using the export or open module declaration to get reflective access to the classes inside the module.
If there are classes that get generated, or delivered remotely, you will not be able to discover those classes. The normal method is instead to somewhere register the classes you need access to in a file, or reference them in a different class. Or just use convention when it comes to naming.
Seems that it is a bug in the android runtime which was fixed in this commit:
Add access checks to Method and Field reflection.
Prior to this commit it was possible to access fields via reflection in an unrestricted way or even set the value of final fields.
The access check is now implemented in the runtime functions ValidateFieldAccess
and ValidateAccess
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With