Skip to content

Introduce Pico ConfigBean Builder Extensions #5482

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
Dec 2, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f2d6748
config integration into builder
trentjeff Nov 19, 2022
22d198c
checkstyle suppression, and javadoc fixups
trentjeff Nov 21, 2022
743b779
Promote ConfigMapper and ConfigMapperProvider to common level SPI. Th…
trentjeff Nov 22, 2022
50f4ed4
A few tweaks over the last push.
trentjeff Nov 22, 2022
c5f0339
A few tweaks over the last push.
trentjeff Nov 22, 2022
1cd03c9
Suppress false positives (#5450)
barchetta Nov 17, 2022
dfee561
Fix handling of optional whitespace at the beginning of headers. (#5441)
tomas-langer Nov 17, 2022
f77e47a
NullPointerException when there is an illegal character in the reques…
klustria Nov 18, 2022
b5747c8
Error handling support in HTTP for Nima WebServer. (#5436)
tomas-langer Nov 20, 2022
8256e47
move bean utils from builder spi to processor module. (#5448)
trentjeff Nov 21, 2022
453da59
remove -Ddocker.build=true (#5485)
aserkes Nov 21, 2022
f5f6d24
Fix Guava version to match that required by the grpc-java libraries (…
thegridman Nov 22, 2022
10038f1
5379 TempDir support for tests (#5508)
aserkes Nov 24, 2022
74de234
Kafka producer nacking fix 5510 (#5531)
danielkec Nov 24, 2022
ba35447
4836 graalvm 22 4.x (#5378)
tomas-langer Nov 24, 2022
22f67b0
Tyrus integration into Nima (#5464)
spericas Nov 28, 2022
2a83a85
Bump-up reactive messaging/ops to 3.0 (#5526)
danielkec Nov 28, 2022
3cfb5c9
5469 - forEachCS (#5532)
danielkec Nov 28, 2022
1e6a678
Fixed OpentraceableClientE2ETest to be more deterministic (#5536)
tomas-langer Nov 28, 2022
13707ea
[4.x] - Fix Intermittent TestJBatchEndpoint.runJob (#5542)
dalexandrov Nov 28, 2022
b01279d
5377 custom exception for CharBuffer (#5505)
aserkes Nov 28, 2022
9977d1e
Fix incorrect tags comparison when trying to match metric IDs (#5550)
tjquinno Nov 29, 2022
03a01eb
config integration into builder
trentjeff Nov 19, 2022
127c6e5
checkstyle suppression, and javadoc fixups
trentjeff Nov 21, 2022
f7e72e0
Promote ConfigMapper and ConfigMapperProvider to common level SPI. Th…
trentjeff Nov 22, 2022
925da74
A few tweaks over the last push.
trentjeff Nov 22, 2022
e010a87
A few tweaks over the last push.
trentjeff Nov 22, 2022
15a8ff2
Merge branch 'pico4' of github.com:trentjeff/helidon into pico4
trentjeff Nov 29, 2022
67de03d
relocating /pico/builder to /builder
trentjeff Nov 29, 2022
2299910
checkstyles, formats, and import ordering
trentjeff Nov 29, 2022
728e14c
some review comments addressed
trentjeff Nov 29, 2022
3bd66fa
checkstyles
trentjeff Nov 29, 2022
2dda9ec
more checkstyles
trentjeff Nov 29, 2022
c355b7a
Changes to builder modules
tomas-langer Dec 1, 2022
b0f7758
Changes to config beans and build fixes.
tomas-langer Dec 1, 2022
2d95c5b
1. allowNulls support added.
trentjeff Dec 1, 2022
85fdb09
fix failing test
trentjeff Dec 1, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions builder/builder/src/main/java/io/helidon/builder/Builder.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@
*/
String DEFAULT_SUFFIX = "";

/**
* The default value for {@link #allowNulls()}.
*/
boolean DEFAULT_ALLOW_NULLS = false;

/**
* The default list type used for the generated class implementation for any references to {@link java.util.List} is found
* on the methods of the {@link Builder}-annotation interface.
Expand Down Expand Up @@ -167,6 +172,14 @@
*/
boolean requireBeanStyle() default false;

/**
* Should the bean and the builder allow for the possibility of nullable non-{@link java.util.Optional} values to be present.
* Default is {@code false}.
*
* @return true to allow for the possibility of nullable non-Optional values to be present
*/
boolean allowNulls() default DEFAULT_ALLOW_NULLS;

/**
* The list implementation type to apply, defaulting to {@link #DEFAULT_LIST_TYPE}.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,42 @@
@Deprecated
public class RequiredAttributeVisitor implements AttributeVisitor<Object> {
private final List<String> errors = new ArrayList<>();
private final boolean allowNullsByDefault;

/**
* Default constructor.
*/
// note: this needs to remain public since it will be new'ed from code-generated builder processing ...
// important note: this needs to remain public since it will be new'ed from code-generated builder processing ...
public RequiredAttributeVisitor() {
this(Builder.DEFAULT_ALLOW_NULLS);
}

/**
* Constructor.
*
* @param allowNullsByDefault true if nulls should be allowed
*/
// important note: this needs to remain public since it will be new'ed from code-generated builder processing ...
public RequiredAttributeVisitor(boolean allowNullsByDefault) {
this.allowNullsByDefault = allowNullsByDefault;
}

@Override
// important note: this needs to remain public since it will be new'ed from code-generated builder processing ...
public void visit(String attrName,
Supplier<Object> valueSupplier,
Map<String, Object> meta,
Object userDefinedCtx,
Class<?> type,
Class<?>... typeArgument) {
boolean required = Boolean.parseBoolean((String) meta.get("required"));
if (!required) {
String requiredStr = (String) meta.get("required");
boolean requiredPresent = Objects.nonNull(requiredStr);
boolean required = Boolean.parseBoolean(requiredStr);
if (!required && requiredPresent) {
return;
}

if (allowNullsByDefault && !requiredPresent) {
return;
}

Expand All @@ -71,6 +90,7 @@ public void visit(String attrName,
*
* @throws java.lang.IllegalStateException when any attributes are in violation with the validation policy
*/
// important note: this needs to remain public since it will be new'ed from code-generated builder processing ...
public void validate() {
if (!errors.isEmpty()) {
throw new IllegalStateException(String.join(", ", errors));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import io.helidon.pico.types.TypedElementName;

import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.BUILDER_ANNO_TYPE_NAME;
import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_ALLOW_NULLS;
import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_INCLUDE_META_ATTRIBUTES;
import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_LIST_TYPE;
import static io.helidon.builder.processor.tools.DefaultBuilderCreatorProvider.DEFAULT_MAP_TYPE;
Expand All @@ -49,7 +50,7 @@ public class BodyContext {
private final boolean doingConcreteType;
private final TypeName implTypeName;
private final TypeInfo typeInfo;
private final AnnotationAndValue builderAnnotation;
private final AnnotationAndValue builderTriggerAnnotation;
private final Map<String, TypedElementName> map = new LinkedHashMap<>();
private final List<TypedElementName> allTypeInfos = new ArrayList<>();
private final List<String> allAttributeNames = new ArrayList<>();
Expand All @@ -59,7 +60,8 @@ public class BodyContext {
private final boolean hasStreamSupportOnBuilder;
private final boolean includeMetaAttributes;
private final boolean requireLibraryDependencies;
private final boolean isBeanStyleRequired;
private final boolean beanStyleRequired;
private final boolean allowNulls;
private final String listType;
private final String mapType;
private final String setType;
Expand All @@ -75,32 +77,32 @@ public class BodyContext {
* @param doingConcreteType true if the concrete type is being generated, otherwise the abstract class
* @param implTypeName the impl type name
* @param typeInfo the type info
* @param builderAnnotation the builder annotation
* @param builderTriggerAnnotation the builder annotation
*/
BodyContext(boolean doingConcreteType,
TypeName implTypeName,
TypeInfo typeInfo,
AnnotationAndValue builderAnnotation) {
AnnotationAndValue builderTriggerAnnotation) {
this.doingConcreteType = doingConcreteType;
this.implTypeName = implTypeName;
this.typeInfo = typeInfo;
this.builderAnnotation = builderAnnotation;
this.hasStreamSupportOnImpl = hasStreamSupportOnImpl(doingConcreteType, builderAnnotation);
this.hasStreamSupportOnBuilder = hasStreamSupportOnBuilder(doingConcreteType, builderAnnotation);
this.includeMetaAttributes = toIncludeMetaAttributes(builderAnnotation, typeInfo);
this.requireLibraryDependencies = toRequireLibraryDependencies(builderAnnotation, typeInfo);
this.isBeanStyleRequired = toRequireBeanStyle(builderAnnotation, typeInfo);
this.listType = toListImplType(builderAnnotation, typeInfo);
this.mapType = toMapImplType(builderAnnotation, typeInfo);
this.setType = toSetImplType(builderAnnotation, typeInfo);
this.builderTriggerAnnotation = builderTriggerAnnotation;
this.hasStreamSupportOnImpl = hasStreamSupportOnImpl(doingConcreteType, builderTriggerAnnotation);
this.hasStreamSupportOnBuilder = hasStreamSupportOnBuilder(doingConcreteType, builderTriggerAnnotation);
this.includeMetaAttributes = toIncludeMetaAttributes(builderTriggerAnnotation, typeInfo);
this.requireLibraryDependencies = toRequireLibraryDependencies(builderTriggerAnnotation, typeInfo);
this.beanStyleRequired = toRequireBeanStyle(builderTriggerAnnotation, typeInfo);
this.allowNulls = toAllowNulls(builderTriggerAnnotation, typeInfo);
this.listType = toListImplType(builderTriggerAnnotation, typeInfo);
this.mapType = toMapImplType(builderTriggerAnnotation, typeInfo);
this.setType = toSetImplType(builderTriggerAnnotation, typeInfo);
gatherAllAttributeNames(this, typeInfo);
assert (allTypeInfos.size() == allAttributeNames.size());
this.hasParent = Objects.nonNull(parentTypeName.get());
this.ctorBuilderAcceptTypeName = (hasParent)
? typeInfo.typeName()
: (
Objects.nonNull(parentAnnotationType.get()) && typeInfo.elementInfo().isEmpty()
? typeInfo.superTypeInfo().get().typeName() : typeInfo.typeName());
: (Objects.nonNull(parentAnnotationType.get()) && typeInfo.elementInfo().isEmpty()
? typeInfo.superTypeInfo().orElseThrow().typeName() : typeInfo.typeName());
this.genericBuilderClassDecl = "Builder";
this.genericBuilderAliasDecl = ("B".equals(typeInfo.typeName().className())) ? "BU" : "B";
this.genericBuilderAcceptAliasDecl = ("T".equals(typeInfo.typeName().className())) ? "TY" : "T";
Expand Down Expand Up @@ -134,12 +136,13 @@ public TypeInfo typeInfo() {
}

/**
* Returns the builder annotation that triggers things.
* Returns the builder annotation that triggered things.
*
* @return the builder annotation
* @see io.helidon.builder.Builder
*/
public AnnotationAndValue builderAnnotation() {
return builderAnnotation;
public AnnotationAndValue builderTriggerAnnotation() {
return builderTriggerAnnotation;
}

/**
Expand Down Expand Up @@ -207,6 +210,7 @@ protected boolean hasStreamSupportOnBuilder() {

/**
* Returns true if meta attributes should be generated.
* See {@link io.helidon.builder.Builder#includeMetaAttributes()}.
*
* @return true if meta attributes should be generated
*/
Expand All @@ -216,6 +220,7 @@ protected boolean includeMetaAttributes() {

/**
* Returns true if Helidon library dependencies should be expected.
* See {@link io.helidon.builder.Builder#requireLibraryDependencies()}.
*
* @return true if Helidon library dependencies are expected
*/
Expand All @@ -225,15 +230,27 @@ protected boolean requireLibraryDependencies() {

/**
* Returns true if bean "getter" and "is" style is required.
* See {@link io.helidon.builder.Builder#requireBeanStyle()} .
*
* @return true if bean style is required
*/
protected boolean isBeanStyleRequired() {
return isBeanStyleRequired;
protected boolean beanStyleRequired() {
return beanStyleRequired;
}

/**
* Returns true if nulls are allowed.
* See {@link io.helidon.builder.Builder#allowNulls()}.
*
* @return true if allow nulls
*/
protected boolean allowNulls() {
return allowNulls;
}

/**
* Returns the list type generated.
* See {@link io.helidon.builder.Builder#listImplType()}.
*
* @return the list type
*/
Expand All @@ -243,6 +260,7 @@ public String listType() {

/**
* Returns the map type generated.
* See {@link io.helidon.builder.Builder#mapImplType()}.
*
* @return the map type
*/
Expand All @@ -252,6 +270,7 @@ public String mapType() {

/**
* Returns the set type generated.
* See {@link io.helidon.builder.Builder#setImplType()}.
*
* @return the set type
*/
Expand Down Expand Up @@ -335,73 +354,86 @@ private static boolean hasStreamSupportOnBuilder(boolean ignoreDoingConcreteClas
/**
* In support of {@link io.helidon.builder.Builder#includeMetaAttributes()}.
*/
private static boolean toIncludeMetaAttributes(AnnotationAndValue builderAnnotation,
private static boolean toIncludeMetaAttributes(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String val = searchForBuilderAnnotation("includeMetaAttributes", builderAnnotation, typeInfo);
String val = searchForBuilderAnnotation("includeMetaAttributes", builderTriggerAnnotation, typeInfo);
return val == null ? DEFAULT_INCLUDE_META_ATTRIBUTES : Boolean.parseBoolean(val);
}

/**
* In support of {@link io.helidon.builder.Builder#requireLibraryDependencies()}.
*/
private static boolean toRequireLibraryDependencies(AnnotationAndValue builderAnnotation,
private static boolean toRequireLibraryDependencies(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String val = searchForBuilderAnnotation("requireLibraryDependencies", builderAnnotation, typeInfo);
String val = searchForBuilderAnnotation("requireLibraryDependencies", builderTriggerAnnotation, typeInfo);
return val == null ? DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES : Boolean.parseBoolean(val);
}

/**
* In support of {@link io.helidon.builder.Builder#requireBeanStyle()}.
*/
private static boolean toRequireBeanStyle(AnnotationAndValue builderAnnotation,
private static boolean toRequireBeanStyle(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String val = searchForBuilderAnnotation("requireBeanStyle", builderAnnotation, typeInfo);
String val = searchForBuilderAnnotation("requireBeanStyle", builderTriggerAnnotation, typeInfo);
return Boolean.parseBoolean(val);
}

/**
* In support of {@link io.helidon.builder.Builder#allowNulls()} ()}.
*/
private static boolean toAllowNulls(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String val = searchForBuilderAnnotation("allowNulls", builderTriggerAnnotation, typeInfo);
return val == null ? DEFAULT_ALLOW_NULLS : Boolean.parseBoolean(val);
}

/**
* In support of {@link io.helidon.builder.Builder#listImplType()}.
*/
private static String toListImplType(AnnotationAndValue builderAnnotation,
private static String toListImplType(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String type = searchForBuilderAnnotation("listImplType", builderAnnotation, typeInfo);
String type = searchForBuilderAnnotation("listImplType", builderTriggerAnnotation, typeInfo);
return (!BuilderTypeTools.hasNonBlankValue(type)) ? DEFAULT_LIST_TYPE : type;
}

/**
* In support of {@link io.helidon.builder.Builder#mapImplType()} ()}.
*/
private static String toMapImplType(AnnotationAndValue builderAnnotation,
private static String toMapImplType(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String type = searchForBuilderAnnotation("mapImplType", builderAnnotation, typeInfo);
String type = searchForBuilderAnnotation("mapImplType", builderTriggerAnnotation, typeInfo);
return (!BuilderTypeTools.hasNonBlankValue(type)) ? DEFAULT_MAP_TYPE : type;
}

/**
* In support of {@link io.helidon.builder.Builder#setImplType()}.
*/
private static String toSetImplType(AnnotationAndValue builderAnnotation,
private static String toSetImplType(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String type = searchForBuilderAnnotation("setImplType", builderAnnotation, typeInfo);
String type = searchForBuilderAnnotation("setImplType", builderTriggerAnnotation, typeInfo);
return (!BuilderTypeTools.hasNonBlankValue(type)) ? DEFAULT_SET_TYPE : type;
}

private static String searchForBuilderAnnotation(String key,
AnnotationAndValue builderAnnotation,
AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String val = builderAnnotation.value(key).orElse(null);
String val = builderTriggerAnnotation.value(key).orElse(null);
if (val != null) {
return val;
}

if (!builderAnnotation.typeName().equals(BUILDER_ANNO_TYPE_NAME)) {
builderAnnotation = DefaultAnnotationAndValue
if (!builderTriggerAnnotation.typeName().equals(BUILDER_ANNO_TYPE_NAME)) {
AnnotationAndValue builderAnnotation = DefaultAnnotationAndValue
.findFirst(BUILDER_ANNO_TYPE_NAME.name(), typeInfo.annotations()).orElse(null);
if (Objects.nonNull(builderAnnotation)) {
val = builderAnnotation.value(key).orElse(null);
}
}

if (val == null && typeInfo.superTypeInfo().isPresent()) {
val = searchForBuilderAnnotation(key, builderTriggerAnnotation, typeInfo.superTypeInfo().get());
}

return val;
}

Expand All @@ -410,11 +442,11 @@ private static void gatherAllAttributeNames(BodyContext ctx,
TypeInfo superTypeInfo = typeInfo.superTypeInfo().orElse(null);
if (Objects.nonNull(superTypeInfo)) {
Optional<? extends AnnotationAndValue> superBuilderAnnotation = DefaultAnnotationAndValue
.findFirst(ctx.builderAnnotation.typeName().name(), superTypeInfo.annotations());
.findFirst(ctx.builderTriggerAnnotation.typeName().name(), superTypeInfo.annotations());
if (superBuilderAnnotation.isEmpty()) {
gatherAllAttributeNames(ctx, superTypeInfo);
} else {
populateMap(ctx.map, superTypeInfo, ctx.isBeanStyleRequired);
populateMap(ctx.map, superTypeInfo, ctx.beanStyleRequired);
}

if (Objects.isNull(ctx.parentTypeName.get())
Expand All @@ -427,7 +459,7 @@ private static void gatherAllAttributeNames(BodyContext ctx,
}

for (TypedElementName method : typeInfo.elementInfo()) {
String beanAttributeName = toBeanAttributeName(method, ctx.isBeanStyleRequired);
String beanAttributeName = toBeanAttributeName(method, ctx.beanStyleRequired);
TypedElementName existing = ctx.map.get(beanAttributeName);
if (Objects.nonNull(existing)
&& BeanUtils.isBooleanType(method.typeName().name())
Expand Down
Loading