Skip to content

Latest commit

 

History

History
209 lines (146 loc) · 5.75 KB

README.md

File metadata and controls

209 lines (146 loc) · 5.75 KB

BuilderGenerator

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

How to use

Setup annotation processing

TODO

API

TODO

Builder

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

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

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();
    }
}

Generating builder class

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);
    }
}

Property specification

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.

Optional properties

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();
    }
}

Features

  • Method Reference Validation
  • Builder inner class validation
  • Default value provider and validator inlining (read @Inline javadoc).

Notes

  • BuilderGenerator does not require a base Builder<T, B extends Builder<T, B>> class, but it is recommended to provide a build() method.
  • BuilderGenerator automatically generate null checks for non-null Object properties