The Helidon Builder provides compile-time code generation for fluent builders. It was inspired by Lombok, but the implementation here in Helidon is different in a few ways:
- The Builder annotation targets interface or annotation types only. Your interface effectively contains the attributes of your getter as well as serving as the contract for your getter methods.
- Generated classes implement your target interface (or annotation) and provide a fluent builder that will always have an implementation of toString(), hashCode(), and equals(). implemented
- Generated classes always behave like a SuperBuilder from Lombok. Basically this means that builders can form a hierarchy on the types they target (e.g., Level2 derives from Level1 derives from Level0, etc.).
- Lombok uses AOP while the Helidon Builder generates source code. You can use the Builder annotation (as well as other annotations in the package and ConfiguredOption) to control the naming and other features of what and how the implementation classes are generated and behave.
- Builders are extensible - you can provide your own implementation of the Builder Processor SPI to customize the generated classes for your situation.
Supported annotation types (see builder for further details):
- Builder - similar to Lombok's SuperBuilder.
- Singular - similar to Lombok's Singular.
- NonNull - accomplished alternatively via Helidon's ConfiguredOption#required.
- Default - accomplished alternatively via Helidon's ConfiguredOption#value.
Explicitly unsupported (i.e., these are just a few of the types that do not have a counterpart from Helidon's Builder):
- NoArgsConstructor - must instead use one of the toBuilder() methods
- AllArgsConstructor - must instead use one of the toBuilder() methods
Any and all types are supported by the Builder, with special handling for List, Map, Set, and Optional types. The target interface, however, should only contain getter like methods (i.e., has a non-void return and takes no arguments). All static and default methods are ignored on the target being processed.
The Helidon Builder is independent of other parts of Helidon. It can therefore be used in a standalone manner. The generated implementation class will not require any special module to support those classes - just the types from your interface and standard JRE types are used. This is made possible when your Builder has the requireBuilderLibrary=false. See the javadoc for details.
- Write your interface that you want to have a builder for.
public interface MyConfigBean {
String getName();
boolean isEnabled();
int getPort();
}- Annotate your interface definition with Builder, and optionally use ConfiguredOption, Singular, etc. Remember to review the annotation attributes javadoc for any customizations.
- Compile (using the builder-processor in your annotation classpath).
The result of this will create (under ./target/generated-sources/annotations):
- MyConfigBeanImpl (in the same package as MyConfigBean) that will support multi-inheritance builders named MyConfigBeanImpl.Builder.
- Support for toString(), hashCode(), and equals() are always included.
- Support for toBuilder().
- Support for streams (see javadoc for Builder).
- Support for attribute visitors (see test-builder).
- Support for attribute validation (see ConfiguredOption#required() and test-builder).
- Support for builder interception (i.e., including decoration or mutation). (see test-builder).
- builder - provides the compile-time annotations, as well as optional runtime supporting types.
- processor-spi - defines the Builder Processor SPI runtime definitions used by builder tooling. This module is only needed at compile time.
- processor-tools - provides the concrete creators & code generators. This module is only needed at compile time.
- processor - the annotation processor which delegates to the processor-tools module for the main processing logic. This module is only needed at compile time.
- tests/builder - tests that can also serve as examples for usage.
To implement your own custom Builder:
- See pico/builder-config for an example.
See tests/builder for usage examples.