JDK-7122138 : IAE thrown because Introspector ignores synthetic methods
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2011-12-16
  • Updated: 2013-12-16
  • Resolved: 2012-02-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7 JDK 8
7u4Fixed 8 b25Fixed
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_02"
Java(TM) SE Runtime Environment (build 1.7.0_02-b13)
Java HotSpot(TM) 64-Bit Server VM (build 22.0-b10, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
This bug is independent on OS.

A DESCRIPTION OF THE PROBLEM :
When calling java.beans.Introspector.getTargetPropertyInfo(), Java7 ignores Synthetic methods as shown below.
----------------------------------------------------------------------
private PropertyDescriptor[] getTargetPropertyInfo() {
  .... ....
  // Now analyze each method.
  for (int i = 0; i < methodList.length; i++) {
      Method method = methodList[i];
      if (method == null || method.isSynthetic()) {
          continue;
      }
  .... ....
}
----------------------------------------------------------------------

This optimization will bring about problem: wrong method will be returned in some case.

Take two classes below as an example.
----------------------------------------------------------------------
package com.oracle;
class Super {
    String name;
    public void setName(String name) { this.name = name; }
    public String getName() { return name; }
}

package com.oracle;
public class Sub extends Super {
}

----------------------------------------------------------------------

The class Super is not a public class, it can be accessed only in the package com.oracle. Moreover, both of
its methods getName/setName are not accessible globally either, even if they are declared as public.

The class Sub extends the class Super, and inherents methods getName/setName from the class Super. Compiler
will generate synthetic methods for them, because they are not overrided.
And because this is a public class, both of these synthetic methods getName/setName are accessible globally.

If we invoke Introspector.getBeanInfo(Sub.class).getPropertyDescriptors(), Java7 will return the
PropertyDescriptor of property "name" and its getter/setter method of the class Super. Because Java7 ignores
synthetic methods of the class Sub as shown above.

When we use these methods of class Super to access an instance of Sub with: method.invoke(objectOfSub, args),
an IllegalAccessException will be thrown out because the method getName/setName of class Super can not be
accessed outside of the package com.oracle.

In the same situation, Java6 will return the synthetic methods getName/setName of the class Sub. Thus Java6
does not have this problem.


REGRESSION.  Last worked in version 6u29

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Define a super class and its sub-class as below
=====================================================
package com.oracle;
class Super {
    String name;
    public void setName(String name) {this.name = name;}
    public String getName(){return name;}
}
=====================================================
package com.oracle;
public class Sub extends Super {
}

=====================================================
Execute Unit test case below and the IAE will be thrown out.
=====================================================
package test;

import java.beans.*;
import java.lang.reflect.Method;

import org.junit.Test;
import static org.junit.Assert.*;
import com.oracle.*;

public class PropertyTest {

    @Test
    public void test() throws Exception {
        Class<Sub> clz = Sub.class;
        PropertyDescriptor[] pds =
                           Introspector.getBeanInfo(clz).getPropertyDescriptors() ;
        Sub sub = clz.newInstance();
        for(PropertyDescriptor pd : pds){
            if("name".equals(pd.getName())){
                Method method = pd.getWriteMethod();
                System.out.println(method.toString());
                method.invoke(sub, new Object[]{"Dapeng Hu"});
            }
        }
        System.out.println(sub.getName());
    }
}

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
 The expected result is that the "setName" method is invoked correctly and the value of "name" property is "Dapeng Hu".
ACTUAL -
The following exception is thrown out:

java.lang.IllegalAccessException: Class test.PropertyTest can not access a member of class target.Super with modifiers "public"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:95)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253)
	at java.lang.reflect.Method.invoke(Method.java:594)


REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
As a workaround, declare the class Super as public, the problem will be fixed.

Comments
EVALUATION Seems it is a regression after the 6528714 fix. We should provide another fix for that issue.
16-01-2012