Geertjan is a DZone Zone Leader and has posted 467 posts at DZone. You can read more from them at their website. View Full User Profile

Interview: Reinier & Roel on Lombok

12.08.2009
| 16388 views |
  • submit to reddit
Project Lombok removes the need for you to code a lot of the standard boilerplate, such as "getters" and "setters", that have helped cause developers to leave Java, in favor of other languages. Using annotations provided by Lombok, your application's bytecode can be modified at runtime, as explained below in an interview with Reinier Zwitserloot and Roel Spilker, the two developers behind Lombok.

First of all, can you say a few things about who you are?

Reinier: My name is Reinier Zwitserloot. I spend most of my time developing and marketing my startup, tipit.to, which lets you put tip jars (for donations) on any website. In my free time, I like to work on projects that seem like fun. Not just Lombok, but also, for example, massively multiplayer minesweeper or wiring up an exercise bike to a computer.

Roel: I am Roel Spilker. During the day I spend my time working at TOPdesk on a Service Management Tool. Most of my fun projects are software or electronics related.

Before we go further, why is Lombok called Lombok?

Reinier: Java projects usually riff on the idea that Java is a coffee related concept. However, Java is also an island in the Indonesian archipelago. If you move east from Java, you first hit Bali. East of Bali: Lombok.

Roel: Lombok is also Indonesian for chilli, and is used in some parts of the world as a synonym for chilli, even outside of Indonesia. This gives us a nice opportunity for a logo... and ties into the tag line "Spicing up your Java".

Lombok was very enthusiastically received at Devoxx this year. It seems to be a pretty new thing, since the v0.9.2 "Hailbunny" release is now in beta. What's the history of Lombok?

Reinier: This past week I was looking through a few of my old projects and ran across a site Roel and I put up way back in early 2005, with some suggestions for Java, in response to a call for ways to reduce boilerplate in Java 6 by Graham Hamilton (it's still live, at http://java-boilerplate.blogspot.com/). It includes @Getter and @Setter, and also something that looks a lot like the CICE closures proposal, so I guess both Roel and I have been thinking about boilerplate busting features for Java for a long time.

Roel: Another concept we thought about was an IDE plugin that hides boilerplate in the source view (for example, render a standard getter as @Getter on a field, like Lombok supports), and even lets you type like this, but saves back to a vanilla Java file so other people on your team, and any other tools that work with your source file, aren't affected. We dropped this idea when we realized there were too many hurdles (such as: how do we prevent a getter from moving around, mucking up your source control commit logs). It's very similar to Lombok, though.

Reinier: Sometime in the middle of last year, I was chatting with Perry Nguyen on ##java (IRC java channel on freenode), and I mentioned some of these ideas. He showed me a simple proof of concept that used some creative casting to implement something similar to @Getter and @Setter on just Java.

Roel and I fleshed this out into a complete engine and then set to work on figuring out how to add support for Eclipse (we are both Eclipse users). We couldn't make it work with Perry's trick, but at this point we were sufficiently committed that we kept searching for a way, and eventually worked it out using Lombok's current approach to supporting both Eclipse and NetBeans: Java agents.

According to the git repository, the first release we put on the website was tagged on the 26th of July, so Lombok is still a very new project. I'm not sure of the exact date, but Roel and I did the bulk of the work for that first public release (v0.8.1, mostly named in honor of our earlier failed attempts to create something like this) in 2 weeks of pair programming every evening.

Can you give us a brief overview of all the annotations and what they do?

Reinier: http://projectlombok.org/features/index.html will probably do a better job, but to summarize:

  • @Getter, @Setter, @ToString, @EqualsAndHashCode, and @Data all fill in the usual boilerplate that your IDE can generate for you as well via the source menu (getters, setters, a toString that prints fields, and equals and hashCode implementation that compares fields, and a constructor that has a parameter for each final field). With the Lombok annotations, you don't have to see (or write, or maintain!) all this boilerplate, which can really add up:


  • There's also @Cleanup. You annotate a local variable that needs to always be closed in order to avoid resource leaks (such as, say, FileOutputStream, or socket.getInputStream(), or a JDBC ResultSet), and Lombok takes care of it for you. All statements following the declaration, up to the point where that variable name goes out of scope, are compiled as if they are in a try block, with an accompanying finally block that calls close() on the resource.

    I actually use @Cleanup the most myself, but a show of hands at our Devoxx talk shows that @Data is the clear winner amongst Lombok users.

  • Lombok also has @Synchronized, which is just like the 'synchronized' keyword on methods, except it'll create a private final field with a private lock, instead of locking on 'this', which could lead to unforeseen deadlocks if other code also locks on your object.

  • Finally, there's @SneakyThrows. The concept of a checked exception is actually just a javac feature. Similar to generics erasure, at the JVM level, checked exceptions don't exist; any exception, checked or unchecked, can be thrown anywhere, regardless of try/catch blocks or 'throws' clauses on methods. Jython, Scala, JRuby, and most other languages that run on the JVM don't have checked exceptions either, which is why these languages still work on the JVM. @SneakyThrows gives you this power for Java; you annotate your method with for example @SneakyThrows(IOException.class), and the compiler will stop complaining that you need to handle IOExceptions in that method. I've seen a lot of code where checked exceptions are simply swallowed, or logged. Throwing these exceptions onwards is almost always better than ignoring them, though for example interface restrictions can get in the way, so @SneakyThrows gives you a way out.

Can we expect new boilerplate busters in the future?

Roel: Yes we can! There are two features that come to mind immediately: @Delegate and @Mixin. The first has to do with composition, and really shows its strengh when you use the decorator pattern. If you annotate a field with @Delegate, all methods of the type of the field will be generated in the class the field is in, and the implementation will just delegate the call to the field.

The second, @Mixin, will let you easily add behavior to your class, based on your own public API. So, if your class implements Comparable, you can mix-in the methods greaterThan, lessThan, etc. These methods will internally call compareTo.

What's going on under the hood? I.e., how does an annotation result in the boilerplate ending up in the bytecode?

Reinier: The annotation processor API only lets you create new files, it does not let you modify the file that has the annotation inside of it. Which is what Lombok does, so Lombok does not use the annotation processor API.

Instead, Lombok uses the annotation processor API only as a mechanism to inject itself into the compilation process. All annotation processors are initialized early in the compilation process, and Lombok modifies javac when it is initialized as an annotation processor. We change only one thing: The AST (the raw source code, parsed into a tree form) is first handed off to Lombok, which generates whatever needs to be generated, before javac continues.

Roel: We do something similar in Eclipse, except that in IDEs it's a bit more complicated. Annotation processors run, at best, when you save the file, but IDEs do a lot more than compile code. They show syntax errors as you type, they have an auto-complete dialog, refactor scripts, and features like 'jump to declaration', all of which need to be aware of something like a @Getter annotation. So, in Eclipse, we use a Java agent. Java agents are offered the chance to modify bytecode before the JVM loads a class. Lombok, when running on Eclipse or NetBeans, will actually rewrite the parser code and insert a call into Lombok with the AST, so that all IDE functions that work on the AST, from compiling, to syntax checking, to auto complete dialogs, get the proper ASTs with all generated methods in them.

When would and when would it not make sense to use Lombok? For example, is it for production scenarios only?

Reinier: Well, the class files produced from a source file with Lombok annotations in it are indistinguishable from class files produced from source files written out in full, so Lombok can certainly be used in production code. The biggest reason not to use it is if someone on your team uses IntelliJ IDEA, or some other IDE that isn't Eclipse or NetBeans, as Lombok doesn't work on other IDEs (yet!)

A second issue is that Lombok requires javac 1.6, but this is not that big of a deal for us, as Java 1.5 has been end-of-lifed some months ago.

There are also some corner cases in the IDEs that we haven't fully solved yet. For example, if you try to run the 'extract method' refactor script on code that is inside a @Synchronized method, you get an Eclipse error instead of refactored code. We're working on fixing these as we find them, but if you use Eclipse's refactor scripts a lot, you may want to avoid @Cleanup and @Synchronized in particular.

Roel: Other than that, resource cleanup and easy struct-like classes really change how you code. I've seen a lot of projects use some form of a 'Pair' class, for example, to allow a method to return 2 values. However, in almost all cases, a unique class to hold these two values would be the nicer design, but it's too much effort to create this class. With Lombok, the effort is minimal, and as a result you end up writing better code. So, we encourage everyone to use it!

If I take my @Override annotations away, my code will still work. However, if I take my Lombok annotations away, I have a lot of work ahead of me in adding boilerplate code. In other words, doesn't Lombok break some implicit rules of annotations?

Roel: Yes, it does. However, in the unlikely scenario this causes problems, the v0.9.2 "Hailbunny" release, currently in beta, includes the "delombok" tool, which will remove all traces of Lombok from your code. It takes source files containing for example: "@Getter private int x;" and spits out a source file with the annotation removed, and the getX() method added.

How has Lombok been received thus far? Can you give us a few examples of the varying responses?

Reinier: Far more positive than we originally thought when we released it. Because the Java community is so large, any language change of any sort is usually met with a lot of resistance. For example, discussions about checked exceptions are usually quite fierce, but @SneakyThrows, which has one foot in the door of abolishing them altogether, isn't criticized nearly as much as I expected.

The Sun core team that works on language changes (Joe Darcy and Alex Buckley, for example) were pretty negative at first, but we talked to them at Devoxx, and they made some good points, and we laid out some plans on how to address some of them. In the meantime, the NetBeans team has provided crucial patches that have enabled us to write the beta NetBeans support in record time (Thanks, Jan Lahoda!), as well as a patch to support Lombok in the latest version of JDK7's javac, so we seem to have fans within Sun as well.

Roel: Dick Wall and the rest of the Java Posse have been championing Lombok, probably because the posse has been looking a lot at alternative language on the JVM recently, like Scala. Lombok basically ports some of the nice parts of other languages to Java. For example, @Data is very similar to Scala case classes.

What are the main highlights of the v0.9.2 "Hailbunny" release, currently in beta, and how did those come about?

Reinier: The v0.9.2 "Hailbunny" release, currently in beta, has tons of new features.
 
Roel: The current release on the website is pretty stable. However, for the next release, called Hailbunny,  there is a lot of new and exciting stuff. Here's the list:

  • Preliminary NetBeans support.
  • JDK 7 support.
  • Delombok, to allow source-processors like the javadoc tool and the GWT-compiler to work with lomboked code.
  • Improved Eclipse support, for which we created a new patcher-framework.
  • Enhanced current features.

Reinier: The JDK 7 and NetBeans support listed above are due to patches from Jan Lahoda (from the NetBeans team). "delombok" is something Roel had been working on for a while, and has been part of our plan for Lombok from the beginning. He's recently had some time to finish it.

Roel: Another consequence of "delombok" is that we've been adding a lot of integration tests. We can now use "delombok" to automatically compare Lombok's transformations against a hand-written source file that should be equal.

We're considering releasing it as v0.10 instead of 0.9.2.

Now that the beta of the v0.9.2 "Hailbunny" release is out, what needs to happen for the full release to be pushed out the door? And what about the releases after that?

Reinier: We'll probably do the Google thing and remain in beta for a long time. We aren't ready to christen a Lombok release as 'v1.0.0' until:
 
  • We support all 3 major IDEs: Eclipse, NetBeans IDE, and IntelliJ IDEA.
  • We've sorted out all the corner cases; every refactor script should work.
  • We have IDE plugins for all three major IDEs, offering new refactor scripts unique to Lombok (such as: refactor a getter into a @Getter annotation, for example), as well as a feature to show the result of Lombok's transformations so you can tell exactly what's going on.
  • The API for writing your own transformations is stable.
  • We are certain that the annotations that Lombok supports don't ever need to undergo a breaking change.

Roel: Fortunately, as Lombok is purely a compiler/IDE assistant, a beta Lombok does not prevent you from using it. You can always stop using Lombok by running your code through "delombok", and the class files that you use in a production environment are no different than what you'd have ended up with if you hadn't used Lombok to begin with.

Would you like code contributions from the broader community and, if so, in which specific areas?

Reinier: Oh, yes, absolutely, we loooove code contributions.

In particular, in areas of other IDEs and code tools that we don't yet support. Those NetBeans patches were pretty much on the top of our patches wishlist. If some intrepid IntelliJ expert sends us patches for that, we'd be as happy as pigs in mud. Also, patches that fix some of the corner cases in IDEs we do support are also very welcome.

Roel: But, mostly, if you run into weird cases, send in a bug report. We've made it very simple and you don't need to sign up for anything. Just go to projectlombok.org and click 'Report an Issue'.

Thanks Reinier and Roel... and all the best with the further development of this great tool!

Published at DZone with permission of its author, Geertjan Wielenga.