JDK-7058630 : JSR 292 method handle proxy violates contract for Object methods
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2011-06-23
  • Updated: 2013-08-07
  • Resolved: 2011-08-02
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
7u40Fixed 8 b01Fixed
Related Reports
Relates :  
Description
import java.lang.invoke.*;
import java.util.Arrays;

class BadProxy {
    private static void run() {
        System.out.println("hello, world");
    }
    public static void main(String... av) throws Throwable {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle run = lookup.findStatic(lookup.lookupClass(), "run", MethodType.methodType(void.class));
        Runnable r = MethodHandleProxies.asInterfaceInstance(Runnable.class, run);
        testRunnable(r);
    }
    private static void testRunnable(Runnable r) {
        r.run();
        Object o = r;
        boolean eq = (o == o);
        int     hc = System.identityHashCode(o);
        String  st = o.getClass().getName() + "@" + Integer.toHexString(hc);
        Object expect = Arrays.asList(st, eq, hc);
        System.out.println("expect st/eq/hc = "+expect);
        Object actual = Arrays.asList(o.toString(), o.equals(o), o.hashCode());
        System.out.println("actual st/eq/hc = "+actual);
        if (!expect.equals(actual))  throw new AssertionError(expect+" != "+actual);
    }
}
/*
Bug:

hello, world
expect st/eq/hc = [$Proxy0@58431c, true, 5784348]
actual st/eq/hc = [java.lang.invoke.MethodHandleProxies$1@9e0c79, false, 10357881]
Exception in thread "main" java.lang.AssertionError: [$Proxy0@58431c, true, 5784348] != [java.lang.invoke.MethodHandleProxies$1@9e0c79, false, 10357881]
	at BadProxy.testRunnable(BadProxy.java:24)
	at BadProxy.main(BadProxy.java:12)

Expected:

hello, world
expect st/eq/hc = [$Proxy0@db81f3, true, 14385651]
actual st/eq/hc = [$Proxy0@db81f3, true, 14385651]

Fix:

diff --git a/src/share/classes/java/lang/invoke/MethodHandleProxies.java b/src/share/classes/java/lang/invoke/MethodHandleProxies.java
--- a/src/share/classes/java/lang/invoke/MethodHandleProxies.java
+++ b/src/share/classes/java/lang/invoke/MethodHandleProxies.java
@@ -165,7 +165,7 @@
                         if (method.getDeclaringClass() == WrapperInstance.class)
                             return getArg(method.getName());
                         if (isObjectMethod(method))
-                            return callObjectMethod(this, method, args);
+                            return callObjectMethod(proxy, method, args);
                         throw new InternalError("bad proxy method: "+method);
                     }
                 }));

*/

Comments
http://hg.openjdk.java.net/jdk8/tl/jdk/rev/bfc5ec581c48
07-08-2013

EVALUATION yes
23-06-2011

SUGGESTED FIX See description.
23-06-2011

WORK AROUND Don't use object methods on proxies. Such usage is rare. Avoid putting them in java.util.Collections, which use the Object.equals method for Collection.contains, etc.
23-06-2011