Search code examples
javareflectionjava-6methodhandle

How can I use method handles with JDK 6?


Strange situation here. I need to invoke the same class instance method many many times (1000/second range) without the ability to import or build against the library needed. I am trying to call a method within my JEE project that uses a class from an application server's provided library. The JEE project still needs to run on other application servers so I cannot simply build against that library. Reflection is the only solution I think.

When going so rapidly, time to execute is orders of magnitude slower using reflection than with direct invocation.

After some research, I discovered static final MethodHandles:

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;



public class Test {

    static final MethodHandle sfmh;

    static {
        MethodHandle mh = null;
        try {
            final Class<?> clazz = Class.forName("com.me.lib");
            Method m = clazz.getMethod("MyMethod");
            mh = MethodHandles.lookup().unreflect(m);
        } catch (Throwable e) {
            mh = null;
        }

        sfmh = mh;
    }

    public static void main(String[] args) throws Throwable {
        int i = 0;
        System.out.println("starting");
        long start = System.currentTimeMillis();
        for(i = 0; i < 1000000000; i++) {
            sfmh.invokeExact();
        }
        long total = System.currentTimeMillis() - start;
        System.out.println("Time: " + total + " milliseconds");
    }

}

The works great and gets me an acceptable speed result (2-4 times slower instead of 200x slower). There seems to be an issue to this perfect solution -- I need this to run on Java 6 (boo, hiss, it's a requirement)

When compiling against 1.6 I get:

Invocation of polymorphic methods not allowed for source level below 1.7

on the line

sfmh.invokeExact();

Is there any solution that takes advantage of the concept of MethodHandle that works with 1.6?


Solution

  • No, method handles were only added in JDK 7 and are not accessible before that. Neither can you compile a class against the method handle API as the JDK 6 does not understand the @PolymorphicSignature annotation; method handles are compiled slightly different that other methods using a synthetic signature.

    Beyond that, reflection is not slower on modern JVMs, maybe run your application on a recent JVM instead? It is perfectly fine to run Java 6 code on a JVM v8. Finally, your benchmark is flawed for many reasons. Maybe your reflection code is not slow even today? The JVM knows a concept that is known as inflation that avoids the performance overhead of a JNI call.

    Here are some results using a harness on a v8 JVM, comparing reflection, common invocation and method handles: https://gist.github.com/raphw/881e1745996f9d314ab0