diff --git a/bom/application/pom.xml b/bom/application/pom.xml index ed61f45ad8030..62d27e7483461 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -39,7 +39,7 @@ 2.1.12 0.22.0 21.3 - 3.0.3 + 3.1 4.0.1 4.0.1 1.3 diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java index bffd54d9b832c..8e9dce3d6591d 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigBuildStep.java @@ -2,6 +2,7 @@ import static io.quarkus.arc.processor.Annotations.getParameterAnnotations; import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT; +import static io.quarkus.deployment.annotations.ExecutionTime.STATIC_INIT; import static io.quarkus.deployment.builditem.ConfigClassBuildItem.Kind.MAPPING; import static io.quarkus.deployment.builditem.ConfigClassBuildItem.Kind.PROPERTIES; import static io.quarkus.deployment.configuration.ConfigMappingUtils.CONFIG_MAPPING_NAME; @@ -49,8 +50,10 @@ import io.quarkus.arc.processor.Annotations; import io.quarkus.arc.processor.AnnotationsTransformer; import io.quarkus.arc.processor.BeanConfigurator; +import io.quarkus.arc.processor.BuiltinScope; import io.quarkus.arc.processor.DotNames; import io.quarkus.arc.processor.InjectionPointInfo; +import io.quarkus.arc.processor.ObserverInfo; import io.quarkus.arc.runtime.ConfigBeanCreator; import io.quarkus.arc.runtime.ConfigMappingCreator; import io.quarkus.arc.runtime.ConfigRecorder; @@ -135,8 +138,23 @@ void registerCustomConfigBeanTypes(BeanDiscoveryFinishedBuildItem beanDiscovery, } @BuildStep - void validateConfigInjectionPoints(ValidationPhaseBuildItem validationPhase, - BuildProducer configProperties) { + void configPropertyInjectionPoints( + ValidationPhaseBuildItem validationPhase, + BuildProducer configProperties, + BuildProducer reflectiveClass) { + + // @Observes @Initialized(ApplicationScoped.class) requires validation at static init + Set observerMethods = new HashSet<>(); + for (ObserverInfo observer : validationPhase.getBeanProcessor().getBeanDeployment().getObservers()) { + if (observer.isSynthetic()) { + continue; + } + AnnotationInstance instance = Annotations.getParameterAnnotation(observer.getObserverMethod(), + DotNames.INITIALIZED); + if (instance != null && instance.value().asClass().name().equals(BuiltinScope.APPLICATION.getName())) { + observerMethods.add(observer.getObserverMethod()); + } + } for (InjectionPointInfo injectionPoint : validationPhase.getContext().getInjectionPoints()) { if (injectionPoint.hasDefaultedQualifier()) { @@ -185,47 +203,43 @@ void validateConfigInjectionPoints(ValidationPhaseBuildItem validationPhase, propertyDefaultValue = defaultValue.asString(); } - configProperties.produce(new ConfigPropertyBuildItem(propertyName, injectedType, propertyDefaultValue)); + if (injectionPoint.getTarget().kind().equals(METHOD) + && observerMethods.contains(injectionPoint.getTarget().asMethod())) { + configProperties + .produce(ConfigPropertyBuildItem.staticInit(propertyName, injectedType, propertyDefaultValue)); + } + + configProperties.produce(ConfigPropertyBuildItem.runtimeInit(propertyName, injectedType, propertyDefaultValue)); } } } @BuildStep - @Record(RUNTIME_INIT) - void validateConfigValues(ConfigRecorder recorder, List configProperties, - BeanContainerBuildItem beanContainer, BuildProducer reflectiveClass) { - // IMPL NOTE: we do depend on BeanContainerBuildItem to make sure that the BeanDeploymentValidator finished its processing - - // the non-primitive types need to be registered for reflection since Class.forName is used at runtime to load the class - for (ConfigPropertyBuildItem item : configProperties) { - Type requiredType = item.getPropertyType(); - String propertyType = requiredType.name().toString(); - if (requiredType.kind() != Kind.PRIMITIVE) { - reflectiveClass.produce(ReflectiveClassBuildItem.builder(propertyType).build()); - } - } + @Record(STATIC_INIT) + void validateStaticInitConfigProperty( + ConfigRecorder recorder, + List configProperties, + BuildProducer reflectiveClass) { - Set propertiesToValidate = new HashSet<>(); - for (ConfigPropertyBuildItem configProperty : configProperties) { - String rawTypeName = configProperty.getPropertyType().name().toString(); - List actualTypeArgumentNames = Collections.emptyList(); - if (configProperty.getPropertyType().kind() == Kind.PARAMETERIZED_TYPE) { - List argumentTypes = configProperty.getPropertyType().asParameterizedType().arguments(); - actualTypeArgumentNames = new ArrayList<>(argumentTypes.size()); - for (Type argumentType : argumentTypes) { - actualTypeArgumentNames.add(argumentType.name().toString()); - if (argumentType.kind() != Kind.PRIMITIVE) { - reflectiveClass.produce(ReflectiveClassBuildItem.builder(argumentType.name().toString()) - .build()); - } - } + recorder.validateConfigProperties( + configProperties.stream() + .filter(ConfigPropertyBuildItem::isStaticInit) + .map(p -> configPropertyToConfigValidation(p, reflectiveClass)) + .collect(toSet())); + } - } - propertiesToValidate.add(new ConfigValidationMetadata(configProperty.getPropertyName(), - rawTypeName, actualTypeArgumentNames, configProperty.getDefaultValue())); - } + @BuildStep + @Record(RUNTIME_INIT) + void validateRuntimeConfigProperty( + ConfigRecorder recorder, + List configProperties, + BuildProducer reflectiveClass) { - recorder.validateConfigProperties(propertiesToValidate); + recorder.validateConfigProperties( + configProperties.stream() + .filter(ConfigPropertyBuildItem::isRuntimeInit) + .map(p -> configPropertyToConfigValidation(p, reflectiveClass)) + .collect(toSet())); } @BuildStep @@ -524,6 +538,30 @@ public static boolean isHandledByProducers(Type type) { MP_CONFIG_VALUE_NAME.equals(type.name()); } + private static ConfigValidationMetadata configPropertyToConfigValidation(ConfigPropertyBuildItem configProperty, + BuildProducer reflectiveClass) { + String typeName = configProperty.getPropertyType().name().toString(); + List typeArgumentNames = Collections.emptyList(); + + if (configProperty.getPropertyType().kind() != Kind.PRIMITIVE) { + reflectiveClass.produce(ReflectiveClassBuildItem.builder(typeName).build()); + } + + if (configProperty.getPropertyType().kind() == Kind.PARAMETERIZED_TYPE) { + List argumentTypes = configProperty.getPropertyType().asParameterizedType().arguments(); + typeArgumentNames = new ArrayList<>(argumentTypes.size()); + for (Type argumentType : argumentTypes) { + typeArgumentNames.add(argumentType.name().toString()); + if (argumentType.kind() != Kind.PRIMITIVE) { + reflectiveClass.produce(ReflectiveClassBuildItem.builder(argumentType.name().toString()).build()); + } + } + } + + return new ConfigValidationMetadata(configProperty.getPropertyName(), typeName, typeArgumentNames, + configProperty.getDefaultValue()); + } + private static Map configClassesToTypesMap(List configClasses, ConfigClassBuildItem.Kind kind) { Map configClassesTypes = new HashMap<>(); diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigPropertyBuildItem.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigPropertyBuildItem.java index ad5fef88ab6cf..5e78261619882 100644 --- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigPropertyBuildItem.java +++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/ConfigPropertyBuildItem.java @@ -3,6 +3,7 @@ import org.jboss.jandex.Type; import io.quarkus.builder.item.MultiBuildItem; +import io.quarkus.runtime.ExecutionMode; /** * Represents a mandatory config property that needs to be validated at runtime. @@ -11,11 +12,18 @@ public final class ConfigPropertyBuildItem extends MultiBuildItem { private final String propertyName; private final Type propertyType; private final String defaultValue; + private final ExecutionMode executionMode; + + private ConfigPropertyBuildItem( + final String propertyName, + final Type propertyType, + final String defaultValue, + final ExecutionMode executionMode) { - public ConfigPropertyBuildItem(final String propertyName, final Type propertyType, final String defaultValue) { this.propertyName = propertyName; this.propertyType = propertyType; this.defaultValue = defaultValue; + this.executionMode = executionMode; } public String getPropertyName() { @@ -29,4 +37,30 @@ public Type getPropertyType() { public String getDefaultValue() { return defaultValue; } + + public ExecutionMode getExecutionMode() { + return executionMode; + } + + public boolean isStaticInit() { + return executionMode.equals(ExecutionMode.STATIC_INIT); + } + + public boolean isRuntimeInit() { + return executionMode.equals(ExecutionMode.RUNTIME_INIT); + } + + public static ConfigPropertyBuildItem staticInit( + final String propertyName, + final Type propertyType, + final String defaultValue) { + return new ConfigPropertyBuildItem(propertyName, propertyType, defaultValue, ExecutionMode.STATIC_INIT); + } + + public static ConfigPropertyBuildItem runtimeInit( + final String propertyName, + final Type propertyType, + final String defaultValue) { + return new ConfigPropertyBuildItem(propertyName, propertyType, defaultValue, ExecutionMode.RUNTIME_INIT); + } } diff --git a/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ClassConfigurationPropertiesUtil.java b/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ClassConfigurationPropertiesUtil.java index a9082db669ce8..a8b14681e05b9 100644 --- a/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ClassConfigurationPropertiesUtil.java +++ b/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/ClassConfigurationPropertiesUtil.java @@ -399,9 +399,8 @@ private ResultHandle populateConfigObject(ClassLoader classLoader, ClassInfo con } for (ConfigPropertyBuildItemCandidate candidate : configPropertyBuildItemCandidates) { - configProperties - .produce(new ConfigPropertyBuildItem(candidate.getConfigPropertyName(), candidate.getConfigPropertyType(), - null)); + configProperties.produce(ConfigPropertyBuildItem.runtimeInit(candidate.getConfigPropertyName(), + candidate.getConfigPropertyType(), null)); } return configObject; diff --git a/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/InterfaceConfigurationPropertiesUtil.java b/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/InterfaceConfigurationPropertiesUtil.java index 7b642060b1cd9..a1dec9502c709 100644 --- a/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/InterfaceConfigurationPropertiesUtil.java +++ b/extensions/spring-boot-properties/deployment/src/main/java/io/quarkus/spring/boot/properties/deployment/InterfaceConfigurationPropertiesUtil.java @@ -259,8 +259,8 @@ private String generateImplementationForInterfaceConfigPropertiesRec(ClassInfo o method.declaringClass().name(), methodCreator, config); methodCreator.returnValue(value); if (defaultValueStr == null || ConfigProperty.UNCONFIGURED_VALUE.equals(defaultValueStr)) { - configProperties - .produce(new ConfigPropertyBuildItem(fullConfigName, returnType, defaultValueStr)); + configProperties.produce( + ConfigPropertyBuildItem.runtimeInit(fullConfigName, returnType, defaultValueStr)); } } } diff --git a/tcks/microprofile-config/pom.xml b/tcks/microprofile-config/pom.xml index f36b1ca04bfd5..2263e81879cb7 100644 --- a/tcks/microprofile-config/pom.xml +++ b/tcks/microprofile-config/pom.xml @@ -13,7 +13,7 @@ Quarkus - TCK - MicroProfile Config - 3.0.3 + 3.1 @@ -43,10 +43,6 @@ false - - - - false