diff --git a/cdi/src/main/java/io/smallrye/config/inject/ConfigExtension.java b/cdi/src/main/java/io/smallrye/config/inject/ConfigExtension.java index 5bbd60451..2c18813ae 100644 --- a/cdi/src/main/java/io/smallrye/config/inject/ConfigExtension.java +++ b/cdi/src/main/java/io/smallrye/config/inject/ConfigExtension.java @@ -101,8 +101,7 @@ protected void processConfigProperties( // Each config class is both in SmallRyeConfig and managed by a configurator bean. // CDI requires more beans for injection points due to binding prefix. - ConfigClass properties = ConfigClass.configClass(annotatedType.getJavaClass(), - annotatedType.getAnnotation(ConfigProperties.class).prefix()); + ConfigClass properties = ConfigClass.configClass(annotatedType.getJavaClass()); configProperties.add(properties); configPropertiesBeans.add(properties); } @@ -132,7 +131,7 @@ protected void processConfigInjectionPoints(@Observes ProcessInjectionPoint) injectionPoint.getType(), - injectionPoint.getAnnotated().getAnnotation(ConfigProperties.class).prefix()); + injectionPoint.getAnnotated().getAnnotation(ConfigProperties.class).prefix(), false); // If the prefix is empty at the injection point, fallbacks to the class prefix (already registered) if (!properties.getPrefix().equals(ConfigProperties.UNCONFIGURED_PREFIX)) { @@ -145,7 +144,7 @@ protected void processConfigInjectionPoints(@Observes ProcessInjectionPoint) injectionPoint.getType(), - injectionPoint.getAnnotated().getAnnotation(ConfigMapping.class).prefix()); + injectionPoint.getAnnotated().getAnnotation(ConfigMapping.class).prefix(), true); // If the prefix is empty at the injection point, fallbacks to the class prefix (already registered) if (!mapping.getPrefix().isEmpty()) { configMappings.add(mapping); diff --git a/implementation/src/main/java/io/smallrye/config/ConfigMapping.java b/implementation/src/main/java/io/smallrye/config/ConfigMapping.java index 16577577e..344da684e 100644 --- a/implementation/src/main/java/io/smallrye/config/ConfigMapping.java +++ b/implementation/src/main/java/io/smallrye/config/ConfigMapping.java @@ -26,6 +26,9 @@ * } * * + * A Config Mapping must match every configuration path available in the Config system. If a property name + * server.name exists, then it must be mapped with a method String name(). + *

* This annotation is also used in CDI aware environments to scan and register Config Mappings. Otherwise, Config * Mapping interfaces require registration via * {@link SmallRyeConfigBuilder#withMapping(java.lang.Class)}. @@ -52,6 +55,14 @@ */ NamingStrategy namingStrategy() default NamingStrategy.KEBAB_CASE; + /** + * Enable or disable the Config Mapping requirement to match every configuration path available in the Config + * system. By default, the validation is enabled. + * + * @return a boolean true to enable the validation, or false to disable it. + */ + boolean validateUnknown() default true; + enum NamingStrategy { /** * The method name is used as is to map the configuration property. diff --git a/implementation/src/main/java/io/smallrye/config/ConfigMappings.java b/implementation/src/main/java/io/smallrye/config/ConfigMappings.java index c463298a7..2cc18bef5 100644 --- a/implementation/src/main/java/io/smallrye/config/ConfigMappings.java +++ b/implementation/src/main/java/io/smallrye/config/ConfigMappings.java @@ -119,10 +119,12 @@ static String prefix(final String prefix, final String path) { public static final class ConfigClass { private final Class klass; private final String prefix; + private final boolean validateUnknown; - public ConfigClass(final Class klass, final String prefix) { + public ConfigClass(final Class klass, final String prefix, final boolean validateUnknown) { this.klass = klass; this.prefix = prefix; + this.validateUnknown = validateUnknown; } public Class getKlass() { @@ -133,6 +135,10 @@ public String getPrefix() { return prefix; } + public boolean isValidateUnknown() { + return validateUnknown; + } + @Override public boolean equals(final Object o) { if (this == o) { @@ -151,21 +157,26 @@ public int hashCode() { } public static ConfigClass configClass(final Class klass, final String prefix) { - return new ConfigClass(klass, prefix); + return new ConfigClass(klass, prefix, true); + } + + public static ConfigClass configClass(final Class klass, final String prefix, final boolean validateUnknown) { + return new ConfigClass(klass, prefix, validateUnknown); } public static ConfigClass configClass(final Class klass) { if (klass.isInterface()) { ConfigMapping configMapping = klass.getAnnotation(ConfigMapping.class); String prefix = configMapping != null ? configMapping.prefix() : ""; - return configClass(klass, prefix); + boolean validateUnknown = configMapping == null || configMapping.validateUnknown(); + return configClass(klass, prefix, validateUnknown); } else { ConfigProperties configProperties = klass.getAnnotation(ConfigProperties.class); String prefix = configProperties != null ? configProperties.prefix() : ""; if (prefix.equals(ConfigProperties.UNCONFIGURED_PREFIX)) { prefix = ""; } - return configClass(klass, prefix); + return configClass(klass, prefix, false); } } } diff --git a/implementation/src/main/java/io/smallrye/config/SmallRyeConfigBuilder.java b/implementation/src/main/java/io/smallrye/config/SmallRyeConfigBuilder.java index 19b6f5623..8943d7bfa 100644 --- a/implementation/src/main/java/io/smallrye/config/SmallRyeConfigBuilder.java +++ b/implementation/src/main/java/io/smallrye/config/SmallRyeConfigBuilder.java @@ -776,7 +776,11 @@ public final class MappingBuilder { private final List ignoredPaths = new ArrayList<>(); public void mapping(ConfigClass configClass) { + Assert.checkNotNullParam("configClass", configClass); mapping(configClass.getKlass(), configClass.getPrefix()); + if (!configClass.isValidateUnknown()) { + ignoredPath(configClass.getPrefix() + ".**"); + } } public void mapping(Class type, String prefix) { diff --git a/implementation/src/test/java/io/smallrye/config/ConfigMappingInterfaceTest.java b/implementation/src/test/java/io/smallrye/config/ConfigMappingInterfaceTest.java index 92861cd2e..237e928de 100644 --- a/implementation/src/test/java/io/smallrye/config/ConfigMappingInterfaceTest.java +++ b/implementation/src/test/java/io/smallrye/config/ConfigMappingInterfaceTest.java @@ -2659,4 +2659,20 @@ interface Nested { String value(); } } + + @Test + void ignoreUnknownAnnotation() { + SmallRyeConfig config = new SmallRyeConfigBuilder() + .withSources(config("ignore.value", "value", "ignore.unknown", "unknown")) + .withMapping(IgnoreUnknownAnnotation.class) + .build(); + + IgnoreUnknownAnnotation mapping = config.getConfigMapping(IgnoreUnknownAnnotation.class); + assertEquals("value", mapping.value()); + } + + @ConfigMapping(prefix = "ignore", validateUnknown = false) + interface IgnoreUnknownAnnotation { + String value(); + } }