About Lombok

There’s an annotation for that!
  FR, EO
 7 min. to read
 No comment yet
  (last mod.: 2022-04-18)

A few months back, a new guy joined our team and the Java world after a few years of being a .NET programmer. He had many reactions like, “What, you need to write that yourself in Java? In .NET, the compiler does it for you!”

It’s true that, in Java, the language and conventions drive you to write a non-negligible amount of low-value code. But don’t fear! Lombok aims at simplifying that task for you.

Please note this post is not a tutorial, but merely a quick intro to what Lombok can do for you.

The Purpose #

What Is Boilerplate Code? #

Imagine writing a Java class, assuming you respect the best practices. Each field must be private and accessed only through… well, accessors.

It means that, each time you add a field, you must declare new getters and setters. If your object is immutable, all fields must be initialized at instantiation. That implies your constructor must set all these fields, and if you add new fields, you must update your constructor too.

That is boilerplate code. It’s code that you write, no matter the project, no matter the class, that has little logic in it. It’s code that is frustrating to write, because a machine could do it in your stead (actually, you probably do it with a few strokes and shortcuts in your IDE).

Now, when you come from other languages where all this is implicit or declarative (see TypeScript or C#), writing this code explicitly seems like a artefact from an ancient world. It seems obsolete or, at the best, just painful.

That’s what Lombok was created for.

How Does Lombok Solve That? #

The heart of Lombok is annotations: instead of writing your boilerplate code, you declare what you want to be there without having to write it yourself. For instance, if you need your class to have an all-args constructor, you annotate it with @AllArgsConstructor. See below for some other examples.

Now, what happens to these annotations? We’re used to them being used at runtime to customize some behaviour, do some AOP or so (Spring, Jackson, we’re fondly thinking of you). It’s not how Lombok works, though.

In addition to providing a collection of annotations, Lombok is also an annotation processor: when on the path of your Java compiler, it’ll analyze your annotated code at compilation time and generate its classes accordingly. This means it brings you comfort for writing code, but has no impact on your application performance since it won’t use reflection.1

How To Get Started? #

Please note this post is not a tutorial. I’m only scratching the surface here, so that you may look more into it if you’re interested.

To work with Lombok, here’s what you’ll need:

  • some Maven configuration;
  • a plugin for your IDE.

Let’s dive a bit into this.

Maven Configuration #

It’s not complicated, you’ll see. In your POM, add your dependency:

2  <groupId>org.projectlombok</groupId>
3  <artifactId>lombok</artifactId>
4  <version>1.18.22</version>
5  <scope>provided</scope>

That’s it! Usually, this is enough.

One Gotcha #

There is one additional thing to do in two cases:

  • if you’re using JDK9+ with module-info.java;
  • if you’ve already configured an annotation processor2.

If that’s your situation, you must configure the annotationProcessorPaths of the Maven Compiler Plugin. It looks like this:

2	<path>
3		<groupId>org.projectlombok</groupId>
4		<artifactId>lombok</artifactId>
5		<version>1.18.22</version>
6	</path>

That’s it!

A Note About the Dependency Scope #

You may have noticed the Lombok dependency is in provided scope. It basically means “I don’t need this to be included at runtime.” You do need the annotations when compiling, but they’re eliminated from the generated class. That’s why having them on the classpath when running would be a waste, since they’ll never be loaded.

If you’re using Spring Boot’s fat jar (and probably other similar mechanism), the provided scope is ignored. If that is the case, you should add the <optional>true</optional> to your dependency declaration.

2  <groupId>org.projectlombok</groupId>
3  <artifactId>lombok</artifactId>
4  <version>1.18.22</version>
5  <scope>provided</scope>
6  <optional>true</optional>

IDE Plugin #

Your IDE usually compiles classes as soon as you modify them, but it does it its own way, not caring about annotation processors or such, unless you install plugins or spend time configuring. When using Lombok, that usually results in it whining about not knowing the getter you’re calling.

Lombok got it covered and provides plugins, whether you’re using an Eclipse-based IDE, an IntelliJ product, Netbeans or a Visual Studio Code-compatible editor. Just open the most relevant page on Lombok’s webite (under the “Install” menu) and discover the installation procedure for your tool.

Lombok Annotation Examples #

Now you’re set up and ready to go. What should you do?

I suggest we begin with the basics: accessors.

Accessors #

OK, so let’s admit you got a DTO with fields and you don’t want to explicitly write the getters and setters. Just annotate your class (or your fields) with @Getter and @Setter, and you’re done!

By default, the accessors will be public but you can override that to suit your needs.

 1import lombok.AccessLevel;
 2import lombok.Getter;
 3import lombok.Setter;
 7public class Book {
 8    private String title;
 9    private String author;
11    @Getter(access = AccessLevel.NONE)
12    private String somePrivateFieldThatMustNotHaveAGetter;

Much less verbose than your usual Java POJO, eh?

Constructors #

You need a constructor to instantiate your class. Three annotations are available in Lombok especially for that purpose:

  • @NoArgsConstructor is quite explicit.
  • @AllArgsConstructor is too.
  • @RequiredArgsConstructor creates a constructor with a parameter for each field that needs initializing at instantiation (eg. final fields).

As is the case with the accessors, you can set the scope with the access parameter.

 1import lombok.AccessLevel;
 2import lombok.AllArgsConstructor;
 3import lombok.Getter;
 4import lombok.NoArgsConstructor;
 5import lombok.Setter;
10@NoArgsConstructor(access = AccessLevel.PROTECTED)
11public class Book {
12    private String title;
13    private String author;

One fabulous thing: you don’t need to update your constructor if you add or remove fields. That will be automatic!3

Builders #

As time passes, I tend to do more and more immutable objects. However, an immutable POJO with a lot of fields is a pain to initialize and the all-args constructor is not clear. That is why I love the builder approach.

And Lombok has an annotation for that, too!

Say I update my Book class as follows:

1import lombok.Builder;
2import lombok.Getter;
6public class Book {
7    private String title;
8    private String author;

I can then init a book using this:

2    .title("Roverandom")
3    .author("John Ronald Reuel Tolkien")
4    .build();

If you ever tried to write a builder on your own, you must appreciate the time this saves you.

And Much, Much More #

I’ll stop here for the examples as I suppose you are getting bored. Just know that there are annotations to generate your equals() and hashcode() methods, your toString(), or even to add a log field from your favourite logging framework.

Also know that you can specify some additional or default behaviours in a lombok.config file to place at the root of your project, just beside the pom.xml.

To Go Further #

Of course, you can find a lot of tutorials about Lombok, but I warmly invite you to have a look at the official doc. It’s well done, each annotation comes with an example showing you how it’s translated in “vanilla” Java, and it tells you the possible configurations.

And as with any new tool, a bit of experimentation can only help.

  1. At the worst, it’ll have a negative impact on your compilation time, but unless you have a very, very large project with massive use of Lombok, I’m not sure you’ll be able to tell. ↩︎

  2. Normally, the compiler plugin picks up annotation processors automatically from the dependencies. Manually setting the processors, however, deactivates that sensing of what’s on the classpath. ↩︎

  3. Of course, the calls to the constructors will require refactoring, but you’ll locate those quite easily through the compiler errors. ↩︎