diff --git a/builder/api/src/main/java/io/helidon/builder/api/Prototype.java b/builder/api/src/main/java/io/helidon/builder/api/Prototype.java index 60239d248a3..adabc7af673 100644 --- a/builder/api/src/main/java/io/helidon/builder/api/Prototype.java +++ b/builder/api/src/main/java/io/helidon/builder/api/Prototype.java @@ -68,26 +68,6 @@ public interface Builder { default BUILDER self() { return (BUILDER) this; } - - /** - * Resolve an instance to a built instance (if it is a builder). - * This method is used by generated code to ensure that instances passed to us have gone through - * builder interceptors and required validation. - * - * @param instance instance to check - * @return the same instance if not a builder, or a built instance - * @param type of the parameter - */ - @SuppressWarnings("unchecked") - default T resolveBuilder(T instance) { - if (instance instanceof Builder builder) { - return (T) builder.buildPrototype(); - } - if (instance instanceof io.helidon.common.Builder builder) { - return (T) builder.build(); - } - return instance; - } } /** @@ -214,14 +194,14 @@ public interface Factory { boolean beanStyle() default false; /** - * Used to intercept the builder, right before method build is called. + * Used to decorate the builder, right before method build is called. * Validations are done AFTER the interceptor is handled. * This class may be package local if located in the same package as blueprint. * The class must have accessible constructor with no parameters. * - * @return interceptor type + * @return decorator type */ - Class builderInterceptor() default BuilderInterceptor.class; + Class decorator() default BuilderDecorator.class; } /** @@ -235,17 +215,16 @@ public interface Factory { * by your very builder interceptor. * * @param the type of the bean builder to intercept - * @see Prototype.Blueprint#builderInterceptor() + * @see io.helidon.builder.api.Prototype.Blueprint#decorator() */ @FunctionalInterface - public interface BuilderInterceptor { + public interface BuilderDecorator { /** * Provides the ability to intercept (i.e., including decoration or mutation) the target. * * @param target the target being intercepted - * @return the mutated or replaced target (must not be null) */ - T intercept(T target); + void decorate(T target); } /** diff --git a/builder/processor/src/main/java/io/helidon/builder/processor/GenerateAbstractBuilder.java b/builder/processor/src/main/java/io/helidon/builder/processor/GenerateAbstractBuilder.java index b521f35e170..96904bc19f9 100644 --- a/builder/processor/src/main/java/io/helidon/builder/processor/GenerateAbstractBuilder.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/GenerateAbstractBuilder.java @@ -98,9 +98,8 @@ static void generate(PrintWriter pw, } else { pw.print(PROTOTYPE_BUILDER); } - pw.print(","); - pw.print(prototypeWithTypes); - pw.println(" {"); + pw.println(" {"); + // builder fields fields(pw, typeContext, true); @@ -143,57 +142,12 @@ static void generate(PrintWriter pw, fromInstanceMethod(pw, typeContext, prototypeWithTypes); fromBuilderMethod(pw, typeContext, typeArgumentNames); - // method preBuildPrototype() - handles providers, interceptor + // method preBuildPrototype() - handles providers, decorator preBuildPrototypeMethod(pw, typeContext); validatePrototypeMethod(pw, typeContext); CustomMethods customMethods = typeContext.customMethods(); - for (CustomMethods.CustomMethod customMethod : customMethods.prototypeMethods()) { - // todo these sections should be moved to CustomMethod implementation once we have class model - // builder - custom implementation methods for new prototype interface methods - CustomMethods.Method generated = customMethod.generatedMethod().method(); - // public TypeName boxed() - with implementation - if (!generated.javadoc().isEmpty()) { - Javadoc parsed = Javadoc.parse(generated.javadoc()).removeFirstParam(); - pw.print(SOURCE_SPACING); - pw.println("/**"); - for (String docLine : parsed.toLines()) { - pw.print(SOURCE_SPACING); - pw.print(" *"); - pw.println(docLine); - } - pw.print(SOURCE_SPACING); - pw.println(" */"); - } - for (String annotation : customMethod.generatedMethod().annotations()) { - pw.print(SOURCE_SPACING); - pw.print('@'); - pw.println(annotation); - } - if (!customMethod.generatedMethod().annotations().contains(OVERRIDE)) { - pw.print(SOURCE_SPACING); - pw.println("@Override"); - } - pw.print(SOURCE_SPACING); - pw.print("public "); - pw.print(generated.returnType().fqName()); - pw.print(" "); - pw.print(generated.name()); - pw.print("("); - pw.print(generated.arguments() - .stream() - .map(it -> it.typeName().fqName() + " " + it.name()) - .collect(Collectors.joining(", "))); - pw.println(") {"); - pw.print(SOURCE_SPACING); - pw.print(SOURCE_SPACING); - pw.print(customMethod.generatedMethod().callCode()); - pw.println(";"); - pw.print(SOURCE_SPACING); - pw.println("}"); - pw.println(); - } for (CustomMethods.CustomMethod customMethod : customMethods.builderMethods()) { // builder specific custom methods (not part of interface) CustomMethods.Method generated = customMethod.generatedMethod().method(); @@ -402,7 +356,7 @@ public BUILDER config(Config config) { } TypeName returnType = TypeName.createFromGenericDeclaration("BUILDER"); - // first setters (implement interface) + // first setters for (PrototypeProperty child : properties) { for (GeneratedMethod setter : child.setters(returnType, child.configuredOption().description())) { // this is builder setters @@ -454,6 +408,12 @@ public BUILDER config(Config config) { } // then getters + /* + If has default value - return type + If primitive & optional - return type + If collection - return type + Otherwise return Optional + */ for (PrototypeProperty child : properties) { String getterName = child.getterName(); /* @@ -481,11 +441,8 @@ String host() { } pw.print(SOURCE_SPACING); pw.print(SOURCE_SPACING); - pw.println("@Override"); - pw.print(SOURCE_SPACING); - pw.print(SOURCE_SPACING); pw.print("public "); - pw.print(child.typeName().fqName()); + pw.print(child.builderGetterType().fqName()); pw.print(" "); pw.print(getterName); pw.println("() {"); @@ -630,36 +587,24 @@ private static void fromBuilderMethod(PrintWriter pw, TypeContext typeContext, S pw.print(SOURCE_SPACING); TypeName declaredType = property.typeHandler().declaredType(); - if (declaredType.primitive() || declaredType.isOptional()) { - pw.print(property.typeHandler().setterName()); - pw.print("(builder."); - pw.print(property.typeHandler().getterName()); - pw.println("());"); - } else if (declaredType.isSet() || declaredType.isList() || declaredType.isMap()) { - pw.print("add"); - pw.print(capitalize(property.name())); - pw.print("(builder."); - pw.print(property.typeHandler().getterName()); - pw.println("());"); - } else { + if (property.builderGetterOptional()) { // property that is either mandatory or internally nullable - pw.print("if (builder."); + pw.print("builder."); pw.print(property.typeHandler().getterName()); - pw.println("() != null) {"); - pw.print(SOURCE_SPACING); - pw.print(SOURCE_SPACING); - pw.print(SOURCE_SPACING); - pw.print(SOURCE_SPACING); + pw.print("().ifPresent(this::"); pw.print(property.typeHandler().setterName()); + pw.println(");"); + } else { + if (declaredType.isSet() || declaredType.isList() || declaredType.isMap()) { + pw.print("add"); + pw.print(capitalize(property.name())); + } else { + pw.print(property.typeHandler().setterName()); + } pw.print("(builder."); pw.print(property.typeHandler().getterName()); pw.println("());"); - pw.print(SOURCE_SPACING); - pw.print(SOURCE_SPACING); - pw.print(SOURCE_SPACING); - pw.println("}"); } - } pw.print(SOURCE_SPACING); pw.print(SOURCE_SPACING); @@ -709,7 +654,7 @@ private static void preBuildPrototypeMethod(PrintWriter pw, pw.println("/**"); pw.print(SOURCE_SPACING); pw.print(SOURCE_SPACING); - pw.println(" * Handles providers and interceptors."); + pw.println(" * Handles providers and decorators."); pw.print(SOURCE_SPACING); pw.print(SOURCE_SPACING); pw.println(" */"); @@ -803,14 +748,13 @@ private static void preBuildPrototypeMethod(PrintWriter pw, } } } - if (typeContext.typeInfo().builderInterceptor().isPresent()) { - // TODO we should use the resulting builder, or remove the return type from interceptor + if (typeContext.typeInfo().decorator().isPresent()) { pw.print(SOURCE_SPACING); pw.print(SOURCE_SPACING); pw.print(SOURCE_SPACING); pw.print("new "); - pw.print(typeContext.typeInfo().builderInterceptor().get().fqName()); - pw.println("().intercept(this);"); + pw.print(typeContext.typeInfo().decorator().get().fqName()); + pw.println("().decorate(this);"); pw.println(); } pw.print(SOURCE_SPACING); @@ -1252,23 +1196,31 @@ private static void implAssignToFields(PrintWriter pw, TypeContext typeContext) pw.print("this."); pw.print(child.name()); pw.print(" = "); - if (child.typeHandler().declaredType().genericTypeName().equals(LIST)) { + TypeName declaredType = child.typeHandler().declaredType(); + if (declaredType.genericTypeName().equals(LIST)) { pw.print("java.util.List.copyOf(builder."); pw.print(child.getterName()); pw.println("());"); - } else if (child.typeHandler().declaredType().genericTypeName().equals(SET)) { + } else if (declaredType.genericTypeName().equals(SET)) { pw.print("java.util.Collections.unmodifiableSet(new java.util.LinkedHashSet<>(builder."); pw.print(child.getterName()); pw.println("()));"); - } else if (child.typeHandler().declaredType().genericTypeName().equals(MAP)) { + } else if (declaredType.genericTypeName().equals(MAP)) { pw.print("java.util.Collections.unmodifiableMap(new java.util.LinkedHashMap<>(builder."); pw.print(child.getterName()); pw.println("()));"); } else { - // optional and other types are just plainly assigned - pw.print(" builder."); - pw.print(child.getterName()); - pw.println("();"); + if (child.builderGetterOptional() && !declaredType.isOptional()) { + // builder getter optional, but type not, we call get (must be present - is validated) + pw.print(" builder."); + pw.print(child.getterName()); + pw.println("().get();"); + } else { + // optional and other types are just plainly assigned + pw.print(" builder."); + pw.print(child.getterName()); + pw.println("();"); + } } } } diff --git a/builder/processor/src/main/java/io/helidon/builder/processor/PrototypeProperty.java b/builder/processor/src/main/java/io/helidon/builder/processor/PrototypeProperty.java index 0a67e9d0049..a0c133fdd76 100644 --- a/builder/processor/src/main/java/io/helidon/builder/processor/PrototypeProperty.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/PrototypeProperty.java @@ -144,8 +144,18 @@ TypeName typeName() { return typeHandler.declaredType(); } + TypeName builderGetterType() { + return typeHandler.builderGetterType(configuredOption.required(), + configuredOption.hasDefault()); + } String builderGetter() { - return typeHandler().generateBuilderGetter(); + return typeHandler.generateBuilderGetter(configuredOption.required(), + configuredOption.hasDefault()); + } + + boolean builderGetterOptional() { + return typeHandler.builderGetterOptional(configuredOption.required(), + configuredOption.hasDefault()); } public String fieldDeclaration(boolean isBuilder) { diff --git a/builder/processor/src/main/java/io/helidon/builder/processor/TypeContext.java b/builder/processor/src/main/java/io/helidon/builder/processor/TypeContext.java index 7be0de8a6fa..0474b7c0acb 100644 --- a/builder/processor/src/main/java/io/helidon/builder/processor/TypeContext.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/TypeContext.java @@ -39,7 +39,7 @@ import io.helidon.common.types.TypeValues; import static io.helidon.builder.processor.Types.BLUEPRINT_TYPE; -import static io.helidon.builder.processor.Types.BUILDER_INTERCEPTOR; +import static io.helidon.builder.processor.Types.BUILDER_DECORATOR; import static io.helidon.builder.processor.Types.CONFIGURED_OPTION_TYPE; import static io.helidon.builder.processor.Types.CONFIGURED_TYPE; import static io.helidon.builder.processor.Types.IMPLEMENT_TYPE; @@ -191,8 +191,8 @@ static TypeContext create(ProcessingContext processingContext, .filter(it -> it) // filter our falses .findFirst() .orElse(false); - Optional builderInterceptor = blueprintAnnotation.getValue("builderInterceptor") - .filter(Predicate.not(BUILDER_INTERCEPTOR::equals)) + Optional decorator = blueprintAnnotation.getValue("decorator") + .filter(Predicate.not(BUILDER_DECORATOR::equals)) .map(TypeName::create); // factory is if the blueprint implements Factory @@ -225,7 +225,7 @@ static TypeContext create(ProcessingContext processingContext, prototypeBuilder, prototypeImpl, runtimeObject, - builderInterceptor, + decorator, superPrototype, annotationsToGenerate(blueprint)); @@ -448,7 +448,7 @@ record TypeInformation( TypeName prototypeBuilder, TypeName prototypeImpl, Optional runtimeObject, - Optional builderInterceptor, + Optional decorator, Optional superPrototype, List annotationsToGenerate) { public TypeName prototypeBuilderBase() { diff --git a/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandler.java b/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandler.java index 57a7c87056b..d34bc564d88 100644 --- a/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandler.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandler.java @@ -90,34 +90,31 @@ protected static String collectionImplType(TypeName typeName) { return LINKED_HASH_SET_TYPE.fqName(); } - protected static List resolveBuilderLines(TypeName typeName, String variableName) { - /* - Make sure that if we got builder, we build it, so the values are correctly filled with interceptors, and validated - with required validators - */ - if (typeName.primitive() - || typeName.isOptional() - || typeName.array() - || typeName.isList() - || typeName.isSet() - || typeName.isMap()) { - // primitive types do not have builders, other types (set, array etc.) - we may add support later if needed - return List.of(); - } - if (typeName.packageName().startsWith("java.")) { - // java packages do not have builders we support - return List.of(); - } - return List.of(variableName + " = resolveBuilder(" + variableName + ");"); - } - @Override public String toString() { return declaredType.fqName() + " " + name; } - String generateBuilderGetter() { - return name; + TypeName builderGetterType(boolean required, boolean hasDefault) { + if (builderGetterOptional(required, hasDefault)) { + if (declaredType().isOptional()) { + // already wrapped + return declaredType(); + } else { + return TypeName.builder(TypeNames.OPTIONAL) + .addTypeArgument(declaredType().boxed()) + .build(); + } + } + return declaredType(); + } + + String generateBuilderGetter(boolean required, boolean hasDefault) { + if (builderGetterOptional(required, hasDefault)) { + return "java.util.Optional.ofNullable(" + name + ")"; + } else { + return name; + } } String fieldDeclaration(PrototypeProperty.ConfiguredOption configured, @@ -267,6 +264,26 @@ protected void charArraySetter(PrototypeProperty.ConfiguredOption configured, )); } + boolean builderGetterOptional(boolean required, boolean hasDefault) { + // optional and collections - good return types + if (declaredType().isList() + || declaredType().isMap() + || declaredType().isSet()) { + return false; + } + if (declaredType().isOptional()) { + return true; + } + // optional and primitive type - good return type (uses default for primitive if not customized) + if (!required && declaredType().primitive()) { + return false; + } + // has default, and not Optional - return type (never can be null) + // any other case (required, optional without defaults) - return optional + return !hasDefault; + + } + private void declaredSetter(PrototypeProperty.ConfiguredOption configured, List setters, TypeName returnType, @@ -275,7 +292,6 @@ private void declaredSetter(PrototypeProperty.ConfiguredOption configured, if (!declaredType.primitive()) { lines.add("Objects.requireNonNull(" + name() + ");"); } - lines.addAll(resolveBuilderLines(actualType(), name())); lines.add("this." + name() + " = " + name() + ";"); lines.add("return self();"); diff --git a/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerCollection.java b/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerCollection.java index 87ce8657079..d6ec1f3a026 100644 --- a/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerCollection.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerCollection.java @@ -97,7 +97,8 @@ Optional generateFromConfig(PrototypeProperty.ConfiguredOption configure @Override TypeName argumentTypeName() { return TypeName.builder(collectionType) - .addTypeArgument(toWildcard(actualType())); + .addTypeArgument(toWildcard(actualType())) + .build(); } @Override @@ -262,7 +263,6 @@ private void singularSetter(PrototypeProperty.ConfiguredOption configured, List lines = new ArrayList<>(); lines.add("Objects.requireNonNull(" + singularName + ");"); - lines.addAll(resolveBuilderLines(actualType(), singularName)); lines.add("this." + name() + ".add(" + singularName + ");"); lines.add("return self();"); diff --git a/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerMap.java b/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerMap.java index e4b115bad55..c0c710775b6 100644 --- a/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerMap.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerMap.java @@ -192,7 +192,6 @@ void setters(PrototypeProperty.ConfiguredOption configured, List lines = new ArrayList<>(); lines.add("Objects.requireNonNull(key);"); lines.add("Objects.requireNonNull(" + singularName + ");"); - lines.addAll(resolveBuilderLines(actualType(), singularName)); lines.add("this." + name() + ".put(key, " + secondArgToPut(actualType(), singularName) + ");"); lines.add("return self();"); setters.add(new GeneratedMethod( diff --git a/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerOptional.java b/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerOptional.java index 4641bb8901e..16c2e976930 100644 --- a/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerOptional.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/TypeHandlerOptional.java @@ -35,11 +35,6 @@ class TypeHandlerOptional extends TypeHandler.OneTypeHandler { super(name, getterName, setterName, declaredType); } - @Override - String generateBuilderGetter() { - return "Optional.ofNullable(" + name() + ")"; - } - @Override String fieldDeclaration(PrototypeProperty.ConfiguredOption configured, boolean isBuilder, boolean alwaysFinal) { StringBuilder fieldDeclaration = new StringBuilder("private "); @@ -70,7 +65,8 @@ String fieldDeclaration(PrototypeProperty.ConfiguredOption configured, boolean i @Override TypeName argumentTypeName() { return TypeName.builder(OPTIONAL) - .addTypeArgument(toWildcard(actualType())); + .addTypeArgument(toWildcard(actualType())) + .build(); } @Override @@ -91,7 +87,6 @@ void setters(PrototypeProperty.ConfiguredOption configured, // declared setter - optional is package local, field is never optional in builder List lines = new ArrayList<>(); lines.add("Objects.requireNonNull(" + name() + ");"); - lines.addAll(resolveBuilderLines(actualType(), name())); lines.add("this." + name() + " = " + name() + ";"); lines.add("return self();"); @@ -148,7 +143,8 @@ void setters(PrototypeProperty.ConfiguredOption configured, FactoryMethods.FactoryMethod fm = factoryMethod.builder().get(); TypeName builderType; - if (fm.factoryMethodReturnType().className().equals("Builder")) { + String className = fm.factoryMethodReturnType().className(); + if (className.equals("Builder") || className.endsWith(".Builder")) { builderType = fm.factoryMethodReturnType(); } else { builderType = TypeName.create(fm.factoryMethodReturnType().fqName() + ".Builder"); diff --git a/builder/processor/src/main/java/io/helidon/builder/processor/Types.java b/builder/processor/src/main/java/io/helidon/builder/processor/Types.java index 6450239d3b9..1a587dfd29c 100644 --- a/builder/processor/src/main/java/io/helidon/builder/processor/Types.java +++ b/builder/processor/src/main/java/io/helidon/builder/processor/Types.java @@ -34,7 +34,7 @@ final class Types { static final String RUNTIME_PROTOTYPE = "io.helidon.builder.api.RuntimeType.PrototypedBy"; static final String PROTOTYPE = "io.helidon.builder.api.Prototype.Api"; static final String PROTOTYPE_SAME_GENERIC = "io.helidon.builder.api.Prototype.SameGeneric"; - static final String BUILDER_INTERCEPTOR = "io.helidon.builder.api.Prototype.BuilderInterceptor"; + static final String BUILDER_DECORATOR = "io.helidon.builder.api.Prototype.BuilderDecorator"; static final String IMPLEMENT = "io.helidon.builder.api.Prototype.Implement"; static final String CONFIDENTIAL = "io.helidon.builder.api.Prototype.Confidential"; static final String REDUNDANT = "io.helidon.builder.api.Prototype.Redundant"; diff --git a/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/BeanBuilderInterceptor.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/BeanBuilderInterceptor.java index 7deaf305996..03eea5e2be5 100644 --- a/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/BeanBuilderInterceptor.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/BeanBuilderInterceptor.java @@ -21,14 +21,14 @@ /** * See {@link InterceptedBean}. */ -class BeanBuilderInterceptor implements Prototype.BuilderInterceptor> { +class BeanBuilderInterceptor implements Prototype.BuilderDecorator> { private int callCount; @Override - public InterceptedBean.BuilderBase intercept(InterceptedBean.BuilderBase target) { + public void decorate(InterceptedBean.BuilderBase target) { if (callCount++ > 0) { throw new AssertionError(); } - return target.helloMessage("Hello " + target.name()); + target.helloMessage("Hello " + target.name().orElse("Not configured")); } } diff --git a/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/InterceptedBeanBlueprint.java b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/InterceptedBeanBlueprint.java index b1f6823d290..e0b2c82159d 100644 --- a/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/InterceptedBeanBlueprint.java +++ b/builder/tests/builder/src/main/java/io/helidon/builder/test/testsubjects/InterceptedBeanBlueprint.java @@ -22,7 +22,7 @@ /** * Demonstrates interception of builders. */ -@Prototype.Blueprint(builderInterceptor = BeanBuilderInterceptor.class) +@Prototype.Blueprint(decorator = BeanBuilderInterceptor.class) interface InterceptedBeanBlueprint { /** diff --git a/common/configurable/src/main/java/io/helidon/common/configurable/ResourceBuilderInterceptor.java b/common/configurable/src/main/java/io/helidon/common/configurable/ResourceBuilderDecorator.java similarity index 82% rename from common/configurable/src/main/java/io/helidon/common/configurable/ResourceBuilderInterceptor.java rename to common/configurable/src/main/java/io/helidon/common/configurable/ResourceBuilderDecorator.java index 453167752c3..a8b2118f3c7 100644 --- a/common/configurable/src/main/java/io/helidon/common/configurable/ResourceBuilderInterceptor.java +++ b/common/configurable/src/main/java/io/helidon/common/configurable/ResourceBuilderDecorator.java @@ -22,16 +22,16 @@ import io.helidon.builder.api.Prototype; -class ResourceBuilderInterceptor implements Prototype.BuilderInterceptor> { +class ResourceBuilderDecorator implements Prototype.BuilderDecorator> { @Override - public ResourceConfig.BuilderBase intercept(ResourceConfig.BuilderBase target) { + public void decorate(ResourceConfig.BuilderBase target) { boolean useProxy = target.useProxy(); if (!useProxy) { target.proxy(Optional.empty()); - return target; + return; } if (target.proxy().isPresent()) { - return target; + return; } if (target.proxyHost().isPresent()) { String proxyHost = target.proxyHost().get(); @@ -40,6 +40,5 @@ class ResourceBuilderInterceptor implements Prototype.BuilderInterceptor { /** diff --git a/common/key-util/src/main/java/io/helidon/common/pki/KeysBlueprint.java b/common/key-util/src/main/java/io/helidon/common/pki/KeysBlueprint.java index 37dc21b6b5e..eb9c87e863f 100644 --- a/common/key-util/src/main/java/io/helidon/common/pki/KeysBlueprint.java +++ b/common/key-util/src/main/java/io/helidon/common/pki/KeysBlueprint.java @@ -36,7 +36,7 @@ * So if a Private key is defined both explicitly and through PEM, the explicitly defined key would be used. */ @Configured -@Prototype.Blueprint(builderInterceptor = KeysBuilderInterceptor.class) +@Prototype.Blueprint(decorator = KeysBuilderDecorator.class) interface KeysBlueprint { /** * Configure keys from a keystore. diff --git a/common/key-util/src/main/java/io/helidon/common/pki/KeysBuilderInterceptor.java b/common/key-util/src/main/java/io/helidon/common/pki/KeysBuilderDecorator.java similarity index 96% rename from common/key-util/src/main/java/io/helidon/common/pki/KeysBuilderInterceptor.java rename to common/key-util/src/main/java/io/helidon/common/pki/KeysBuilderDecorator.java index c0a288160c0..68375cef840 100644 --- a/common/key-util/src/main/java/io/helidon/common/pki/KeysBuilderInterceptor.java +++ b/common/key-util/src/main/java/io/helidon/common/pki/KeysBuilderDecorator.java @@ -28,11 +28,11 @@ import io.helidon.common.configurable.Resource; import io.helidon.common.configurable.ResourceException; -class KeysBuilderInterceptor implements Prototype.BuilderInterceptor> { +class KeysBuilderDecorator implements Prototype.BuilderDecorator> { private static final System.Logger LOGGER = System.getLogger(Keys.class.getName()); @Override - public Keys.BuilderBase intercept(Keys.BuilderBase target) { + public void decorate(Keys.BuilderBase target) { try { target.keystore().ifPresent(keystoreConfig -> updateFromKeystore(target, keystoreConfig)); target.pem().ifPresent(pemConfig -> updateFromPem(target, pemConfig)); @@ -42,7 +42,6 @@ class KeysBuilderInterceptor implements Prototype.BuilderInterceptor> { + class BuilderDecorator implements Prototype.BuilderDecorator> { @Override - public SocketOptions.BuilderBase intercept(SocketOptions.BuilderBase target) { + public void decorate(SocketOptions.BuilderBase target) { target.putSocketOption(StandardSocketOptions.SO_RCVBUF, target.socketReceiveBufferSize()); target.putSocketOption(StandardSocketOptions.SO_SNDBUF, target.socketSendBufferSize()); target.putSocketOption(StandardSocketOptions.SO_REUSEADDR, target.socketReuseAddress()); target.putSocketOption(StandardSocketOptions.SO_KEEPALIVE, target.socketKeepAlive()); target.putSocketOption(StandardSocketOptions.TCP_NODELAY, target.tcpNoDelay()); - - return target; } } } diff --git a/common/types/src/main/java/io/helidon/common/types/Annotation.java b/common/types/src/main/java/io/helidon/common/types/Annotation.java index 58e3d236d0d..e72d18a1b2c 100644 --- a/common/types/src/main/java/io/helidon/common/types/Annotation.java +++ b/common/types/src/main/java/io/helidon/common/types/Annotation.java @@ -18,6 +18,7 @@ import java.util.Objects; +import io.helidon.builder.api.Prototype; import io.helidon.common.Errors; /** @@ -25,7 +26,7 @@ * * @see #builder() */ -public interface Annotation extends AnnotationBlueprint, io.helidon.builder.api.Prototype.Api, Comparable { +public interface Annotation extends AnnotationBlueprint, Prototype.Api, Comparable { /** * Create a new fluent API builder to customize configuration. * @@ -46,7 +47,7 @@ static Builder builder(Annotation instance) { } /** - *Creates an instance for an annotation with no value. + * Creates an instance for an annotation with no value. * * @param annoType the annotation type * @return the new instance @@ -56,7 +57,7 @@ static Annotation create(Class annoTy } /** - *Creates an instance for an annotation with no value. + * Creates an instance for an annotation with no value. * * @param annoType the annotation type * @return the new instance @@ -66,10 +67,10 @@ static Annotation create(TypeName annoType) { } /** - *Creates an instance for an annotation with a value. + * Creates an instance for an annotation with a value. * * @param annoType the annotation type - * @param value the annotation value + * @param value the annotation value * @return the new instance */ static Annotation create(Class annoType, String value) { @@ -77,10 +78,10 @@ static Annotation create(Class annoTy } /** - *Creates an instance for an annotation with a value. + * Creates an instance for an annotation with a value. * * @param annoType the annotation type - * @param values the annotation values + * @param values the annotation values * @return the new instance */ static Annotation create(Class annoType, @@ -89,10 +90,10 @@ static Annotation create(Class annoTy } /** - *Creates an instance for an annotation with a value. + * Creates an instance for an annotation with a value. * * @param annoTypeName the annotation type name - * @param value the annotation value + * @param value the annotation value * @return the new instance */ static Annotation create(TypeName annoTypeName, String value) { @@ -100,10 +101,10 @@ static Annotation create(TypeName annoTypeName, String value) { } /** - *Creates an instance for annotation with zero or more values. + * Creates an instance for annotation with zero or more values. * * @param annoTypeName the annotation type name - * @param values the annotation values + * @param values the annotation values * @return the new instance */ static Annotation create(TypeName annoTypeName, java.util.Map values) { @@ -113,17 +114,16 @@ static Annotation create(TypeName annoTypeName, java.util.Map va /** * Fluent API builder base for {@link io.helidon.common.types.Annotation}. * - * @param type of the builder extending this abstract builder + * @param type of the builder extending this abstract builder * @param type of the prototype interface that would be built by {@link #buildPrototype()} */ abstract class BuilderBase, PROTOTYPE extends Annotation> - implements io.helidon.builder.api.Prototype.Builder, Annotation { + implements io.helidon.builder.api.Prototype.Builder { private final java.util.Map values = new java.util.LinkedHashMap<>(); private TypeName typeName; /** * Protected to support extensibility. - * */ protected BuilderBase() { } @@ -146,41 +146,17 @@ public BUILDER from(Annotation prototype) { * @param builder existing builder prototype to update this builder from * @return updated builder instance */ - public BUILDER from(Annotation.BuilderBase builder) { - if (builder.typeName() != null) { - typeName(builder.typeName()); - } + public BUILDER from(BuilderBase builder) { + builder.typeName().ifPresent(this::typeName); addValues(builder.values()); return self(); } /** - * Handles providers and interceptors. - */ - protected void preBuildPrototype() { - } - - /** - * Validates required properties. - */ - protected void validatePrototype() { - Errors.Collector collector = Errors.collector(); - if (typeName == null) { - collector.fatal(getClass(), "Property \"type-name\" is required, but not set"); - } - collector.collect().checkValid(); - } - - @Override - public int compareTo(Annotation o) { - return AnnotationSupport.compareTo(this, o); - } - - /** - *Annotation type name from annotation type. + * Annotation type name from annotation type. * - *@param annoType annotation class - *@return updated builder instance + * @param annoType annotation class + * @return updated builder instance */ public BUILDER type(java.lang.reflect.Type annoType) { AnnotationSupport.type(this, annoType); @@ -188,10 +164,10 @@ public BUILDER type(java.lang.reflect.Type annoType) { } /** - *Configure the value of this annotation (property of name {@code value}). + * Configure the value of this annotation (property of name {@code value}). * - *@param value value of the annotation - *@return updated builder instance + * @param value value of the annotation + * @return updated builder instance */ public BUILDER value(String value) { AnnotationSupport.value(this, value); @@ -215,7 +191,7 @@ public BUILDER typeName(TypeName typeName) { * The type name, e.g., {@link java.util.Objects} -> "java.util.Objects". * * @param consumer consumer of builder for - * the annotation type name + * the annotation type name * @return updated builder instance * @see #typeName() */ @@ -231,6 +207,7 @@ public BUILDER typeName(java.util.function.Consumer consumer) * Get a key-value of all the annotation properties. * * This method replaces all values with the new ones. + * * @param values key-value pairs of all the properties present * @return updated builder instance * @see #values() @@ -246,6 +223,7 @@ public BUILDER values(java.util.Map values) * Get a key-value of all the annotation properties. * * This method keeps existing values, then puts all new values into the map. + * * @param values key-value pairs of all the properties present * @return updated builder instance * @see #values() @@ -260,7 +238,8 @@ public BUILDER addValues(java.util.Map value * Get a key-value of all the annotation properties. * * This method adds a new value to the map, or replaces it if the key already exists. - * @param key key to add or replace + * + * @param key key to add or replace * @param value new value for the key * @return updated builder instance * @see #values() @@ -277,9 +256,8 @@ public BUILDER putValue(String key, String value) { * * @return the type name */ - @Override - public TypeName typeName() { - return typeName; + public java.util.Optional typeName() { + return java.util.Optional.ofNullable(typeName); } /** @@ -287,7 +265,6 @@ public TypeName typeName() { * * @return the values */ - @Override public java.util.Map values() { return values; } @@ -300,6 +277,23 @@ public String toString() { + "}"; } + /** + * Validates required properties. + */ + protected void validatePrototype() { + Errors.Collector collector = Errors.collector(); + if (typeName == null) { + collector.fatal(getClass(), "Property \"type-name\" is required, but not set"); + } + collector.collect().checkValid(); + } + + /** + * Handles providers and decorators. + */ + protected void preBuildPrototype() { + } + /** * Generated implementation of the prototype, can be extended by descendant prototype implementations. */ @@ -309,10 +303,11 @@ protected static class AnnotationImpl implements Annotation { /** * Create an instance providing a builder. + * * @param builder extending builder base of this prototype */ protected AnnotationImpl(BuilderBase builder) { - this.typeName = builder.typeName(); + this.typeName = builder.typeName().get(); this.values = java.util.Collections.unmodifiableMap(new java.util.LinkedHashMap<>(builder.values())); } diff --git a/common/types/src/main/java/io/helidon/common/types/TypeInfo.java b/common/types/src/main/java/io/helidon/common/types/TypeInfo.java index 264537ecf1b..37d78a1f8b7 100644 --- a/common/types/src/main/java/io/helidon/common/types/TypeInfo.java +++ b/common/types/src/main/java/io/helidon/common/types/TypeInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023 Oracle and/or its affiliates. + * Copyright (c) 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. @@ -50,11 +50,11 @@ static Builder builder(TypeInfo instance) { /** * Fluent API builder base for {@link io.helidon.common.types.TypeInfo}. * - * @param type of the builder extending this abstract builder + * @param type of the builder extending this abstract builder * @param type of the prototype interface that would be built by {@link #buildPrototype()} */ abstract class BuilderBase, PROTOTYPE extends TypeInfo> - implements io.helidon.builder.api.Prototype.Builder, TypeInfo { + implements io.helidon.builder.api.Prototype.Builder { private final java.util.List elementInfo = new java.util.ArrayList<>(); private final java.util.List otherElementInfo = new java.util.ArrayList<>(); private final java.util.Map> referencedTypeNamesToAnnotations = @@ -69,7 +69,6 @@ abstract class BuilderBase, PROT /** * Protected to support extensibility. - * */ protected BuilderBase() { } @@ -101,17 +100,13 @@ public BUILDER from(TypeInfo prototype) { * @return updated builder instance */ public BUILDER from(BuilderBase builder) { - if (builder.typeName() != null) { - typeName(builder.typeName()); - } - if (builder.typeKind() != null) { - typeKind(builder.typeKind()); - } + builder.typeName().ifPresent(this::typeName); + builder.typeKind().ifPresent(this::typeKind); addElementInfo(builder.elementInfo()); addOtherElementInfo(builder.otherElementInfo()); addReferencedTypeNamesToAnnotations(builder.referencedTypeNamesToAnnotations()); addReferencedModuleNames(builder.referencedModuleNames()); - superTypeInfo(builder.superTypeInfo()); + builder.superTypeInfo().ifPresent(this::superTypeInfo); addInterfaceTypeInfo(builder.interfaceTypeInfo()); addModifiers(builder.modifiers()); addAnnotations(builder.annotations()); @@ -119,23 +114,23 @@ public BUILDER from(BuilderBase builder) { } /** - * Handles providers and interceptors. - */ - protected void preBuildPrototype() { - } - - /** - * Validates required properties. + * The type element kind. + *

+ * Such as + *

    + *
  • {@value TypeValues#KIND_INTERFACE}
  • + *
  • {@value TypeValues#KIND_ANNOTATION_TYPE}
  • + *
  • and other constants on {@link TypeValues}
  • + *
+ * + * @param typeKind the type element kind. + * @return updated builder instance + * @see #typeKind() */ - protected void validatePrototype() { - Errors.Collector collector = Errors.collector(); - if (typeName == null) { - collector.fatal(getClass(), "Property \"type-name\" is required, but not set"); - } - if (typeKind == null) { - collector.fatal(getClass(), "Property \"type-kind\" is required, but not set"); - } - collector.collect().checkValid(); + public BUILDER typeKind(String typeKind) { + Objects.requireNonNull(typeKind); + this.typeKind = typeKind; + return self(); } /** @@ -155,7 +150,7 @@ public BUILDER typeName(TypeName typeName) { * The type name. * * @param consumer consumer of builder for - * the type name + * the type name * @return updated builder instance * @see #typeName() */ @@ -168,17 +163,21 @@ public BUILDER typeName(java.util.function.Consumer consumer) } /** - * The type element kind. + * Any Map, List, Set, or method that has {@link TypeName#typeArguments()} will be analyzed and any + * type arguments will have + * its annotations added here. Note that this only applies to non-built-in types. * - * @param typeKind the type element kind (e.g., "{@value TypeValues#KIND_INTERFACE}", - * "{@value TypeValues#KIND_ANNOTATION_TYPE}", - * etc.) + * This method replaces all values with the new ones. + * + * @param referencedTypeNamesToAnnotations all referenced types * @return updated builder instance - * @see #typeKind() + * @see #referencedTypeNamesToAnnotations() */ - public BUILDER typeKind(String typeKind) { - Objects.requireNonNull(typeKind); - this.typeKind = typeKind; + public BUILDER referencedTypeNamesToAnnotations(java.util.Map> referencedTypeNamesToAnnotations) { + Objects.requireNonNull(referencedTypeNamesToAnnotations); + this.referencedTypeNamesToAnnotations.clear(); + this.referencedTypeNamesToAnnotations.putAll(referencedTypeNamesToAnnotations); return self(); } @@ -301,33 +300,31 @@ public BUILDER addOtherElementInfo(java.util.function.Consumer> referencedTypeNamesToAnnotations) { + public BUILDER addReferencedTypeNamesToAnnotations(java.util.Map> referencedTypeNamesToAnnotations) { Objects.requireNonNull(referencedTypeNamesToAnnotations); - this.referencedTypeNamesToAnnotations.clear(); this.referencedTypeNamesToAnnotations.putAll(referencedTypeNamesToAnnotations); return self(); } /** - * Any Map, List, Set, or method that has {@link TypeName#typeArguments()} will be analyzed and any - * type arguments will have - * its annotations added here. Note that this only applies to non-built-in types. + * The parent/super class for this type info. * - * This method keeps existing values, then puts all new values into the map. - * @param referencedTypeNamesToAnnotations all referenced types + * @param consumer the super type * @return updated builder instance - * @see #referencedTypeNamesToAnnotations() + * @see #superTypeInfo() */ - public BUILDER addReferencedTypeNamesToAnnotations(java.util.Map> referencedTypeNamesToAnnotations) { - Objects.requireNonNull(referencedTypeNamesToAnnotations); - this.referencedTypeNamesToAnnotations.putAll(referencedTypeNamesToAnnotations); + public BUILDER superTypeInfo(java.util.function.Consumer consumer) { + Objects.requireNonNull(consumer); + var builder = TypeInfo.builder(); + consumer.accept(builder); + this.superTypeInfo(builder.build()); return self(); } @@ -337,7 +334,8 @@ public BUILDER addReferencedTypeNamesToAnnotations(java.util.Map superTypeInfo) { - Objects.requireNonNull(superTypeInfo); - this.superTypeInfo = superTypeInfo.orElse(null); - return self(); - } - /** * Clear existing value of this property. + * * @return updated builder instance * @see #superTypeInfo() */ @@ -477,17 +468,17 @@ public BUILDER superTypeInfo(TypeInfo superTypeInfo) { } /** - * The parent/super class for this type info. + * The interface classes for this type info. * - * @param consumer the super type + * @param consumer the interface type info * @return updated builder instance - * @see #superTypeInfo() + * @see #interfaceTypeInfo() */ - public BUILDER superTypeInfo(java.util.function.Consumer consumer) { + public BUILDER addInterfaceTypeInfo(java.util.function.Consumer consumer) { Objects.requireNonNull(consumer); var builder = TypeInfo.builder(); consumer.accept(builder); - this.superTypeInfo(builder.build()); + this.interfaceTypeInfo.add(builder.build()); return self(); } @@ -532,18 +523,12 @@ public BUILDER addInterfaceTypeInfo(TypeInfo interfaceTypeInfo) { } /** - * The interface classes for this type info. + * The type name. * - * @param consumer the interface type info - * @return updated builder instance - * @see #interfaceTypeInfo() + * @return the type name */ - public BUILDER addInterfaceTypeInfo(java.util.function.Consumer consumer) { - Objects.requireNonNull(consumer); - var builder = TypeInfo.builder(); - consumer.accept(builder); - this.interfaceTypeInfo.add(builder.build()); - return self(); + public Optional typeName() { + return Optional.ofNullable(typeName); } /** @@ -645,24 +630,20 @@ public BUILDER addAnnotation(java.util.function.Consumer con return self(); } - /** - * The type name. - * - * @return the type name - */ - @Override - public TypeName typeName() { - return typeName; - } - /** * The type element kind. + *

+ * Such as + *

    + *
  • {@value TypeValues#KIND_INTERFACE}
  • + *
  • {@value TypeValues#KIND_ANNOTATION_TYPE}
  • + *
  • and other constants on {@link TypeValues}
  • + *
* * @return the type kind */ - @Override - public String typeKind() { - return typeKind; + public Optional typeKind() { + return Optional.ofNullable(typeKind); } /** @@ -670,7 +651,6 @@ public String typeKind() { * * @return the element info */ - @Override public java.util.List elementInfo() { return elementInfo; } @@ -681,7 +661,6 @@ public java.util.List elementInfo() { * * @return the other element info */ - @Override public java.util.List otherElementInfo() { return otherElementInfo; } @@ -693,7 +672,6 @@ public java.util.List otherElementInfo() { * * @return the referenced type names to annotations */ - @Override public java.util.Map> referencedTypeNamesToAnnotations() { return referencedTypeNamesToAnnotations; } @@ -703,7 +681,6 @@ public java.util.Map> referencedTypeNamesTo * * @return the referenced module names */ - @Override public java.util.Map referencedModuleNames() { return referencedModuleNames; } @@ -713,7 +690,6 @@ public java.util.Map referencedModuleNames() { * * @return the super type info */ - @Override public Optional superTypeInfo() { return Optional.ofNullable(superTypeInfo); } @@ -723,7 +699,6 @@ public Optional superTypeInfo() { * * @return the interface type info */ - @Override public java.util.List interfaceTypeInfo() { return interfaceTypeInfo; } @@ -733,7 +708,6 @@ public java.util.List interfaceTypeInfo() { * * @return the modifiers */ - @Override public java.util.Set modifiers() { return modifiers; } @@ -744,7 +718,6 @@ public java.util.Set modifiers() { * * @return the annotations */ - @Override public java.util.List annotations() { return annotations; } @@ -761,6 +734,39 @@ public String toString() { + "}"; } + /** + * Validates required properties. + */ + protected void validatePrototype() { + Errors.Collector collector = Errors.collector(); + if (typeName == null) { + collector.fatal(getClass(), "Property \"type-name\" is required, but not set"); + } + if (typeKind == null) { + collector.fatal(getClass(), "Property \"type-kind\" is required, but not set"); + } + collector.collect().checkValid(); + } + + /** + * The parent/super class for this type info. + * + * @param superTypeInfo the super type + * @return updated builder instance + * @see #superTypeInfo() + */ + BUILDER superTypeInfo(Optional superTypeInfo) { + Objects.requireNonNull(superTypeInfo); + this.superTypeInfo = superTypeInfo.orElse(null); + return self(); + } + + /** + * Handles providers and decorators. + */ + protected void preBuildPrototype() { + } + /** * Generated implementation of the prototype, can be extended by descendant prototype implementations. */ @@ -778,11 +784,12 @@ protected static class TypeInfoImpl implements TypeInfo { /** * Create an instance providing a builder. + * * @param builder extending builder base of this prototype */ protected TypeInfoImpl(BuilderBase builder) { - this.typeName = builder.typeName(); - this.typeKind = builder.typeKind(); + this.typeName = builder.typeName().get(); + this.typeKind = builder.typeKind().get(); this.elementInfo = java.util.List.copyOf(builder.elementInfo()); this.otherElementInfo = java.util.List.copyOf(builder.otherElementInfo()); this.referencedTypeNamesToAnnotations = java.util.Collections.unmodifiableMap(new java.util.LinkedHashMap<>( diff --git a/common/types/src/main/java/io/helidon/common/types/TypeName.java b/common/types/src/main/java/io/helidon/common/types/TypeName.java index bb682fd4deb..62b1286a7ec 100644 --- a/common/types/src/main/java/io/helidon/common/types/TypeName.java +++ b/common/types/src/main/java/io/helidon/common/types/TypeName.java @@ -44,8 +44,7 @@ * * @see #builder() */ -public interface TypeName - extends TypeNameBlueprint, Prototype.Api, Comparable { +public interface TypeName extends TypeNameBlueprint, Prototype.Api, Comparable { /** * Create a new fluent API builder to customize configuration. * @@ -66,7 +65,7 @@ static Builder builder(TypeName instance) { } /** - *Create a type name from a type (such as class). + * Create a type name from a type (such as class). * * @param type the type * @return type name for the provided type @@ -76,7 +75,7 @@ static TypeName create(java.lang.reflect.Type type) { } /** - *Creates a type name from a fully qualified class name. + * Creates a type name from a fully qualified class name. * * @param typeName the FQN of the class type * @return the TypeName for the provided type name @@ -86,7 +85,7 @@ static TypeName create(String typeName) { } /** - *Creates a type name from a generic alias type name. + * Creates a type name from a generic alias type name. * * @param genericAliasTypeName the generic alias type name * @return the TypeName for the provided type name @@ -96,29 +95,29 @@ static TypeName createFromGenericDeclaration(String genericAliasTypeName) { } /** - *Return the boxed equivalent of this type. - *If this is not a primitive type, returns this instance. + * Return the boxed equivalent of this type. + * If this is not a primitive type, returns this instance. * - *@return boxed type for this type, or this type if not primitive + * @return boxed type for this type, or this type if not primitive */ TypeName boxed(); /** - *The base generic type name, stripped of any {@link TypeName#typeArguments()}. - *This is equivalent to the type name represented by {@link TypeName#name()}. + * The base generic type name, stripped of any {@link io.helidon.common.types.TypeName#typeArguments()}. + * This is equivalent to the type name represented by {@link io.helidon.common.types.TypeName#name()}. * - *@return based generic type name + * @return based generic type name */ TypeName genericTypeName(); /** * Fluent API builder base for {@link io.helidon.common.types.TypeName}. * - * @param type of the builder extending this abstract builder + * @param type of the builder extending this abstract builder * @param type of the prototype interface that would be built by {@link #buildPrototype()} */ abstract class BuilderBase, PROTOTYPE extends TypeName> - implements io.helidon.builder.api.Prototype.Builder, TypeName { + implements io.helidon.builder.api.Prototype.Builder { private final java.util.List enclosingNames = new java.util.ArrayList<>(); private final java.util.List typeArguments = new java.util.ArrayList<>(); private String packageName = ""; @@ -130,7 +129,6 @@ abstract class BuilderBase, PROT /** * Protected to support extensibility. - * */ protected BuilderBase() { } @@ -160,12 +158,8 @@ public BUILDER from(TypeName prototype) { * @return updated builder instance */ public BUILDER from(BuilderBase builder) { - if (builder.packageName() != null) { - packageName(builder.packageName()); - } - if (builder.className() != null) { - className(builder.className()); - } + packageName(builder.packageName()); + builder.className().ifPresent(this::className); addEnclosingNames(builder.enclosingNames()); primitive(builder.primitive()); array(builder.array()); @@ -176,69 +170,10 @@ public BUILDER from(BuilderBase builder) { } /** - * Handles providers and interceptors. - */ - protected void preBuildPrototype() { - } - - /** - * Validates required properties. - */ - protected void validatePrototype() { - Errors.Collector collector = Errors.collector(); - if (className == null) { - collector.fatal(getClass(), "Property \"class-name\" is required, but not set"); - } - collector.collect().checkValid(); - } - - @Override - public int compareTo(TypeName o) { - return TypeNameSupport.compareTo(this, o); - } - - /** - *Return the boxed equivalent of this type. - *If this is not a primitive type, returns this instance. - * - *@return boxed type for this type, or this type if not primitive - */ - @Override - public TypeName boxed() { - return TypeNameSupport.boxed(this); - } - - @Override - public String toString() { - return TypeNameSupport.toString(this); - } - - @Override - public String name() { - return TypeNameSupport.name(this); - } - - /** - *The base generic type name, stripped of any {@link TypeName#typeArguments()}. - *This is equivalent to the type name represented by {@link TypeName#name()}. + * Update builder from the provided type. * - *@return based generic type name - */ - @Override - public TypeName genericTypeName() { - return TypeNameSupport.genericTypeName(this); - } - - @Override - public String fqName() { - return TypeNameSupport.fqName(this); - } - - /** - *Update builder from the provided type. - * - *@param type type to get information (package name, class name, primitive, array) - *@return updated builder instance + * @param type type to get information (package name, class name, primitive, array) + * @return updated builder instance */ public BUILDER type(java.lang.reflect.Type type) { TypeNameSupport.type(this, type); @@ -412,7 +347,7 @@ public BUILDER addTypeArgument(TypeName typeArgument) { * @return updated builder instance * @see #typeArguments() */ - public BUILDER addTypeArgument(java.util.function.Consumer consumer) { + public BUILDER addTypeArgument(java.util.function.Consumer consumer) { Objects.requireNonNull(consumer); var builder = TypeName.builder(); consumer.accept(builder); @@ -425,7 +360,6 @@ public BUILDER addTypeArgument(java.util.function.Consumer con * * @return the package name */ - @Override public String packageName() { return packageName; } @@ -435,9 +369,8 @@ public String packageName() { * * @return the class name */ - @Override - public String className() { - return className; + public java.util.Optional className() { + return java.util.Optional.ofNullable(className); } /** @@ -447,7 +380,6 @@ public String className() { * * @return the enclosing names */ - @Override public java.util.List enclosingNames() { return enclosingNames; } @@ -457,7 +389,6 @@ public java.util.List enclosingNames() { * * @return the primitive */ - @Override public boolean primitive() { return primitive; } @@ -467,7 +398,6 @@ public boolean primitive() { * * @return the array */ - @Override public boolean array() { return array; } @@ -477,7 +407,6 @@ public boolean array() { * * @return the generic */ - @Override public boolean generic() { return generic; } @@ -487,7 +416,6 @@ public boolean generic() { * * @return the wildcard */ - @Override public boolean wildcard() { return wildcard; } @@ -497,11 +425,27 @@ public boolean wildcard() { * * @return the type arguments */ - @Override public java.util.List typeArguments() { return typeArguments; } + /** + * Validates required properties. + */ + protected void validatePrototype() { + Errors.Collector collector = Errors.collector(); + if (className == null) { + collector.fatal(getClass(), "Property \"class-name\" is required, but not set"); + } + collector.collect().checkValid(); + } + + /** + * Handles providers and decorators. + */ + protected void preBuildPrototype() { + } + /** * Generated implementation of the prototype, can be extended by descendant prototype implementations. */ @@ -517,11 +461,12 @@ protected static class TypeNameImpl implements TypeName { /** * Create an instance providing a builder. + * * @param builder extending builder base of this prototype */ protected TypeNameImpl(BuilderBase builder) { this.packageName = builder.packageName(); - this.className = builder.className(); + this.className = builder.className().get(); this.enclosingNames = java.util.List.copyOf(builder.enclosingNames()); this.primitive = builder.primitive(); this.array = builder.array(); @@ -608,11 +553,10 @@ public boolean equals(Object o) { if (!(o instanceof TypeName other)) { return false; } - return Objects.equals(packageName, other.packageName()) - && Objects.equals(className, other.className()) - && Objects.equals(enclosingNames, other.enclosingNames()) - && primitive == other.primitive() - && array == other.array(); + return Objects.equals(packageName, other.packageName()) && Objects.equals(className, + other.className()) && Objects.equals( + enclosingNames, + other.enclosingNames()) && primitive == other.primitive() && array == other.array(); } @Override diff --git a/common/types/src/main/java/io/helidon/common/types/TypedElementInfo.java b/common/types/src/main/java/io/helidon/common/types/TypedElementInfo.java index a4e7a2ad98f..2e7e18b80eb 100644 --- a/common/types/src/main/java/io/helidon/common/types/TypedElementInfo.java +++ b/common/types/src/main/java/io/helidon/common/types/TypedElementInfo.java @@ -48,20 +48,20 @@ static Builder builder(TypedElementInfo instance) { } /** - *Provides a description for this instance. + * Provides a description for this instance. * - *@return provides the {typeName}{space}{elementName} + * @return provides the {typeName}{space}{elementName} */ String toDeclaration(); /** * Fluent API builder base for {@link io.helidon.common.types.TypedElementInfo}. * - * @param type of the builder extending this abstract builder + * @param type of the builder extending this abstract builder * @param type of the prototype interface that would be built by {@link #buildPrototype()} */ abstract class BuilderBase, PROTOTYPE extends TypedElementInfo> - implements io.helidon.builder.api.Prototype.Builder, TypedElementInfo { + implements io.helidon.builder.api.Prototype.Builder { private final java.util.List elementTypeAnnotations = new java.util.ArrayList<>(); private final java.util.List componentTypes = new java.util.ArrayList<>(); private final java.util.Set modifiers = new java.util.LinkedHashSet<>(); @@ -76,7 +76,6 @@ abstract class BuilderBase, PROT /** * Protected to support extensibility. - * */ protected BuilderBase() { } @@ -109,79 +108,39 @@ public BUILDER from(TypedElementInfo prototype) { * @return updated builder instance */ public BUILDER from(BuilderBase builder) { - description(builder.description()); - if (builder.typeName() != null) { - typeName(builder.typeName()); - } - if (builder.elementName() != null) { - elementName(builder.elementName()); - } - if (builder.elementTypeKind() != null) { - elementTypeKind(builder.elementTypeKind()); - } - defaultValue(builder.defaultValue()); + builder.description().ifPresent(this::description); + builder.typeName().ifPresent(this::typeName); + builder.elementName().ifPresent(this::elementName); + builder.elementTypeKind().ifPresent(this::elementTypeKind); + builder.defaultValue().ifPresent(this::defaultValue); addElementTypeAnnotations(builder.elementTypeAnnotations()); addComponentTypes(builder.componentTypes()); addModifiers(builder.modifiers()); - enclosingType(builder.enclosingType()); + builder.enclosingType().ifPresent(this::enclosingType); addParameterArguments(builder.parameterArguments()); addAnnotations(builder.annotations()); return self(); } /** - * Handles providers and interceptors. - */ - protected void preBuildPrototype() { - } - - /** - * Validates required properties. - */ - protected void validatePrototype() { - Errors.Collector collector = Errors.collector(); - if (typeName == null) { - collector.fatal(getClass(), "Property \"type-name\" is required, but not set"); - } - if (elementName == null) { - collector.fatal(getClass(), "Property \"element-name\" is required, but not set"); - } - if (elementTypeKind == null) { - collector.fatal(getClass(), "Property \"element-type-kind\" is required, but not set"); - } - collector.collect().checkValid(); - } - - @Override - public String toString() { - return TypedElementInfoSupport.toString(this); - } - - /** - *Provides a description for this instance. - * - *@return provides the {typeName}{space}{elementName} - */ - @Override - public String toDeclaration() { - return TypedElementInfoSupport.toDeclaration(this); - } - - /** - * Description, such as javadoc, if available. + * The enclosing type name for this typed element. Applicable when this instance represents a + * {@link TypeValues#KIND_FIELD}, or + * {@link TypeValues#KIND_METHOD}, or + * {@link TypeValues#KIND_PARAMETER} * - * @param description description of this element + * @param enclosingType the enclosing type element * @return updated builder instance - * @see #description() + * @see #enclosingType() */ - BUILDER description(Optional description) { - Objects.requireNonNull(description); - this.description = description.orElse(null); + public BUILDER enclosingType(TypeName enclosingType) { + Objects.requireNonNull(enclosingType); + this.enclosingType = enclosingType; return self(); } /** * Clear existing value of this property. + * * @return updated builder instance * @see #description() */ @@ -222,7 +181,7 @@ public BUILDER typeName(TypeName typeName) { * the method. * * @param consumer consumer of builder for - * the type name of the element + * the type name of the element * @return updated builder instance * @see #typeName() */ @@ -260,21 +219,9 @@ public BUILDER elementTypeKind(String elementTypeKind) { return self(); } - /** - * The default value assigned to the element, represented as a string. - * - * @param defaultValue the default value as a string - * @return updated builder instance - * @see #defaultValue() - */ - BUILDER defaultValue(Optional defaultValue) { - Objects.requireNonNull(defaultValue); - this.defaultValue = defaultValue.orElse(null); - return self(); - } - /** * Clear existing value of this property. + * * @return updated builder instance * @see #defaultValue() */ @@ -392,21 +339,25 @@ public BUILDER addModifier(String modifier) { /** * The enclosing type name for this typed element. Applicable when this instance represents a - * {@link TypeValues#KIND_FIELD} or - * {@link TypeValues#KIND_METHOD}. + * {@link TypeValues#KIND_FIELD}, or + * {@link TypeValues#KIND_METHOD}, or + * {@link TypeValues#KIND_PARAMETER} * - * @param enclosingType the enclosing type element + * @param consumer the enclosing type element * @return updated builder instance * @see #enclosingType() */ - BUILDER enclosingType(Optional enclosingType) { - Objects.requireNonNull(enclosingType); - this.enclosingType = enclosingType.orElse(null); + public BUILDER enclosingType(java.util.function.Consumer consumer) { + Objects.requireNonNull(consumer); + var builder = TypeName.builder(); + consumer.accept(builder); + this.enclosingType(builder.build()); return self(); } /** * Clear existing value of this property. + * * @return updated builder instance * @see #enclosingType() */ @@ -416,35 +367,30 @@ public BUILDER clearEnclosingType() { } /** - * The enclosing type name for this typed element. Applicable when this instance represents a - * {@link TypeValues#KIND_FIELD} or - * {@link TypeValues#KIND_METHOD}. + * Parameter arguments applicable if this type element represents a {@link TypeValues#KIND_METHOD}. + * Each instance of this list + * will be the individual {@link TypeValues#KIND_PARAMETER}'s for the method. * - * @param enclosingType the enclosing type element + * @param consumer the list of parameters belonging to this method if applicable * @return updated builder instance - * @see #enclosingType() + * @see #parameterArguments() */ - public BUILDER enclosingType(TypeName enclosingType) { - Objects.requireNonNull(enclosingType); - this.enclosingType = enclosingType; + public BUILDER addParameterArgument(java.util.function.Consumer consumer) { + Objects.requireNonNull(consumer); + var builder = TypedElementInfo.builder(); + consumer.accept(builder); + this.parameterArguments.add(builder.build()); return self(); } /** - * The enclosing type name for this typed element. Applicable when this instance represents a - * {@link TypeValues#KIND_FIELD} or - * {@link TypeValues#KIND_METHOD}. + * The type name for the element (e.g., java.util.List). If the element is a method, then this is the return type of + * the method. * - * @param consumer the enclosing type element - * @return updated builder instance - * @see #enclosingType() + * @return the type name */ - public BUILDER enclosingType(java.util.function.Consumer consumer) { - Objects.requireNonNull(consumer); - var builder = TypeName.builder(); - consumer.accept(builder); - this.enclosingType(builder.build()); - return self(); + public Optional typeName() { + return Optional.ofNullable(typeName); } /** @@ -494,20 +440,12 @@ public BUILDER addParameterArgument(TypedElementInfo parameterArgument) { } /** - * Parameter arguments applicable if this type element represents a {@link TypeValues#KIND_METHOD}. - * Each instance of this list - * will be the individual {@link TypeValues#KIND_PARAMETER}'s for the method. + * The element (e.g., method, field, etc) name. * - * @param consumer the list of parameters belonging to this method if applicable - * @return updated builder instance - * @see #parameterArguments() + * @return the element name */ - public BUILDER addParameterArgument(java.util.function.Consumer consumer) { - Objects.requireNonNull(consumer); - var builder = TypedElementInfo.builder(); - consumer.accept(builder); - this.parameterArguments.add(builder.build()); - return self(); + public Optional elementName() { + return Optional.ofNullable(elementName); } /** @@ -574,40 +512,29 @@ public BUILDER addAnnotation(java.util.function.Consumer con * * @return the description */ - @Override public Optional description() { return Optional.ofNullable(description); } /** - * The type name for the element (e.g., java.util.List). If the element is a method, then this is the return type of - * the method. - * - * @return the type name - */ - @Override - public TypeName typeName() { - return typeName; - } - - /** - * The element (e.g., method, field, etc) name. + * The kind of element (e.g., method, field, etc). * - * @return the element name + * @return the element type kind */ - @Override - public String elementName() { - return elementName; + public Optional elementTypeKind() { + return Optional.ofNullable(elementTypeKind); } /** - * The kind of element (e.g., method, field, etc). + * The enclosing type name for this typed element. Applicable when this instance represents a + * {@link TypeValues#KIND_FIELD}, or + * {@link TypeValues#KIND_METHOD}, or + * {@link TypeValues#KIND_PARAMETER} * - * @return the element type kind + * @return the enclosing type */ - @Override - public String elementTypeKind() { - return elementTypeKind; + public Optional enclosingType() { + return Optional.ofNullable(enclosingType); } /** @@ -615,7 +542,6 @@ public String elementTypeKind() { * * @return the default value */ - @Override public Optional defaultValue() { return Optional.ofNullable(defaultValue); } @@ -625,7 +551,6 @@ public Optional defaultValue() { * * @return the element type annotations */ - @Override public java.util.List elementTypeAnnotations() { return elementTypeAnnotations; } @@ -635,7 +560,6 @@ public java.util.List elementTypeAnnotations() { * * @return the component types */ - @Override public java.util.List componentTypes() { return componentTypes; } @@ -645,23 +569,10 @@ public java.util.List componentTypes() { * * @return the modifiers */ - @Override public java.util.Set modifiers() { return modifiers; } - /** - * The enclosing type name for this typed element. Applicable when this instance represents a - * {@link TypeValues#KIND_FIELD} or - * {@link TypeValues#KIND_METHOD}. - * - * @return the enclosing type - */ - @Override - public Optional enclosingType() { - return Optional.ofNullable(enclosingType); - } - /** * Parameter arguments applicable if this type element represents a {@link TypeValues#KIND_METHOD}. * Each instance of this list @@ -669,7 +580,6 @@ public Optional enclosingType() { * * @return the parameter arguments */ - @Override public java.util.List parameterArguments() { return parameterArguments; } @@ -680,11 +590,75 @@ public java.util.List parameterArguments() { * * @return the annotations */ - @Override public java.util.List annotations() { return annotations; } + /** + * Validates required properties. + */ + protected void validatePrototype() { + Errors.Collector collector = Errors.collector(); + if (typeName == null) { + collector.fatal(getClass(), "Property \"type-name\" is required, but not set"); + } + if (elementName == null) { + collector.fatal(getClass(), "Property \"element-name\" is required, but not set"); + } + if (elementTypeKind == null) { + collector.fatal(getClass(), "Property \"element-type-kind\" is required, but not set"); + } + collector.collect().checkValid(); + } + + /** + * Description, such as javadoc, if available. + * + * @param description description of this element + * @return updated builder instance + * @see #description() + */ + BUILDER description(Optional description) { + Objects.requireNonNull(description); + this.description = description.orElse(null); + return self(); + } + + /** + * The default value assigned to the element, represented as a string. + * + * @param defaultValue the default value as a string + * @return updated builder instance + * @see #defaultValue() + */ + BUILDER defaultValue(Optional defaultValue) { + Objects.requireNonNull(defaultValue); + this.defaultValue = defaultValue.orElse(null); + return self(); + } + + /** + * Handles providers and decorators. + */ + protected void preBuildPrototype() { + } + + /** + * The enclosing type name for this typed element. Applicable when this instance represents a + * {@link TypeValues#KIND_FIELD}, or + * {@link TypeValues#KIND_METHOD}, or + * {@link TypeValues#KIND_PARAMETER} + * + * @param enclosingType the enclosing type element + * @return updated builder instance + * @see #enclosingType() + */ + BUILDER enclosingType(Optional enclosingType) { + Objects.requireNonNull(enclosingType); + this.enclosingType = enclosingType.orElse(null); + return self(); + } + /** * Generated implementation of the prototype, can be extended by descendant prototype implementations. */ @@ -703,13 +677,14 @@ protected static class TypedElementInfoImpl implements TypedElementInfo { /** * Create an instance providing a builder. + * * @param builder extending builder base of this prototype */ protected TypedElementInfoImpl(BuilderBase builder) { this.description = builder.description(); - this.typeName = builder.typeName(); - this.elementName = builder.elementName(); - this.elementTypeKind = builder.elementTypeKind(); + this.typeName = builder.typeName().get(); + this.elementName = builder.elementName().get(); + this.elementTypeKind = builder.elementTypeKind().get(); this.defaultValue = builder.defaultValue(); this.elementTypeAnnotations = java.util.List.copyOf(builder.elementTypeAnnotations()); this.componentTypes = java.util.List.copyOf(builder.componentTypes()); diff --git a/common/types/src/test/java/io/helidon/common/types/TypeNameTest.java b/common/types/src/test/java/io/helidon/common/types/TypeNameTest.java index 3bc47cd07de..bf83ef6f706 100644 --- a/common/types/src/test/java/io/helidon/common/types/TypeNameTest.java +++ b/common/types/src/test/java/io/helidon/common/types/TypeNameTest.java @@ -393,7 +393,7 @@ void builderOfType() { @Test void extendsTypeName() { - TypeName extendsName = TypeName.builder(create(Map.class)).wildcard(true); + TypeName extendsName = TypeName.builder(create(Map.class)).wildcard(true).build(); assertThat(extendsName.fqName(), equalTo("? extends java.util.Map")); assertThat(extendsName.declaredName(), equalTo("java.util.Map")); assertThat(extendsName.name(), equalTo("java.util.Map")); diff --git a/common/uri/src/main/java/io/helidon/common/uri/UriBuilderSupport.java b/common/uri/src/main/java/io/helidon/common/uri/UriBuilderSupport.java index b32c1685d92..3c883826833 100644 --- a/common/uri/src/main/java/io/helidon/common/uri/UriBuilderSupport.java +++ b/common/uri/src/main/java/io/helidon/common/uri/UriBuilderSupport.java @@ -22,16 +22,15 @@ final class UriBuilderSupport { private UriBuilderSupport() { } - static final class UriInfoInterceptor implements Prototype.BuilderInterceptor> { + static final class UriInfoInterceptor implements Prototype.BuilderDecorator> { UriInfoInterceptor() { } @Override - public UriInfo.BuilderBase intercept(UriInfo.BuilderBase target) { + public void decorate(UriInfo.BuilderBase target) { if (target.port() == 0) { target.port(defaultPort(target.scheme())); } - return target; } private static int defaultPort(String scheme) { diff --git a/common/uri/src/main/java/io/helidon/common/uri/UriInfoBlueprint.java b/common/uri/src/main/java/io/helidon/common/uri/UriInfoBlueprint.java index 6f42713ca08..64565d8896a 100644 --- a/common/uri/src/main/java/io/helidon/common/uri/UriInfoBlueprint.java +++ b/common/uri/src/main/java/io/helidon/common/uri/UriInfoBlueprint.java @@ -25,7 +25,7 @@ /** * Information about URI, that can be used to invoke a specific request over the network. */ -@Prototype.Blueprint(builderInterceptor = UriBuilderSupport.UriInfoInterceptor.class) +@Prototype.Blueprint(decorator = UriBuilderSupport.UriInfoInterceptor.class) @Prototype.CustomMethods(UriBuilderSupport.UriInfoCustomMethods.class) interface UriInfoBlueprint { diff --git a/inject/api/src/main/java/io/helidon/inject/api/ActivationLogEntryBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ActivationLogEntryBlueprint.java index e47fd03b739..c5dabfa0c4a 100644 --- a/inject/api/src/main/java/io/helidon/inject/api/ActivationLogEntryBlueprint.java +++ b/inject/api/src/main/java/io/helidon/inject/api/ActivationLogEntryBlueprint.java @@ -29,7 +29,7 @@ * @see Activator * @see DeActivator */ -@Prototype.Blueprint(builderInterceptor = ActivationLogEntryBlueprint.Interceptor.class) +@Prototype.Blueprint(decorator = ActivationLogEntryBlueprint.BuilderDecorator.class) interface ActivationLogEntryBlueprint { /** @@ -92,14 +92,14 @@ interface ActivationLogEntryBlueprint { /** * Ensures that the non-nullable fields are populated with default values. */ - class Interceptor implements Prototype.BuilderInterceptor> { + class BuilderDecorator implements Prototype.BuilderDecorator> { - Interceptor() { + BuilderDecorator() { } @Override - public ActivationLogEntry.BuilderBase intercept(ActivationLogEntry.BuilderBase b) { - if (b.time() == null) { + public void decorate(ActivationLogEntry.BuilderBase b) { + if (b.time().isEmpty()) { b.time(Instant.now()); } @@ -107,11 +107,9 @@ class Interceptor implements Prototype.BuilderInterceptor stackTraceAsList() { .orElseGet(List::of); } - class BuilderInterceptor implements Prototype.BuilderInterceptor> { + class BuilderDecorator implements Prototype.BuilderDecorator> { @Override - public CallingContext.BuilderBase intercept(CallingContext.BuilderBase target) { - if (target.threadName() == null) { + public void decorate(CallingContext.BuilderBase target) { + if (target.threadName().isEmpty()) { target.threadName(Thread.currentThread().getName()); } - return target; } } diff --git a/inject/api/src/main/java/io/helidon/inject/api/InjectorOptionsBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/InjectorOptionsBlueprint.java index d38fef40e5b..b4187dbb99c 100644 --- a/inject/api/src/main/java/io/helidon/inject/api/InjectorOptionsBlueprint.java +++ b/inject/api/src/main/java/io/helidon/inject/api/InjectorOptionsBlueprint.java @@ -24,7 +24,7 @@ * * @see Injector */ -@Prototype.Blueprint(builderInterceptor = InjectorOptionsBlueprint.Interceptor.class) +@Prototype.Blueprint(decorator = InjectorOptionsBlueprint.BuilderDecorator.class) interface InjectorOptionsBlueprint { /** * The strategy the injector should apply. The default is {@link Injector.Strategy#ANY}. @@ -45,16 +45,15 @@ interface InjectorOptionsBlueprint { /** * This will ensure that the activation request is populated. */ - class Interceptor implements Prototype.BuilderInterceptor> { - Interceptor() { + class BuilderDecorator implements Prototype.BuilderDecorator> { + BuilderDecorator() { } @Override - public InjectorOptions.BuilderBase intercept(InjectorOptions.BuilderBase target) { - if (target.activationRequest() == null) { + public void decorate(InjectorOptions.BuilderBase target) { + if (target.activationRequest().isEmpty()) { target.activationRequest(InjectionServices.createActivationRequestDefault()); } - return target; } } diff --git a/inject/api/src/main/java/io/helidon/inject/api/InternalBootstrapBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/InternalBootstrapBlueprint.java index 3b4698b6d93..1343815b525 100644 --- a/inject/api/src/main/java/io/helidon/inject/api/InternalBootstrapBlueprint.java +++ b/inject/api/src/main/java/io/helidon/inject/api/InternalBootstrapBlueprint.java @@ -23,7 +23,7 @@ /** * Internal bootstrap is what we store when {@link InjectionServices#globalBootstrap(Bootstrap)} is used. */ -@Prototype.Blueprint(builderInterceptor = InternalBootstrapBlueprint.BuilderInterceptor.class) +@Prototype.Blueprint(decorator = InternalBootstrapBlueprint.BuilderDecorator.class) interface InternalBootstrapBlueprint { /** @@ -40,13 +40,12 @@ interface InternalBootstrapBlueprint { */ Optional callingContext(); - class BuilderInterceptor implements Prototype.BuilderInterceptor> { + class BuilderDecorator implements Prototype.BuilderDecorator> { @Override - public InternalBootstrap.BuilderBase intercept(InternalBootstrap.BuilderBase target) { + public void decorate(InternalBootstrap.BuilderBase target) { if (target.bootStrap().isEmpty()) { target.bootStrap(Bootstrap.create()); } - return target; } } } diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBlueprint.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBlueprint.java index cf45f36ec8e..da1706b8173 100644 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBlueprint.java +++ b/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBlueprint.java @@ -29,7 +29,7 @@ * @see Services * @see ServiceInfoCriteria */ -@Prototype.Blueprint(builderInterceptor = ServiceInfoBuildInterceptor.class) +@Prototype.Blueprint(decorator = ServiceInfoBuildDecorator.class) @Prototype.CustomMethods(ServiceInfoBlueprint.CustomMethods.class) interface ServiceInfoBlueprint extends ServiceInfoBasicsBlueprint, ServiceInfoBasics { diff --git a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBuildInterceptor.java b/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBuildDecorator.java similarity index 80% rename from inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBuildInterceptor.java rename to inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBuildDecorator.java index 16113b13876..f084c282a27 100644 --- a/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBuildInterceptor.java +++ b/inject/api/src/main/java/io/helidon/inject/api/ServiceInfoBuildDecorator.java @@ -21,12 +21,11 @@ /** * Ensures that all external contracts are also treated as normal contracts, etc. */ -class ServiceInfoBuildInterceptor implements Prototype.BuilderInterceptor> { +class ServiceInfoBuildDecorator implements Prototype.BuilderDecorator> { @Override - public ServiceInfo.BuilderBase intercept(ServiceInfo.BuilderBase target) { + public void decorate(ServiceInfo.BuilderBase target) { target.addContractsImplemented(target.externalContractsImplemented()); - return target; } } diff --git a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBean.java b/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBean.java index b7f16164809..8a93b278d39 100644 --- a/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBean.java +++ b/inject/configdriven/processor/src/main/java/io/helidon/inject/configdriven/processor/ConfigBean.java @@ -38,7 +38,8 @@ public static ConfigBean create(TypeInfo configBeanTypeInfo) { if (className.endsWith("Blueprint")) { className = className.substring(0, className.length() - 9); typeName = TypeName.builder(configBeanTypeInfo.typeName().genericTypeName()) - .className(className); + .className(className) + .build(); } else { throw new IllegalArgumentException("Type annotation with @Prototype.Blueprint does not" + " end with Blueprint: " + configBeanTypeInfo.typeName()); diff --git a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractApplicationCreatorMojo.java b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractApplicationCreatorMojo.java index ce7798cfaea..9eea0bfb84a 100644 --- a/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractApplicationCreatorMojo.java +++ b/inject/maven-plugin/src/main/java/io/helidon/inject/maven/plugin/AbstractApplicationCreatorMojo.java @@ -381,8 +381,10 @@ Set toNames(List> services) { void warn(String msg) { Optional optBuilder = CallingContextFactory.createBuilder(false); - CallingContext callCtx = optBuilder.map(builder -> builder - .update(it -> Optional.ofNullable(getThisModuleName()).ifPresent(it::moduleName))).orElse(null); + CallingContext callCtx = optBuilder.map(builder -> builder + .update(it -> Optional.ofNullable(getThisModuleName()).ifPresent(it::moduleName))) + .map(CallingContext.Builder::build) + .orElse(null); String desc = "no modules to process"; String ctxMsg = (callCtx == null) ? toErrorMessage(desc) : toErrorMessage(callCtx, desc); ToolsException e = new ToolsException(ctxMsg); diff --git a/inject/processor/src/main/java/io/helidon/inject/processor/CustomAnnotationProcessor.java b/inject/processor/src/main/java/io/helidon/inject/processor/CustomAnnotationProcessor.java index e025ac269df..e9db98c704c 100644 --- a/inject/processor/src/main/java/io/helidon/inject/processor/CustomAnnotationProcessor.java +++ b/inject/processor/src/main/java/io/helidon/inject/processor/CustomAnnotationProcessor.java @@ -165,10 +165,11 @@ void doInner(TypeName annoTypeName, for (CustomAnnotationTemplateCreator producer : producers) { req.genericTemplateCreator(new GenericTemplateCreatorDefault(producer.getClass(), utils())); - res.request(req); - CustomAnnotationTemplateResponse producerResponse = process(producer, req); + CustomAnnotationTemplateRequest request = req.build(); + res.request(request); + CustomAnnotationTemplateResponse producerResponse = process(producer, request); if (producerResponse != null) { - res = CustomAnnotationTemplateResponses.aggregate(req, res, producerResponse); + res = CustomAnnotationTemplateResponses.aggregate(request, res.build(), producerResponse); } } CustomAnnotationTemplateResponse response = res.build(); diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/AbstractServiceProvider.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/AbstractServiceProvider.java index f884b60c7fc..581d8bd6733 100644 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/AbstractServiceProvider.java +++ b/inject/runtime/src/main/java/io/helidon/inject/runtime/AbstractServiceProvider.java @@ -32,6 +32,7 @@ import java.util.stream.Collectors; import io.helidon.common.types.TypeName; +import io.helidon.inject.api.AccessModifier; import io.helidon.inject.api.ActivationLog; import io.helidon.inject.api.ActivationLogEntry; import io.helidon.inject.api.ActivationPhaseReceiver; @@ -43,6 +44,7 @@ import io.helidon.inject.api.DeActivationRequest; import io.helidon.inject.api.DeActivator; import io.helidon.inject.api.DependenciesInfo; +import io.helidon.inject.api.ElementKind; import io.helidon.inject.api.Event; import io.helidon.inject.api.InjectionPointInfo; import io.helidon.inject.api.InjectionPointProvider; @@ -415,35 +417,42 @@ public ActivationResult activate(ActivationRequest req) { // if we get here then we own the semaphore for activation... try { + Phase finishing = res.finishingActivationPhase().orElse(null); if (res.targetActivationPhase().ordinal() >= Phase.ACTIVATION_STARTING.ordinal() - && (Phase.INIT == res.finishingActivationPhase() - || Phase.PENDING == res.finishingActivationPhase() - || Phase.ACTIVATION_STARTING == res.finishingActivationPhase() - || Phase.DESTROYED == res.finishingActivationPhase())) { + && (Phase.INIT == res.finishingActivationPhase().orElse(null) + || Phase.PENDING == finishing + || Phase.ACTIVATION_STARTING == finishing + || Phase.DESTROYED == finishing)) { doStartingLifecycle(logEntryAndResult); } + finishing = res.finishingActivationPhase().orElse(null); if (res.targetActivationPhase().ordinal() >= Phase.GATHERING_DEPENDENCIES.ordinal() - && (Phase.ACTIVATION_STARTING == res.finishingActivationPhase())) { + && (Phase.ACTIVATION_STARTING == finishing)) { doGatheringDependencies(logEntryAndResult); } + finishing = res.finishingActivationPhase().orElse(null); if (res.targetActivationPhase().ordinal() >= Phase.CONSTRUCTING.ordinal() - && (Phase.GATHERING_DEPENDENCIES == res.finishingActivationPhase())) { + && (Phase.GATHERING_DEPENDENCIES == finishing)) { doConstructing(logEntryAndResult); } + finishing = res.finishingActivationPhase().orElse(null); if (res.targetActivationPhase().ordinal() >= Phase.INJECTING.ordinal() - && (Phase.CONSTRUCTING == res.finishingActivationPhase())) { + && (Phase.CONSTRUCTING == finishing)) { doInjecting(logEntryAndResult); } + finishing = res.finishingActivationPhase().orElse(null); if (res.targetActivationPhase().ordinal() >= Phase.POST_CONSTRUCTING.ordinal() - && (Phase.INJECTING == res.finishingActivationPhase())) { + && (Phase.INJECTING == finishing)) { doPostConstructing(logEntryAndResult); } + finishing = res.finishingActivationPhase().orElse(null); if (res.targetActivationPhase().ordinal() >= Phase.ACTIVATION_FINISHING.ordinal() - && (Phase.POST_CONSTRUCTING == res.finishingActivationPhase())) { + && (Phase.POST_CONSTRUCTING == finishing)) { doActivationFinishing(logEntryAndResult); } + finishing = res.finishingActivationPhase().orElse(null); if (res.targetActivationPhase().ordinal() >= Phase.ACTIVE.ordinal() - && (Phase.ACTIVATION_FINISHING == res.finishingActivationPhase())) { + && (Phase.ACTIVATION_FINISHING == finishing)) { doActivationActive(logEntryAndResult); } @@ -533,12 +542,24 @@ public ServiceInjectionPlanBinder.Binder resolvedBind(String id, Class serviceType) { try { InjectionResolver resolver = (InjectionResolver) AbstractServiceProvider.this; + TypeName typeName = TypeName.create(serviceType); ServiceInfoCriteria serviceInfo = ServiceInfoCriteria.builder() - .serviceTypeName(TypeName.create(serviceType)) + .serviceTypeName(typeName) .build(); + InjectionPointInfo ipInfo = InjectionPointInfo.builder() .id(id) - .dependencyToServiceInfo(serviceInfo); + .dependencyToServiceInfo(serviceInfo) + // the following values are required, but dummy in this instance + .elementKind(ElementKind.METHOD) + .elementTypeName(typeName) + .elementName("none") + .serviceTypeName(typeName) + .access(AccessModifier.PUBLIC) + .ipType(typeName) + .ipName("none") + .baseIdentity("none") + .build(); Object resolved = Objects.requireNonNull( resolver.resolve(ipInfo, requiredInjectionServices(), AbstractServiceProvider.this, false)); HelidonInjectionPlan plan = createBuilder(id) @@ -714,7 +735,7 @@ public ActivationResult deactivate(DeActivationRequest req) { this.lastActivationThreadId = Thread.currentThread().getId(); doPreDestroying(logEntryAndResult); - if (Phase.PRE_DESTROYING == logEntryAndResult.activationResult.finishingActivationPhase()) { + if (Phase.PRE_DESTROYING == logEntryAndResult.activationResult.finishingActivationPhase().orElse(null)) { doDestroying(logEntryAndResult); } onFinished(logEntryAndResult); @@ -1052,7 +1073,7 @@ protected LogEntryAndResult createLogEntryAndResult(Phase targetPhase) { .serviceProvider(this) .event(Event.STARTING) .threadId(Thread.currentThread().getId()) - .activationResult(activationResult); + .activationResult(activationResult.build()); return new LogEntryAndResult(logEntry, activationResult); } @@ -1191,7 +1212,7 @@ private LogEntryAndResult preambleActivate(ActivationRequest req) { lastActivationThreadId = Thread.currentThread().getId(); logEntryAndResult.logEntry.threadId(lastActivationThreadId); - if (logEntryAndResult.activationResult.finished()) { + if (logEntryAndResult.activationResult.build().finished()) { didAcquire = false; activationSemaphore.release(); } diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlans.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlans.java index e5d5674c9a8..1c0e746bb58 100644 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlans.java +++ b/inject/runtime/src/main/java/io/helidon/inject/runtime/DefaultInjectionPlans.java @@ -427,7 +427,8 @@ private static List toEligibleInjectionRefs(InjectionPointInfo ipInfo, ContextualServiceQuery query = ContextualServiceQuery.builder() .injectionPointInfo(ipInfo) .serviceInfoCriteria(ipInfo.dependencyToServiceInfo()) - .expected(expected); + .expected(expected) + .build(); for (ServiceProvider sp : list) { Collection instances = sp.list(query); result.addAll(instances); diff --git a/inject/runtime/src/main/java/io/helidon/inject/runtime/Dependencies.java b/inject/runtime/src/main/java/io/helidon/inject/runtime/Dependencies.java index 4d45c7e0bbe..877689047f1 100644 --- a/inject/runtime/src/main/java/io/helidon/inject/runtime/Dependencies.java +++ b/inject/runtime/src/main/java/io/helidon/inject/runtime/Dependencies.java @@ -78,14 +78,14 @@ public static DependenciesInfo combine(DependenciesInfo parentDeps, ? (DependenciesInfo.Builder) deps : DependenciesInfo.builder(deps); parentDeps.serviceInfoDependencies().forEach(builder::addServiceInfoDependencies); - return forceBuild(builder); + return builder.build(); } - static String toBaseIdentity(InjectionPointInfo dep) { - ElementKind kind = Objects.requireNonNull(dep.elementKind()); - String elemName = Objects.requireNonNull(dep.elementName()); - AccessModifier access = Objects.requireNonNull(dep.access()); - String packageName = toPackageName(dep.serviceTypeName()); + static String toBaseIdentity(InjectionPointInfo.Builder dep) { + ElementKind kind = dep.elementKind().orElseThrow(); + String elemName = dep.elementName().orElseThrow(); + AccessModifier access = dep.access().orElseThrow(); + String packageName = toPackageName(dep.serviceTypeName().orElseThrow()); String baseId; if (ElementKind.FIELD == kind) { @@ -98,11 +98,11 @@ static String toBaseIdentity(InjectionPointInfo dep) { return baseId; } - static String toId(InjectionPointInfo dep) { - ElementKind kind = Objects.requireNonNull(dep.elementKind()); - String elemName = Objects.requireNonNull(dep.elementName()); - AccessModifier access = Objects.requireNonNull(dep.access()); - String packageName = toPackageName(dep.serviceTypeName()); + static String toId(InjectionPointInfo.Builder dep) { + ElementKind kind = dep.elementKind().orElseThrow(); + String elemName = dep.elementName().orElseThrow(); + AccessModifier access = dep.access().orElseThrow(); + String packageName = toPackageName(dep.serviceTypeName().orElseThrow()); String id; if (ElementKind.FIELD == kind) { @@ -182,22 +182,6 @@ public static String toMethodIdentity(String elemName, return result + "(" + elemOffset + ")"; } - /** - * Returns the non-builder version of the passed dependencies. - * - * @param deps the dependencies, but might be actually in builder form - * @return will always be the built version of the dependencies - */ - private static DependenciesInfo forceBuild(DependenciesInfo deps) { - Objects.requireNonNull(deps); - - if (deps instanceof DependenciesInfo.Builder) { - deps = ((DependenciesInfo.Builder) deps).build(); - } - - return deps; - } - private static String toPackageName(TypeName typeName) { String packageName = typeName.packageName(); return packageName.isBlank() ? null : packageName; @@ -540,7 +524,7 @@ public Optional commitLastDependency() { ipInfoBuilder.baseIdentity(toBaseIdentity(ipInfoBuilder)); ipInfoBuilder.id(id); ServiceInfoCriteria criteria = ServiceInfoCriteria.builder() - .addContractImplemented(ipInfoBuilder.elementTypeName()) + .addContractImplemented(ipInfoBuilder.elementTypeName().orElseThrow()) .qualifiers(ipInfoBuilder.qualifiers()) .build(); diff --git a/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesConfigTest.java b/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesConfigTest.java index d2afde46c65..f002e2a5bc5 100644 --- a/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesConfigTest.java +++ b/inject/runtime/src/test/java/io/helidon/inject/runtime/DefaultInjectionServicesConfigTest.java @@ -28,7 +28,8 @@ class DefaultInjectionServicesConfigTest { @Test void testIt() { - InjectionServicesConfig cfg = DefaultInjectionServicesConfig.createDefaultConfigBuilder(); + InjectionServicesConfig cfg = DefaultInjectionServicesConfig.createDefaultConfigBuilder() + .build(); assertThat(cfg.providerName(), optionalValue(is("oracle"))); assertThat(cfg.providerVersion(), optionalValue(is("1"))); } diff --git a/inject/runtime/src/test/java/io/helidon/inject/runtime/InvocationTest.java b/inject/runtime/src/test/java/io/helidon/inject/runtime/InvocationTest.java index bb5eda08848..1926bdbb406 100644 --- a/inject/runtime/src/test/java/io/helidon/inject/runtime/InvocationTest.java +++ b/inject/runtime/src/test/java/io/helidon/inject/runtime/InvocationTest.java @@ -25,9 +25,19 @@ import io.helidon.common.types.TypeName; import io.helidon.common.types.TypeValues; import io.helidon.common.types.TypedElementInfo; +import io.helidon.inject.api.Activator; +import io.helidon.inject.api.ContextualServiceQuery; +import io.helidon.inject.api.DeActivator; +import io.helidon.inject.api.DependenciesInfo; import io.helidon.inject.api.Interceptor; import io.helidon.inject.api.InvocationContext; import io.helidon.inject.api.InvocationException; +import io.helidon.inject.api.Phase; +import io.helidon.inject.api.PostConstructMethod; +import io.helidon.inject.api.PreDestroyMethod; +import io.helidon.inject.api.ServiceInfo; +import io.helidon.inject.api.ServiceProvider; +import io.helidon.inject.api.ServiceProviderBindable; import jakarta.inject.Provider; import org.junit.jupiter.api.Test; @@ -38,17 +48,19 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; -@SuppressWarnings("unchecked") class InvocationTest { TestInterceptor first = new TestInterceptor("first"); TestInterceptor second = new TestInterceptor("second"); InvocationContext dummyCtx = InvocationContext.builder() + .serviceProvider(new DummyServiceProvider()) + .serviceTypeName(TypeName.create(DummyServiceProvider.class)) .elementInfo(TypedElementInfo.builder() .elementName("test") .elementTypeKind(TypeValues.KIND_METHOD) .typeName(TypeName.create(InvocationTest.class)) .build()) - .interceptors(List.of(first.provider, second.provider)); + .interceptors(List.of(first.provider, second.provider)) + .build(); ArrayList calls = new ArrayList<>(); @Test @@ -68,12 +80,15 @@ void normalCaseWithInterceptors() { @Test void normalCaseWithNoInterceptors() { InvocationContext dummyCtx = InvocationContext.builder() + .serviceProvider(new DummyServiceProvider()) + .serviceTypeName(TypeName.create(DummyServiceProvider.class)) .elementInfo(TypedElementInfo.builder() .elementName("test") .elementTypeKind(TypeValues.KIND_METHOD) .typeName(TypeName.create(InvocationTest.class)) .build()) - .interceptors(List.of()); + .interceptors(List.of()) + .build(); Object[] args = new Object[] {}; Boolean result = Invocation.createInvokeAndSupply(dummyCtx, (arguments) -> calls.add(arguments), args); @@ -334,4 +349,71 @@ public String toString() { } } + private static class DummyServiceProvider implements ServiceProvider { + + @Override + public Optional first(ContextualServiceQuery query) { + return Optional.empty(); + } + + @Override + public String id() { + return null; + } + + @Override + public String description() { + return null; + } + + @Override + public boolean isProvider() { + return false; + } + + @Override + public ServiceInfo serviceInfo() { + return null; + } + + @Override + public DependenciesInfo dependencies() { + return null; + } + + @Override + public Phase currentActivationPhase() { + return null; + } + + @Override + public Optional activator() { + return Optional.empty(); + } + + @Override + public Optional deActivator() { + return Optional.empty(); + } + + @Override + public Optional postConstructMethod() { + return Optional.empty(); + } + + @Override + public Optional preDestroyMethod() { + return Optional.empty(); + } + + @Override + public Optional> serviceProviderBindable() { + return Optional.empty(); + } + + @Override + public Class serviceType() { + return null; + } + } } diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/AbstractCreator.java b/inject/tools/src/main/java/io/helidon/inject/tools/AbstractCreator.java index 63bada38461..3ba8b909782 100644 --- a/inject/tools/src/main/java/io/helidon/inject/tools/AbstractCreator.java +++ b/inject/tools/src/main/java/io/helidon/inject/tools/AbstractCreator.java @@ -284,7 +284,8 @@ ModuleInfoDescriptor createModuleInfo(ModuleInfoCreatorRequest req) { } } - return addProviderRequirementsTo(descriptorBuilder, generatedAnno); + return addProviderRequirementsTo(descriptorBuilder, generatedAnno) + .build(); } } diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorDefault.java b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorDefault.java index 3c105ee756e..7a0f9beaa6f 100644 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorDefault.java +++ b/inject/tools/src/main/java/io/helidon/inject/tools/ActivatorCreatorDefault.java @@ -129,7 +129,8 @@ static TypeName toModuleTypeName(ActivatorCreatorRequest req, String className = toModuleClassName(req.codeGen().classPrefixName()); return TypeName.builder() .packageName(packageName) - .className(className); + .className(className) + .build(); } static String toModuleClassName(String modulePrefix) { diff --git a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoUtil.java b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoUtil.java index 91ec24157b4..acf14f77c50 100644 --- a/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoUtil.java +++ b/inject/tools/src/main/java/io/helidon/inject/tools/ModuleInfoUtil.java @@ -38,7 +38,7 @@ private ModuleInfoUtil() { static boolean addIfAbsent(ModuleInfoDescriptor.Builder builder, String target, Supplier itemSupplier) { - Optional existing = builder.first(target); + Optional existing = first(builder, target); if (existing.isEmpty()) { ModuleInfoItem item = Objects.requireNonNull(itemSupplier.get()); assert (target.equals(item.target())) : "target mismatch: " + target + " and " + item.target(); @@ -146,4 +146,11 @@ static ModuleInfoItem usesExternalContract(String externalContract) { static ModuleInfoItem usesExternalContract(TypeName externalContract) { return usesExternalContract(externalContract.fqName()); } + + private static Optional first(ModuleInfoDescriptor.BuilderBase builder, String target) { + return builder.items() + .stream() + .filter(it -> it.target().equals(target)) + .findFirst(); + } } diff --git a/inject/tools/src/test/java/io/helidon/inject/tools/ModuleInfoDescriptorTest.java b/inject/tools/src/test/java/io/helidon/inject/tools/ModuleInfoDescriptorTest.java index d1a3ed916fd..9e5c159357b 100644 --- a/inject/tools/src/test/java/io/helidon/inject/tools/ModuleInfoDescriptorTest.java +++ b/inject/tools/src/test/java/io/helidon/inject/tools/ModuleInfoDescriptorTest.java @@ -266,7 +266,7 @@ void mergeCreate() { IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> descriptor.mergeCreate(descriptor)); assertThat(e.getMessage(), equalTo("can't merge with self")); - ModuleInfoDescriptor mergeCreated = descriptor.mergeCreate(ModuleInfoDescriptor.builder(descriptor)); + ModuleInfoDescriptor mergeCreated = descriptor.mergeCreate(ModuleInfoDescriptor.builder(descriptor).build()); assertThat(descriptor.contents(), equalTo(mergeCreated.contents())); ModuleInfoDescriptor descriptor1 = ModuleInfoDescriptor.builder() diff --git a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProvider.java b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProvider.java index 0aa109d43be..390a87ff1bc 100644 --- a/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProvider.java +++ b/integrations/oci/sdk/runtime/src/main/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProvider.java @@ -101,6 +101,20 @@ private static AbstractAuthenticationDetailsProvider select(OciConfig ociConfig) + OciConfig.CONFIG_KEY); } + static String toNamedProfile(InjectionPointInfo.Builder ipiBuilder) { + Optional named = findFirst(Named.class, ipiBuilder.qualifiers()); + if (named.isEmpty()) { + return null; + } + + String nameProfile = named.get().value().orElse(null); + if (nameProfile == null || nameProfile.isBlank()) { + return null; + } + + return nameProfile.trim(); + } + static String toNamedProfile(InjectionPointInfo ipi) { if (ipi == null) { return null; diff --git a/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProviderTest.java b/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProviderTest.java index 44cfacd1489..25030a05168 100644 --- a/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProviderTest.java +++ b/integrations/oci/sdk/runtime/src/test/java/io/helidon/integrations/oci/sdk/runtime/OciAuthenticationDetailsProviderTest.java @@ -87,7 +87,7 @@ void testUserHomePrivateKeyPath() { @Test void testToNamedProfile() { - assertThat(OciAuthenticationDetailsProvider.toNamedProfile(null), + assertThat(OciAuthenticationDetailsProvider.toNamedProfile((InjectionPointInfo) null), nullValue()); InjectionPointInfo.Builder ipi = InjectionPointInfo.builder() diff --git a/nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigBlueprint.java b/nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigBlueprint.java index f43a6dca9c9..a0af18faf53 100644 --- a/nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigBlueprint.java +++ b/nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigBlueprint.java @@ -31,7 +31,7 @@ import io.helidon.config.metadata.Configured; import io.helidon.config.metadata.ConfiguredOption; -@Prototype.Blueprint(builderInterceptor = TlsConfigInterceptor.class) +@Prototype.Blueprint(decorator = TlsConfigDecorator.class) @Configured interface TlsConfigBlueprint extends Prototype.Factory { String DEFAULT_PROTOCOL = "TLS"; diff --git a/nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigInterceptor.java b/nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigDecorator.java similarity index 98% rename from nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigInterceptor.java rename to nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigDecorator.java index a81fe88ad4f..1790df386c2 100644 --- a/nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigInterceptor.java +++ b/nima/common/tls/src/main/java/io/helidon/nima/common/tls/TlsConfigDecorator.java @@ -45,17 +45,15 @@ import io.helidon.builder.api.Prototype; import io.helidon.common.LazyValue; -class TlsConfigInterceptor implements Prototype.BuilderInterceptor> { +class TlsConfigDecorator implements Prototype.BuilderDecorator> { // secure random cannot be stored in native image, it must // be initialized at runtime private static final LazyValue RANDOM = LazyValue.create(SecureRandom::new); @Override - public TlsConfig.BuilderBase intercept(TlsConfig.BuilderBase target) { + public void decorate(TlsConfig.BuilderBase target) { sslParameters(target); sslContext(target); - - return target; } private void sslContext(TlsConfig.BuilderBase target) { diff --git a/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/AsyncConfigBlueprint.java b/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/AsyncConfigBlueprint.java index d4928fc6f96..03c2076ac48 100644 --- a/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/AsyncConfigBlueprint.java +++ b/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/AsyncConfigBlueprint.java @@ -27,7 +27,7 @@ /** * {@link io.helidon.nima.faulttolerance.Async} configuration bean. */ -@Prototype.Blueprint(builderInterceptor = AsyncConfigBlueprint.BuilderInterceptor.class) +@Prototype.Blueprint(decorator = AsyncConfigBlueprint.BuilderDecorator.class) @Configured interface AsyncConfigBlueprint extends Prototype.Factory { /** @@ -60,15 +60,13 @@ interface AsyncConfigBlueprint extends Prototype.Factory { */ Optional> onStart(); - class BuilderInterceptor implements Prototype.BuilderInterceptor> { + class BuilderDecorator implements Prototype.BuilderDecorator> { @Override - public AsyncConfig.BuilderBase intercept(AsyncConfig.BuilderBase target) { + public void decorate(AsyncConfig.BuilderBase target) { if (target.name().isEmpty()) { target.config() .ifPresent(cfg -> target.name(cfg.name())); } - - return target; } } } diff --git a/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/BulkheadConfigBlueprint.java b/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/BulkheadConfigBlueprint.java index 704f3fa37b2..a5885cf13b4 100644 --- a/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/BulkheadConfigBlueprint.java +++ b/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/BulkheadConfigBlueprint.java @@ -29,7 +29,7 @@ */ @ConfigBean(repeatable = true) @Configured(root = true, prefix = "fault-tolerance.bulkheads") -@Prototype.Blueprint(builderInterceptor = BulkheadConfigBlueprint.BuilderInterceptor.class) +@Prototype.Blueprint(decorator = BulkheadConfigBlueprint.BuilderDecorator.class) interface BulkheadConfigBlueprint extends Prototype.Factory { /** * Default limit. @@ -78,14 +78,13 @@ interface BulkheadConfigBlueprint extends Prototype.Factory { */ Optional name(); - class BuilderInterceptor implements Prototype.BuilderInterceptor> { + class BuilderDecorator implements Prototype.BuilderDecorator> { @Override - public BulkheadConfig.BuilderBase intercept(BulkheadConfig.BuilderBase target) { + public void decorate(BulkheadConfig.BuilderBase target) { if (target.name().isEmpty()) { target.config() .ifPresent(cfg -> target.name(cfg.name())); } - return target; } } } diff --git a/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/CircuitBreakerConfigBlueprint.java b/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/CircuitBreakerConfigBlueprint.java index 6e66c487636..b4390b9b6a0 100644 --- a/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/CircuitBreakerConfigBlueprint.java +++ b/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/CircuitBreakerConfigBlueprint.java @@ -26,7 +26,7 @@ import io.helidon.config.metadata.ConfiguredOption; import io.helidon.inject.configdriven.api.ConfigBean; -@Prototype.Blueprint(builderInterceptor = CircuitBreakerConfigBlueprint.BuilderInterceptor.class) +@Prototype.Blueprint(decorator = CircuitBreakerConfigBlueprint.BuilderDecorator.class) @Configured(prefix = "fault-tolerance.circuit-breakers", root = true) @ConfigBean(wantDefault = true, repeatable = true) interface CircuitBreakerConfigBlueprint extends Prototype.Factory { @@ -101,15 +101,13 @@ interface CircuitBreakerConfigBlueprint extends Prototype.Factory> applyOn(); - class BuilderInterceptor implements Prototype.BuilderInterceptor> { + class BuilderDecorator implements Prototype.BuilderDecorator> { @Override - public CircuitBreakerConfig.BuilderBase intercept(CircuitBreakerConfig.BuilderBase target) { + public void decorate(CircuitBreakerConfig.BuilderBase target) { if (target.name().isEmpty()) { target.config() .ifPresent(cfg -> target.name(cfg.name())); } - - return target; } } } diff --git a/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/RetryConfigBlueprint.java b/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/RetryConfigBlueprint.java index fea39d9133f..2b31f4bbae0 100644 --- a/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/RetryConfigBlueprint.java +++ b/nima/fault-tolerance/fault-tolerance/src/main/java/io/helidon/nima/faulttolerance/RetryConfigBlueprint.java @@ -28,7 +28,7 @@ * {@link Retry} configuration bean. */ // @ConfigBean(value = "fault-tolerance.retries", repeatable = true, wantDefaultConfigBean = true) -@Prototype.Blueprint(builderInterceptor = RetryConfigBlueprint.BuilderInterceptor.class) +@Prototype.Blueprint(decorator = RetryConfigBlueprint.BuilderDecorator.class) @Configured(root = true, prefix = "fault-tolerance.retries") interface RetryConfigBlueprint extends Prototype.Factory { /** @@ -125,9 +125,9 @@ interface RetryConfigBlueprint extends Prototype.Factory { */ Optional retryPolicy(); - class BuilderInterceptor implements Prototype.BuilderInterceptor> { + class BuilderDecorator implements Prototype.BuilderDecorator> { @Override - public RetryConfig.BuilderBase intercept(RetryConfig.BuilderBase target) { + public void decorate(RetryConfig.BuilderBase target) { if (target.name().isEmpty()) { target.config() .ifPresent(cfg -> target.name(cfg.name())); @@ -135,7 +135,6 @@ class BuilderInterceptor implements Prototype.BuilderInterceptor { /** @@ -62,15 +62,13 @@ interface TimeoutConfigBlueprint extends Prototype.Factory { */ Optional executor(); - class BuilderInterceptor implements Prototype.BuilderInterceptor> { + class BuilderDecorator implements Prototype.BuilderDecorator> { @Override - public TimeoutConfig.BuilderBase intercept(TimeoutConfig.BuilderBase target) { + public void decorate(TimeoutConfig.BuilderBase target) { if (target.name().isEmpty()) { target.config() .ifPresent(cfg -> target.name(cfg.name())); } - - return target; } } } diff --git a/nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextBuilderInterceptor.java b/nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextBuilderDecorator.java similarity index 79% rename from nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextBuilderInterceptor.java rename to nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextBuilderDecorator.java index 3d3d04e2587..758ea82a654 100644 --- a/nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextBuilderInterceptor.java +++ b/nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextBuilderDecorator.java @@ -18,14 +18,13 @@ import io.helidon.builder.api.Prototype; -class MediaContextBuilderInterceptor implements Prototype.BuilderInterceptor> { +class MediaContextBuilderDecorator implements Prototype.BuilderDecorator> { @Override - public MediaContextConfig.BuilderBase intercept(MediaContextConfig.BuilderBase target) { + public void decorate(MediaContextConfig.BuilderBase target) { if (target.registerDefaults()) { target.addMediaSupport(StringSupport.create()) .addMediaSupport(PathSupport.create()) .addMediaSupport(FormParamsSupport.create()); } - return target; } } diff --git a/nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextConfigBlueprint.java b/nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextConfigBlueprint.java index db7735f8061..2eb105d8bc2 100644 --- a/nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextConfigBlueprint.java +++ b/nima/http/media/media/src/main/java/io/helidon/nima/http/media/MediaContextConfigBlueprint.java @@ -24,7 +24,7 @@ import io.helidon.config.metadata.ConfiguredOption; import io.helidon.nima.http.media.spi.MediaSupportProvider; -@Prototype.Blueprint(builderInterceptor = MediaContextBuilderInterceptor.class) +@Prototype.Blueprint(decorator = MediaContextBuilderDecorator.class) @Configured interface MediaContextConfigBlueprint extends Prototype.Factory { /** diff --git a/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/Http2ClientConfigSupport.java b/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/Http2ClientConfigSupport.java index ac7032a3de9..3ea64e4b183 100644 --- a/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/Http2ClientConfigSupport.java +++ b/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/Http2ClientConfigSupport.java @@ -20,17 +20,15 @@ import io.helidon.nima.http2.WindowSize; class Http2ClientConfigSupport { - static class ProtocolConfigInterceptor implements Prototype.BuilderInterceptor> { + static class ProtocolConfigDecorator implements Prototype.BuilderDecorator> { @Override - public Http2ClientProtocolConfig.BuilderBase intercept(Http2ClientProtocolConfig.BuilderBase target) { + public void decorate(Http2ClientProtocolConfig.BuilderBase target) { int maxFrameSize = target.maxFrameSize(); if (maxFrameSize < WindowSize.DEFAULT_MAX_FRAME_SIZE || maxFrameSize > WindowSize.MAX_MAX_FRAME_SIZE) { throw new IllegalArgumentException( "Max frame size needs to be a number between 2^14(16_384) and 2^24-1(16_777_215)" ); } - - return target; } } } diff --git a/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/Http2ClientProtocolConfigBlueprint.java b/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/Http2ClientProtocolConfigBlueprint.java index dcc4d4df761..7ca79778b9d 100644 --- a/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/Http2ClientProtocolConfigBlueprint.java +++ b/nima/http2/webclient/src/main/java/io/helidon/nima/http2/webclient/Http2ClientProtocolConfigBlueprint.java @@ -23,7 +23,7 @@ import io.helidon.config.metadata.ConfiguredOption; import io.helidon.nima.webclient.spi.ProtocolConfig; -@Prototype.Blueprint(builderInterceptor = Http2ClientConfigSupport.ProtocolConfigInterceptor.class) +@Prototype.Blueprint(decorator = Http2ClientConfigSupport.ProtocolConfigDecorator.class) @Configured interface Http2ClientProtocolConfigBlueprint extends ProtocolConfig { @Override diff --git a/nima/http2/webclient/src/test/java/io/helidon/nima/http2/webclient/Http2WebClientTest.java b/nima/http2/webclient/src/test/java/io/helidon/nima/http2/webclient/Http2WebClientTest.java index 0aed70b088e..a4e82118f74 100644 --- a/nima/http2/webclient/src/test/java/io/helidon/nima/http2/webclient/Http2WebClientTest.java +++ b/nima/http2/webclient/src/test/java/io/helidon/nima/http2/webclient/Http2WebClientTest.java @@ -104,7 +104,8 @@ static void setUpServer(WebServerConfig.Builder serverBuilder) { .host("localhost") .addConnectionSelector(Http2ConnectionSelector.builder() .http2Config(Http2Config.builder() - .initialWindowSize(10)) + .initialWindowSize(10) + .build()) .build()) .putSocket("https", builder -> builder.port(-1) .host("localhost") diff --git a/nima/http2/webserver/src/main/java/io/helidon/nima/http2/webserver/Http2ConfigBlueprint.java b/nima/http2/webserver/src/main/java/io/helidon/nima/http2/webserver/Http2ConfigBlueprint.java index 093cfdf976b..cfe6e129a81 100644 --- a/nima/http2/webserver/src/main/java/io/helidon/nima/http2/webserver/Http2ConfigBlueprint.java +++ b/nima/http2/webserver/src/main/java/io/helidon/nima/http2/webserver/Http2ConfigBlueprint.java @@ -27,7 +27,7 @@ /** * HTTP/2 server configuration. */ -@Prototype.Blueprint(builderInterceptor = Http2ConfigBlueprint.Http2ConfigInterceptor.class) +@Prototype.Blueprint(decorator = Http2ConfigBlueprint.Http2ConfigDecorator.class) @Configured(provides = ProtocolConfig.class) interface Http2ConfigBlueprint extends ProtocolConfig { /** @@ -130,19 +130,18 @@ default String type() { return Http2ConnectionProvider.CONFIG_NAME; } - class Http2ConfigInterceptor implements Prototype.BuilderInterceptor> { + class Http2ConfigDecorator implements Prototype.BuilderDecorator> { @Override - public Http2Config.BuilderBase intercept(Http2Config.BuilderBase target) { - if (target.name() == null) { + public void decorate(Http2Config.BuilderBase target) { + if (target.name().isEmpty()) { target.name("@default"); } - if (target.requestedUriDiscovery() == null) { + if (target.requestedUriDiscovery().isEmpty()) { target.requestedUriDiscovery(RequestedUriDiscoveryContext.builder() - .socketId(target.name()) + .socketId(target.name().orElse("@default")) .build()); } - return target; } } } diff --git a/nima/testing/junit5/webserver/src/main/java/io/helidon/nima/testing/junit5/webserver/HelidonServerJunitExtension.java b/nima/testing/junit5/webserver/src/main/java/io/helidon/nima/testing/junit5/webserver/HelidonServerJunitExtension.java index 0848d814a0c..7c9a619c6d5 100644 --- a/nima/testing/junit5/webserver/src/main/java/io/helidon/nima/testing/junit5/webserver/HelidonServerJunitExtension.java +++ b/nima/testing/junit5/webserver/src/main/java/io/helidon/nima/testing/junit5/webserver/HelidonServerJunitExtension.java @@ -246,7 +246,7 @@ private void addRouting(WebServerConfig.Builder builder) { if (listenerConfig == null) { builder.putSocket(socketName, listenerBuilder.build()); } else { - builder.putSocket(socketName, ListenerConfig.builder(listenerConfig).from(listenerBuilder)); + builder.putSocket(socketName, ListenerConfig.builder(listenerConfig).from(listenerBuilder).build()); } } }); diff --git a/nima/tests/integration/http2/server/src/test/java/io/helidon/nima/tests/integration/http2/webserver/FlowControlTest.java b/nima/tests/integration/http2/server/src/test/java/io/helidon/nima/tests/integration/http2/webserver/FlowControlTest.java index 905fe17a759..52644c870ab 100644 --- a/nima/tests/integration/http2/server/src/test/java/io/helidon/nima/tests/integration/http2/webserver/FlowControlTest.java +++ b/nima/tests/integration/http2/server/src/test/java/io/helidon/nima/tests/integration/http2/webserver/FlowControlTest.java @@ -77,11 +77,12 @@ class FlowControlTest { static void setUpServer(WebServerConfig.Builder serverBuilder) { serverBuilder .addProtocol(Http2Config.builder() - .initialWindowSize(WindowSize.DEFAULT_WIN_SIZE)) + .initialWindowSize(WindowSize.DEFAULT_WIN_SIZE) + .build()) .addConnectionSelector(Http2ConnectionSelector.builder() .http2Config(Http2Config.builder() .initialWindowSize(WindowSize.DEFAULT_WIN_SIZE) - ) + .build()) .build()) .host("localhost") .routing(router -> router diff --git a/nima/webclient/api/src/main/java/io/helidon/nima/webclient/api/HttpClientConfigBlueprint.java b/nima/webclient/api/src/main/java/io/helidon/nima/webclient/api/HttpClientConfigBlueprint.java index ccaf8a53970..786ddb8fabd 100644 --- a/nima/webclient/api/src/main/java/io/helidon/nima/webclient/api/HttpClientConfigBlueprint.java +++ b/nima/webclient/api/src/main/java/io/helidon/nima/webclient/api/HttpClientConfigBlueprint.java @@ -43,7 +43,7 @@ * This can be used by any HTTP client version, and does not act as a factory, for easy extensibility. */ @Configured -@Prototype.Blueprint(builderInterceptor = HttpClientConfigSupport.HttpBuilderInterceptor.class) +@Prototype.Blueprint(decorator = HttpClientConfigSupport.HttpBuilderDecorator.class) @Prototype.CustomMethods(HttpClientConfigSupport.HttpCustomMethods.class) interface HttpClientConfigBlueprint extends HttpConfigBaseBlueprint { /** @@ -151,7 +151,7 @@ default ClientRequestHeaders defaultRequestHeaders() { * * @return media context */ - @ConfiguredOption + @ConfiguredOption("create()") MediaContext mediaContext(); /** diff --git a/nima/webclient/api/src/main/java/io/helidon/nima/webclient/api/HttpClientConfigSupport.java b/nima/webclient/api/src/main/java/io/helidon/nima/webclient/api/HttpClientConfigSupport.java index e82e4e65588..9a1004b8b66 100644 --- a/nima/webclient/api/src/main/java/io/helidon/nima/webclient/api/HttpClientConfigSupport.java +++ b/nima/webclient/api/src/main/java/io/helidon/nima/webclient/api/HttpClientConfigSupport.java @@ -65,7 +65,7 @@ static void baseUri(HttpClientConfig.BuilderBase builder, String baseUri) } /** - * Set a default header value. + * Add a default header value. * * @param builder builder to update * @param name name of the header @@ -77,7 +77,7 @@ static void addHeader(HttpClientConfig.BuilderBase builder, Http.HeaderNam } /** - * Set default header value. This method is not optimal and should only be used when the header name is really + * Add default header value. This method is not optimal and should only be used when the header name is really * obtained from a string, in other cases, use an alternative with {@link io.helidon.common.http.Http.HeaderName} * or {@link io.helidon.common.http.Http.HeaderValue}. * @@ -92,63 +92,49 @@ static void addHeader(HttpClientConfig.BuilderBase builder, String name, S } } - static class HttpBuilderInterceptor implements Prototype.BuilderInterceptor> { + static class HttpBuilderDecorator implements Prototype.BuilderDecorator> { @Override - public HttpClientConfig.BuilderBase intercept(HttpClientConfig.BuilderBase target) { - if (target.tls() == null) { + public void decorate(HttpClientConfig.BuilderBase target) { + if (target.tls().isEmpty()) { target.tls(EMPTY_TLS.get()); } target.socketOptions(SocketOptions.builder() .update(it -> { - if (target.socketOptions() != null) { - it.from(target.socketOptions()); - } + target.socketOptions().ifPresent(it::from); }) .update(it -> target.connectTimeout().ifPresent(it::connectTimeout)) .update(it -> target.readTimeout().ifPresent(it::readTimeout)) .build()); - if (target.dnsAddressLookup() == null) { + if (target.dnsAddressLookup().isEmpty()) { target.dnsAddressLookup(DnsAddressLookup.defaultLookup()); } - if (target.dnsResolver() == null) { + if (target.dnsResolver().isEmpty()) { target.dnsResolver(DISCOVERED_DNS_RESOLVER.get()); } target.defaultHeadersMap() .forEach((key, value) -> target.addHeader(Http.Header.create(Http.Header.create(key), value))); - if (target.mediaContext() == null) { - if (target.mediaSupports().isEmpty()) { - target.mediaContext(MediaContext.create()); - } else { - target.mediaContext(MediaContext.builder() - .update(it -> target.mediaSupports().forEach(it::addMediaSupport)) - .build()); - } - } else { - if (!target.mediaSupports().isEmpty()) { - target.mediaContext(MediaContext.builder() - .update(it -> target.mediaSupports().forEach(it::addMediaSupport)) - .fallback(target.mediaContext()) - .build()); - } + if (!target.mediaSupports().isEmpty()) { + target.mediaContext(MediaContext.builder() + .update(it -> target.mediaSupports().forEach(it::addMediaSupport)) + .fallback(target.mediaContext()) + .build()); } - if (target.contentEncoding() == null) { + if (target.contentEncoding().isEmpty()) { target.contentEncoding(ContentEncodingContext.create()); } - if (target.executor() == null) { + if (target.executor().isEmpty()) { target.executor(LoomClient.EXECUTOR.get()); } - if (target.proxy() == null) { + if (target.proxy().isEmpty()) { target.proxy(Proxy.noProxy()); } - - return target; } } } diff --git a/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ClientConfigBlueprint.java b/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ClientConfigBlueprint.java index e972efba2d5..e4f1e916d2f 100644 --- a/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ClientConfigBlueprint.java +++ b/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ClientConfigBlueprint.java @@ -17,17 +17,19 @@ package io.helidon.nima.webclient.http1; import io.helidon.builder.api.Prototype; +import io.helidon.config.metadata.ConfiguredOption; import io.helidon.nima.webclient.api.HttpClientConfig; /** * HTTP/1.1. full webclient configuration. */ -@Prototype.Blueprint(builderInterceptor = Http1ClientConfigSupport.Http1BuilderInterceptor.class) +@Prototype.Blueprint interface Http1ClientConfigBlueprint extends HttpClientConfig, Prototype.Factory { /** * HTTP/1.1 specific configuration. * * @return protocol specific configuration */ + @ConfiguredOption("create()") Http1ClientProtocolConfig protocolConfig(); } diff --git a/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ClientConfigSupport.java b/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ClientConfigSupport.java deleted file mode 100644 index a743f8be8c6..00000000000 --- a/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ClientConfigSupport.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package io.helidon.nima.webclient.http1; - -import io.helidon.builder.api.Prototype; - -class Http1ClientConfigSupport { - private Http1ClientConfigSupport() { - } - - static class Http1BuilderInterceptor implements Prototype.BuilderInterceptor> { - @Override - public Http1ClientConfig.BuilderBase intercept(Http1ClientConfig.BuilderBase target) { - if (target.protocolConfig() == null) { - target.protocolConfig(Http1ClientProtocolConfig.create()); - } - return target; - } - } -} diff --git a/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ProtocolConfigProvider.java b/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ProtocolConfigProvider.java index 59bdf069e48..65d48d5a7c4 100644 --- a/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ProtocolConfigProvider.java +++ b/nima/webclient/http1/src/main/java/io/helidon/nima/webclient/http1/Http1ProtocolConfigProvider.java @@ -39,6 +39,7 @@ public String configKey() { public Http1ClientProtocolConfig create(Config config, String name) { return Http1ClientProtocolConfig.builder() .config(config) - .name(name); + .name(name) + .build(); } } diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ListenerConfigBlueprint.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ListenerConfigBlueprint.java index 595859f3e4a..41c788b61ed 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ListenerConfigBlueprint.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/ListenerConfigBlueprint.java @@ -48,7 +48,7 @@ * Configuration of a server listener (server socket). */ @Configured -@Prototype.Blueprint(builderInterceptor = ListenerConfigBlueprint.ConfigInterceptor.class) +@Prototype.Blueprint(decorator = ListenerConfigBlueprint.ConfigDecorator.class) interface ListenerConfigBlueprint { /** * Configuration of protocols. This may be either protocol selectors, or protocol upgraders from HTTP/1.1. @@ -284,9 +284,9 @@ default void configureSocket(ServerSocket socket) { } } - class ConfigInterceptor implements Prototype.BuilderInterceptor> { + class ConfigDecorator implements Prototype.BuilderDecorator> { @Override - public ListenerConfig.BuilderBase intercept(ListenerConfig.BuilderBase target) { + public void decorate(ListenerConfig.BuilderBase target) { String name = target.name(); if (name == null && target.config().isPresent()) { Config config = target.config().get(); @@ -299,10 +299,10 @@ class ConfigInterceptor implements Prototype.BuilderInterceptor { @@ -62,15 +62,13 @@ interface WebServerConfigBlueprint extends ListenerConfigBlueprint, Prototype.Fa */ Optional serverContext(); - class ServerConfigInterceptor implements Prototype.BuilderInterceptor> { + class ServerConfigDecorator implements Prototype.BuilderDecorator> { @Override - public WebServerConfig.BuilderBase intercept(WebServerConfig.BuilderBase target) { + public void decorate(WebServerConfig.BuilderBase target) { if (target.sockets().containsKey(WebServer.DEFAULT_SOCKET_NAME)) { throw new ConfigException("Default socket must be configured directly on server config node, or through" + " \"ServerConfig.Builder\", not as a separated socket."); } - - return target; } } } diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1BuilderInterceptor.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1BuilderDecorator.java similarity index 85% rename from nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1BuilderInterceptor.java rename to nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1BuilderDecorator.java index d99acae8724..686792913f1 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1BuilderInterceptor.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1BuilderDecorator.java @@ -19,23 +19,21 @@ import io.helidon.builder.api.Prototype; import io.helidon.common.http.RequestedUriDiscoveryContext; -class Http1BuilderInterceptor implements Prototype.BuilderInterceptor> { +class Http1BuilderDecorator implements Prototype.BuilderDecorator> { @Override - public Http1Config.BuilderBase intercept(Http1Config.BuilderBase target) { + public void decorate(Http1Config.BuilderBase target) { receiveListeners(target); sentListeners(target); - if (target.name() == null) { + if (target.name().isEmpty()) { target.name("@default"); } - if (target.requestedUriDiscovery() == null) { + if (target.requestedUriDiscovery().isEmpty()) { target.requestedUriDiscovery(RequestedUriDiscoveryContext.builder() - .socketId(target.name()) + .socketId(target.name().orElse("@default")) .build()); } - - return target; } private void sentListeners(Http1Config.BuilderBase target) { diff --git a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ConfigBlueprint.java b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ConfigBlueprint.java index b879337a948..2f3f9e200b8 100644 --- a/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ConfigBlueprint.java +++ b/nima/webserver/webserver/src/main/java/io/helidon/nima/webserver/http1/Http1ConfigBlueprint.java @@ -27,7 +27,7 @@ /** * HTTP/1.1 server configuration. */ -@Prototype.Blueprint(builderInterceptor = Http1BuilderInterceptor.class) +@Prototype.Blueprint(decorator = Http1BuilderDecorator.class) @Configured(provides = ProtocolConfig.class) interface Http1ConfigBlueprint extends ProtocolConfig { /** diff --git a/nima/websocket/client/src/main/java/io/helidon/nima/websocket/client/WsClient.java b/nima/websocket/client/src/main/java/io/helidon/nima/websocket/client/WsClient.java index 1acd6783452..d0ab7ffb3ca 100644 --- a/nima/websocket/client/src/main/java/io/helidon/nima/websocket/client/WsClient.java +++ b/nima/websocket/client/src/main/java/io/helidon/nima/websocket/client/WsClient.java @@ -22,6 +22,7 @@ import io.helidon.builder.api.RuntimeType; import io.helidon.nima.webclient.api.WebClient; import io.helidon.nima.webclient.http1.Http1Client; +import io.helidon.nima.webclient.spi.Protocol; import io.helidon.nima.websocket.WsListener; /** @@ -29,6 +30,12 @@ */ @RuntimeType.PrototypedBy(WsClientConfig.class) public interface WsClient extends RuntimeType.Api { + /** + * Protocol to use to obtain an instance of WebSocket specific clietn from + * {@link io.helidon.nima.webclient.api.WebClient#client(io.helidon.nima.webclient.spi.Protocol)}. + */ + Protocol PROTOCOL = WsProtocolProvider::new; + /** * A new fluent API builder to create new instances of client. * diff --git a/nima/websocket/client/src/main/java/io/helidon/nima/websocket/client/WsProtocolConfigProvider.java b/nima/websocket/client/src/main/java/io/helidon/nima/websocket/client/WsProtocolConfigProvider.java index 247d6029968..cb165abd321 100644 --- a/nima/websocket/client/src/main/java/io/helidon/nima/websocket/client/WsProtocolConfigProvider.java +++ b/nima/websocket/client/src/main/java/io/helidon/nima/websocket/client/WsProtocolConfigProvider.java @@ -40,6 +40,7 @@ public String configKey() { public WsClientProtocolConfig create(Config config, String name) { return WsClientProtocolConfig.builder() .config(config) - .name(name); + .name(name) + .build(); } }