Public version of CodeAPI BuilderGen.
BuilderGenerator generates the builder based on the source-code (CodeAPI BuilderGen generates builder based on class-file).
BuilderGenerator can only generate Java builders but supports all languages that generate Java Annotation Processing stubs
.
Classes generated by BuilderGenerator does not requires runtime-dependency
TODO
TODO
BuilderGenerator is designed to generate Builders for immutable objects, base classes must contains an inner class Builder<T, B extends Builder<T, B>>
, also we recommend you to have a Builder<BASE_CLASS, ?> builder()
method.
Base classes are classes that provide getter methods for properties. This class must provide a Builder
class that standardize builder methods. Builder methods (with
methods) can also provide property options, see @PropertyInfo documentation or Property specification section.
Example of valid base class:
interface Person {
String getName();
int getAge();
Builder<Person, ?> builder();
interface Builder<T extends Person, B extends Builder<T, B>> extends com.myproject.BaseBuilder<T, B> {
Builder<T, B> withName(String name);
Builder<T, B> withAge(int age);
// These methods are optional.
String getName();
String getAge();
}
}
A base Builder
class is recommended to provide a build()
method.
Note: BuilderGenerator provides a Builder
class, but is not recommended to extend this class (to avoid runtime-dependency on BuilderGenerator).
Example of BaseBuilder
:
interface BaseBuilder<T, B extends BaseBuilder<T, B>> {
T build();
}
Implementation class is a concrete class that implements the base class.
Example:
class PersonImpl implements Person {
private final String name;
private final int age;
public PersonImpl(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String getName() {
return this.name;
}
@Override
public int getAge() {
return this.age;
}
@Override
public Builder<Person, ?> builder() {
throw new UnsupportedOperationException();
}
}
To generate Builder class you need to annotate the constructor of the implementation class OR annotate a static factory method.
Annotated constructor example:
class PersonImpl implements Person {
private final String name;
private final int age;
@GenBuilder(base = Person.class)
public PersonImpl(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String getName() {
return this.name;
}
@Override
public int getAge() {
return this.age;
}
@Override
public Builder<Person, ?> builder() {
return new PersonBuilder(this);
}
}
Factory method example:
final class MyFactory {
@GenBuilder
public static Person personFactory(String name, int age) {
return new PersonImpl(name, age);
}
}
BytecodeGenerator provide a way to specify some property options like: value validator, default value provider and nullability.
To specify options for a property you need to annotate the base builder property method.
Example:
interface Person {
String getName();
int getAge();
Builder<Person, ?> builder();
interface Builder<T extends Person, B extends Builder<T, B>> extends com.myproject.BaseBuilder<T, B> {
Builder<T, B> withName(String name);
@PropertyInfo(validator = @Validator(@MethodRef(value = Validators.class, name = "positiveInt")))
Builder<T, B> withAge(int age);
// These methods are optional.
String getName();
String getAge();
}
}
By default, properties value cannot be null.
BuilderGenerator supports Optional properties. Only properties where the getter method in the base class returns a Optional<T>
instance are marked as optional property.
Example:
interface Person {
String getName();
int getAge();
Optional<LocalDate> getBirthDate();
Builder<Person, ?> builder();
interface Builder<T extends Person, B extends Builder<T, B>> extends com.myproject.BaseBuilder<T, B> {
Builder<T, B> withName(String name);
@PropertyInfo(validator = @Validator(@MethodRef(value = Validators.class, name = "positiveInt")))
Builder<T, B> withAge(int age);
// Make sure to accept non-Optional type. If you use Optional<LocalData> BuilderGenerator will not mark the property as 'optional property'.
Builder<T, B> withBirthDate(LocalDate birthDate);
// These methods are optional.
String getName();
String getAge();
Optional<LocalData> getBirthDate();
}
}
- Method Reference Validation
Builder
inner class validation- Default value provider and validator inlining (read @Inline javadoc).
- BuilderGenerator does not require a base
Builder<T, B extends Builder<T, B>>
class, but it is recommended to provide abuild()
method. - BuilderGenerator automatically generate null checks for non-null
Object
properties