Overview

Reducing boilerplate code with Project Lombok

No Comments

It’s not a secret that Java is quite verbose and will require a developer to often write significantly more code for the same task than other languages. To address this problem, we’ve mentioned a library called Lombok on the codecentric blog in the past – see here and here. In short, it’s a code generation library that provides a set of annotations you can use to drastically reduce boilerplate code in your applications. I’ve personally used it with great success on a number of occasions and since the topic came up in my current project I wanted to elaborate on it bit more and address a few problems I was confronted with. As we’ve covered the basics before, let me get right to a few specific features and topics that I find noteworthy on top of that.

Using @Builder

For some time now, Lombok provides an annotation for implementing the Builder pattern on your classes. Doing this manually is a good example of Java’s verbosity:

@Getter
@EqualsAndHashCode
@AllArgsConstructor
public class Person {
  private String firstname;
  private String lastname;
  private String email;
 
  public static Builder builder() {
    return new Builder();
  }
 
  public static class Builder {
 
    private String firstname;
    private String lastname;
    private String email;
 
    public Builder fistname(String firstname) {
      this.firstname = firstname;
      return this;
    }
 
    public Builder lastname(String lastname) {
      this.lastname = lastname;
      return this;
    }
 
    public Builder email(String email) {
      this.email = email;
      return this;
    }
 
    public Person build() {
      return new Person(firstname, lastname, email);
    }
  }
}

With every additional property this code will grow significantly. There’s more sophisticated builder implementations that will for example guarantee that mandatory values are set during the construction of an object, but in my experience, most implementations of the builder pattern look like my example above. Let’s see how Lombok helps:

@Getter
@EqualsAndHashCode
@AllArgsConstructor
@Builder
public class Person {
  private final String firstname;
  private final String lastname;
  private final String email;
}

That’s it! One line and you have the same implementation as shown before. There’s some parameters that you can use to customize the generated builder. @Builder(toBuilder=true) will generate a toBuilder() method that will copy the contents of an existent Person instance to a builder, for example. That’s useful if you want to copy and change an object.

Other libraries have been doing builder generation before Lombok, but I know of none that integrate as smoothly. PojoBuilder – for example – will create seperate class files in a folder that you have to add to your project’s classpath. In contrast, Lombok hooks into the compile phase and will change the abstract syntax tree of the target class itself.

As with anything, the example case above looks intriguing but once you start working seriously, you often encounter edge cases and all kinds of problems. Generally, my experience has been very positive, but when working with the @Builder pattern I actually had a few problems to solve.

@Builder and generics

When I first put @Builder on a generic class I was confronted with a compiler error.

@Builder
public class Response {
  private T body;
}
 
Response<String> response = Response.builder().body("body").build();

The compiler complains about an incompatible assignment, as the result of the build process is Response<Object>. What’s required is a hint for the compiler when creating the builder, you’ll have to specify the requested type explicitly when creating the builder:

Response<String> response = Response.<String>builder().body("body").build();

@Builder and inheritance

Sometimes you use @Builder on a class that inherits from a parent class. Lombok will not consider fields from the superclass in the generated builder class. There’s a workaround, though. Normally, you use @Builder as a type annotation, but you can also use it on constructors and methods. What you can do in this case is create a constructor that takes all the arguments that are required for your class (including the ones for the superclass) and then place @Builder on the constructor.

@AllArgsConstructor
public class Parent {
  private String a;
}
 
public class Child extends Parent {
 
  private String b;
 
  @Builder
  public Child(String a, String b){
    super(a);
    this.b = b;
  }
}

You’ll get a complete builder and can use it like this:

Child.builder().a("testA").b("testB").build();

Lombok and constructor injection

In the context of dependency injection I like to use constructors to pass dependencies into objects: I find it unreasonable to create incomplete objects and to have dependencies set afterwards. In order to use constructor injection, you often have to be able to annotate a constructor. How do you do this if you have Lombok generate your constructors? It turns out, there is an experimental feature that can help you with this:

@AllArgsConstructor(onConstructor = @__(@Autowired) )
public class HelloLombok {
 
  public Dependency dependency;
}

Lombok will then add the provided annotation to the generated constructor. You’re right, the syntax looks a bit funny (see the small print at the bottom of the feature documentation for details). And because of the way it is implemented Lombok makes it clear, that this is experimental and might change or disappear in the future. If you can live with that, than it will enable you to combine Lombok and constructor injection (as well as a few other things). If not, you can always choose to not use Lombok for these constructors, of course.

Integrating Lombok

Integrating Lombok into your project is quite easy: For one thing, you need to have Lombok on the project’s classpath in order to get a build working. But equally important is integration with your IDE. I’ve been using both Eclipse and Intellij when working with Lombok, but there are other integrations as well. Again, the Lombok website gives a good overview about what has to be done: For Eclipse, you run the Lombok jar as a java application and tell it about the location of your Eclipse installation, for Intellij there’s a Plugin that you can install via the plugin repository.

The best code that you can write is the code that you don’t write. Lombok is tremendously useful, it will help you to trim your codebase and focus on the important parts of your applications. I’ve been using it for a few years now and I have not experienced any real problems, so far. I recommend you try it yourself!

Tags

Reinhard is an IT consultant and software engineer working in the Munich office of codecentric. For the most part of his career Reinhard has been specializing in Java technologies and acquired expert knowledge with a variety of frameworks and tools. He has a special interest in software testing, clean code, web based APIs and distributed systems.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Comment

Your email address will not be published. Required fields are marked *