Skip to content

Commit 7179876

Browse files
authored
Extend Builder to support abstract and concrete codegen, and add validation of required attributes during builder().build() (#5228)
* add validation to Builder * address most review comments from Tomas * addressing other review comments
1 parent 50c29a3 commit 7179876

File tree

87 files changed

+3125
-2140
lines changed

Some content is hidden

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

87 files changed

+3125
-2140
lines changed

bom/pom.xml

+3-8
Original file line numberDiff line numberDiff line change
@@ -1406,22 +1406,17 @@
14061406
<!-- Pico Builder -->
14071407
<dependency>
14081408
<groupId>io.helidon.pico.builder</groupId>
1409-
<artifactId>helidon-pico-builder-api</artifactId>
1409+
<artifactId>helidon-pico-builder</artifactId>
14101410
<version>${helidon.version}</version>
14111411
</dependency>
14121412
<dependency>
14131413
<groupId>io.helidon.pico.builder</groupId>
1414-
<artifactId>helidon-pico-builder-spi</artifactId>
1414+
<artifactId>helidon-pico-builder-processor-spi</artifactId>
14151415
<version>${helidon.version}</version>
14161416
</dependency>
14171417
<dependency>
14181418
<groupId>io.helidon.pico.builder</groupId>
1419-
<artifactId>helidon-pico-builder-tools</artifactId>
1420-
<version>${helidon.version}</version>
1421-
</dependency>
1422-
<dependency>
1423-
<groupId>io.helidon.pico.builder</groupId>
1424-
<artifactId>helidon-pico-builder-runtime-tools</artifactId>
1419+
<artifactId>helidon-pico-builder-processor-tools</artifactId>
14251420
<version>${helidon.version}</version>
14261421
</dependency>
14271422
<dependency>

common/testing/junit5/src/main/java/io/helidon/common/testing/junit5/OptionalMatcher.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ private OptionalMatcher() {
3636
* <p>
3737
* Usage example:
3838
* <pre>
39-
* assertThat(myOptional, present(is("expected")));
39+
* assertThat(myOptional, optionalValue(is("expected")));
4040
* </pre>
4141
* @param matcher matcher to validate the content of the optional
4242
* @param <T> type of the value
@@ -51,7 +51,7 @@ public static <T> Matcher<Optional<T>> optionalValue(Matcher<? super T> matcher)
5151
* <p>
5252
* Usage example:
5353
* <pre>
54-
* assertThat(myOptional, empty());
54+
* assertThat(myOptional, optionalEmpty());
5555
* </pre>
5656
* @param <T> type of the optional
5757
* @return matcher validating the {@link java.util.Optional} is empty
@@ -66,7 +66,7 @@ public static <T> Matcher<Optional<T>> optionalEmpty() {
6666
* <p>
6767
* Usage example:
6868
* <pre>
69-
* assertThat(myOptional, present());
69+
* assertThat(myOptional, optionalPresent());
7070
* </pre>
7171
* @param <T> type of the value
7272
* @return matcher validating the {@link java.util.Optional} is present

pico/builder/README.md

+25-23
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
# pico-builder
22

3-
The <b>Pico 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:
3+
The <b>Helidon Pico 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:
44
<ol>
5-
<li>Pico Builders target interface or annotation types only.</li>
6-
<li>Generated classes implement the target interface (or annotation) and provide a fluent builder that will always have an implementation of <i>toString(), hashCode(), and equals().</i></li>
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) and provide a fluent builder that will always have an implementation of <i>toString(), hashCode(), and equals().</i> implemented</li>
77
<li>Generated classes always behave like a <i>SuperBuilder</i> from Lombok. Basically this means that builders can form
88
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 Pico Builder generates source code (in conjunction with the proper Builder annotation processor).</li>
10-
<li>Pico Builders are extensible - you can provide your own implementation of the SPI to customize the generated classes.</li>
9+
<li>Lombok uses AOP while the Pico 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>Pico 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>
1111
</ol>
1212

13-
Supported annotation types (see [api](./api/src/main/java/io/helidon/pico/builder/api) for further details):
13+
Supported annotation types (see [builder](./builder/src/main/java/io/helidon/pico/builder) for further details):
1414
* Builder - similar to Lombok's SuperBuilder.
1515
* Singular - similar to Lombok's Singular.
1616

@@ -20,9 +20,9 @@ are ignored on the target being processed.
2020

2121
The Helidon Pico Builder is completely independent of other parts of Pico. It can therefore be used in a standalone manner. The
2222
generated implementation class will not require any special module to support those classes - just the types from your interface
23-
and standard JRE types are used.
23+
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.
2424

25-
## Usage
25+
## Getting Started
2626
1. Write your interface that you want to have a builder for.
2727
```java
2828
public interface MyConfigBean {
@@ -31,28 +31,30 @@ public interface MyConfigBean {
3131
int getPort();
3232
}
3333
```
34-
2. Annotate your interface definition with <i>Builder</i>, and optionally use <i>ConfiguredOption</i>, <i>Singular</i>, etc.
34+
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.
3535
3. Compile (using the <i>pico-builder-processor</i> in your annotation classpath).
3636

37-
The result of this will create (under ./target/generated-sources):
37+
The result of this will create (under ./target/generated-sources/annotations):
3838
* MyConfigBeanImpl (in the same package as MyConfigBean) that will support multi-inheritance builders named MyConfigBeanImpl.Builder.
3939
* Support for toString(), hashCode(), and equals() are always included.
4040
* Support for toBuilder().
41-
* Support for streams (see javadoc for [Builder](./api/src/main/java/io/helidon/pico/builder/Builder.java)).
41+
* Support for streams (see javadoc for [Builder](./builder/src/main/java/io/helidon/pico/builder/Builder.java)).
42+
* Support for attribute visitors (see [test-builder](./tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/package-info.java)).
43+
* Support for attribute validation (see ConfiguredOption#required() and [builder](./tests/builder/src/main/java/io/helidon/pico/builder/test/testsubjects/package-info.java)).
4244

4345
The implementation of the processor also allows for a provider-based extensibility mechanism.
4446

45-
## modules
46-
* [api](./api) - defines the compile-time annotations. Typically this module is only needed at compile time.
47-
* [spi](./spi) - defines the SPI runtime definitions used by builder tooling. Only needed at compile time.
48-
* [tools](./tools) - provides the creators / code generators. Only needed at compile time.
49-
* [runtime-tools](./runtime-tools) - provides optional runtime utility classes the can helpful at compile time as well as runtime.
50-
* [processor](./processor) - the annotation processor which delegates to the tools module for processing. Only needed at compile time.
51-
* [test-builder](./test-builder) - internal tests that can also serve as examples for usage.
52-
53-
## provider
54-
To implement your own provider:
55-
* Write an implementation for <i>BuilderCreator</i> having a higher-than-default <i>Weighted</i> value as compared to <i>DefaultBuilderCreator</i>.
47+
## Modules
48+
* [builder](./builder) - provides the compile-time annotations, as well as optional runtime supporting types.
49+
* [processor-spi](./processor-spi) - defines the Builder Processor SPI runtime definitions used by builder tooling. This module is only needed at compile time.
50+
* [processor-tools](./processor-tools) - provides the concrete creators & code generators. This module is only needed at compile time.
51+
* [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.
52+
* [tests/builder](./tests/builder) - internal tests that can also serve as examples on usage.
53+
54+
## Customizations
55+
To implement your own custom <i>Builder</i>:
56+
* Write an implementation of <i>BuilderCreator</i> having a higher-than-default <i>Weighted</i> value as compared to <i>DefaultBuilderCreator</i>.
5657
* Include your module with this creator in your annotation processing path.
5758

58-
See [test-builder](./test-builder) for usage examples.
59+
## Usage
60+
See [tests/builder](./tests/builder) for usage examples.

pico/builder/api/README.md

-3
This file was deleted.

pico/builder/api/src/main/java/module-info.java

-25
This file was deleted.

pico/builder/builder/README.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# pico-builder
2+
3+
This module can either be used compile-time only or at runtime as well depending upon your usage.
4+
5+
See the [main](../README.md) document for details.

pico/builder/spi/pom.xml renamed to pico/builder/builder/pom.xml

+11-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<project xmlns="http://maven.apache.org/POM/4.0.0"
2121
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2222
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
23+
2324
<parent>
2425
<groupId>io.helidon.pico.builder</groupId>
2526
<artifactId>helidon-pico-builder-project</artifactId>
@@ -28,21 +29,23 @@
2829
</parent>
2930
<modelVersion>4.0.0</modelVersion>
3031

31-
<artifactId>helidon-pico-builder-spi</artifactId>
32-
<name>Helidon Pico Builder SPI</name>
32+
<artifactId>helidon-pico-builder</artifactId>
33+
<name>Helidon Pico Builder</name>
3334

3435
<dependencies>
3536
<dependency>
36-
<groupId>io.helidon.common</groupId>
37-
<artifactId>helidon-common</artifactId>
37+
<groupId>io.helidon.config</groupId>
38+
<artifactId>helidon-config-metadata</artifactId>
39+
<scope>provided</scope>
3840
</dependency>
3941
<dependency>
40-
<groupId>io.helidon.pico</groupId>
41-
<artifactId>helidon-pico-types</artifactId>
42+
<groupId>io.helidon.common</groupId>
43+
<artifactId>helidon-common</artifactId>
4244
</dependency>
4345
<dependency>
44-
<groupId>io.helidon.pico.builder</groupId>
45-
<artifactId>helidon-pico-builder-api</artifactId>
46+
<groupId>io.helidon.common.testing</groupId>
47+
<artifactId>helidon-common-testing-junit5</artifactId>
48+
<scope>test</scope>
4649
</dependency>
4750
<dependency>
4851
<groupId>org.hamcrest</groupId>

pico/builder/api/src/main/java/io/helidon/pico/builder/api/Annotated.java renamed to pico/builder/builder/src/main/java/io/helidon/pico/builder/Annotated.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package io.helidon.pico.builder.api;
17+
package io.helidon.pico.builder;
1818

1919
import java.lang.annotation.ElementType;
2020
import java.lang.annotation.Retention;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2022 Oracle and/or its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.helidon.pico.builder;
18+
19+
import java.util.Map;
20+
import java.util.function.Supplier;
21+
22+
/**
23+
* A functional interface that can be used to visit all attributes of this type.
24+
* <p>
25+
* This type is used when {@link io.helidon.pico.builder.Builder#requireLibraryDependencies()} is used.
26+
*/
27+
@FunctionalInterface
28+
public interface AttributeVisitor {
29+
30+
/**
31+
* Visits the attribute named 'attrName'.
32+
*
33+
* @param attrName the attribute name
34+
* @param valueSupplier the attribute value supplier
35+
* @param meta the meta information for the attribute
36+
* @param userDefinedCtx a user defined context that can be used for holding an object of your choosing
37+
* @param type the type of the attribute
38+
* @param typeArgument the type arguments (if type is a parameterized / generic type)
39+
*/
40+
void visit(String attrName,
41+
Supplier<Object> valueSupplier,
42+
Map<String, Object> meta,
43+
Object userDefinedCtx,
44+
Class<?> type,
45+
Class<?>... typeArgument);
46+
47+
}

0 commit comments

Comments
 (0)