Comparing Java Records with Lombok

Java records and Lombok are both tools that aim to reduce boilerplate code in Java, but they have different approaches and use cases. In this article we will compare them to understand which is the perfect use case of each approach.

Java Records overview:

  • Built-In Language Feature: Java records are a language feature introduced in Java 16, providing a concise way to declare immutable data-centric classes. They are part of the Java language itself, enabling simpler syntax for defining data classes.
  • Automatic Generation of Methods: Java records automatically generate equals(), hashCode(), and toString() methods based on the components, reducing the need for manual implementation.
  • Immutability by Default: Records create immutable objects by default, promoting safer data handling in applications.
  • Clear Intent: They are explicitly designed for data-centric classes, making the intent of the class clearer in terms of representing data structures.

For example:

public record Person(String name, int age, String address) {
    // Additional constructors, methods, or components can be added here
}

Lombok Library overview:

  • Compatibility with Older Java Versions: Lombok is a third-party library compatible with older Java versions (from Java 6 onwards), allowing developers to reduce boilerplate code in older projects.
  • Wide Range of Features: Lombok offers various annotations (@Getter, @Setter, @Builder, etc.) that can be applied to class fields to automatically generate getters, setters, builders, and more, enhancing developer productivity.
  • Customization and Flexibility: It provides more flexibility in terms of customizing the generated code or selectively applying annotations to specific fields or classes.
  • Ecosystem and Adoption: Lombok has a well-established ecosystem with widespread adoption, offering a wide array of features beyond just reducing boilerplate code.

For example:

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Student {
    private String name;
    private int age;
    private String department;

    // Constructor, methods, or additional annotations can be added here
}

Please note that, in order to use Lombok API, you need to include an external dependency in your Project:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version><!-- Specify the Lombok version --></version>
    <scope>provided</scope>
</dependency>

More details about Lombok and Java are discussed in this article: Speed up your Java coding with Lombok

Lombok vs Java Records: which to choose?

After a brief overview, let’s see which are the advantages and disadvantages of each solution:

Java Records

Advantages:

  • Java records are part of the Java language itself, so there is no need to add any additional dependencies to your project.
  • Java records are immutable, which makes them thread-safe and easier to reason about.
  • Java records are concise and expressive, which can make your code easier to read and write.

Disadvantages:

  • Java records do not support all of the features that Lombok does, such as constructors, builders, and custom annotations.
  • Java records may not have the same level of support in Development Environment such as Lombok. This is due to the fact that you need to configure and use a JDK compatible with Java Records

Lombok

Advantages:

  • Lombok is a library that can be used to generate boilerplate code, such as getters, setters, constructors, and builders.
  • Lombok is very flexible, as it supports a wide range of features.
  • Lombok is well-supported by IDEs, as IDEs typically have plugins that can help you use Lombok effectively.

Disadvantages:

  • Lombok is a third-party library, so you need to add it as a dependency to your project.
  • Lombok can make your code more difficult to read, as it can generate a lot of code that is not immediately obvious.
  • Lombok can be more difficult to troubleshoot, as errors in Lombok-generated code can be more difficult to track down.

In general, Java records are a good choice for simple, immutable data structures. Lombok is a good choice for more complex data structures that require more flexibility.

Here is a table summarizing the key differences between Java records and Lombok:

Lombok vs Java records

Java Records vs Lombok in JPA applications

The comparison of benefits between Java Records and Lombok becomes even more intricate when considering JPA applications, as each approach offers its own unique advantages and drawbacks.

In line of principle, you cannot use a Java Record to map directly a JPA Entity as you can read in this article: Writing JPA applications using Java Records . On the other hand, Java Record can still play well with JPA applications when you use them as carrier for JPA applications. For example to carry data to a JPA application which uses the Criteria API.

In contrast, the Lombok Library can map directly Java Entity Classes. For example:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity

public class User {
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String userName;
    private Integer age;
    private String address;
}

Even though you can map your Java Entity Classes with Lombok annotations, there are some caveats that you must be aware of:

  1. Use @Data sparingly: While @Data is convenient for generating boilerplate code, it can cause issues with JPA, particularly with bidirectional relationships. It’s generally recommended to use @Data selectively and only for simple entities.
  2. Be mindful of @EqualsAndHashCode and @ToString: These annotations can conflict with JPA’s entity identity and equality checks. To ensure data integrity, it’s recommended to explicitly define @Id, @EqualsAndHashCode, and @ToString annotations for JPA entities.
  3. Avoid @AllArgsConstructor for JPA entities: @AllArgsConstructor automatically generates constructors for all fields, which can interfere with JPA’s entity lifecycle management. Instead, use @RequiredArgsConstructor and explicitly specify the required fields in the constructor.
  4. Use @Builder judiciously: @Builder is a convenient way to create builder classes for constructing entities, but it can also lead to issues with JPA if not used carefully. Ensure that builder methods don’t modify entity state and don’t conflict with JPA lifecycle callbacks.

Conclusion

This article was a walk through Java Records and the Lombok library to discuss the advantages and disadvantages of each solution. In general, Java records are a perfect addition to Java language to code simple DTO. The Lombok framework allows more complex boilerplate reduction, at the price of some caveats in the usage.