Skip to content
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

Builder updates, fixes and enhancements #5977

Merged
merged 2 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
18 changes: 16 additions & 2 deletions builder/builder/src/main/java/io/helidon/builder/Builder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -43,7 +43,8 @@
*/
@SuppressWarnings("rawtypes")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
// note: runtime retention needed for cases when derived builders are inherited across modules
@Retention(RetentionPolicy.RUNTIME)
@BuilderTrigger
public @interface Builder {

Expand All @@ -67,6 +68,11 @@
*/
boolean DEFAULT_ALLOW_NULLS = false;

/**
* The default value for {@link #includeGeneratedAnnotation()}.
*/
boolean DEFAULT_INCLUDE_GENERATED_ANNOTATION = false;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defaulting this to false for a little bit longer to give time to evaluate


/**
* 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 @@ -180,6 +186,14 @@
*/
boolean allowNulls() default DEFAULT_ALLOW_NULLS;

/**
* Should the code generated types included the {@code Generated} annotation. Including this annotation will require an
* additional module dependency on your modules to include {@code jakarta.annotation-api}.
*
* @return true to include the Generated annotation
*/
boolean includeGeneratedAnnotation() default DEFAULT_INCLUDE_GENERATED_ANNOTATION;

/**
* The interceptor implementation type. See {@link BuilderInterceptor} for further details. Any interceptor applied will be called
* prior to validation. The interceptor implementation can be any lambda-like implementation for the {@link BuilderInterceptor}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,9 +18,11 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import io.helidon.pico.types.AnnotationAndValue;
import io.helidon.pico.types.TypeName;
Expand All @@ -36,6 +38,7 @@ public class DefaultTypeInfo implements TypeInfo {
private final List<TypedElementName> elementInfo;
private final List<TypedElementName> otherElementInfo;
private final TypeInfo superTypeInfo;
private final Set<String> modifierNames;

/**
* Default constructor taking the builder as an argument.
Expand All @@ -50,6 +53,7 @@ protected DefaultTypeInfo(Builder b) {
this.elementInfo = List.copyOf(b.elementInfo);
this.otherElementInfo = List.copyOf(b.otherElementInfo);
this.superTypeInfo = b.superTypeInfo;
this.modifierNames = Set.copyOf(b.modifierNames);
}

/**
Expand Down Expand Up @@ -91,6 +95,11 @@ public Optional<TypeInfo> superTypeInfo() {
return Optional.ofNullable(superTypeInfo);
}

@Override
public Set<String> modifierNames() {
return modifierNames;
}

@Override
public String toString() {
return getClass().getSimpleName() + "(" + toStringInner() + ")";
Expand All @@ -105,7 +114,8 @@ protected String toStringInner() {
return "typeName=" + typeName()
+ ", elementInfo=" + elementInfo()
+ ", annotations=" + annotations()
+ ", superTypeInfo=" + superTypeInfo();
+ ", superTypeInfo=" + superTypeInfo()
+ ", modifierNames=" + modifierNames();
}

/**
Expand All @@ -115,6 +125,7 @@ public static class Builder implements io.helidon.common.Builder<Builder, Defaul
private final List<AnnotationAndValue> annotations = new ArrayList<>();
private final List<TypedElementName> elementInfo = new ArrayList<>();
private final List<TypedElementName> otherElementInfo = new ArrayList<>();
private final Set<String> modifierNames = new LinkedHashSet<>();
private TypeName typeName;
private String typeKind;

Expand Down Expand Up @@ -229,7 +240,32 @@ public Builder otherElementInfo(Collection<TypedElementName> val) {
*/
public Builder addOtherElementInfo(TypedElementName val) {
Objects.requireNonNull(val);
otherElementInfo.add(Objects.requireNonNull(val));
otherElementInfo.add(val);
return this;
}

/**
* Sets the modifiers to val.
*
* @param val the value
* @return this fluent builder
*/
public Builder modifierNames(Collection<String> val) {
Objects.requireNonNull(val);
this.modifierNames.clear();
this.modifierNames.addAll(val);
return this;
}

/**
* Adds a single modifier val.
*
* @param val the value
* @return this fluent builder
*/
public Builder addModifierName(String val) {
Objects.requireNonNull(val);
modifierNames.add(val);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,6 +18,7 @@

import java.util.List;
import java.util.Optional;
import java.util.Set;

import io.helidon.pico.types.AnnotationAndValue;
import io.helidon.pico.types.TypeName;
Expand Down Expand Up @@ -67,8 +68,15 @@ public interface TypeInfo {
/**
* The parent/super class for this type info.
*
* @return the super type.
* @return the super type
*/
Optional<TypeInfo> superTypeInfo();

/**
* Element modifiers.
*
* @return element modifiers
*/
Set<String> modifierNames();

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,7 +21,6 @@
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.TypeElement;

import io.helidon.pico.types.AnnotationAndValue;
import io.helidon.pico.types.TypeName;

/**
Expand All @@ -34,13 +33,13 @@ public interface TypeInfoCreatorProvider {
/**
* Creates a {@link TypeInfo}.
*
* @param annotation the annotation that triggered the creation
* @param annoTypeName the annotation type name that triggered the creation
* @param typeName the type name that is being processed that is annotated with the triggering annotation
* @param element the element representative of the typeName
* @param processingEnv the processing environment
* @return the type info associated with the arguments being processed, or empty if not able to process the type
*/
Optional<TypeInfo> createTypeInfo(AnnotationAndValue annotation,
Optional<TypeInfo> createTypeInfo(TypeName annoTypeName,
TypeName typeName,
TypeElement element,
ProcessingEnvironment processingEnv);
Expand Down
8 changes: 7 additions & 1 deletion builder/processor-tools/pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2022 Oracle and/or its affiliates.
Copyright (c) 2022, 2023 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -52,6 +52,12 @@
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config-metadata</artifactId>
</dependency>
<!-- to support the Generated annotation -->
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.helidon.common.testing</groupId>
<artifactId>helidon-common-testing-junit5</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -25,6 +25,7 @@
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

import io.helidon.builder.Builder;
import io.helidon.builder.processor.spi.TypeInfo;
import io.helidon.pico.types.AnnotationAndValue;
import io.helidon.pico.types.DefaultAnnotationAndValue;
Expand All @@ -33,7 +34,6 @@
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 Down Expand Up @@ -63,6 +63,7 @@ public class BodyContext {
private final boolean requireLibraryDependencies;
private final boolean beanStyleRequired;
private final boolean allowNulls;
private final boolean includeGeneratedAnnotation;
private final String listType;
private final String mapType;
private final String setType;
Expand All @@ -73,6 +74,7 @@ public class BodyContext {
private final String genericBuilderClassDecl;
private final String genericBuilderAliasDecl;
private final String genericBuilderAcceptAliasDecl;
private final String publicOrPackagePrivateDecl;
private final TypeName interceptorTypeName;
private final String interceptorCreateMethod;

Expand All @@ -85,9 +87,9 @@ public class BodyContext {
* @param builderTriggerAnnotation the builder annotation
*/
BodyContext(boolean doingConcreteType,
TypeName implTypeName,
TypeInfo typeInfo,
AnnotationAndValue builderTriggerAnnotation) {
TypeName implTypeName,
TypeInfo typeInfo,
AnnotationAndValue builderTriggerAnnotation) {
this.doingConcreteType = doingConcreteType;
this.implTypeName = implTypeName;
this.typeInfo = typeInfo;
Expand All @@ -98,6 +100,7 @@ public class BodyContext {
this.requireLibraryDependencies = toRequireLibraryDependencies(builderTriggerAnnotation, typeInfo);
this.beanStyleRequired = toRequireBeanStyle(builderTriggerAnnotation, typeInfo);
this.allowNulls = toAllowNulls(builderTriggerAnnotation, typeInfo);
this.includeGeneratedAnnotation = toIncludeGeneratedAnnotation(builderTriggerAnnotation, typeInfo);
this.listType = toListImplType(builderTriggerAnnotation, typeInfo);
this.mapType = toMapImplType(builderTriggerAnnotation, typeInfo);
this.setType = toSetImplType(builderTriggerAnnotation, typeInfo);
Expand All @@ -124,6 +127,9 @@ public class BodyContext {
searchForBuilderAnnotation("interceptorCreateMethod", builderTriggerAnnotation, typeInfo);
this.interceptorCreateMethod = (interceptorCreateMethod == null || interceptorCreateMethod.isEmpty())
? null : interceptorCreateMethod;
this.publicOrPackagePrivateDecl = (typeInfo.typeKind().equals("INTERFACE")
|| typeInfo.modifierNames().isEmpty()
|| typeInfo.modifierNames().contains("PUBLIC")) ? "public " : "";
}

/**
Expand Down Expand Up @@ -266,6 +272,16 @@ protected boolean allowNulls() {
return allowNulls;
}

/**
* Returns true if {@code jakarta.annotations.Generated} annotation should be generated.
* See {@link io.helidon.builder.Builder#includeGeneratedAnnotation()}.
*
* @return true if the Generated annotation should be generated on the target beans
*/
protected boolean includeGeneratedAnnotation() {
return includeGeneratedAnnotation;
}

/**
* Returns the list type generated.
* See {@link io.helidon.builder.Builder#listImplType()}.
Expand Down Expand Up @@ -359,6 +375,14 @@ protected String genericBuilderAcceptAliasDecl() {
return genericBuilderAcceptAliasDecl;
}

/**
* Returns "public" or "" for public or package private declaration, accordingly.
*
* @return the modifier declaration
*/
public String publicOrPackagePrivateDecl() {
return publicOrPackagePrivateDecl;
}
/**
* Returns the interceptor implementation type name.
* See {@link io.helidon.builder.Builder#interceptor()}.
Expand Down Expand Up @@ -435,7 +459,7 @@ private static boolean hasStreamSupportOnBuilder(boolean ignoreDoingConcreteClas
private static boolean toIncludeMetaAttributes(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String val = searchForBuilderAnnotation("includeMetaAttributes", builderTriggerAnnotation, typeInfo);
return val == null ? DEFAULT_INCLUDE_META_ATTRIBUTES : Boolean.parseBoolean(val);
return (val == null) ? DEFAULT_INCLUDE_META_ATTRIBUTES : Boolean.parseBoolean(val);
}

/**
Expand All @@ -444,7 +468,7 @@ private static boolean toIncludeMetaAttributes(AnnotationAndValue builderTrigger
private static boolean toRequireLibraryDependencies(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
String val = searchForBuilderAnnotation("requireLibraryDependencies", builderTriggerAnnotation, typeInfo);
return val == null ? DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES : Boolean.parseBoolean(val);
return (val == null) ? DEFAULT_REQUIRE_LIBRARY_DEPENDENCIES : Boolean.parseBoolean(val);
}

/**
Expand All @@ -457,12 +481,21 @@ private static boolean toRequireBeanStyle(AnnotationAndValue builderTriggerAnnot
}

/**
* In support of {@link io.helidon.builder.Builder#allowNulls()} ()}.
* 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);
return (val == null) ? Builder.DEFAULT_ALLOW_NULLS : Boolean.parseBoolean(val);
}

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

/**
Expand All @@ -475,7 +508,7 @@ private static String toListImplType(AnnotationAndValue builderTriggerAnnotation
}

/**
* In support of {@link io.helidon.builder.Builder#mapImplType()} ()}.
* In support of {@link io.helidon.builder.Builder#mapImplType()}.
*/
private static String toMapImplType(AnnotationAndValue builderTriggerAnnotation,
TypeInfo typeInfo) {
Expand Down Expand Up @@ -528,7 +561,7 @@ private static void gatherAllAttributeNames(BodyContext ctx,
}

if (Objects.isNull(ctx.parentTypeName.get())
&& superTypeInfo.typeKind().equals("INTERFACE")) {
&& superTypeInfo.typeKind().equals(DefaultBuilderCreatorProvider.INTERFACE)) {
ctx.parentTypeName.set(superTypeInfo.typeName());
} else if (Objects.isNull(ctx.parentAnnotationType.get())
&& superTypeInfo.typeKind().equals("ANNOTATION_TYPE")) {
Expand Down
Loading