KapreSoft
Thank you for unblocking ads; your support allows us to continue delivering free, high-quality content that truly matters to you.

Lombok • Using @With Annotation to Clone Immutable Objects

 
 

Overview

Using Lombok’s @With Annotation to Clone Immutable Objects is a beneficial feature that helps developers minimize code replication and ceremonial code. It is the next best alternative to Copy Constructs in object-oriented programming. The @With annotation also requires @AllArgsConstructor to function correctly.

Project

For rapid application development the maven project provided in this example used the spring initializr page https://start.spring.io to generate the initial source code.

The source code referenced by this article can be found at https://github.com/kapresoft/lombok-with.

Use Case

In this simple example, we will model a resident of a house. The Resident class can be modeled in Lombok as:

@Value @Builder
public class Resident {

    @With
    String fullName;
    @With
    String phoneNumber;
    String streetAddress;
    String city;
    String state;
    String zipCode;
    String country;

}

Source: Resident.java

In order to utilize the power @With annotation, you must use it in conjunction with @AllArgsConstructor. In the above class definition, @Value is used. The @Value is a simplification for configuring a class with immutable fields.

The @Value annotation can be similarly modeled by @Getter and final fields and other annotations as shown below:

@Getter 
@FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE) 
@AllArgsConstructor 
@ToString 
@EqualsAndHashCode
public class Resident {
    @Getter @With
    private final String fullName;
    // ... etc
}

Please Refer to Lombok • Builders and Copy Constructors for more details on immutable objects in Lombok.

A few thing worth mentioning is that you must adhere to Lombok’s class field naming convention. Static fields are not supported by @With and $ symbols are ignored.

A single resident can then be created and verified as:

@Test
void createSingleResident() {
    final Resident johnDoe = Resident.builder()
            .streetAddress("100 Main St")
            .city("Bellevue").state("WA")
            .fullName("John Doe")
            .phoneNumber("425-555-1000")
            .city("Bellevue").state("WA").zipCode("98004")
            .build();
    assertThat(johnDoe.getFullName()).as("Full Name")
            .isEqualTo("John Doe");
    assertThat(johnDoe.getPhoneNumber()).as("Phone Number")
            .isEqualTo("425-555-1000");
    assertThat(johnDoe.getCity()).as("City")
            .isEqualTo("Bellevue");
    assertThat(johnDoe.getState()).as("State")
            .isEqualTo("WA");
    assertThat(johnDoe.getState()).as("ZipCode")
            .isEqualTo("98004");
}

Source: ResidentTest.java

Suppose there are two other residents. Those additional residents can be cloned from the existing immutable instance johnDoe. A newly created clone and immutable Resident objects janeDoe and teenageDaughter with a slightly different information modified by withFullName(String) and withPhoneNumber(String) methods.

@Test
void createResidents() {
    final Resident johnDoe = Resident.builder()
            .streetAddress("100 Main St")
            .city("Bellevue").state("WA")
            .fullName("John Doe")
            .phoneNumber("425-555-1000")
            .city("Bellevue").state("WA").zipCode("98004")
            .build();
    assertThat(johnDoe.getFullName()).as("Full Name")
            .isEqualTo("John Doe");
    assertThat(johnDoe.getPhoneNumber()).as("Phone Number")
            .isEqualTo("425-555-1000");

    final Resident janeDoe = johnDoe
            .withFullName("Jane Doe")
            .withPhoneNumber("425-555-1001");
    assertThat(janeDoe.getFullName()).as("Full Name")
            .isEqualTo("Jane Doe");
    assertThat(janeDoe.getPhoneNumber()).as("Phone Number")
            .isEqualTo("425-555-1001");

    final Resident teenageDaughter = johnDoe.withFullName("Jennifer Doe")
            .withPhoneNumber("425-555-1002");
    assertThat(teenageDaughter.getFullName()).as("Full Name")
            .isEqualTo("Jennifer Doe");
    assertThat(teenageDaughter.getPhoneNumber()).as("Phone Number")
            .isEqualTo("425-555-1002");

}

Source: ResidentTest.java

Class, Field and Access Level Configuration

The @With annotation is a class or field-level annotation.

Class Level

In the main example, the @With was placed at the field-level. In this example, a class-level @With annotation means that a ‘with’ method is generated for each and every field.

@Value @Builder @With
public class Resident {

    String fullName;
    String phoneNumber;
    String streetAddress;
    String city;
    String state;
    String zipCode;
    String country;

}
final Resident johnDoe = Resident.builder()
            .streetAddress("100 Main St")
            .city("Bellevue").state("WA")
            .fullName("John Doe")
            .phoneNumber("425-555-1000")
            .city("Bellevue").state("WA").zipCode("98004")
            .build();

final Resident janeDoe = johnDoe
        .withFullName("Jane Doe")
        .withPhoneNumber("425-555-1001")
        .withStreetAddress("100 Rodeo Drive")
        .withCity("Beverly Hills")
        .withState("CA")
        .withZipCode("90210");

Access Level

The @With may also be configured with an access level:

@With(value = AccessLevel.PACKAGE)
String fullName;

The above configuration will produce a method:

Resident withFullName(String fullName) {
        // ... function body here ...
}

Summary

This article covered how to use Lombok’s @With annotation at a class and field level; an example use-case to generate clones of immutable objects with a change in multiple fields. We also covered configuring the method access level (private, protected, public, or package-level) of the generated “with” methods in Lombok.

Full code examples are available at Github https://github.com/kapresoft/lombok-with.

Suggested Reading


Lombok • The Good, The Bad, and The Ugly
Within the Java development community, Lombok often emerges as a polarizing subject. This library’s chief aim is to minimize the tedium of boilerplate code—a persistent thorn in the side of many Java developers. Nevertheless, every tool brings its own concessions to the table.
Lombok • @Value Annotation Best Practices
When it comes to clean coding and enhanced testability in Java applications, Project Lombok is a game-changer. Its @Value annotation not only simplifies your code but also enhances its readability, maintainability, and testability.
Lombok • @Data Annotation Best Practices
When it comes to clean and efficient Java coding, the power of Project Lombok cannot be overstated. Specifically, the @Data annotation provided by Lombok stands out as a valuable tool for Java developers.
Cleaner Code and Enhanced Testability: Harnessing the Power of Lombok Builders
In the realm of Java development, the quest for cleaner code and improved testability is ever-present. One formidable ally in this quest is Project Lombok, a mature library that revolutionizes the way Java developers handle boilerplate code.
Lombok val vs var
Lombok has gained immense popularity among Java developers for its ability to simplify coding practices by reducing boilerplate code. In the vast ocean of features offered by Lombok, two features stand out: val and var. In this deep dive, we’ll uncover the secrets of these two variables and demonstrate their utility.
Lombok Test Coverage
When it comes to software development, testing plays a crucial role in ensuring the quality and reliability of the codebase. Test coverage, in particular, is a metric that measures the extent to which the source code of a program has been tested.
Lombok Disadvantages
In the world of Java development, optimizing code efficiency and reducing boilerplate is a constant pursuit. To address these challenges, various tools and libraries have emerged, and one such popular option is Lombok—a Java library that offers annotations for code generation, resulting in benefits such as time-saving and code simplification. However, as with any tool, there are both advantages and drawbacks to consider.
Lombok @Singular Annotation
Lombok is a Java library that provides a set of annotations and utility classes to reduce boilerplate code in Java projects. One of its popular annotations is @Singular, which generates builder methods for collections.
Java • Avoid Getters & Setters Methods With Lombok
This article provides an overview of how to avoid the repetitive code associated with writing getter and setter methods in Java classes using Lombok. By using Lombok’s annotations, such as @Getter and @Setter, developers can generate these methods automatically, thereby reducing the amount of boilerplate code required in their classes.
Lombok • @AllArgsConstruct vs @RequiredArgsConstructor
What is the difference between @AllArgsConstruct and @RequiredArgsConstructor in Lombok? The main difference between @AllArgsConstructor and @RequiredArgsConstructor is in the fields that are included in the generated constructor.
Lombok • How to Use Constructor
To use the constructor with Lombok, you can annotate your class with @AllArgsConstructor or @RequiredArgsConstructor. @AllArgsConstructor generates a constructor that takes in all the fields in the class as arguments, while @RequiredArgsConstructor generates a constructor that takes in only the final or @NonNull fields as arguments.
Lombok • An Overview
Lombok is a Java library that provides annotations to help reduce boilerplate code and increase developer productivity. By using Lombok annotations, Java developers can automatically generate common code such as getters, setters, constructors, equals and hashCode methods, and more.
Lombok • Exclude Generated Code From Test Coverage
When using Lombok in a Java project, the library generates code at compile-time, such as getters, setters, constructors, equals and hashCode methods, and more.
Lombok • Builders and Copy Constructors
Lombok’s builder and copy constructor feature using @Builder is a mechanism that allows the implementation of the Builder Pattern and Copy Constructors in Object-Oriented Programming. This article further illustrates how Lombok mitigates the disadvantages of creating builder methods and copy constructors making Lombok’s @Builder a good foundation for design and code maintainability.