Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.
See all our reports

Recognize and Conquer Java Proxies, Default Methods and Method Handles


Last week I had a great privilege to attend to the Jfokus conference in Stockholm. First of all I want to say that it was an exceptional conference both from the incredible sessions one could listen to and from the impeccable organisation.

Some time ago, in a review of major Java conferences we established that despite the conference being complex beasts, the most influential factors to success include: speakers and how accessible they are to the attendees, session content, for obvious reasons, and various educational activities that come as extra bonuses to the main tracks. Jfokus excelled in all of them.

If you were there, it’s never late to thank Mattias Karlsson and everyone involved for organising the conference. Thank you Jfokus team, you did a great job!

During the workshop day, before the conference, Marcus Lagergren organised and ran the VM Tech summit, an event for programming language enthusiasts and virtual machines aficionados. Needless to say, that it was an immensely exciting day where you could witness the absolute best engineers and programming language designers talk about what is currently important for the JVM, plans for the future and various technical topics.

One of the topics that was mentioned several times and discussed throughout the day, were MethodHandles. In this post I want to explain a little about what they are, how they can be useful not only for programming language designers, but also for regular Java developers.

MethodHandles in an Elevator

Here’s the elevator pitch… Originally, the MethodHandle class, instances of which represent typed references to a method (or a constructor), was added into JDK 1.7 which together with invokedynamic made Java much more dynamic than before. However, it is quite a low-level detail of the Java language, that many of us never saw used explicitly in the wild. Even on our blog they are probably only mentioned once, in this quite hardcore blogpost about creating lambda functions in bytecode with ASM or jitescript by Michael Rasmussen.

However, if you use any dynamic JVM language, say JRuby or Groovy, or a framework that decides its actions at runtime, you definitely use MethodHandles under the hood.

Java 7 also added the MethodHandles class that simplified the task of creating and manipulating these. The API which MethodHandles provides is not perfect, especially for transforming MethodHandles, although libraries have since been developed that make it easier, like invokebinder by Charles Nutter (JRuby, anyone?).

MethodHandles outside the Elevator

Now you kinda know what they are, let’s investigate the original API to better familiarise ourselves with the concept, oh and look at some code :)

Imagine we have a class with a simple method to experiment with:

public class C {
 public String sayHello(String name) {
   String message = "Hello " + name;
   return message;

Let’s create and play with a method handle referencing method sayHello(). First of all we need to create a Lookup instance. A Lookup represents the place in our code in which we are constructing a method handle to comply with all possible future security manager and visibility checks.

Next, we specify which method we want to find and reference it, providing a class name, method name and the types of the return value and arguments. Intuitively this data should be enough to find a method, even if overloaded or overridden.

Here’s how it looks in the code, basically just a single line of chained method calls:

public static void main(String[] argv) throws NoSuchMethodException, IllegalAccessException {
 MethodHandle sayHelloHandle =
     MethodType.methodType(String.class, String.class));


This code conveniently finds our sayHello() method and produces some output so we know it didn’t crash.


In the documentation, there’s a great looking table of what the various find*() methods provide us with, but for now we can just roll with the basic intuition: findVirtual() will find our instance method. Use findStatic() for static methods, findConstructor() for constructors, etc. Pretty straightforward actually.


So, looking methods up is just the third of the capability. The main fun begins when we try to transform MethodHandle. For example to run in a try-catch block, or bind to some instance of the C class, in our earlier example.

For now we’ll concentrate on the latter, however if you an exceptions kinda person, MethodHandles.catchException() is a great place to start digging.

To specify the this instance for the sayHello invocation we bind the method handle. After that, the resulting handle can be invoked multiple times with various arguments and behave as you would expect it to:

MethodHandle ready = sayHelloHandle.bindTo(new C());

The output of the lines above is obvious.

Hello RebelLabs
Hello Oleg

The main benefit of MethodHandles is that you can create a reference to a method which type is only known at runtime and efficiently look it up and invoke it. But when does this become handy to the average developer? Welcome, Java proxies.

Java Proxies and Default Methods

Sometimes in life you wish you had a proxy instead of a real object. Maybe you want to add some tracing log statements to method executions or maybe a library you use doesn’t satisfy your contract of throwing exceptions instead of returning nulls.

Who you gonna call? GhostBusters! Surely you know how to use a proxy.

Even if you don’t yet, it can be explained in under 2 minutes (although I’m a little dizzy after the last elevator trip so I’ll just stay out and say it!). JDK proxies only work on interfaces, so we’ll need an experimental interface for our example. Luckily, we have one handy right here:

public interface A {
   String amplify(Number a);
   Number getA();
   String toString();

   default String zzz() {
     System.out.println("Sleeping: zzzz");
     return "42";

To create a proxy of type A, we can use the following code.

A a = (A) Proxy.newProxyInstance(C.class.getClassLoader(), new Class[] { A.class },
 (proxy, method, args) -> {
   System.out.println("Proxying: " + method.getName() + " " + Arrays.toString(args));
   return "Success";

The most important point here is the InvocationHandler instance, represented by the lambda of (proxy, method, args). When something calls a method on our proxy, like a.amplify(0), the invocation handler will receive the control flow. And we can decide how to handle the method call. A good practice usually is to provide an actual instance of the interface to which you can delegate all the work.

In our case we just log the method we’re proxying and return a dummy value. Calling something like, produces the “Proxying” statement in the standard output.


Proxying: amplify [0]

What if the interface dictates return value to be of a different type? For example, the getA() method is said to return a Number.

If this were JavaScript, I bet we wouldn’t even notice it. Java thoughtfully throws a ClassCastException.

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number

Thank you, Java!

Another question is then, what happens with the default methods? Will the proxy intercept that as well or will the default implementation be called? If the proxy will intercept it, can we call the default implementation ourselves? After all it is specified right there in the interface body.

The short answer is that the proxy will intercept it, and it’s not that trivial to call the default implementation without using method handles.

MethodHandles to the rescue

First of all, let’s look at the InvocationHandler interface in more detail and figure out what do we have to work on. The signature of the invoke method we operate within is the following.

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

The proxy parameter is our actual proxy instance (great naming, right), so it implements the interface A we need. args are the arguments passed to the proxy method invocation. And finally the method parameter is, well, hopefully self-explanatory.

The first thing is to filter default method invocations. Java 8 supports this with a convenient
method.isDefault() check being available right out of the box.

And then we need the following incantation to create a MethodHandle, bind it to the proxy instance and invoke the handle with the correct arguments:

A a = (A) Proxy.newProxyInstance(C.class.getClassLoader(), new Class[] { A.class },
 (proxy, method, args) -> {
   if(method.isDefault()) {
     final Class<?> declaringClass = method.getDeclaringClass();
          Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
              constructor.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE)
              .unreflectSpecial(method, declaringClass)
   System.out.println("Proxying: " + method.getName() + " " + Arrays.toString(args));
   return "Success";

Why does it work and just calling proxy.method(args) doesn’t? MethodHandle utilises the invokespecial instruction to call the method directly. In order to achieve that we had to go through several steps:

  • declare MethodHandles.Lookup constructor accessible
  • use the constructor to create a lookup object with PRIVATE access
  • create a method handle that won’t check for overriden method, etc. with the unreflectSpecial() call

In a real world code you’d probably keep the constructor initialization somewhere outside of the proxy, but for the toy example this works. Now if I run invoke the default method on a from the code above, I’ll get the expected result.


Sleeping: zzzz


In this post we briefly looked at what MethodHandles allow you to do in Java, how you can create them and manipulate them. While it still is most useful for JVM languages and frameworks to decide which methods to call at runtime, there are also valid use cases to do similar from your Java code as well.

Do you have a great use case for method handles or have a question about proxies? Leave a comment below or ping me on Twitter: @shelajev.

Oh, and if you’re rushing to enhance your codebase with default methods in interfaces, think again. It might become messy and your code can become less predictable. Check out my other post about abusing default methods in interfaces and what it can lead to.