Tuesday, October 28, 2014

Initialize object with Java reflection mechanism

Java 7 has an improved way of working with object's reflection in comparison with older versions.
For example, at version 6 in order to initialize object and its fields we need.
1) initialize class object instance using type name of the target object
2) if some object's methods (for example 'setXxx') should be invoked, need to find it and pass corresponding parameters - be aware of parameter type, it must me consistent with original method signature.


Object param = new SomeType(); // SomeType must be included in a signature of the target method 
String type = "com.vbashur.MyType"
Class<?> clazz = Class.forName(type);
Object paramObject = clazz.newInstance();
String setterName = "setMyValue"

for (Method m : clazz.getDeclaredMethods()) { // if parameters are known, use getDeclaredMethod
    if (m.getName().equals(setterName)) {
        m.invoke(paramObject, param);
        break;
    }
}

The piece of code above may throw a bunch of ugly exceptions (llegalAccessException,
IllegalArgumentException, InvocationTargetException, InstantiationException, ClassNotFoundException) and works quite slow. In order to access private method it requires Method.setAccessible() to be invoked.

MethodHandle is a Java-7-way

1) What we need to do is to declare MethodType object firstly. A MethodType is an immutable object that represents the type signature of a method.



MethodType object can be created via special factory using the following method:

MethodType.methodType(RetType.class, Arg0Type.class, Arg1Type.class, ...);

MethodType mt = MethodType.methodType(Class<?>); // insert your target class object

2) The next transitional state is getting lookup object which helps us to find appropriate method in a target class.

MethodHandles.Lookup lk = MethodHandles.lookup();

3) Invoke your method

MethodHandle mHandle = lk.findVirtual(Class<?>, "methodName", mt); // provide your class object and corresponding method name
Result code:

public class MyClass {
    public void showGreetings(String name) {
        System.out.println("Hi " + name);
    }
}

public void importScenarios2Test()  {
    MethodType mt = MethodType.methodType(void.class, String.class);
    MethodHandles.Lookup lk = MethodHandles.lookup();
    try {
        Class<?> clazz = Class.forName("com.vbashur.MyClass");
        Object mc = clazz.newInstance();
        MethodHandle mHandle = lk.findVirtual(TypeInfoProviderTest.class, "showGreetings", mt);
        mHandle.invoke(mc, "Maaan");
    } catch (NoSuchMethodException | IllegalAccessException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (Throwable e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }       
}

To be honest, I don't think that MethodHandle is easier to use than Reflection API, however MethodHandle mechanism has a few benefits:
- it has full access to all methods allowed in a current context
- works faster (in some conditions)
The last argument sometimes may be sufficient, for some projects that should use reflection repeatedly. Performance of MethodHandle depends on the way you are using it. In some cases Reflection API shows better results.
There are some links to get more information about MethodHandle performance.
http://chriskirk.blogspot.kr/2014/05/which-is-faster-in-java-reflection-or.html
http://vanillajava.blogspot.kr/2011/08/methodhandle-performance-in-java-7.html



No comments:

Post a Comment