FULL PRODUCT VERSION :
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) Client VM (build 16.3-b01, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
Accessing protected static fields and methods is not possible for subclasses using reflection. This is due to a bug in the method verifyMemberAccess() of class sun.reflect.Reflection:
In lines 110 ff. it is checked, that the caller's class (named currentClass) is a subclass of the member's class (named memberClass):
if (Modifier.isProtected(modifiers)) {
// See if currentClass is a subclass of memberClass
if (isSubclassOf(currentClass, memberClass)) {
successSoFar = true;
}
}
In the static case the variable targetClass is set to memberClass, line 135:
Class targetClass = (target == null ? memberClass : target.getClass());
Later on the following code is reached (lines 141 ff.)
if (!isSubclassOf(targetClass, currentClass)) {
return false;
}
The arguments order in this call to method isSubclassOf() is obviously wrong!
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
javac a/A.java a/b/B.java
java a.b.B
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Successfully set protected static member in a static way
Successfully set protected static member in a non-static way
ACTUAL -
java.lang.IllegalAccessException: Class a.b.B can not access a member of class a.A with modifiers "protected static"
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.reflect.Field.doSecurityCheck(Unknown Source)
at java.lang.reflect.Field.getFieldAccessor(Unknown Source)
at java.lang.reflect.Field.set(Unknown Source)
at a.b.B.reflectiveAccess(B.java:21)
at a.b.B.main(B.java:12)
Successfully set protected static member in a non-static way
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
-----
package a;
public class A
{
protected static Object member;
}
-----
package a.b;
public class B extends a.A
{
public static void main(String[] args) throws Exception
{
new B().reflectiveAccess();
}
public void reflectiveAccess() throws Exception
{
java.lang.reflect.Field member = a.A.class.getDeclaredField("member");
try {
member.set(null, new Object());
System.out.println("Successfully set protected static member in a static way");
}
catch (Exception e) {
e.printStackTrace(System.err);
}
try {
member.set(this, new Object());
System.out.println("Successfully set protected static member in a non-static way");
}
catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
-----
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
1) Use a customized implementation of sun.reflect.FieldAccessor, sun.reflect.MethodAccessor and sun.reflect.ConstructorAccessor.
2) Reflectively access protected static members by passing in a target object.