JDK-7157574 : method handles returned by reflective lookup API sometimes have wrong receiver type
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Affected Version: 7-pool
  • Priority: P3
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: generic
  • CPU: generic
  • Submitted: 2012-03-28
  • Updated: 2012-12-05
  • Resolved: 2012-06-26
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
8-poolResolved
Related Reports
Relates :  
Description
When an inherited non-static field or method is looked up in a class C using Lookup.findVirtual(C...), etc., the JSR 292 API, the first argument of the resulting method handle must be the receiver ('this'), and must be the requested class (or more specific, in the case of findSpecial or a lookup of a protected method).

But currently, if a supertype T defines the looked-up method or field and C inherits it, the returned method handle might have the more specific initial type T.

The relevant javadoc (and 292 spec.) is as follows:
     * The formal parameter {@code this} stands for the self-reference of type {@code C};
     * if it is present, it is always the leading argument to the method handle invocation.
     * (In the case of some {@code protected} members, {@code this} may be
     * restricted in type to the lookup class; see below.)

Because of this bug, all of the assertions fail in the following example:

import java.lang.invoke.*;
import static java.lang.invoke.MethodHandles.*;
import static java.lang.invoke.MethodType.*;
class Test_0000000 {
    interface Intf { void m1(); }
    abstract class Super implements Intf { abstract void m2(); public int f2; }
    abstract class Sub extends Super { }
    public static void main(String... av) throws Throwable {
        MethodHandle m1 = lookup().findVirtual(Sub.class, "m1", methodType(void.class));
        System.out.println(m1);
        MethodHandle m2 = lookup().findVirtual(Sub.class, "m2", methodType(void.class));
        System.out.println(m2);
        MethodHandle f2 = lookup().findGetter(Sub.class, "f2", int.class);
        System.out.println(f2);
        MethodHandle f2s = lookup().findSetter(Sub.class, "f2", int.class);
        System.out.println(f2s);
        assertEquals(Sub.class, m1.type().parameterType(0));
        assertEquals(Sub.class, m2.type().parameterType(0));
        assertEquals(Sub.class, f2.type().parameterType(0));
        assertEquals(Sub.class, f2s.type().parameterType(0));
    }
    private static void assertEquals(Object expect, Object observe) {
        if (java.util.Objects.equals(expect, observe))  return;
        String msg = ("expected "+expect+" but observed "+observe);
        System.out.println("FAILED: "+msg);
        throw new AssertionError(msg);
    }
}

Test: java/lang/invoke/7157574/Test7157574.java 
Comments
Updated for the aurora show this as known bug
05-12-2012

EVALUATION Has been fixed by other changes; not reproducible in current JDK7 or JDK8 release. Will include a regression test for this in the next major update to JDK code.
26-06-2012