Reusing code scattered among the inheritance tree
Many components of the
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:
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:
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 MixInFactoryComparing 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:
MixInFactoryBut 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!