Backend Development 13 min read

Lombok: Shortcut or Technical Debt? Lessons from a Year of Using Java Boilerplate Reduction

After a year of using Project Lombok, the author reflects on its initial appeal for reducing Java boilerplate, then reveals how hidden technical debt, version incompatibilities, reduced readability, and increased coupling can outweigh its benefits, urging teams to weigh its adoption carefully.

macrozheng
macrozheng
macrozheng
Lombok: Shortcut or Technical Debt? Lessons from a Year of Using Java Boilerplate Reduction

If you are reading this article, you probably already have some familiarity with Project Lombok. Are you ready to embrace Lombok, or are you considering recommending this cool library to your team? Before you decide, consider the author's reflections after a year of using Lombok.

Lombok is a useful Java library that lets you write less code while looking cool; a few simple annotations can eliminate a large amount of boilerplate. However, most source code is read, and only a little is executed .

One year ago, like most people, I believed Lombok would improve the Java coding experience and strongly recommended it to my team. After a year, I began to have concerns, especially when upgrading the Java version of the open‑source blog system Una‑Boot. I realized Lombok had fallen into a trick trap. Analyzing its source code and understanding the annotations, I found I did not need a non‑standard third‑party library to make Java code look sleek. Introducing Lombok gave a short‑term thrill, but the price was accumulating technical debt as the project progressed.

The Beginning of Love, the Origin of Hate

When you see the many "magic moves" Lombok offers, you won’t mind adding a plugin to your IDE. For IntelliJ IDEA users, just search for "Lombok Plugin" and install it. Falling in love with Lombok starts with installing the plugin, and the hate begins from there.

Before using Lombok, a typical JavaBean looks like this:

<code>public class MyObject {
    private Long id;
    private String name;
    private int age;
    private int gender;

    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public int getGender() { return gender; }
    public void setGender(int gender) { this.gender = gender; }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyObject obj = (MyObject) o;
        return age == obj.age && gender == obj.gender &&
               Objects.equals(id, obj.id) && Objects.equals(name, obj.name);
    }
    @Override
    public int hashCode() { return Objects.hash(id, name, age, gender); }
    @Override
    public String toString() {
        return "MyObject{" + "id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + "}";
    }
}
</code>

Every JavaBean is filled with such getter, setter, equals, hashCode, and toString boilerplate, making the code look "fat". After installing the Lombok plugin, the IDE recognizes the annotations and the code becomes much slimmer:

<code>@Getter
@Setter
public class MyObject {
    private Long id;
    private String name;
    private int age;
    private int gender;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyObject obj = (MyObject) o;
        return age == obj.age && gender == obj.gender &&
               Objects.equals(id, obj.id) && Objects.equals(name, obj.name);
    }

    @Override
    public int hashCode() { return Objects.hash(id, name, age, gender); }

    @Override
    public String toString() {
        return "MyObject{" + "id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + "}";
    }
}
</code>

You might think Lombok can only do this, but it can make your code even slimmer. By adding

@EqualsAndHashCode

, the equals and hashCode methods are generated automatically:

<code>@Getter
@Setter
@EqualsAndHashCode
public class MyObject {
    private Long id;
    private String name;
    private int age;
    private int gender;

    @Override
    public String toString() {
        return "MyObject{" + "id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + "}";
    }
}
</code>

Now the code looks much cleaner, but we can go further. Adding

@ToString

removes the need for a manual toString method:

<code>@Getter
@Setter
@EqualsAndHashCode
@ToString
public class MyObject {
    private Long id;
    private String name;
    private int age;
    private int gender;
}
</code>

Finally, Lombok provides a composite annotation

@Data

that replaces all the above annotations with a single line:

<code>@Data
public class MyObject {
    private Long id;
    private String name;
    private int age;
    private int gender;
}
</code>

Beyond these, Lombok offers other annotations such as

@Slf4j

,

@NoArgsConstructor

,

@AllArgsConstructor

, etc., but they are not the focus of this article.

Distorted Aesthetics, Hidden Risks

Using Lombok makes the code look sleek, but it also puts the code into an "sub‑healthy" state. Remember the earlier statement: All source code is mostly read, and only a little is executed.

In principle, we aim to reduce boilerplate to make code more concise and maintainable. Lombok achieves this by injecting methods at compile time, which is a clever trick but not intelligent or safe. It can break existing Java features and hurt readability. Below are the main pain points observed after using Lombok.

1. JDK Version Issues

When upgrading a project from Java 8 to Java 11, Lombok stopped working. I had to remove all Lombok annotations and let the IDE generate getters, setters, equals, hashCode, toString, and constructors, or use the Delombok tool. This consumes a lot of time.

2. Forced Adoption

If your code uses Lombok, anyone who depends on your code must also install the Lombok plugin and understand its annotations; otherwise the code will not compile. This feels intrusive.

3. Poor Readability

Lombok hides the details of JavaBean encapsulation. For example,

@AllArgsConstructor

generates a massive constructor that allows external code to set every field, which can be unsafe. With many fields, the generated constructor has dozens of parameters in an order controlled by Lombok, making debugging difficult. Before running the code, you can only imagine what the methods look like.

4. Increased Code Coupling

When a module uses Lombok, all dependent modules must also include Lombok as a dependency and install the plugin. This invasive coupling can become disastrous when combined with JDK version problems.

5. Cost vs Benefit

Lombok feels great at first, but it pollutes the code, harms Java’s integrity, readability, and safety, and adds technical debt. If you want concise code while preserving readability and efficiency, consider using mainstream JVM languages such as Scala or Kotlin.

Conclusion

Lombok is an excellent Java library that provides syntactic sugar to simplify code and reduce boilerplate. However, it is not a standard Java library. Using Lombok increases team technical debt, reduces code readability, and raises coupling and debugging difficulty. While it reduces boilerplate, it also introduces unknown risks. If you are working on a team or large project, discuss carefully with your team before deciding whether to adopt Lombok.

code qualitytechnical debtLombokBoilerplate
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.