avatarMilos Zivkovic

Summary

The article discusses the ongoing relevance and misconceptions surrounding Lombok in Java development, despite the introduction of newer language features like records in Java 17.

Abstract

Lombok remains a valuable tool in Java development, contrary to some developers' beliefs that it is obsolete or encourages bad practices. The article addresses common misconceptions, such as the idea that Lombok can trick the compiler with annotations like @SneakyThrows, which circumvents checked exception handling. It argues that proper use of Lombok can lead to cleaner, more readable code without sacrificing error handling. While features like @Value have been rendered obsolete by Java 17's records, other annotations like @Builder continue to be useful, especially in conjunction with records for creating partial record builders. The article also acknowledges the challenges of migrating from Lombok in legacy codebases and the potential pitfalls of using delombok. It emphasizes the importance of understanding annotations' inner workings, citing @With as an example, and suggests that Java's evolution, including the anticipated introduction of withers, will continue to reduce the need for certain Lombok features.

Opinions

  • Lombok is unfairly criticized by some developers who prefer writing boilerplate code manually.
  • The @SneakyThrows annotation is seen as a hack but can be beneficial when used appropriately, especially with proper error handling.
  • Despite the introduction of records in Java 17, Lombok's other annotations like @Builder remain essential for developers, including those working with older Java versions.
  • The use of delombok can lead to unexpected issues, and the generated code may not always be ideal.
  • Developers should be cautious and informed about the annotations they use, understanding both their benefits and potential drawbacks.
  • The evolution of Java, with features like records and the future implementation of withers, is gradually making some Lombok annotations less necessary.

Why Is Lombok Still in Every Java Developer Toolkit?

Why Lombok still holds its respected place amongst experienced Java developers

Lexica.art

“Why are you using Lombok to generate getters and setters? I prefer to write them on my own.” — says my coworker and merges the boilerplate getters into the codebase.

Why are developers against Lombok? What are the wrong beliefs they have about Lombok? And why do they prefer to write the boilerplate on their own?

Any tool is deadly if used wrong. One such tool is Lombok. Simple annotation can backfire and cause weird bugs. And this happens only if one abuses Lombok, otherwise it’s a great tool.

Here are some of the misbeliefs I’ve heard about Lombok.

You can trick the compiler using Lombok

@SneakyThrows circumvents the need to handle the checked exception. It’s impossible to have the handlers written without a lot of boilerplate.

This is a hack and trick for the compiler. There’s no counterargument.

Do we really sacrifice so much using this hack? I wouldn’t say so.

With proper error handling up in the call stack, you won’t feel this hack. And on the backend, you get a more readable code that’s easier to consume.

We won’t go into checked exceptions and if they’re evil or not. What Lombok enables us here is to iterate faster. If it’s possible that an exception slips through the cracks, then it’s your concern.

I’ve never had any issues whatsoever with @SneakyThrows. As long as you know what you’re doing.

@SneakyThrows shouldn’t be used to shut up the compiler in every situation. Using SneakyThrows does help when you don’t care about exceptions at that specific place.

You can use Lombok’s obsolete features (are these really obsolete?)

@Value is pointless if you're writing Java 17 or higher.

Records render this annotation obsolete. Even so, we still need Lombok for other annotations.

Hibernate entities benefit greatly from Lombok’s @NoArgsConstructor @Builder and others (avoid @Data though). Lombok is of great help with JPA, and it's certainly a good use case.

You’ll probably use @Builder with records, as there's no native way of building partial records. When withers get implemented for records Builder won't be needed. Until then this is the easiest way of generating partial record builders.

Code generated with Lombok’s @Builder applied to the record.

 
package com.example.demoslombok;  
  
public record User(String name, String lastName) {  
    public User(String name, String lastName) {  
        this.name = name;  
        this.lastName = lastName;  
    }  
  
    public static User.UserBuilder builder() {  
        return new User.UserBuilder();  
    }  
  
    public String name() {  
        return this.name;  
    }  
  
    public String lastName() {  
        return this.lastName;  
    }  
  
    public static class UserBuilder {  
        private String name;  
        private String lastName;  
  
        UserBuilder() {  
        }  
  
        public User.UserBuilder name(final String name) {  
            this.name = name;  
            return this;  
        }  
  
        public User.UserBuilder lastName(final String lastName) {  
            this.lastName = lastName;  
            return this;  
        }  
  
        public User build() {  
            return new User(this.name, this.lastName);  
        }  
  
        public String toString() {  
            return "User.UserBuilder(name=" + this.name + ", lastName=" + this.lastName + ")";  
        }  
    }  
}

You don’t @Getter and @Setter for value objects (records).

It’s always better to use records than have Lombok generate them for you. Unless you want mutable objects, records remove all the need for Lombok-generated getters on your custom Java classes.

@Setter is already non-existent for records. Nor will you need it for immutable objects. Every record has a compact construct that suits your needs for immutable objects.

And this is all fine for folks with the pleasure of working with Java 17. But what about those who work with older Java versions?

Most forget that Java upgrades aren’t a non-event in some projects. These features make their Java development easier. So people depend on these features.

Another trait of using Lombok on older codebases, upgrades could wreak havoc. Even though you have delombok, that can backfire in certain use cases.

Here’s a developer’s insight into how delombok doesn’t work as expected:

The urban myth said that moving away from Lombok was a one-step process using delombok to produce the expanded code to replace your annotated files. However, the generated files were extremely ugly and not following any styling, I don’t remember all the problems that we faced. But one example was the use of @NonNull annotations that were converted to many lines using if/throw blocks instead of one-line solutions like Guava Preconditions or Validate from Apache Commons. This should have been expected because makes sense to have the generated code with vanilla Java instead of adding more dependencies, but nobody realizes the real work needed to perform this transition until it’s needed. We ended modifying the implementation of the annotated files instead of using the delomboked files, which was a lot of work. In this situation, many people might prefer to leave Lombok there, but my main concern was what would happen if eventually a migration is really needed to support a major Java upgrade (right now Lombok is still facing problems with Java 9–11), so we preferred to avoid that concern and solve the problem of boilerplate code later.

Use annotations sparingly and where they seem fit. Don’t trust delombok so much as the generated code can be even worse.

You need to know the annotation's inner workings beforehand

Some features of Lombok are forgotten and unused. As an example, Lombok does have withers. But no one heard of them because of the big brother @Builder.

And that’s so for a reason.

@Builder is memory friendlier option than @With.

@Builder isn't related to the number of properties. This annotation only creates the instance of the builder and the instance.

@With creates a new instance for each property. This is a consequence as each intermediate needs to be immutable.

This is just a single example of when annotations can make or break your development experience. But Java as a language evolves to counter these anomalies.

So you won’t even need to learn all of these inner workings. The previous example was record, you now don’t need @Value and you don't care any longer about that annotation.

The same will happen with @With. When withers land we'll forget this annotation. A lot of care is taken to land withers, so they're still not in Java releases.

Lombok can help with the obstacles they’ve faced with this annotation. Discussions around Lombok’s withers are a gold mine for designing Java language features. Or at least they help me understand the problems of withers.

For example, if you look into the comments for the WithBy issue you’ll see the problems Valhalla and Amber will solve. For example, self-referential types, which primitive Valhalla types won’t let happen. And that’s why this problem needs a language solution.

Java
Lombok
Getters And Setters
Java17
Java8
Recommended from ReadMedium