For example: I have an immutable cass Person.
The Builder the class can be named: PersonBuilder, Person.Builder or
Person.PersonBuilder. It depends on conventions. I'll use
PersonBuilder there.
Instantiation: there are some possibilities:
1. PersonBuilder can instantiate Person by a build() method. However,
I can make Person from PersonBuilder by constructor (new PersonBuilder
(aPerson)) or a static method (PersonBuilder.createFromPerson
(aPerson)). *So Person does not depend on its Builder.*
2. Person can instantiate PersonBuilder by a createBuilder() method.
However, PersonBuilder can instantiate Person by new Person
(aPersonBuilder) or Person.createFromBuilder(aPersonBuilder). It's
really crazy, I think.
3. Person can instantiate PersonBuilder by a createBuilder() method
and PersonBuilder can instantiate Person by a build() method.
There is my immutable class Person:
import lombok.Data;
public final @Data class Person {
private final String firstName;
private final String lastName;
private final Email email;
}
Now I'd like to create the PersonBuilder.
Independent version (first possibility - Person does not depend on the
Builder):
import lombok.BuilderFor;
@BuilderFor(Person.class) // Class Person has exactly one constructor.
Otherwise it causes an error.
public class PersonBuilderWithIndependentPerson {
}
I can specify the constructor:
import lombok.BuilderFor;
@BuilderFor(Person.class, method="Person
(String,String,com.somewhere.Email)")
public class PersonBuilderWithIndependentPerson {
}
If I want to use a static factory, not a constructor.
import lombok.BuilderFor;
@BuilderFor(forClass=PersonFactory.class, method="createPerson") //
Class Person has exactly one createPerson method. Otherwise it causes
an error.
public class PersonBuilderWithIndependentPerson {
}
I can specify the method:
import lombok.BuilderFor;
@BuilderFor(forClass=PersonFactory.class, method="createPerson(String,
String)") // e-mail is generated, loaded or null - it depends on
PersonFactory.createPerson(String, String)
public class PersonBuilderWithIndependentPerson {
}
There is an advantage: I can add custom methods to my Builder (e.g.
public void setEmail(String email){ setEmail(new Email
(email)); }).
There is one issue: it is neccessary to leave parameter names in
compiled code, I think. (I currently don't fully understand how do
these compile-time annotations work. So I am maybe wrong.)
Note that I've low experience with annotations, so you maybe know
better syntax (e.g. better syntax for method/constructor links).
You can also use third possibility (Person.createBuilder() and
PersonBuilder.build()):
import lombok.Data;
import lombok.Buildable;
public final @Buildable @Data class Person {// PersonBuilder class
will be created.
private final String firstName;
private final String lastName;
private final Email email;
}
It is also useful to can determine the name:
import lombok.Data;
import lombok.Buildable;
public final @Buildable(name="SpecialPersonBuilderName") @Data class
Person { // SpecialPersonBuilderName will be created.
private final String firstName;
private final String lastName;
private final Email email;
}
I think that @Buildable+@Data should use the constructor generated by
@Data. If you'd like to use another constructor, you must annotate the
constructor. It is simple, isnť it? However, it is not possible to use
more @Buildable annotations per class because of the createBuilder()
method.
Well, I'd like to have a custom methods in my PersonBuilder:
import lombok.Data;
import lombok.BuildableBy;
public final @BuildableBy(PersonBuilder.class) @Data class Person {//
@BuildableBy creates createBuilder() method and checks whether
PersonBuilder is Builder for this class.
private final String firstName;
private final String lastName;
private final Email email;
}
Now I have to create the PersonBuilder class:
import lombok.Data;
@BuilderForBuildable(Person.class)// this will also cause check that
Person or exactly one of its constructor is @BuildableBy
(PersonBuilder.class).
public class PersonBuilder {
{
// default values:
setFirstName("John");// it is null if not set
setLastName("Smith");// it is null if not set
// default value of email is null
}
public void setEmail(String email) {
setEmail(new Email(email));
}
}
Default values are also solved.
Note that I prefer name createBuilder() to newBuilder() because of the
verb.
Ad crazyPlan#2: I don't understand.