JDK-6888164 : Bridge methods break obtaining of declaring class annotations
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 6u10
  • Priority: P3
  • Status: Resolved
  • Resolution: Won't Fix
  • OS: linux
  • CPU: x86
  • Submitted: 2009-10-05
  • Updated: 2013-04-09
  • Resolved: 2013-04-09
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux sickboy-pc 2.6.27-11-generic #1 SMP Wed Apr 1 20:53:41 UTC 2009 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
java.beans.Introspector returns bridge methods (introduced in 6342411) as read/write methods. method.getDeclaringClass() in such case does not return the expected class (ancestor) where the methods are declared. User can't obtain annotations declared on the class where the property accessors were really declared.

This works with JDK5 compiled classes.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile classes with JDK6. Execute BeanInfoTest. It won't find any annotations on read/write methods of a property because it will return bridging methods and the declaring class of these bridging methods.

Compiled with JDK5 it finds annotations ok as the declaring class is the real class declaring the methods.

This was probably introduced by fix for issue 6342411.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Same as with JDK5 compiled classes. Because of this annotation based code might stop working.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
=================BeanInfoTest.java=================
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;

public class BeanInfoTest {

    public static void main(String[] args) throws IntrospectionException {
        final BeanInfo bi = Introspector.getBeanInfo(Descendant.class);
        final PropertyDescriptor[] pds = bi.getPropertyDescriptors();
        for (PropertyDescriptor p : pds) {
            System.out.println(p.getName() + ":");
            if (p.getReadMethod() != null) {
                info(p.getReadMethod());
            }
            if (p.getWriteMethod() != null) {
                info(p.getWriteMethod());
            }
        }
    }
    
    public static void info(Method m) {
        System.out.println(m.getDeclaringClass().getName() + "." + m.getName());
        System.out.println(Arrays.toString(m.getAnnotations()));
        System.out.println(Arrays.toString(m.getDeclaringClass().getAnnotations()));
    }
}

=================Ancestor.java=================
@Test
class Ancestor {

    private String a;

    @Test
    public String getA() {
        return a;
    }
    
    @Test
    public void setA(String a) {
        this.a = a;
    }
}
=================Descendant.java=================
public class Descendant extends Ancestor {

}
=================Test.java=================
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Test {

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Check whether the read/write method is synthetic bridge and try to find the same method in superclass(es).

Comments
This bug is more a reflection libraries issue than a javac issue.
09-04-2013