Total Pageviews

2017/08/03

[Lombok] Utilize @Builder annotation to produce complex builder APIs for your classes

Problem
If you would like to apply builder pattern in your Java class, the class will looks like:
package albert.practice.designPattern.builder;

public class User {

    private String firstName;
    private String lastName;
    private String email;

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public String getEmail() {
        return email;
    }

    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.email = builder.email;
    }

    @Override
    public String toString() {
        return "User [firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + "]";
    }

    public static class UserBuilder {
        private String firstName;
        private String lastName;
        private String email;

        public UserBuilder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public UserBuilder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public UserBuilder email(String email) {
            this.email = email;
            return this;
        }

        public User build() {
            User user = new User(this);
            return user;
        }
    }
}


Compared with POJO class, you may notice the number of lines of code increase at least to double in builder pattern. Does it has any convenient approach to implement and yield the same benefit which builder pattern bring for us?

How-To
You can make good use of @Builder annotation which provide by Project Lombok. The updated code look like:
package albert.practice.designPattern.builder;

import lombok.Builder;
import lombok.Getter;
import lombok.ToString;

/*
 * The @Builder annotation produces complex builder APIs for your classes.
 * @Builder lets you automatically produce the code required to have your class be instantiable with code such as:
 * Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();
 */
@Builder
@Getter
@ToString
public class User2 {
    
    private String firstName;
    private String lastName;
    private String email;

}


Here is the test code:
package albert.practice.designPattern.builder;

import static org.junit.Assert.assertNotNull;

import org.junit.Test;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class UserTest {

    @Test
    public void testUser() {
        User user = new User.UserBuilder().firstName("Albert").lastName("Kuo")
                .email("test@gmail.com").build();
        log.debug("user = " + user.toString());
        assertNotNull(user);
    }

    @Test
    public void testUser2() {
        User2 user2 = new User2.User2Builder().firstName("Albert").lastName("Kuo")
                .email("test@gmail.com").build();
        log.debug("user2 = " + user2.toString());
        assertNotNull(user2);
    }

}



Maven dependencies are as bellows:
  <dependencies>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.8</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.21</version>
        </dependency>

        <!-- logback -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.1.7</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
        </dependency>
    </dependencies>

Reference
[1] https://projectlombok.org/features/Builder.html



No comments: