The Lombok Illusion (Chapter 5)
You open a new Spring Boot project and you create a DTO, then an entity, and you’re staring at getters, setters, constructors, equals() , hashCode() , toString() . Someone on the team suggests to put lombok’s @Data , or “just slap @Builder on it, it’ll be cleaner.” Forty lines become five and it looks great in the PR. Then it hits a real codebase, OpenAPI generation doesn't behave the way the…
In the corporate landscape of Java development, a common approach observed is the utilization of Lombok annotations to streamline code generation. A prime example is the @Data annotation, which facilitates the creation of getters, setters, constructors, equals(), hashCode(), and toString() methods with just a single line of code. The convenience of this approach is undeniable, as it reduces boilerplate and enables faster development. However, the underlying trade-offs often go unnoticed until issues arise.
When Lombok annotations are employed, the generated code - getters, setters, and other methods - is abstracted away from the developer. While this may seem advantageous at first glance, it introduces a significant drawback: the behavior becomes hidden, residing in a separate step that is not immediately visible within the source code. Consequently, debugging becomes more challenging, as the generated code is not easily accessible to the developer.
This abstraction is particularly problematic when dealing with core application behavior such as getters, setters, constructors, equals(), hashCode(), and toString(). These elements form the public API of an object and should be directly visible, searchable, and debuggable. Generating them with Lombok violates this principle, as the behavior remains intact but is concealed from the developer. Lombok annotations may provide convenience in the short term, but they can lead to hidden complexities down the line.
The annotation most frequently employed is @Data, which automatically generates getters, setters, toString(), equals(), and hashCode() for all fields within a JPA entity. This approach presents a problem even before any business logic is implemented. An entity inherently carries persistence identity, lazy proxies, mutable state, and more, which does not align with the characteristics of a plain data bag. Field-based equality ignores identity semantics entirely, leading to potential issues down the road.
Moreover, generated toString() methods that walk relationships can pose logging hazards. When invoked at the wrong moment, they may trigger database calls, resulting in recursion in logs and potentially crashing the logging pipeline. This issue has been observed to crash logging pipelines rather than simply producing ugly output. Additionally, if the persistence context is closed by the time the log is generated, it may throw a LazyInitializationException, confusing the actual issue with the logging code.
While Builders offer an alternative to Lombok annotations, they are not entirely free from drawbacks either. @Builder, the most commonly used annotation, provides a cleaner constructor and more readable construction at the call site. However, it does not guarantee good architecture underneath. For immutable request models, a record can be a better choice, offering all the necessary components - constructor, accessors, equals(), hashCode(), toString() - generated by the language itself without the need for annotation processors or generated builder classes.
The one annotation that demands cautious consideration is @SuperBuilder. Inheritance already makes domain models more complex to follow, and adding generated nested builders and field shadowing on top of ORM concerns can introduce bugs that compile fine but fail later. Null fields that nobody set on purpose, updates silently dropping values, and database rows that appear technically valid while the business state is quietly wrong are all potential consequences.
Debugging such issues can prove time-consuming, as the generated code may not align with the compiler's view, leading to disagreements between frameworks and tools in the build process.
In conclusion, while Lombok annotations offer convenience in the short term, they introduce hidden complexities that can lead to debugging challenges, obscure core application behavior, and create discrepancies across various tools and JDK versions. Developers are encouraged to weigh the trade-offs carefully and consider alternative approaches, such as writing code by hand, to maintain control over their source code and ensure a more robust and maintainable codebase.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — it may contain errors, so check the original before relying on it.