JDK-8040656 : Classes with overriden methods with covariant returns return random read methods
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 7u21
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • Submitted: 2013-06-20
  • Updated: 2014-07-29
  • Resolved: 2014-04-21
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 8 JDK 9
8u20Fixed 9 b15Fixed
Description
FULL PRODUCT VERSION :
java version  " 1.7.0_21 " 
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux 2.6.32-48-generic #110-Ubuntu SMP Fri May 31 18:32:53 UTC 2013 x86_64 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
Consider a bean class B that implements an interface, and which has a bean method with a covariant return type:

public interface A {
        public Object getFoo();
    }

public class B implements A {
        @Override
        public String getFoo() {
            return null;
        }
}

When you call Introspector.getBeanInfo(B.class).getMethodDescriptors(), the method descriptor for getFoo() randomly returns either Object getFoo() (a synthetic bridge method added by javac due to covariant return types) or String getFoo() (the actual method that appears in B).

REGRESSION.  Last worked in version 6u45

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Execute the following program.  I classes B and C are identical except for some dummy methods added to B.  On my machine this prints:

public java.lang.String scrap.IntrospectorTest$B.getFoo()
public java.lang.Object scrap.IntrospectorTest$C.getFoo()

I would expect it to return identically for both classes, since the getFoo() method is identical.  If you add or remove additional dummy methods to the classes, the results change. If you kick off some threads or do other heavy things before doing the introspection, the result changes.  Basically the return value is random (but the B vs C was the easiest way I found to make a reproducible test case).

Because of the randomness, you might get different results on your machine!


ACTUAL -
See above.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
See above

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package scrap;

import java.beans.*;

public class IntrospectorTest {
    
    public interface A {
        public Object getFoo();
    }
    
    public class B implements A {
        @Override
        public String getFoo() {
            return null;
        }
        
        // if you add/delete these dummy methods, the bean method for getFoo() will
        // flip back and fort between Object getFoo() (bride) and String getFoo() (the
        // covariant method that actually appears in the source)
        public Object getFoo1() { return null; }
        public Object getFoo2() { return null; }
        public Object getFoo3() { return null; }
        public Object getFoo4() { return null; }
        public Object getFoo5() { return null; }
    }
    
    public class C implements A {
        @Override
        public String getFoo() {
            return null;
        }
    }

    public static void main(String[] args) throws Exception {
        printMethods(B.class);
        printMethods(C.class);

    }

    private static void printMethods(final Class<?> clazz) throws IntrospectionException {
        BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
        for (MethodDescriptor desc : beanInfo.getMethodDescriptors()) {
            if (desc.getName().equals( " getFoo " )) {
                System.out.println(desc.getMethod());
            }
        }
    }

}
---------- END SOURCE ----------
Comments
http://cr.openjdk.java.net/~malenkov/8040656.9.0/ We should prefer a normal method to a synthetic one.
17-04-2014

This affects all previous versions till 5, in which bridge synthetic methods were introduced.
17-04-2014

is it affecting 8 or 9?
17-04-2014