Home > API and Patterns, Reflection and Generics > Reflection without Strings

Reflection without Strings

Sometimes reflection is very handy, but using reflection often involves referencing methods by Strings, which can get you into major trouble when you are refactoring your code. If a method belongs to an interface though, there is salvation. But let me first tell you how it started and what I did about it.

The framework we are using in my current Project uses a UI abstraction layer, made of so-called “adapters”, which represent a GUI-toolkit independent representation of UI widgets to be used in the controllers. In the simplest case these adapters are just bound to a model and fire PropertyChangeEvents, which are handled by a GUI toolkit dependent adapter that translates these events to method calls on the UI-widget. So what this framework does is to separate the GUI toolkit from the controller side and it does that really well.
For the rest of this blog, I will stay on the controller side, where we find the GUI toolkit independent adapters. Now to bind an adapter to a model one possible technique is to give it a so-called ValueProvider, which has a simple interface (there are no generics yet):

public interface IValueProvider{
 Object getValue();
 void setValue(Object o);
}

These value providers sometimes hold some conversion logic or lazy initializations on write access, which is just what happened in my case. In my controller I had 11 of these value providers and 9 of them were similar, except the called another method in the business object:

IValueProvider newFooValueProvider(){
  return new IValueProvider(){
    public Object getValue(){
     return convertToUi(getOptions().getFoo());
    }
    public void setValue(final Object value){
      ensureOptionsInitialized();
      getOptions().setFoo(convertToModel(value));
    }
  };
}
IValueProvider newBarValueProvider(){
  return new IValueProvider(){
    public Object getValue(){
     return convertToUi(getOptions().getBar());
    }
    public void setValue(final Object value){
      ensureOptionsInitialized();
      getOptions().setBar(convertToModel(value));
    }
  };
}
//…seven more like these …

Pretty repetitive and screaming to be refactored, you’d think. I first thought of using an abstract ValueProvider class, but that meant I still needed a new class per attribute, which still cluttered my code. This is one of these moments where you probably wished you had closures to avoid the clutter. Without closures I decided to use the next best thing: Reflection.

An intermediate solution

Reflection is a mighty tool in cases like this: I could just create a ValueProvider that takes a proper getter and setter method and let it invoke those after doing the standard stuff. This is almost as easy said than done:

private IValueProvider newValueProvider(final Method getter, final Method setter){
  return new IValueProvider(){
    public Object getValue(){
     try{
       return convertToUi(getter.invoke(getOptions()));
     }catch ( IllegalAccessException e){ 
       ExceptionHelper.toRuntimeException(e);
     }catch( InvocationTargetException){
       ExceptionHelper.toRuntimeException(e);
     }
    }
    public void setValue(final Object value){
      try{
        ensureOptionsInitialized();
        setter.invoke(getOptions(),convertToModel(value));
     }catch ( IllegalAccessException e){ 
       ExceptionHelper.toRuntimeException(e);
     }catch( InvocationTargetException){
       ExceptionHelper.toRuntimeException(e);
     }
    }
  };
}
//…

Now I had nine methods which looked like:

IValueProvider newFooValueProvider(){
  Method getter = ReflectionHelper.getMethod(IOptions.class,“getFoo");
  Method setter = ReflectionHelper.getMethod(IOptions.class, “setFoo", Integer.class);
  return newValueProvider(getter,setter); 
}
IValueProvider newBarValueProvider(){
  Method getter = ReflectionHelper.getMethod(IOptions.class,“getBar");
  Method setter = ReflectionHelper.getMethod(IOptions.class, “setBar", Integer.class);
  return newValueProvider(getter,setter); 
}
//…seven more like these…

This looks pretty slick, don’t you think so? The best thing is: it saved me 33 lines of cluttered code. Only thing is: it has a smell, because it references methods by strings and when you rename or move a method your compiler won’t tell you a thing if you mess it up. Your unit tests may uncover your mistake, but then again: It could be so much easier. How nice would it be, if you had fist class methods, so you could write something like: Method getter = #IOptions.getFoo(); to get a reference on the Method object?

Dynamic proxies make your day

A co-worker asked me if there was a way to reference a method without using strings, to make it refactoring-proof. And I told him that I didn’t know how and that this problem has bugged ever since, but as I spoke it out, I happened to have one of the brighter moments in my life, because: As far as interfaces are concerned, this is actually quite easy and the solution was always right in front of me: Dynamic proxies. I love them, for real. The Proxy class probably belongs to the 5 most underrated additions to the Java runtime ever. Application servers make extensive use of dynamic proxies to wrap aspects like thread pooling, remoting, load balancing, transaction logic and similar stuff around beans and services and there are of course some tiny handy tools which use them, some of you might use a particular one on a regular basis, like me: EasyMock.
As it turned out the API of the tool I am about to develop in this blog shared some characteristics with EasyMock in the end.

Let’s start with the simple idea and refine the API step by step.

Class diagram: a dynamic proxy that can implement any interface that uses an InvocationHandler which stores the last method call on the proxy.

The basic idea: The tool creates a dynamic proxy that can implement any interface. Its InvocationHandler hands over the last method that was called on the proxy.

I first started with a class of stateful objects that provide a proxy and a simple getter to provide the user access to the called method:

class MethodFinder {
  private Method method;
  public <T> call(final Class<? extends T> clazz){
    return (T) Proxy.newProxyInstance(
     getClassLoader(), 
     getInterfaces(clazz), 
     new InvocationHandler(){
      public Object invoke(final Object proxy, final Method method, 
          final Object[] args) throws Throwable{     
        this.method = method;
        return null;
      }
    });
  }

  private static Class<?>[] getInterfaces( final Class<?> clazz ) {
    final List<Class<?>> interfaces 
     = new ArrayList<Class<?>>( Arrays.asList( clazz.getInterfaces() ) );
    if ( clazz.isInterface() ) {
      interfaces.add( clazz );
    }
    return interfaces.toArray( new Class<?>[interfaces.size()] );
  }
  public Method method(){return method;}
}

This was the basic draft and it was flawed: It would throw NullPointerExceptions with primitive return types and using it looked like this:

  final MethodFinder mf = new MethodFinder();
  mf.call(IOptions.class).getFoo();
  final Method getter = mf.method();

I liked to get rid of the new-operator. To achieve that I would need to use a static method and a static field. That would get me into new trouble: Multithreaded access. I don’t want to see unpredictable results because one thread might overwrite another one’s current method reference. Luckily I can have an own variable per thread by using a ThreadLocal object, so we can avoid this conflict easily. This way I could also move the proxy’s invocation handler to a constant field and avoid unnecessary object creation. Here’s a second take on the tool:

public class MethodFinder {

  private static final InvocationHandler HANDLER = new InvocationHandler() {
    public Object invoke( final Object proxy, final Method method, 
      final Object[] args ) throws Throwable {
      tlMeth.set( method );
      return null;
    }
  };

  private static final ThreadLocal<Method> tlMeth = new ThreadLocal<Method>();

  public static <T> T call( final Class<? extends T> clazz ) {
    return (T) Proxy.newProxyInstance( 
      getClassLoader(), 
      getInterfaces( clazz ), 
      HANDLER );
  }

  private static Class<?>[] getInterfaces( final Class<?> clazz ) {
    final List<Class<?>> interfaces 
    = new ArrayList<Class<?>>( Arrays.asList( clazz.getInterfaces() ) );
    if ( clazz.isInterface() ) {
      interfaces.add( clazz );
    }
    return interfaces.toArray( new Class<?>[interfaces.size()] );
  }

  public static Method method() {
    try {
      return tlMeth.get();
    } finally {
      tlMeth.remove();
    }
  }

  private static ClassLoader getClassLoader() {
    ClassLoader cl = Thread.currentThread().getContextClassLoader(); //primary
    return cl != null ? cl : MethodFinder.class.getClassLoader(); // fallback
  }
}

With this modification, using this tool looks a little bit better:

  MethodFinder.call(IOptions.class).getFoo();
  final Method getter = MethodFinder.method();

There is still room for improvement. By introducing a new method, I can nest those proxy-calls that call methods, which have a return value. This is the idea expressed in Java code:

  public static Method method() {
    return method(null);
  }

  public static Method method(Object doesntMatter) {
    try {
      return tlMeth.get();
    } finally {
      tlMeth.remove();
    }
  } 

So we can now use this shortcut for non-void-methods:

  final Method getter = MethodFinder.method(MethodFinder.call(IOptions.class).getFoo());

I’d like to add static imports at this point. That makes it look a lot better. Likewise I’d like to notice that for void-methods we cannot use the nested method, but use the two-liner we have used before. Here’s how it looks:

  import static de.plush.brix.tools.reflection.MethodFinder.*;
  //…
  final Method getter = method(call(IOptions.class).getFoo());
  call(IOptions.class).setFoo(null);
  final Method setter = method();

As you can see this is pretty much like configuring expectations with EasyMock. The only thing that keeps us from using this tool in production is that it can’t handle primitive return types yet, but that is easily fixed. Here’s the final result:

import static java.lang.Boolean.FALSE;
import java.lang.reflect.*;
import java.util.*;

public class MethodFinder {

  private static final InvocationHandler HANDLER = new InvocationHandler() {
    public Object invoke( final Object proxy, final Method method, 
        final Object[] args ) throws Throwable {
      tlMeth.set( method );
      final Class<?> returnType = method.getReturnType();
      if ( Boolean.TYPE.equals( returnType ) ) {
        return FALSE;
      } else if ( Byte.TYPE.equals( returnType ) ) { 
        return (byte) 0;
      } else if ( Short.TYPE.equals( returnType  ) ) {
        return (short) 0;
      } else if ( Integer.TYPE.equals( returnType ) ) {
        return 0;
      } else if ( Long.TYPE.equals( returnType ) ) {
        return 0L;
      } else if ( Float.TYPE.equals( returnType ) ) {
        return 0f;
      } else if ( Double.TYPE.equals( returnType ) ) {
        return 0d;
      }
      return null;
    }
  };

  private final static ThreadLocal<Method> tlMeth = new ThreadLocal<Method>();

  public static <T> T call( final Class<? extends T> clazz ) {
    return (T) Proxy.newProxyInstance( 
      getClassLoader(), 
      getInterfaces( clazz ), 
      HANDLER );
  }

  private static Class<?>[] getInterfaces( final Class<?> clazz ) {
    final List<Class<?>> interfaces 
    = new ArrayList<Class<?>>( Arrays.asList( clazz.getInterfaces() ) );
    if ( clazz.isInterface() ) {
      interfaces.add( clazz );
    }
    return interfaces.toArray( new Class<?>[interfaces.size()] );
  }

  public static Method method(){
    return method(null);
  }

  public static Method method(final Object doesntMatter){
    try{
      return tlMeth.get();
    }finally{
      tlMeth.remove();
    }
  }

  private static ClassLoader getClassLoader() {
    ClassLoader cl = Thread.currentThread().getContextClassLoader(); //primary
    return cl != null ? cl : MethodFinder.class.getClassLoader(); // fallback
  }
}

Now here it is: A surprisingly small and simple tool which can ease your pain with refactoring code that relies on reflection.

About these ads
  1. Emeka
    August 10, 2010 at 20:40 | #1

    This is great. I have been longing for an opportunity to learn Proxy and its magic. And now you have shortened my search, thanks so much. I would try out you code, however there is no “import” there yet. Please include the necessary imports, and example codes.

    • August 10, 2010 at 23:37 | #2

      Hi, thanks for the praise.
      I have included the imports in the last source code for your convenience.
      I hoped the small examples would be self-explanatory, but here’s a little sample code including imports, so you can quickly try it out.

      import static de.plush.brix.tools.reflection.MethodFinder.*;
      import static java.util.Arrays.asList;
      
      import java.lang.reflect.*;
      import java.util.List;
      
      class Sample{
      
       public static class ResultPrinter{
        private final Method meth;
      
        public ResultPrinter(Method meth){
         this.meth=meth;
        }
      
        public void print(Object target, Object... args){
         try{
          Object result=meth.invoke(target, args);
          System.out.println(result);
         }catch(IllegalAccessException e){
          e.printStackTrace();
         }catch(InvocationTargetException e){
          e.printStackTrace();
         }
        }
       }
      
       public static void main(String[] args){
        Method getX=method(call(List.class).get(0));
        Method containsO
         = method(call(List.class).contains(null));
      
        List<String> list=asList("Hello", "World", "!");
        new ResultPrinter(getX).print(list, 1);
        new ResultPrinter(containsO).print(list,"Hello");
       }
      }
      

      I hope this helps a little.

  2. Daniel
    August 11, 2010 at 17:32 | #3

    I don’t get it. If I add the following to your sample, I get a ClassCastException:

    [...]
    public static void main(String[] args) {
    Method getA = method(call(MyClass.class).getS());
    new ResultPrinter(getA).print(new MyClass(“Hello”));
    }
    }

    interface MyInterface{
    public String getS();
    }

    class MyClass implements MyInterface{
    private String s;
    public MyClass(String s){
    this.s=s;
    }
    public String getS(){
    return s;
    }
    }

    Exception in thread “main” java.lang.ClassCastException: de.plush.brix.tools.reflection.$Proxy0 cannot be cast to de.plush.brix.tools.reflection.MyClass
    at de.plush.brix.tools.reflection.Sample.main(Sample.java:30)

    So what conditions must be fulfilled for MyClass to be used with your code?

    • August 11, 2010 at 18:53 | #4

      Hi Daniel,
      these dynamic proxies can only implement interfaces, so you need to make sure you’re talking to the interface, not your own class, when using the tool to get a method. So for your example the code needs to look like this:

      public static void main(String[] args) {
      Method getA = method(call(MyInterface.class).getA()); //use interface here
      new ResultPrinter(getA).print(new MyClass(“Hello”));
      }

      That’ll do it.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 40 other followers

%d bloggers like this: