Nicolas Frankel is an IT consultant with 10 years experience in Java / JEE environments. He likes his job so much he writes technical articles on his blog and reviews technical books in his spare time. He also tries to find other geeks like him in universities, as a part-time lecturer. Nicolas is a DZone MVB and is not an employee of DZone and has posted 218 posts at DZone. You can read more from them at their website. View Full User Profile

Lombok Reduces Your Boilerplate Code

12.07.2009
| 9305 views |
  • submit to reddit

In this article, I show you the power of the product I stumbled upon this week: Project Lombok enables you to modify bytecode at compile code. First, I will detail what features Lombok brings you out-of-the-box. In the second part of this article, I will describe how to extend it to generate you own code.

Introduction

Since the dawn of JEE, complaints have been filed regarding the complexity of coding components. I consider EJB v2 a very good example of this complexity: for just a simple EJB, you have to provide the EJB class itself and a home and an interface for each access type (local and remote). This makes it complex, error-prone and more importantly gives you less time to focus on business code where the real value is. Two initiatives show the will to decrease the amount of boilerplate code needed when coding:

  • the Spring Framework’s motto is to decrease JEE complexity. The boilerplate code is written once in the Spring framework and only used by projects.
  • EJB v3 has taken into account the lessons from Spring and aim to reduce boilerplate code too, making local and remote interfaces unnecessary. Eventually, the next version of the specification will make the local and remote home optional too.

The goal of Project Lombok is exactly the same as the previous initiatives but in order to do so, it uses another mechanism.

Annotation processing

Version 5 of the Java language introduced the concept of annotations, code meta-data that could be processed at compile time and/or runtime. Unfortunately, in JDK 5, processing annotations at compile is a 2-step process. First, you have to run the apt executable to process annotations, perhaps creating or modifying source files, then compile your sources with javac. That was not the best approach, so Java 6 removes apt and make javac able to manage annotations, streamlining the process to obtain a simpler single step computing. This is the path taken by Lombok.

Project Lombok

Lombok’s driving feature is to create code you need from annotations in order to reduce the amount of boilerplate code you have to write. It provides you with the following annotations that will change your code (if not your life) forever:

For example, while learning to code the OO way, you were drilled into making your fields private and into writing public accessors to access these fields:

public class Person {

private String name;

public String getName() {

return name;
}

public void setName(String name) {

this.name = name;
}
}

Since this is a bother to write, some (if not all) IDE have a feature to generate the accessors. It has some drawbacks:

  • You have to manually remove the accessors if you remove the field
  • It clutters your real code with boilerplate code
  • Corollary: it takes a real effort to check whether an accessor already exist for a field in a long class

Moreover, creating accessors manually is error-prone: I once searched for hours for a bug in code developed by a fellow developer and finally found the setter was wrong.

Since getter / setter is only meta-data for a field, Lombok’s stance is to treat it like such: in Java, meta-data is managed with annotations. Look at the following code:

import org.lombok.Getter;
import org.lombok.Setter;

public class Person {

@Getter @Setter
private String name;
}

I decompiled the generated class (using JAD) and it creates exactly the same bytecode, only the source code is more concise and less error-prone.

When thinking, I found 3 arguments against using Lombok:

  1. The first argument against using such a strategy is that you can’t create a protected accessor like that. You’re wrong, Lombok is configurable:

    import lombok.AccessLevel;
    import org.lombok.Getter;
    import org.lombok.Setter;

    public class Person {

    @Getter @Setter(AccessLevel.PROTECTED)
    private String name;
    }

    And its true for all the provided annotations! Just look at them.

  2. The second argument against using Lombok is that you don’t know what it does behind the scene. It’s true, but the same could be said for AOP or CGLIB or whatever framework you’re using.
  3. The last argument and IMHO the only one valid enough is that it renders debugging more complex: but so is the use of Java dynamic proxies that Spring uses throughout its code, and still many projects use them.

Use and installation

Using Lombok is a 3-step process:

  1. Put the JAR on the classpath
  2. Add the annotation you want to use
  3. Compile with javac

There’s a catch, though. Notice the last statement and the emphasis on javac. Since most (if not all) the developers you and I know focus a little bit on productivity, chances are you’re using a IDE. I do not know about NetBeans and fellows, but my favorite IDE Eclipse does not use javac to compile but its own internal compiler.

Our friends from Lombok thought about that and Lombok is able to hook into Eclipse compiling process too. In order to do so, just launch lombok.jar and follow the instructions on you screen: it will just add 2 lines to your eclipse.ini.

A word of advice (since I made the mistake): if you launch Eclipse with a command that takes parameters, such as a Windows shortcut, these parameters take precedence and eclipse.ini is silently ignored. Just to let you know…

Lombok extensions

To my knowledge, there’s currently only a single extension of Lombok called Morbok. It lets you create your classical private static final logger with just an annotation.

The advantage of this is that Morbok automatically uses the fully qualified class name as the name of the logger so no more copy paste error. The disadvantage is that if you do not use Commons Logging as you logging framework, you have to configure each @Logger annotation with the framework you want to use, there’s no overall configuration: IMHO, that’s something that could be covered in the next version (is there’s one).

Architecture

First things first, Lombok needs a JDK 6 to compile since annotation processing is done in Java 5 with APT. For now, Lombok hooks into the compiling process immediately after the environment has built the AST for the class.

It then passes the structure thus formed to each of its referenced handlers. There’s a single handler for each annotation: HandleGetter for @Getter, HandlerSetter for @Setter and so on. Handlers are, guess what, responsible for handling annotations.

Extending Lombok

Extending Lombok is a 3-step process:

  1. Create the annotation. Since the annotation is used at compile-time, it can be safely be discarded afterwards so its retention policy can be left to its default value (namely RetentionPolicy.SOURCE)
  2. Create the handler. A handler is a class that directly implements lombok.javac.JavacAnnotationHandler<T extends Annotation>. Why directly? Because Lombok uses the ServiceProvider service and it’s one of its limitations
  3. Reference the fully qualified class name of the handler in a file named lombok.javac.JavacAnnotationHandler under META-INF/services

The real coding takes place in step 2: the interface has a single method handle(AnnotationValues<T> annotation, com.sun.tools.javac.tree.JCTree.JCAnnotation ast, JavacNode annotationNode). Notice the 2nd parameter package? It’s denotes Sun private implementation. It has some big drawbacks:

  • The documentation is sparse if not completely unavailable. You go into unknown territory here
  • Since the com.sun.tools.javac is not part of the public API, it can change at a moment’s notice. You can break your code with each update
  • Remember that previously, I talked about this being only good for Java? That’s still true. If you want this new annotation to work under Eclipse, that’s another handler to write

Example

As an example, I coded an embryo for a @Delegate annotation. Such an annotation on a field indicates that the declaring class should have the same public methods as the field’s class and each method’s body should be a call to its delegate’s method.

public class Delegator {

@Delegate
private DelegateObject object;

...
}

public class DelegateObject {

public void doSomething() {
...
}
}

The previous code should generate the same bytecode as the following code:

public class Delegator {

private DelegateObject object;

public void doSomething() {

object.doSomething();
}
...
}

As yet:

  • it does not handle generics
  • the only handler provided is for javac
  • it is not configurable

The final implementation is left for the brave readers: original sources are here in Eclipse/Maven format.

Conclusion

Some improvements could quickly be made to Lombok. First, I don’t like the monolithic structure the JAR has. IMHO, it could be nicely decoupled into 3 separate JARs: the Lombok agent itself, the provided annotations and associated handlers and finally, the installer.

Moreover, coding two handlers for each annotation is a lost of time. What if you need to support NetBeans too? Perhaps using the Service Provider is a mistake…

Finally, depending on Sun’s internal compiler API is too big a risk. I think that if Lombok could provide a facade to this API, it could be less risky for enterprise to take this road and the bridging could be made by people who understand the API (the Lombok team) and not base developers (like myself).

All in all, and despite these flaws, Lombok looks like a very promising project that could well mimic Spring’s success. That’s what I wish it anyway because it’s real sideway thinking that brings much added value: good luck for the future!

To go further:

 From http://blog.frankel.ch

 

 

Published at DZone with permission of Nicolas Frankel, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Donny A. Wijaya replied on Mon, 2009/12/07 - 3:10am

It would be perfect if AspectJ compiler and Lombok work well together.

Thomas Mueller replied on Mon, 2009/12/07 - 4:43am

Logger name copy paste problem: there is an easy way to solve this:

public class Test {
final static String caller = LogUtil.getCaller();
public static void main(String... args) {
System.out.println("caller class name: " + caller);
}
}
class LogUtil {
static String getCaller() {
return new Exception().getStackTrace()[1].getClassName();
}
}

Zqudlyba Navis replied on Mon, 2009/12/07 - 4:48am

@Nicolas Have you used this in production ?

Jacek Furmankiewicz replied on Mon, 2009/12/07 - 9:58am in response to: Zqudlyba Navis

We are going into production using it in a few weeks. All of our Hibernate entities are coded using Lombok. it's the greatest thing to happen to Java in the last few years. Period.

Nicolas Frankel replied on Mon, 2009/12/07 - 10:48am in response to: Zqudlyba Navis

@zqudlyba

Very good question! No, I haven't yet and won't use it for a while. I'm working at the moment for a company that is stuck on Java 1.5 and Java 1.6 is a prerequisite for Lombok. To be frank, I wouldn't recommend using any project in production before some companies used it before you: in the companies I worked for, the value is in the business code, not in using the latest products.

However, I do think this project should be monitored closely since it could bring some productivity gains soon.

Fu Xiaofeng replied on Mon, 2009/12/07 - 9:12pm

it's funny and useful,thanks for author,thanks for this simple but great Lombok.

Igor Skornyakov replied on Tue, 2009/12/08 - 4:18am

In my opinion the very idea of Lombok is strange. What is the objective? Reduce typing? This is by no means a most significant part of the programmers' job. And some things (such as getters/setters) can be generated automatically by most of modern IDEs. The advantage of using Lombok can be compared with the advantage of using jargon comparing to the normal language - well it can be shorter, even more expressive sometimes, but very few people will consider it as well-written. For me Lambok is merely a textbook example of a language feature (annotations) misuse.

Thomas Mueller replied on Tue, 2009/12/08 - 8:09am

> What is the objective? Reduce typing?

No. Reduce reading.

> very few people will consider it as well-written

What's wrong, except that you are not used to it?

 

Oliver Plohmann replied on Tue, 2009/12/08 - 11:26am

Good idea IMHO, but nothing really new. @Getter and @Setter also exists in Objective-C and is named @property. Nevertheless, I consider this a useful tool. Would be nice if @Synchronized were reentrant as @Synchronized in Objective-C. The keyword synchronized in Java is not reentrant, which means that a deadlock occurs if a thread that is already in the synchronized block tries to enter it again. This is really a pain as you only need to change the sequence in which some methods are called and all of a sudden you have a deadlock where there wasn't one before.
Cheers, Oliver

Igor Skornyakov replied on Tue, 2009/12/08 - 12:02pm in response to: Oliver Plohmann

Well, an opinion of a person with such a "deep" knowledge of Java is very important indeed

Neil Hartner replied on Wed, 2010/11/10 - 1:59pm

Very nice blog.  This is the best resource I could find that explains how to create a custom lombok annotation.

In order to get your example project to compile from maven command-line, I had to modify the maven-compiler-plugin configuration as follows:

       <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
          <compilerArgument>-proc:none</compilerArgument>
        </configuration>
      </plugin>

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.