PROBLEM
Let’s assume we have an immutable Person
object:-
public final class Person implements Serializable { private final String name; private final Collection<Car> cars; public Person(final String name, final Collection<Car> cars) { this.name = name; this.cars = MoreObjects.firstNonNull(cars, ImmutableList.<Car>of()); } public String getName() { return name; } public Collection<Car> getCars() { return cars; } }
… and an immutable Car
object:-
public final class Car implements Serializable { private final String license; private final LocalDate boughtOn; public Car(final String license, final LocalDate boughtOn) { this.license = license; this.boughtOn = boughtOn; } public String getLicense() { return license; } public LocalDate getBoughtOn() { return boughtOn; } }
To create the Person
object, we need to write something like this:-
final Person person = new Person("Mike", Collections.singletonList( new Car("123", new LocalDate(2015, 1, 1))));
If the POJO has a lot of properties, it becomes very difficult to keep track all the constructor argument positions.
SOLUTION
@mkarneim wrote a POJO Builder that creates the builder class(es) at compilation time.
To pull this off, we need to add the following dependency with provided
scope.
<dependency> <groupId>net.karneim</groupId> <artifactId>pojobuilder</artifactId> <version>3.4.0</version> <scope>provided</scope> </dependency>
Next, annotate with the Person
constructor with @GeneratePojoBuilder
. Make the constructor visibility to protected
so that no one can directly instantiate that object.
public final class Person implements Serializable { private final String name; private final Collection<Car> cars; @GeneratePojoBuilder protected Person(final String name, final Collection<Car> cars) { this.name = name; this.cars = MoreObjects.firstNonNull(cars, ImmutableList.<Car>of()); } public String getName() { return name; } public Collection<Car> getCars() { return cars; } }
Do the same for Car
object:-
public final class Car implements Serializable { private final String license; private final LocalDate boughtOn; @GeneratePojoBuilder protected Car(final String license, final LocalDate boughtOn) { this.license = license; this.boughtOn = boughtOn; } public String getLicense() { return license; } public LocalDate getBoughtOn() { return boughtOn; }
Next, and this is probably the most important step… run mvn clean compile
to generate the builder classes. This allows the IDE to help us with code completion when using the builders.
Now, we can create the Person
object like this:-
final Person person = new PersonBuilder() .withCars(ImmutableList.of( new CarBuilder() .withBoughtOn(new LocalDate(2015, 1, 1)) .withLicense("123") .build())) .withName("Mike") .build();
If you are running the program directly from IntelliJ, we need to ensure the program is compiled using Maven. To do this, edit the configuration for the runner class:-
Remove the default Make task:-
Add Maven goals:-
Enter clean and compile:-
Now, when IntelliJ runs the program, the program will be compiled using Maven to ensure no compilation errors on the builder classes during execution.
hi, when i cant modify the pojo that provided by others. there are some tools to create builder for the pojo?