Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Some basic questions about MethodHandle API

Tags:

How can I obtain all declared method through MethodHandles.lookup()? How can I obtain all declared fields?

What is difference betweeen MethodHandle.invoke(), MethodHandle.invokeExact() and MethodHandle.invokeWithArguments()

Also, I will be appreciate for tutorial about using MethodHandle API for Java devloper. I emphasize, I am programming on statically typed language plain old Java and I am not JVM developer, particularly I am not interesting with whole byte-code crap (invokedynamic). I want to figure out how can I use this new API instead of Java Core API.

EDITED-2:

@Glen Best below provided some refferences I want to provide only one http://www.oraclejavamagazine-digital.com/javamagazine/20130102?pg=52&search_term=methodhandle&doc_id=-1#pg50 This is exactly what I was looking for. I figured out that actually there some new vocabalry.. For example, by target is actually meant MethodHandle (and not object to make dispatch upon) and call site is actually code that "invokes" "function pointer" aka MethodHandle. Also it is essential to understand that MethodHandle API is not replacement for Core Reflection API rather than suplement it. For example, you can't "discover" all methods with MethodHandle you need Core Reflection API. But when you "find" you desired method you can switch to MethodHandle and for example, bound some its parameters or "change" (adapt) it's signature to varargs for example.

EDITED:

I am still trying to figure out answer. I wrote some tests that I want to share with all.

package alexander.berkovich;  import static org.junit.Assert.assertSame;  import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Field; import java.lang.reflect.Method;  import org.junit.BeforeClass; import org.junit.Test;  public class MethodHandlerCleanTest {      public static MethodHandles.Lookup lookup;      @BeforeClass     public static void asetUp(){         lookup = MethodHandles.lookup();     }      public static class Check {         public void primitive(final int i){         }         public void wrapper(final Integer i){         }     }      @Test     public void testPrimitive() throws Throwable {         Check check = new Check();          MethodType type = MethodType.methodType(void.class, int.class);          MethodHandle mh = lookup.findVirtual(Check.class, "primitive", type);         mh.invokeWithArguments(check, 1);         mh.invoke(check, (short)2);         mh.invoke(check, Integer.valueOf(3));          Method method = Check.class.getMethod("primitive", int.class);         method.invoke(check, (short)20);         method.invoke(check, Integer.valueOf(21));      }      @Test     public void testWrapper() throws Throwable {         Check check = new Check();          MethodType type = MethodType.methodType(void.class, Integer.class);          MethodHandle mh = lookup.findVirtual(Check.class, "wrapper", type);         mh.invoke(check, 2);          Method method = Check.class.getMethod("wrapper", Integer.class);         method.invoke(check, 20);      }      @SuppressWarnings("unused")     public static class StaticInnerClass {          public static String staticName;         public String name;           public void foo(){}          public static void staticFoo(){}      }      @Test     public void testStaticInnerClassStaticField() throws Throwable {         MethodHandle mhSet = lookup.findStaticSetter(StaticInnerClass.class, "staticName", String.class);         String expected = "mama";         mhSet.invoke(expected);          MethodHandle mhGet = lookup.findStaticGetter(StaticInnerClass.class, "staticName", String.class);         Object obj = mhGet.invoke();         String value = (String)obj;         assertSame(expected, value);      }      @Test     public void testStaticInnerClassField() throws Throwable {         StaticInnerClass sut = new StaticInnerClass();         Field f = StaticInnerClass.class.getDeclaredField("name");         MethodHandle mhSetUnreflect = lookup.unreflectSetter(f);          String expectedUnreflect = "unreflect";         mhSetUnreflect.invoke(sut, expectedUnreflect);           MethodHandle mhSet = lookup.findSetter(StaticInnerClass.class, "name", String.class);         String expected = "mama";         mhSet.invoke(sut, expected);          MethodHandle mhGet = lookup.findGetter(StaticInnerClass.class, "name", String.class);         Object obj = mhGet.invoke(sut);         String value = (String)obj;         assertSame(expected, value);      }      @Test     public void testStaticInnerClassConstructor() throws Throwable {         StaticInnerClass sut = new StaticInnerClass();         MethodType type = MethodType.methodType(void.class);         MethodHandle mh = lookup.findConstructor(StaticInnerClass.class, type);         mh.invoke();     }      @Test     public void testStaticInnerClassMethod() throws Throwable {         StaticInnerClass sut = new StaticInnerClass();         MethodType type = MethodType.methodType(void.class);         MethodHandle mh = lookup.findVirtual(StaticInnerClass.class, "foo", type);         mh.invoke(sut);     }      @Test     public void testStaticInnerClassStaticMethod() throws Throwable {         MethodType type = MethodType.methodType(void.class);         MethodHandle mh = lookup.findStatic(StaticInnerClass.class, "staticFoo", type);         mh.invoke();     }      @SuppressWarnings("unused")     private class InnerClass {         public String name;          public void foo(){}      }     @Test     public void testInnerClassField() throws Throwable {         InnerClass sut = new InnerClass();         MethodHandle mhSet = lookup.findSetter(InnerClass.class, "name", String.class);         String expected = "mama";         mhSet.invoke(sut, expected);          MethodHandle mhGet = lookup.findGetter(InnerClass.class, "name", String.class);         Object obj = mhGet.invoke(sut);         String value = (String)obj;         assertSame(expected, value);      }       @Test     public void testInnerClassConstructor() throws Throwable {         MethodType type = MethodType.methodType(void.class, MethodHandlerCleanTest.class);          //default constructor is private         Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");         field.setAccessible(true);         MethodHandles.Lookup trustedLookup = (MethodHandles.Lookup)                  field                 .get(null);          MethodHandle mh = trustedLookup.findConstructor(InnerClass.class, type);         mh.invoke(this);     }       @Test     public void testInnerClassMethod() throws Throwable {         InnerClass sut = new InnerClass();         MethodType type = MethodType.methodType(void.class);         MethodHandle mh = lookup.findVirtual(InnerClass.class, "foo", type);         mh.invoke(sut);     } 

}

like image 424
alexsmail Avatar asked Apr 15 '13 00:04

alexsmail


People also ask

What is a Methodhandle?

A method handle is a typed, directly executable reference to an underlying method, constructor, field, or similar low-level operation, with optional transformations of arguments or return values. These transformations are quite general, and include such patterns as conversion, insertion, deletion, and substitution.

What is invoke in android?

invoke(method, view); The reason that the context from MainActivity worked as your handler is it's MainActivity. this -- an instance of the MainActivity object and assuming the method you were calling was in MainActivity. the invoke would work.

What is method type?

A method type represents the arguments and return type accepted and returned by a method handle, or the arguments and return type passed and expected by a method handle caller.

What is a handle in Java?

A handle is an abstraction of a network reference to an EJB object. A handle is intended to be used as a "robust" persistent reference to an EJB object. Since: EJB 1.0.


1 Answers

How can I obtain all declared method through MethodHandles.lookup()? How can I obtain all declared fields?

Think of java.lang.invoke as a (fast performing) extension to reflection (java.lang.reflect) - i.e. "invoke" classes are dependent upon "reflection" classes.

  • You obtain reference to all methods/constructors/fields via reflection (java.lang.Class and java.lang.reflect):

    java.lang.Class<?> someClass = ...;  // obtain a Class somehow  // Returns all constructors/methods/fields declared in class,  // whether public/protected/package/private,  // but does NOT include definitions from any ancestors:  java.lang.reflect.Constructor<?>[] declaredConstructors = someClass.getDeclaredConstructors(); java.lang.reflect.Method[] declaredMethods = someClass.getDeclaredMethods(); java.lang.reflect.Field[] declaredFields   = someClass.getDeclaredFields();  // Returns all constructors/methods/fields declared as public members  // in the class AND all ancestors:   java.lang.reflect.Constructor<?>[] publicInheritedConstructors = someClass.getConstructors(); java.lang.reflect.Method[] publicInheritedMethods = someClass.getMethods(); java.lang.reflect.Field[] publicInheritedFields   = someClass.getFields(); 
  • You convert them to MethodHandles via java.lang.invoke.MethodHandles.Lookup:

    java.lang.invoke.MethodType mt;  java.lang.invoke.MethodHandle mh; java.lang.invoke.MethodHandles.Lookup lookup = MethodHandles.lookup();  // process methods for (java.lang.reflect.Method method: declaredMethods) {     mh = lookup.unreflect(method);      // can call mh.invokeExact (requiring first parameter to be the class'      // object instance upon which the method will be invoked, followed by      // the methodparameter types, with an exact match parameter and return      // types) or     // mh.invoke/invokeWithArguments (requiring first parameter to be the      // class' object instance upon which the method will be invoked,      // followed by the method parameter types, with compatible conversions      // performed on input/output types) }  // process constructors for (java.lang.reflect.Constructor<?> constructor: declaredConstructors) {     mh = lookup.unreflectConstructor(constructor);      // can call mh.invokeExact or     // mh.invoke/invokeWithArguments  }  // process field setters for (java.lang.reflect.Field field: declaredFields) {     mh = lookup.unreflectSetter(field);      // can call mh.invokeExact or     // mh.invoke/invokeWithArguments  }  // process field getters for (java.lang.reflect.Field field: declaredFields) {     mh = lookup.unreflectGetter(field);      // can call mh.invokeExact or     // mh.invoke/invokeWithArguments  } 
  • You can determine if the signature of methods/constructors/fields via java.lang.reflect:

    // If generics involved in method signature: Type[] paramTypes = method.getGenericParameterTypes();  Type returnType = method.getGenericReturnType();  // Note: if Class is non-static inner class, first parameter of  // getGenericParameterTypes() is the enclosing class  // If no generics involved in method signature: Class<?>[] paramTypes = declaredMethod.getParameterTypes();  Class<?> returnType = declaredMethod.getReturnType();  // Note: if Class is non-static inner class, first parameter of  // getParameterTypes() is the enclosing class  // Same method calls for declaredConstructor 
  • You can determine if the methods/constructors/fields are static via java.lang.reflect:

    int modifiers = method.getModifiers();  // same method for constructor/field boolean isStatic = java.lang.Modifier.isStatic(modifiers); 

What is difference betweeen MethodHandle.invoke(), MethodHandle.invokeExact() and MethodHandle.invokeWithArguments()?

  • see http://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html#invoke%28java.lang.Object...%29
  • If the MethodHandle is for a non-static method, the first parameter provided to these methods is an instance of the Class which declares the method. The method is invoked on this instance of the class (or on the Class itself for static methods). If the Class is a non-static inner class, the second parameter is an instance of the enclosing/declaring class. The subsequent parameters are the method signature parameters, in order.
  • invokeExact does not do automatic compatible type conversion on input parameters. It requires parameter values (or parameter expressions) to be an exact type match to the method signature, with each parameter provided as a separate argument OR all arguments provided together as an array (signature: Object invokeExact(Object... args)).
  • invoke requires the parameter values (or parameter expressions) to be type compatible match to the method signature - automatic type conversions are performed, with each parameter provided as a separate argument OR all arguments provided together as an array (signature: Object invoke(Object... args))
  • invokeWithArguments requires the parameter values (or parameter expressions) to be type compatible match to the method signature - automatic type conversions are performed, with each parameter provided within a List (signature: Object invokeWithArguments(List<?> arguments))

I will be appreciate for tutorial about using MethodHandle API for Java devloper

There's not much out there, unfortunately. You could try the following. Hopefully, I've given enough info above :^)

http://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandle.html
http://docs.oracle.com/javase/7/docs/api/java/lang/invoke/MethodHandles.Lookup.html
http://www.java7developer.com/blog/?p=191
http://www.oraclejavamagazine-digital.com/javamagazine/20130102?pg=52&search_term=methodhandle&doc_id=-1#pg50
http://www.amazon.com/Well-Grounded-Java-Developer-techniques-programming/dp/1617290068

like image 133
Glen Best Avatar answered Dec 01 '22 13:12

Glen Best