Skip to content

Commit 5ccca37

Browse files
authored
New config builders (helidon-io#7008)
* Plugin version updates * Builder API changes and associated changes to common project * Pico changes (config driven, new builder APIs) * Config changes (new builder API, metadadata updates) * Changes required after changes to common modules and builders * Nima changes * BOM POM * Tests update * Examples * Integration test fixes (and related fixes in production code). * Make sure we do not require transitive dependency on Config for Builder. * Archetype fix
1 parent 823bfd9 commit 5ccca37

914 files changed

Lines changed: 33451 additions & 29993 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

archetypes/helidon/src/main/archetype/nima/common/files/src/main/java/__pkg__/Main.java.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public final class Main {
3737
3838
WebServer server = WebServer.builder()
3939
.routing(Main::routing)
40+
.build()
4041
.start();
4142
4243
System.out.println("WEB server is up! http://localhost:" + server.port() + "/greet");

bom/pom.xml

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,16 @@
681681
<artifactId>helidon-common-types</artifactId>
682682
<version>${helidon.version}</version>
683683
</dependency>
684+
<dependency>
685+
<groupId>io.helidon.common.processor</groupId>
686+
<artifactId>helidon-common-processor</artifactId>
687+
<version>${helidon.version}</version>
688+
</dependency>
689+
<dependency>
690+
<groupId>io.helidon.common.processor</groupId>
691+
<artifactId>helidon-common-processor-helidon-copyright</artifactId>
692+
<version>${helidon.version}</version>
693+
</dependency>
684694
<dependency>
685695
<groupId>io.helidon.common.testing</groupId>
686696
<artifactId>helidon-common-testing-junit5</artifactId>
@@ -1395,6 +1405,11 @@
13951405
<artifactId>helidon-nima-fault-tolerance</artifactId>
13961406
<version>${helidon.version}</version>
13971407
</dependency>
1408+
<dependency>
1409+
<groupId>io.helidon.nima.fault-tolerance</groupId>
1410+
<artifactId>helidon-nima-fault-tolerance-processor</artifactId>
1411+
<version>${helidon.version}</version>
1412+
</dependency>
13981413
<dependency>
13991414
<groupId>io.helidon.nima.openapi</groupId>
14001415
<artifactId>helidon-nima-openapi</artifactId>
@@ -1404,39 +1419,14 @@
14041419
<!-- Builder -->
14051420
<dependency>
14061421
<groupId>io.helidon.builder</groupId>
1407-
<artifactId>helidon-builder</artifactId>
1408-
<version>${helidon.version}</version>
1409-
</dependency>
1410-
<dependency>
1411-
<groupId>io.helidon.builder</groupId>
1412-
<artifactId>helidon-builder-processor-spi</artifactId>
1413-
<version>${helidon.version}</version>
1414-
</dependency>
1415-
<dependency>
1416-
<groupId>io.helidon.builder</groupId>
1417-
<artifactId>helidon-builder-processor-tools</artifactId>
1422+
<artifactId>helidon-builder-api</artifactId>
14181423
<version>${helidon.version}</version>
14191424
</dependency>
14201425
<dependency>
14211426
<groupId>io.helidon.builder</groupId>
14221427
<artifactId>helidon-builder-processor</artifactId>
14231428
<version>${helidon.version}</version>
14241429
</dependency>
1425-
<dependency>
1426-
<groupId>io.helidon.builder</groupId>
1427-
<artifactId>helidon-builder-config</artifactId>
1428-
<version>${helidon.version}</version>
1429-
</dependency>
1430-
<dependency>
1431-
<groupId>io.helidon.builder</groupId>
1432-
<artifactId>helidon-builder-config-processor</artifactId>
1433-
<version>${helidon.version}</version>
1434-
</dependency>
1435-
<dependency>
1436-
<groupId>io.helidon.builder</groupId>
1437-
<artifactId>helidon-builder-testing</artifactId>
1438-
<version>${helidon.version}</version>
1439-
</dependency>
14401430

14411431
<!-- Pico Core -->
14421432
<dependency>

builder/README.md

Lines changed: 39 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,49 @@
1-
# builder
1+
# Helidon Builder
22

3-
The <b>Helidon Builder</b> provides compile-time code generation for fluent builders. It was inspired by [Lombok]([https://projectlombok.org/), but the implementation here in Helidon is different in a few ways:
4-
<ol>
5-
<li>The <i>Builder</i> 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.</li>
6-
<li>Generated classes implement your target interface (or annotation or abstract class) and provide a fluent builder that will always have an implementation of <i>toString(), hashCode(), and equals().</i> implemented</li>
7-
<li>Generated classes always behave like a <i>SuperBuilder</i> from Lombok. Basically this means that builders can form
8-
a hierarchy on the types they target (e.g., Level2 derives from Level1 derives from Level0, etc.).</li>
9-
<li>Lombok uses AOP while the Helidon Builder generates source code. You can use the <i>Builder</i> annotation (as well as other annotations in the package and <i>ConfiguredOption</i>) to control the naming and other features of what and how the implementation classes are generated and behave.</li>
10-
<li>Builders are extensible - you can provide your own implementation of the <b>Builder Processor SPI</b> to customize the generated classes for your situation.</li>
11-
</ol>
3+
This module is used by Helidon to generate types with builders (Prototypes) to be used in API of modules from a blueprint interface.
124

13-
Supported annotation types (see [builder](./builder/src/main/java/io/helidon/builder) for further details):
14-
* Builder - similar to Lombok's SuperBuilder.
15-
* Singular - similar to Lombok's Singular.
16-
* NonNull - accomplished alternatively via Helidon's <i>ConfiguredOption#required</i>.
17-
* Default - accomplished alternatively via Helidon's <i>ConfiguredOption#value</i>.
5+
There are two modules that are used:
6+
- `helidon-builder-api` - module required in `compile` scope, contains annotations and APIs needed to write blueprints, and to build the generated code
7+
- `helidon-builder-processor` - module to be placed on annotation processor path, generates the sources
188

19-
Explicitly unsupported (i.e., these are just a few of the types that do not have a counterpart from Helidon's Builder):
20-
* NoArgsConstructor - must instead use one of the <i>toBuilder()</i> methods
21-
* AllArgsConstructor - must instead use one of the <i>toBuilder()</i> methods
9+
There is one module useful for internal development
10+
- `helidon-builder-tests-common-types` (located under `tests/common-types`) that contains blueprints for the types we use in `helidon-common-types`. As the common types module is used by the processor, we would end up with a cyclic dependency, so this allows us to generate the next iteration of common types (requires manual copying of the generated types)
2211

23-
Any and all types are supported by the Builder, with special handling for List, Map, Set, and Optional types. The target interface,
24-
however, should only contain getter like methods (i.e., has a non-void return and takes no arguments). All static and default methods
25-
are ignored on the target being processed.
12+
## Goals
2613

27-
The Helidon Builder is independent of other parts of Helidon. It can therefore be used in a standalone manner. The
28-
generated implementation class will not require any special module to support those classes - just the types from your interface
29-
and standard JRE types are used. This is made possible when your <i>Builder</i> has the <i>requireBuilderLibrary=false</i>. See the javadoc for details.
14+
Generate all required types for Helidon APIs with builders, that follow the same style (method names, required validation etc.).
15+
16+
The following list of features is currently supported:
17+
- `Builder` also implements the interface of the type (all getters are available also on builder)
18+
- `Type` options - interface returns `Type`, such an option MUST NOT be null in the built instance, there is a validation in place on calling the `build` or `buildPrototype` methods. Getters MAY return null on a builder
19+
- `Optional` options - interface returns `Optional<Type>`, setters use just `Type`, there is a package local setter that accepts `Optional` as well, to support updating a builder from an existing instance
20+
- `List` options - interface returns `List<Type>`, never null - if there is no configured value, empty string is returned
21+
- `Set` options - similar to list
22+
- `Map` options - key/value map, builders support any key/value types, but if configuration is used, the key must be a string
23+
- "Singular" for collection based options, which adds setter for a single value (for `List<String> algorithms()`, there would be the following setters: `algorithms(List<String>)`, `addAlgorithms(List<String>)`, `addAlgorithm(String)`)
24+
- A type can be `@Configured`, which adds integration with Helidon common Config module, by adding a static factory method `create(io.helidon.common.Config)` to the generated type, as well as `config(Config)` method to the generated builder, that sets all options annotated with `@ConfiguredOption` from configuration (if present in the Config instance)
25+
- Capability to update the builder before validation (interceptor)
26+
- Support for custom methods (`@Prototype.CustomMethods`) for factory methods, prototype methods, and builder methods
27+
28+
## Non-Goals
29+
30+
We are not building a general purpose solution, there are limitations that are known and will not be targetted:
31+
- the solution expects that everything is single package - blueprints are required to be package local, which does not allow using built types across packages within a single module
32+
- we only support interface based definition of blueprints (no classes)
33+
- we only support non-nullable options, instead of nullable, use `Optional` getters
34+
- implementation types of collections are fixed to `java.util.ArrayList`, `java.util.LinkedHashSet` and `java.util.LinkedHashMap`
3035

3136
## Getting Started
3237
1. Write your interface that you want to have a builder for.
3338
```java
34-
public interface MyConfigBean {
39+
interface MyConfigBeanBlueprint {
3540
String getName();
3641
boolean isEnabled();
3742
int getPort();
3843
}
3944
```
40-
2. Annotate your interface definition with <i>Builder</i>, and optionally use <i>ConfiguredOption</i>, <i>Singular</i>, etc. Remember to review the annotation attributes javadoc for any customizations.
41-
3. Builder (using the <i>builder-processor</i> in your annotation classpath).
45+
2. Annotate your interface definition with `@Blueprint`, and optionally use `@ConfiguredOption`, `Singular` etc. to customize the getter methods. Remember to review the annotation attributes javadoc for any customizations.
46+
3. Update your pom file to add annotation processor
4247
```xml
4348
...
4449
<build>
@@ -48,13 +53,6 @@ public interface MyConfigBean {
4853
<artifactId>maven-compiler-plugin</artifactId>
4954
<configuration>
5055
<annotationProcessorPaths>
51-
<!-- this path is needed if only requiring the Builder annotation -->
52-
<path>
53-
<groupId>io.helidon.builder</groupId>
54-
<artifactId>helidon-builder-processor</artifactId>
55-
<version>${helidon.version}</version>
56-
</path>
57-
<!-- this path is needed if requiring the ConfigBean annotation (which will automatically bring in the Builder processor transitively) -->
5856
<path>
5957
<groupId>io.helidon.builder</groupId>
6058
<artifactId>helidon-builder-processor</artifactId>
@@ -68,37 +66,10 @@ public interface MyConfigBean {
6866
...
6967
```
7068

71-
The result of this will create (under ./target/generated-sources/annotations):
72-
* MyConfigBeanImpl (in the same package as MyConfigBean) that will support multi-inheritance builders named MyConfigBeanImpl.Builder.
73-
* Support for toString(), hashCode(), and equals() are always included.
74-
* Support for toBuilder().
75-
* Support for streams (see javadoc for [Builder](./builder/src/main/java/io/helidon/builder/Builder.java)).
76-
* Support for attribute visitors (see [test-builder](./tests/builder/src/main/java/io/helidon/builder/test/testsubjects/package-info.java)).
77-
* Support for attribute validation (see ConfiguredOption#required() and [test-builder](./tests/builder/src/main/java/io/helidon/builder/test/testsubjects/package-info.java)).
78-
* Support for builder interception (i.e., including decoration or mutation). (see [test-builder](./tests/builder/src/main/java/io/helidon/builder/test/testsubjects/package-info.java)).
79-
80-
Also note that the generated code from Helidon Builder processors may add other dependencies that you will need to add (typically in <i>provided</i> scope).
81-
```xml
82-
<dependency>
83-
<groupId>jakarta.annotation</groupId>
84-
<artifactId>jakarta.annotation-api</artifactId>
85-
<scope>provided</scope>
86-
<optional>true</optional>
87-
</dependency>
88-
```
89-
90-
## Modules
91-
* [builder](./builder) - provides the compile-time annotations, as well as optional runtime supporting types.
92-
* [processor-spi](./processor-spi) - defines the Builder Processor SPI runtime definitions used by builder tooling. This module is only needed at compile time.
93-
* [processor-tools](./processor-tools) - provides the concrete creators & code generators. This module is only needed at compile time.
94-
* [processor](./processor) - the annotation processor which delegates to the processor-tools module for the main processing logic. This module is only needed at compile time.
95-
* [builder-config](./builder-config) - extension to the builder to additionally support [Helidon (Common) Config](../common/config) and [@ConfigBean](./builder-config/src/main/java/io/helidon/builder/config/ConfigBean.java).
96-
* [builder-config-processor](./builder-config-processor) - defines the ConfigBean builder.
97-
* [tests](./tests) - tests that can also serve as examples for usage.
98-
99-
## Customizations and Extensibility
100-
To implement your own custom <i>Builder</i>:
101-
* See [builder-config](../builder-config) serving as an example.
102-
103-
## Usage
104-
See [tests/builder](./tests/builder) for usage examples.
69+
Generated types will be available under `./target/generated-sources/annotations`
70+
* MyConfigBean (in the same package as MyConfigBeanBlueprint), with inner classes `BuilderBase` (for inheritance), `Builder`,
71+
* Support for `toString()`, `hashCode()`, and `equals()` are always included.
72+
* Support for `builder(MyConfigBean)` to create a new builder from an existing instance
73+
* Support for `from(MyConfigBean)` and `from(MyConfigBean.BuilderBase<?, ?>)` to update builder from an instance or builder
74+
* Support for validation of required and non-nullable options (required options are options that have `@ConfiguredOption(required=true)`, non-nullable option is any option that is not primitive, collection, and does not return an `Optional`)
75+
* Support for builder interception (`@Bluprint(builderInterceptor = MyInterceptor.class)`)

0 commit comments

Comments
 (0)