diff --git a/implementation/src/main/java/io/smallrye/config/SmallRyeConfigSourceInterceptors.java b/implementation/src/main/java/io/smallrye/config/SmallRyeConfigSourceInterceptors.java new file mode 100644 index 000000000..18079d9e4 --- /dev/null +++ b/implementation/src/main/java/io/smallrye/config/SmallRyeConfigSourceInterceptors.java @@ -0,0 +1,79 @@ +package io.smallrye.config; + +import java.util.Iterator; +import java.util.List; + +public class SmallRyeConfigSourceInterceptors implements ConfigSourceInterceptorContext { + private final List interceptors; + + private int current = 0; + + public SmallRyeConfigSourceInterceptors(final List interceptors) { + this.interceptors = interceptors; + } + + ConfigValue getValue(final String name) { + ConfigValue configValue = null; + for (int i = 0; i < interceptors.size(); i++) { + ConfigSourceInterceptor interceptor = interceptors.get(i); + configValue = interceptor.getValue(this, name); + } + return configValue; + } + + @Override + public ConfigValue proceed(final String name) { + ConfigSourceInterceptorContext context = new ConfigSourceInterceptorContext() { + int position = 0; + + @Override + public ConfigValue proceed(final String name) { + return interceptors.get(position++).getValue(this, name); + } + + @Override + public Iterator iterateNames() { + return null; + } + + @Override + public Iterator iterateValues() { + return null; + } + }; + + return context.proceed(name); + } + + @Override + public Iterator iterateNames() { + return null; + } + + @Override + public Iterator iterateValues() { + return null; + } + + public static void main(String[] args) { + SmallRyeConfigSourceInterceptors interceptors = new SmallRyeConfigSourceInterceptors( + List.of(new ConfigSourceInterceptor() { + @Override + public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { + return context.proceed(name); + } + }, new ConfigSourceInterceptor() { + @Override + public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { + return context.proceed(name); + } + }, new ConfigSourceInterceptor() { + @Override + public ConfigValue getValue(final ConfigSourceInterceptorContext context, final String name) { + throw new RuntimeException(); + } + })); + + interceptors.getValue("foo.bar"); + } +} diff --git a/validator/src/main/java/io/smallrye/config/validator/BeanValidationConfigValidator.java b/validator/src/main/java/io/smallrye/config/validator/BeanValidationConfigValidator.java index 7df48a6b1..b9fb46c65 100644 --- a/validator/src/main/java/io/smallrye/config/validator/BeanValidationConfigValidator.java +++ b/validator/src/main/java/io/smallrye/config/validator/BeanValidationConfigValidator.java @@ -96,6 +96,7 @@ default void validateProperty( group = optionalGroup.get(); } + validatePropertyValue(property, currentPath, namingStrategy, mappingObject, problems); validateMappingInterface(property.asGroup().getGroupType(), appendPropertyName(currentPath, property), namingStrategy, group, problems); } catch (IllegalAccessException e) { diff --git a/validator/src/test/java/io/smallrye/config/validator/ValidateConfigTest.java b/validator/src/test/java/io/smallrye/config/validator/ValidateConfigTest.java index fa17ec00f..30b07ec5a 100644 --- a/validator/src/test/java/io/smallrye/config/validator/ValidateConfigTest.java +++ b/validator/src/test/java/io/smallrye/config/validator/ValidateConfigTest.java @@ -42,6 +42,7 @@ import io.smallrye.config.ConfigValidationException; import io.smallrye.config.SmallRyeConfig; import io.smallrye.config.SmallRyeConfigBuilder; +import io.smallrye.config.WithDefault; import io.smallrye.config.WithParentName; public class ValidateConfigTest { @@ -384,6 +385,53 @@ public interface Child extends Parent { } + @Test + void nestedMethodValidation() { + SmallRyeConfig config = new SmallRyeConfigBuilder() + .withValidator(new BeanValidationConfigValidatorImpl()) + .withMapping(MethodValidation.class) + .build(); + + ConfigValidationException validationException = assertThrows(ConfigValidationException.class, + () -> config.getConfigMapping(MethodValidation.class)); + List validations = new ArrayList<>(); + for (int i = 0; i < validationException.getProblemCount(); i++) { + validations.add(validationException.getProblem(i).getMessage()); + } + + assertEquals(1, validationException.getProblemCount()); + assertTrue(validations.contains("method.validation.nested validation executed")); + } + + @ConfigMapping(prefix = "method.validation") + interface MethodValidation { + @NestedValidation + Nested nested(); + + interface Nested { + @WithDefault("value") + String value(); + } + } + + @Target({ METHOD, TYPE }) + @Retention(RUNTIME) + @Constraint(validatedBy = { NestedValidator.class }) + public @interface NestedValidation { + String message() default "validation executed"; + + Class[] groups() default {}; + + Class[] payload() default {}; + } + + public static class NestedValidator implements ConstraintValidator { + @Override + public boolean isValid(final MethodValidation.Nested value, final ConstraintValidatorContext context) { + return false; + } + } + private static void assertValidationsEqual(List validations, String... expectedProblemMessages) { List remainingActual = new ArrayList<>(validations); List remainingExpected = Stream.of(expectedProblemMessages).collect(Collectors.toList());