28

I want to have an easy way to construct test data and have found the Builder pattern to be a good fit as described here. However to reduce boilerplate codes in the component tests, even more, I have found @Builder from Project Lombok to be a nice candidate to try. However, I can't find any documentation or online examples on how to use it on a method. I want to use @Builder on some sort of factory method since I can't make any changes to the implementation.

Can someone give an example on how to actually use @Builder on a method?

roottraveller
  • 7,942
  • 7
  • 60
  • 65
user3139545
  • 6,882
  • 13
  • 44
  • 87

2 Answers2

41

This is how you use @Builder.

//Employee.Java
import lombok.Builder;
import lombok.ToString;

@Builder
@ToString
public class Employee {
   private final String empName;
   private final int salary;
}

//   Main.java

public class Main {

public static void main(String[] args) {
    Employee emp = Employee.builder().empName("Deendaya").salary(100).build();
    System.out.println(emp);
  }
}
Martin Wallgren
  • 503
  • 5
  • 11
Deendayal Garg
  • 5,030
  • 2
  • 19
  • 33
  • Quite neat explanation. – whitehat Nov 21 '17 at 01:07
  • 17
    This does not answer the question: Can someone give an examle on how to actualy use @Builder on a method? – Jeff Dec 08 '17 at 19:39
  • 1
    This is the right answer and [here](https://projectlombok.org/features/Builder) you are told a clear example: `Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();` can be used if you add @Builder annotation to the `Person` class. – joninx Jan 09 '18 at 09:13
  • 10
    @russellhoff It's not actually. The question was specifically about using `@Builder` on a method, not on class level. The [lombok documentation](https://projectlombok.org/features/Builder) has a brief example for class level only, and from the description it's not easy to tell how to use it on method level. – Jens Hoffmann Jan 09 '18 at 14:02
  • @JensHoffmann you're right, OP wanted to know its usage on method level and the official documentation, which is actually quite a mess, doesn't explain it clearly. – joninx Jan 10 '18 at 13:52
  • It's explained cleaner,more simple and more detailed in these link https://www.baeldung.com/lombok-builder-custom-setter and https://www.baeldung.com/lombok-builder – fgul Jan 26 '19 at 16:16
33

Using @Builder on method to create a Dog and Cat instance.

In this example @Value creates a final immutable value object with accessor methods (getters), an all args constructor, equals(), hashCode() and toString().

import static org.junit.Assert.*;
import lombok.Builder;
import lombok.Value;

import org.junit.Test;

@SuppressWarnings("javadoc")
public class ImmutableAnimals {

    @Builder(builderMethodName = "dogBuilder")
    public static Dog newDog(String color, String barkSound) {
        return new Dog(color, barkSound);
    }

    @Builder(builderMethodName = "catBuilder")
    public static Cat newCat(String color, String meowSound) {
        return new Cat(color, meowSound);
    }

    public static interface Animal {
        String getColor();
    }

    @Value
    public static class Cat implements Animal {
        String color;
        String meowSound;
    }

    @Value
    public static class Dog implements Animal {
        String color;
        String barkSound;
    }

    @Test
    public void testDog() {
        final String expectedBarkSound = "woof";
        final String expectedColor = "brown";

        final Dog dog = ImmutableAnimals.dogBuilder()
            .barkSound(expectedBarkSound)
            .color(expectedColor)
            .build();

        assertEquals(expectedBarkSound, dog.getBarkSound());
        assertEquals(expectedColor, dog.getColor());
    }

    @Test
    public void testCat() {
        final String expectedMeowSound = "purr";
        final String expectedColor = "white";

        final Cat cat = ImmutableAnimals.catBuilder()
            .meowSound(expectedMeowSound)
            .color(expectedColor)
            .build();

        assertEquals(expectedMeowSound, cat.getMeowSound());
        assertEquals(expectedColor, cat.getColor());
    }
}

Here's another example with the same domain classes but using mutable values. However, as always favor immutability whenever possible.

import static org.junit.Assert.*;
import lombok.Builder;
import lombok.Data;

import org.junit.Test;

@SuppressWarnings("javadoc")
public class MutableAnimals {

    @Builder(builderMethodName = "dogBuilder")
    public static Dog newDog(String color, String barkSound) {
        final Dog dog = new Dog();
        dog.setBarkSound(barkSound);
        dog.setColor(color);
        return dog;
    }

    @Builder(builderMethodName = "catBuilder")
    public static Cat newCat(String color, String meowSound) {
        final Cat cat = new Cat();
        cat.setMeowSound(meowSound);
        cat.setColor(color);
        return cat;
    }

    public static interface Animal {
        String getColor();
    }

    @Data
    public static class Cat implements Animal {
        String color;
        String meowSound;
    }

    @Data
    public static class Dog implements Animal {
        String color;
        String barkSound;
    }

    @Test
    public void testDog() {
        final String expectedBarkSound = "woof";
        final String expectedColor = "brown";

        final Dog dog = MutableAnimals.dogBuilder()
            .barkSound(expectedBarkSound)
            .color(expectedColor)
            .build();

        assertEquals(expectedBarkSound, dog.getBarkSound());
        assertEquals(expectedColor, dog.getColor());
    }

    @Test
    public void testCat() {
        final String expectedMeowSound = "purr";
        final String expectedColor = "white";

        final Cat cat = MutableAnimals.catBuilder()
            .meowSound(expectedMeowSound)
            .color(expectedColor)
            .build();

        assertEquals(expectedMeowSound, cat.getMeowSound());
        assertEquals(expectedColor, cat.getColor());
    }
}
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
Jeff
  • 3,712
  • 2
  • 22
  • 24