Change Method Call On the Fly:: CallSite

In my previous article, I talked about invokeDynamic, In this article, I will show you the coding how you can leverage the power of invokedynamic.
We all know that to load a class dynamically and call a method at runtime we use Java Reflection, Framework developers are often used Reflection to load class runtime and call a method at runtime. But Reflection has a performance cost as it does the security checking each time, On the other hand, invokeDynamic solves that problem and we can use invokeDynamic to runtime call the method.
To call the method runtime we need Method handle, Mow the interesting thing is we also change the underlying method call based on some parameters, It is a very powerful thing to do, the Same call can invoke different implementation on runtime based on parameter !!!

I try to explain you by a simple example, Say there are two methods call bark and mewaoo, Now based on the animal passed I want to call the corresponding method dynamically?
I will show you the code first then explain the code,
package com.example.methodhandle;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
public class MethodHandleExample {
MutableCallSite callSite = null;
public void bark() {
System.out.println("I am a Dog :: So barking");
}
public void mewaoo() {
System.out.println("I am a Cat :: So Mewaooing");
}
public MethodHandle findMethodHandle(String command) throws NoSuchMethodException, IllegalAccessException {
MethodHandle mh = null;
if ("DOG".equalsIgnoreCase(command)) {
mh = createMethodHandle(MethodType.methodType(void.class), "bark");
} else if ("CAT".equalsIgnoreCase(command)) {
mh = createMethodHandle(MethodType.methodType(void.class), "mewaoo");
} else {
throw new RuntimeException("Give a Proper Command");
}
return mh;

}

public CallSite createCallSite(String command) throws NoSuchMethodException, IllegalAccessException {
if (callSite == null) {
callSite = new MutableCallSite(findMethodHandle(command));
} else {
callSite.setTarget(findMethodHandle(command));
}
return callSite;
}

public MethodHandle createMethodHandle(MethodType methodType, String methodName)
throws NoSuchMethodException, IllegalAccessException {
return MethodHandles.lookup().findVirtual(this.getClass(), methodName, methodType);
}
public static void main(String[] args) {
MethodHandleExample example = new MethodHandleExample();
try {
example.createCallSite("DOG").dynamicInvoker().invoke(example);
example.createCallSite("CAT").dynamicInvoker().invoke(example);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
If I run this code output will be
I am a Dog :: So barking
I am a Cat :: So Mewaooing
Explanation:: To call bark and mewaoo method dynamically based on the passing parameter, We first need to create  MethodHandle for each method.
MethodHandle is such an Object which stores the metadata about the method, Such as the name of the method signature of the method etc.
So here, I create a generic method called createMethodHandle, which returns a method handle.
To create a Method handle we need two major thing name of the method and the MethodType Object, MethodType Object says about the signature of the method. name parameter denotes the name of the method.
I create a generic method called findMethodHandle, This method passes the required parameters to the createMethodHandle method based on the passed command, If the command is a dog, this method pass the method name as bark and method type as void as bark takes nothing and return nothing (Signature of bark method).
Now , to change the invocation of the method we need a Calliste --Which actually flips the call, For two methods we have two different method handle, Calliste bound with a Method handle and  actually call underlying  Method handle , MutableCallsite can change the underlying Method handle Object (Strategy), so Callsite change the MethodHandle based on the command given.
Here I create a method called createCallSIte, which create a single instance of a Callsite Object, and based on the command, Callsite change the target aka MethodHandle.

Conclusion: This is a simple example but using Callsite and Methodhandle you can create a factory of Strategy and based on the situation you can choose the optimum one, so developers perspective it just a method call but ad framework developer you can choose what to call when like lambda in java8 maintained LambdaMewtaFactory.




Post a Comment