Add Custom Validations With Lombok Builders


Categories: java

Introduction

Project Lombok will be able to generate the builder pattern class to make a java bean as immutable. But for some use cases you might need to add custom property validations while building an object. Lets go through lombok features to see how it can help us solve this.

See It In Action

Lombok doesn’t generate any code if you implement something to complement with it’s code generation like getters, setter or any other methods. Lets use this feature to solve the custom validations within builders.

Lets say we have a Customer class like this.

public class Customer {
    private long id;
    private String name;
}

Now we would like to make it as an immutable class with builder pattern so lombok can generate it for us. Inorder to do this we need to add @Builder annotation for this class.

@Getter
@EqualsAndHashCode
@ToString
@Builder(builderClassName = "Builder")
public class Customer {
    private long id;
    private String name;
}

We have a builder ready for us now but without any validations of Customer properties. Lets imagine for our case we need to add validations like id cannot negative or zero and name cannot be null or empty.

@Getter
@EqualsAndHashCode
@ToString
@Builder(builderClassName = "Builder",buildMethodName = "build")
public class Customer {
    private long id;
    private String name;

    static class Builder {
        Customer build() {
            if (id < 0) {
                throw new RuntimeException("Invaid id");
            }
            if (Objects.isNull(name)) {
                throw new RuntimeException("name is null");
            }
            return new Customer(id, name);
        }
    }
}

Remeber we said that lombok won’t generate the code which we implemented for, here we have implemented the build method inside the Builder class and we specified that use the build as buildMethodName using lombok annotations so lombok won’t generate the build method instead simply use the one we implemented.

Lets write some tests to make sure this will work.

public class CustomerTest {

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @Test
    public void testValidCustomer() {
        Customer.Builder customer = Customer.builder();
        customer.id(100);
        customer.name("bob");
        Assert.assertNotNull("Customer not built", customer.build());
    }

    @Test
    public void testInvalidCustomer() {
        expectedException.expect(RuntimeException.class);
        expectedException.expectMessage("name is null");
        Customer.Builder customer = Customer.builder();
        customer.id(100);
        Assert.assertNull("Customer shouldn't built", customer.build());
    }
}

I have two tests testValidCustomer for valid customer and testInvalidCustomer for invalid where not providing the name, both tests passed as expected.

This way we can add any type of validations we want with lombok with eliminating lot of boilerplate code. There are other alternatvies for this type of use cases which eliminate boilerplate code like immutables, AutoValue etc…

References

See also

comments powered by Disqus