It’s the year 2023. JDriven colleagues have gathered to discuss the new trends and deprecations of our work to put on the latest TechRadar. Once everybody is seated, everyone contributes their latest opinions. Very soon discussions run high. Lombok is dropped at the table of discussion as well. After some debate, it is decided. Lombok is put on HOLD!

What’s the point, really?

The main argument to discourage the use of Lombok has been listed as:

The large number of annotations, the need for expertise in the Lombok implementation, and the emergence of newer Java language features like records are factors that make JDriven cautious about using Lombok for new projects.

Furthermore, people complain the setup of the Lombok project uses a nasty hack[1], Lombokified Java code is actually another language, and you can run into tricky situations when you use other annotation processors. Though I do agree with it all, I still think you should use Lombok in every Java codebase you have!

The problem with Java is obvious. It’s just too darn verbose. At the very least, there seems to be a correlation between the number of lines of code and the complexity of a code base[2] . Knowing this, we should strive to eliminate all unnecessary aspects, so we can focus on writing and reading business code.

If you’ve been working in a JVM-based community for a while, you’ve probably heard someone say something along the lines of: “Make sure you have a tool belt instead of a hammer, so you don’t have to treat everything like a nail.”[3]. Well, the same applies to the language(s) you are working with. They are not the end goal, but merely the clay and mortar you need to do your job. So if you can improve your Java hammer by applying a nice Lombok handle, do it!

I will not deny myself the simple pleasure of saying true things

I agree you should think carefully about some annotations before using them. For example, @Cleanup has the same purpose as a try-with-resources statement and @Value has been caught up with a record class if you were to create a simple POJO. But others can be used all the time. Let me just show by example.

What about a Spring bean:

@Slf4j
@Service
@RequiredArgsConstructor
public class SomeProcessor {
    private final SomeRepository repository;
    @Qualifier("someSpecialJmsTemplate")
    private final JmsTemplate jmsTemplate;

    // business logic
}

a copyable record:

@With
public record User(String name, int age) {}

or some service to retrieve reference data:

@Singleton
public class ReferenceDataService {

    @Getter
    private volatile List<RefData> refData;

    @Synchronized
    @SneakyThrows public void refresh() {
        val request = HttpRequest.newBuilder().uri(new URI("<uri>")).GET().build();
        val data = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString()).body();
        refData = new ObjectMapper().readValue(jsonInput, new TypeReference<List<RefData>>(){});
    }
}

The examples speak for themselves. The code is easily readable and focuses on business logic.

Not everything is meant to be something beautiful and long-lasting

There are some catches though. We developers tend to try things out instead of reading the documentation[4], which often leads to bad implementations that could be easily avoided if we followed the RTFM-rule. For Lombok this often means too many annotations and keywords are used, while Lombok does already take care of it all. And in addition, there are inconveniences that are not immediately noticeable.

For example, consider following situation:

@Getter
public abstract class Mammal {
    String name;
    LocalDate dateOfBirth;

    public abstract void makeSound();
}

@Value
public class Dog extends Mammal {
    private int legs;

    public Dog(String name, LocalDate dateOfBirth, int legs) {
        super.name = name;
        super.dateOfBirth = dateOfBirth;
        this.legs = legs;
    }

    @Override
    public void makeSound() {
        System.out.println("Woof! Woof!");
    }
}

Looks good, right? Well, actually there is one problem with this code.

As most of us know, the @Value annotation is a bundle of annotations, one of them the @EqualsAndHashCode. So we don’t have to write those pesky equals and hashCode methods ourselves! Sadly enough, in this case you are tricked, because you actually needed a @EqualsAndHashCode(callSuper = true). Otherwise, the name and date of birth are not taken into account when comparing two Dogs. Secondly, although less important, the private keyword can be omitted because Lombok also makes all fields private if you use @Value.

But there is light at the end of the tunnel, the integration plugins are getting that good Lombok is really being treated like a first-class citizen when developing Java code:

lombok call superclass warning
Figure 1: IntelliJ warning

Is that all you can conjure, Saruman?

One more thing. We use a lot of frameworks. Like, a lot. And of course, sometimes those frameworks bite each other. I could make a very long list, but for starters, take a look at:

I never dreamt of success. I worked for it!

My point is clear! Lombok is not a silver bullet. You have to learn the rough edges to use it properly. But once you do, which you should, it is a very nice addition to Java. Therefore, stop nagging and enjoy your Lombok Hammer to the fullest!

This is my personal opinion, which does not reflect JDriven’s overall view on the subject. Also note that I am a strong supporter of switching to Kotlin, but that is a whole other discussion…

1. For a great explanation in depth read How does the lombok magic work underneath? by Parth.
3. A reference to the Law of the Instrument.
4. Except when there is no or little documentation, then we start complaining. To be honest, developers are a strange breed of people 🤣.
shadow-left