Close

Dynamically implement an Interface

[Last Updated: Apr 6, 2017]

Since version 1.3, JDK has API to implement dynamic proxies based on interfaces.

Dynamic Proxies created by JDK is based on Proxy design pattern

We have to use two important classes from java.lang.reflect package to get started:

  • InvocationHandler
  • Proxy

This static method of Proxy class is the point where a provided interface is dynamically implemented by Java during runtime:

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler  h)

Where the middle parameter 'interfaces' are to be implemented.

The interface java.lang.reflect.InvocationHandler:

package java.lang.reflect;
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

In this example, we are going to demonstrate how to implement an interface during runtime and what we can achieve by doing that.


Creating an Interface

  private static interface MyInterface {
        void doSomething ();
  }

Implementing InvocationHandler

In this very simple example, we are not going to do much in InvocationHandler#invoke. We just want to see how things work:

public class MyInvocationHandler implements InvocationHandler {

    @Override
    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method);
        return null;
    }
}

Creating the Dynamic Proxy

    public static void main (String[] args) {
        MyInvocationHandler handler = new MyInvocationHandler();
        MyInterface o = (MyInterface) Proxy.newProxyInstance(
                            MyInvocationHandler.class.getClassLoader(),
                            new Class[]{MyInterface.class}, handler);
        o.doSomething();
    }

Output:

public abstract void com.logicbig.example.MyInterface.doSomething()


What's happening here?

The method call Proxy.newProxyInstance returns an Object created dynamically by Java during runtime time. There's no compile time processing here. The returned Object implements all interfaces provided as second argument. Java uses Reflection to achieve that.

Out of curiosity, let's print the stacktrace in MyInvocationHandler#invoke method:

public class MyInvocationHandler implements InvocationHandler {

    @Override
    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
       Arrays.stream(Thread.currentThread()
                           .getStackTrace())
                           .forEach(System.out::println);

        return null;
    }
}

Output:

java.lang.Thread.getStackTrace(Thread.java:1552)
com.logicbig.example.MyInvocationHandler.invoke(MyInvocationHandler.java:13)
com.logicbig.example.$Proxy0.doSomething(Unknown Source)
com.logicbig.example.MyInvocationHandler.main(MyInvocationHandler.java:26)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

In the 3rd line from the top, the $Proxy0 is the runtime implementation of our interface:

com.logicbig.example.$Proxy0.doSomething(Unknown Source)

The first parameter of the 'invoke' method is the same $Proxy0 object. We didn't print that out because that will cause recursive calls to the invoke method on toString() method. (System.out.println uses toString to print objects). Why recursive? because each call on $Proxy0 will route to our 'invoke' method, even $Proxy0.toString() call.

In the above example, we are just printing a simple message, but in real scenario we will apply some application specific logic based on the Method argument.


What we can achieve with this feature?

  • Method interceptors.
  • Dynamic Proxy.
  • Remote Proxy.
  • Decorator design pattern.
  • Facade design pattern.
  • Bridge design pattern.
  • Or whatever you can come up with!

In this series of tutorials we will be exploring some of them.



Example Project

Dependencies and Technologies Used:

  • JDK 1.8
  • Maven 3.0.4

Java Dynamic Proxies Select All Download
  • jdk-dynamic-proxies-intro
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • MyInvocationHandler.java

    See Also