Java 1.7 enhanced reflection API: MethodHandle
I just stumbled across some standard library code I had not noticed was added in Java 1.7:
java.lang.invoke. This package provides some interesting alternatives to the reflection code in
java.lang.reflect and the reflection-related methods on
java.lang.Class. Some of the features even have a hint of functional programming!
I suspect this
java.lang.invoke package is mainly aimed at people implementing non-Java languages on the JVM, eg JRuby/JPython/Clojure/Frege. However there seems to be no reason why “normal” Java applications can’t make use of it too.
The primary class is MethodHandle, which represents anything that takes zero or more parameters and returns a value. It primarily offers method “
Object invoke(Object... args)”.
The primary differences between this class and the already-existing
java.lang.reflect.Method appear to be:
- MethodHandle is more abstract; it actually represents any “invokable code”, including constructors. It can also be used to access the value of a field in an object.
- MethodHandles are more efficient than reflection (AIUI, they are implemented by generating code rather than performing reflection).
- There is no access to information about annotations on a method or similar; a MethodHandle doesn’t necessarily map to a Method.
- Security-checks are handled differently
A MethodHandle is obtained via static methods on class
java.lang.invoke.MethodHandles.Lookup. As example,
MethodHandle Lookup.findVirtual(Class target, String name, MethodType signature) returns a MethodHandle that can invoke the specified method on any instance of class target. Also,
MethodHandle Lookup.findGetter(Class target, String propname, Class proptype) returns an object that might invoke a getter or directly read a field.
The “target object” to invoke the method on is usually the first parameter passed to the invoke method. However
MethodHandle.bindTo() performs partial function application(!), returning another MethodHandle which remembers that “bound” value for later use. As the first parameter is the target, this results in a MethodHandle whose “target object” is already selected.
java.lang.invoke.MethodHandles provides additional static methods that decorate a MethodHandle in interesting ways (ie take a MethodHandle and return another one with different behaviour and/or type).
MethodHandleProxies.asInterfaceInstance(someiface, someMethodHandle) can dynamically generate a class that implements that interface and delegates to the method-handle - as long as the interface has only one method whose interface is compatible with the params/return-type the MethodHandle represents. This is an elegantly non-intrusive way to hide the details of reflection-style access from using code.
The MethodHandle interface is (sadly, but obviously) very untyped, taking Objects as parameters and returning Objects as values. However internally it holds the “signature” it supports (see method
type() which returns that signature), and will throw an exception when used incorrectly. Wrapping it using MethodHandleProxies.asInterfaceInstance() provides a nicer typed interface and makes misuse impossible..
The difference in security model (reflection checks access on each invocation, MethodHandle only on creation) means that MethodHandle objects are faster, but that care needs to be taken when passing them around; a “naked MethodHandle” should never be made accessible to code from a different security domain.
Interestingly, pasting the example code from the official Javadoc for MethodHandle into Eclipse triggers an UnsupportedOperationException in the Eclipse JDT compiler ;-). Nevertheless, a trivial refactoring (simplification) of the code is accepted, and works as intended.