; last updated - 10 minutes read

Reusing code scattered among the inheritance tree

Many components of the AngularFaces library share common properties and methods. Some of these methods are simple, some of them are complex. I'd like to move them to another class instead of implementing them multiple times. Unfortunately, the component classes don't derive from a common base class. That's nothing I can fix. That's just the way PrimeFaces and Mojarra are designed. So I can't factor out the common traits using inheritance.

The second common approach, the delegation pattern, certainly works. However, it amounts to writing a lot of boiler plate code. At first glance, this isn't much of a problem since most modern IDEs offer a refactoring tool to implement the boiler plate code. Eclipse is going to help you. But as Venkat Subramaniam pointed out in his Java One 2013 talk, this approach has severe disadvantages. Adding a method to the base class forces you to add it to every class using the base class as a delegate. The same applies to removing a method or changing the signature of a method.

Scala to the rescue!

So what we really want to have is something like Scala's or Groovy's @delegate annotation. This is often referred to as "mixin".[1] Basically, it's a kind of multiple inheritance, but typically mixins or traits are defined in a slightly less anarchic way. For instance, the famous diamond inheritance problem of C++ simply can't occur.

However, porting AngularFaces to another JVM language might reduce the library's attractiveness to other developers, not to mention its versatility. Virtually every JVM language features nice integration with Java, but few JVM languages play nicely with other JVM languages other than Java.

Some time ago I've seen a surprising approach to implement mixins using AspectJ. But again, AspectJ might repel some Java developers and adds to the tool stack.

Another possibility is to wait for Java 8. Defender methods deliver most of the functionality I'm missing. But I don't know how long it takes until OpenShift - where I host the AngularFaces showcase - is going to support Java 8, so this isn't an attractive option, either.

So it's tempting to abandon all hope. But wait - what about Javassist?

Javasisst

Javassist is a library manipulating byte code at run time. For instance, we're going to to add methods to an existing class today. The nice thing about Javassist is we can do so without having to go all the way down to the byte code level. Pure Java does the trick just as well.

Byte code manipulation sounds dangerous, so you might be afraid your operations department won't allow you to use Javassist. This shouldn't be too much of a concern. Javassist can be found in most web applications. For instance, it's part of the Hibernate dependencies. Spring uses a similar library to manipulate byte code (CGLIB). So chances are you'll find it easy to convince your operations department. Unless they deny Hibernate, too.

By the way, I suspect the implementation described below also works with dynamic proxies. If I'm not mistaken Javassist's MethodHandler is roughly the same as java.lang.reflect.InvocationHandler. I didn't explore the dynamic proxy approach yet because I saw Javassist first and the solution works fine.

A simple example

I've prepared a little example to show you how to implement mixins. The Stackoverflow discussion I got the idea from inspired me to create a Dog class as a mixin of two classes. Most dogs bark and love to fetch sticks, so you might think of a Dog as combining two traits: Barker and Stick-Fetcher.[2]

Let's have a look at the two classes:

public abstract class Dog { public void bark() { System.out.println("Woof woof!"); } public abstract void fetch(); } public class Fetcher { public void fetch() { System.out.println("...got the stick!"); } }

The goal is to write a utility class composing the classes:

Breeder breeder = new Breeder(); Dog husky = breeder.breed(Dog.class, Fetcher.class); husky.bark(); husky.fetch();

Notice the abstract method fetch(). A language supporting traits natively doesn't need the abstract class. In Java, we can't get rid of it entirely because we can't call it otherwise. There's no union type in Java. However, it's not necessary to define an abstract method. Interfaces do the trick just as well, maybe even better because they are to the Scala version:

public interface Dog { void bark(); void fetch(); } public abstract class Barker { public void bark() { System.out.println("Woof woof!"); } } public class Fetcher { public void fetch() { System.out.println("...got the stick!"); } } public static void main(String... args) { Breeder breeder = new Breeder(); Dog husky = breeder.breed(Barker.class, Fetcher.class); husky.bark(); husky.fetch(); }

That's not a real mixin, but it's as far as we can get. In any case, it's a lot better than having to copy implementations over and over again - even if the implementation merely consists of calling a delegate.

How can we use Javassist to implement the Breeder class?

A first implementation of mixins

As first step I'd like to implement the method breedDog() before implementinc a generic and abstract getMixin() method later:

public Dog breedDog() { ProxyFactory factory = new ProxyFactory(); factory.setInterfaces(new Class[]{Dog.class}); factory.setSuperclass(Barker.class); factory.setFilter(new MethodFilter() { @Override public boolean isHandled(Method method) { return method.getName().equals("fetch"); } }); MethodHandler handler = new MethodHandler() { Fetcher fetcher = new Fetcher(); @Override public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { if (thisMethod.getName().equals("fetch")) { fetcher.fetch(); return null; } // ToDo: Needs proper error logging in production code! System.out.println("Missing implementation of " + thisMethod); return null; } }; Dog dog; try { dog = (Dog) factory.create(new Class[0], new Object[0], handler); } catch (NoSuchMethodException | IllegalArgumentException | InstantiationException | IllegalAccessException | InvocationTargetException e) { // ToDo: Needs proper error logging in production code! e.printStackTrace(); return null; } return dog; }

Javasisst allows you to create a proxy class. Line 3 declares that the proxy class implements the Dog interface. Line 4 defines the super class of the proxy. The proxy automatically contains every method implemented by Barker. Every other method has to be defined by a method handler. In our case the method handler contains the delegate object (Fetcher), and a single method calling the delegate's fetch method when Dog.fetch() is called.

The generic mixin factory

After these preparations defining a generic mixin factory is straight forward. Instead of checking the hardcoded string literal we'd rather inspect the classes using reflection, calling the first implementation we find. This is pretty much the way traits are defined in Scala.

public class MixInFactory { @SuppressWarnings("unchecked") public T create(Class iface, Class... mixinClasses) throws ReflectiveOperationException { MethodHandler handler = new MixinHandler(iface, mixinClasses); T objectWithMixins; ProxyFactory factory = new ProxyFactory(); factory.setInterfaces(new Class[] { iface }); try { objectWithMixins = (T) factory.create(new Class[0], new Object[0], handler); } catch (ReflectiveOperationException e) { // ToDo: need better logging and exception management System.err.println("Couldn't create object due to " + e.toString()); throw e; } return objectWithMixins; } } class MixinHandler implements MethodHandler { Map delegateTo = new HashMap(); Map methods = new HashMap(); MixinHandler(Class iface, Class... mixinClasses) throws ReflectiveOperationException { for (Class c : mixinClasses) { Object delegate = c.newInstance(); Method[] exposedMethods = c.getDeclaredMethods(); for (Method m : exposedMethods) { final String signature = getSignature(m); if (!delegateTo.containsKey(signature)) { delegateTo.put(signature, delegate); methods.put(signature, m); } } } } private String getSignature(Method m) { String params = ""; Class[] p = m.getParameterTypes(); for (Class param : p) { if (params.length() > 0) { params += "," + param.getSimpleName(); } else { params += "," + param.getSimpleName(); } } return m.getName() + "(" + params + ")"; } @Override public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { final String signature = getSignature(thisMethod); Object delegate = delegateTo.get(signature); Method m = methods.get(signature); return m.invoke(delegate, args); } };

Comparing Javassist mixins to Scala traits

The most important difference to the Scala version is we can't define our mixin at compile time, so expect a certain performance penalty. And of course Scala's syntax looks nicer than our method call:

MixInFactory breeder = new MixInFactory(); Dog dog = breeder.create(Dog.class, Barker.class, Fetcher.class); trait Fetcher{ def fetch = println "...got the stick!" } class Barker { def bark = println "Woof woof!" } class Dog extends Barker with Fetcher{ } val dog = new Dog()

But then, I'd say the Java version looks surprisingly good. I'm not sure yet I'm going to use it in the AngularFaces library, but it's not the syntax that'll stop me.

Speed penalty

What about the speed penalty? The mixin factory relies heavily on reflection, so it's almost sure to suffer from bad performance.

The speed tests I've run clearly show there's a speed penalty, but in many cases, you won't even notice. You shouldn't use my mixins in high-performance code. On the other hand, if your data is saved in a SQL database you'd rather optimize your SQL code instead of avoiding Javasisst mixins.

According to my speed tests indicate that creating a mixin class is roughly 50 times slower than creating a simple class using the new keyword. Calling a mixin function is roughly four times slower than calling a native function. There's plenty of room for speed optimizations, so I'd say these are encouraging results.

Compiling the class to byte code

As I mentioned above, we've used a very primitive approach so far. We also could have used Java's dynamic proxies. Once you've made up your mind to use a sophisticated framework like Javassist you can do a lot better than that. One of the performance optimizations that immediately come to mind is the new InvokeDynamic byte code instruction. InvokeDynamic is a very flexible tool, so maybe it might be worth a try.

However, Javassist doesn't stop at offering method handlers. It also allows us to add methods to a class, compiling it to byte code. So we can optimize the code later by creating the class only once and caching it. Doing so we'll see an enormous performance boost. After the initial bootstrap delay, the dynamically class is just as fast as its Scala counterpart. I'm going to describe this approach in a later article (but you can already have a glimpse at an early version of the source code at my GitHub repository).

Conclusion

Isn't is astonishing what can be achieved with good old Java using clever libraries? I didn't really believe it was possible to implement mixins in (almost) pure Java, let alone implementing them with acceptable performance. Sometimes it feels good to be proved wrong!


Further reading and source code

source code of the example


  1. There are subtle differences between the terms "mixin" and "trait". However, the differences aren't that big, so I'm using both terms as synonims in this article.↩
  2. Of course, I also could use real-world AngularFaces classes as an example. But aren't those barking dogs fetching sticks cute?↩

Comments