diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 560bca913fb14..2608390710093 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -42,7 +42,7 @@ 2.0 1.2 1.6.0 - 2.3.0 + 2.3.1-SNAPSHOT 3.0.2 3.0.1 2.1.4 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 e9430dcd36652..05de04de1c90e 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 @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Supplier; @@ -73,6 +74,7 @@ public class ConfigBuildStep { private static final DotName MP_CONFIG_VALUE_NAME = DotName.createSimple(ConfigValue.class.getName()); private static final DotName CONFIG_MAPPING_NAME = DotName.createSimple(ConfigMapping.class.getName()); + private static final DotName MAP_NAME = DotName.createSimple(Map.class.getName()); private static final DotName SET_NAME = DotName.createSimple(Set.class.getName()); private static final DotName LIST_NAME = DotName.createSimple(List.class.getName()); private static final DotName SUPPLIER_NAME = DotName.createSimple(Supplier.class.getName()); @@ -413,6 +415,7 @@ public static boolean isHandledByProducers(Type type) { DotNames.OPTIONAL_INT.equals(type.name()) || DotNames.OPTIONAL_LONG.equals(type.name()) || DotNames.OPTIONAL_DOUBLE.equals(type.name()) || + MAP_NAME.equals(type.name()) || SET_NAME.equals(type.name()) || LIST_NAME.equals(type.name()) || DotNames.LONG.equals(type.name()) || diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertiesTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertiesTest.java index 1dfb347b14a2a..f587da7d6b66b 100644 --- a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertiesTest.java +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertiesTest.java @@ -3,6 +3,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.util.Map; + import javax.enterprise.context.Dependent; import javax.enterprise.inject.spi.CDI; import javax.inject.Inject; @@ -26,10 +28,16 @@ public class ConfigPropertiesTest { "smallrye.config.mapping.validate-unknown=false\n" + "server.host=localhost\n" + "server.port=8080\n" + + "server.reasons.200=OK Server\n" + + "server.reasons.201=Created Server\n" + "cloud.host=cloud\n" + "cloud.port=9090\n" + + "cloud.reasons.200=OK Cloud\n" + + "cloud.reasons.201=Created Cloud\n" + "host=empty\n" + - "port=0\n"), + "port=0\n" + + "reasons.200=OK\n" + + "reasons.201=Created\n"), "application.properties")); @Inject @@ -78,14 +86,23 @@ void configProperties() { assertNotNull(configProperties); assertEquals("localhost", configProperties.host); assertEquals(8080, configProperties.port); + assertEquals(2, configProperties.reasons.size()); + assertEquals("OK Server", configProperties.reasons.get(200)); + assertEquals("Created Server", configProperties.reasons.get(201)); assertNotNull(configPropertiesCloud); assertEquals("cloud", configPropertiesCloud.host); assertEquals(9090, configPropertiesCloud.port); + assertEquals(2, configPropertiesCloud.reasons.size()); + assertEquals("OK Cloud", configPropertiesCloud.reasons.get(200)); + assertEquals("Created Cloud", configPropertiesCloud.reasons.get(201)); assertNotNull(configPropertiesEmpty); assertEquals("empty", configPropertiesEmpty.host); assertEquals(0, configPropertiesEmpty.port); + assertEquals(2, configPropertiesEmpty.reasons.size()); + assertEquals("OK", configPropertiesEmpty.reasons.get(200)); + assertEquals("Created", configPropertiesEmpty.reasons.get(201)); } @Test @@ -142,6 +159,7 @@ public interface Client { public static class ServerConfigProperties { public String host; public int port; + public Map reasons; } @Dependent diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertyMapInjectionTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertyMapInjectionTest.java new file mode 100644 index 0000000000000..c684a35deafc0 --- /dev/null +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigPropertyMapInjectionTest.java @@ -0,0 +1,118 @@ +package io.quarkus.arc.test.config; + +import static io.smallrye.common.constraint.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; + +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.eclipse.microprofile.config.spi.Converter; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; + +public class ConfigPropertyMapInjectionTest { + @RegisterExtension + static final QuarkusUnitTest TEST = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addAsServiceProvider(Converter.class, VersionConverter.class) + .addAsResource(new StringAsset( + "root.numbers.1=one\n" + + "root.numbers.2=two\n" + + "root.numbers.3=three\n" + + "versions.v1=1.The version 1.2.3\n" + + "versions.v1.2=1.The version 1.2.0\n" + + "versions.v2=2.The version 2.0.0\n"), + "application.properties")); + + @ConfigProperty(name = "root.numbers") + Map numbers; + + @ConfigProperty(name = "root.numbers") + Optional> oNumbers; + + @ConfigProperty(name = "root.numbers") + Supplier> sNumbers; + + @ConfigProperty(name = "versions") + Map versions; + + @ConfigProperty(name = "default.versions", defaultValue = "v0.1=0.The version 0;v1\\=1;2;3=1.The version 1\\;2\\;3;v2\\=2;1;0=2.The version 2\\;1\\;0") + Map versionsDefault; + + @Test + void mapInjection() { + assertNotNull(numbers); + assertEquals(3, numbers.size()); + assertEquals("one", numbers.get(1)); + assertEquals("two", numbers.get(2)); + assertEquals("three", numbers.get(3)); + + assertNotNull(numbers); + assertEquals(3, numbers.size()); + assertEquals("one", numbers.get(1)); + assertEquals("two", numbers.get(2)); + assertEquals("three", numbers.get(3)); + + assertNotNull(oNumbers); + assertTrue(oNumbers.isPresent()); + assertEquals(3, oNumbers.get().size()); + assertEquals("one", oNumbers.get().get(1)); + assertEquals("two", oNumbers.get().get(2)); + assertEquals("three", oNumbers.get().get(3)); + + assertNotNull(sNumbers); + assertEquals(3, sNumbers.get().size()); + assertEquals("one", sNumbers.get().get(1)); + assertEquals("two", sNumbers.get().get(2)); + assertEquals("three", sNumbers.get().get(3)); + + assertEquals(2, versions.size()); + assertEquals(new Version(1, "The version 1.2.3"), versions.get("v1")); + assertEquals(new Version(2, "The version 2.0.0"), versions.get("v2")); + assertEquals(2, versionsDefault.size()); + assertEquals(new Version(1, "The version 1;2;3"), versionsDefault.get("v1=1;2;3")); + assertEquals(new Version(2, "The version 2;1;0"), versionsDefault.get("v2=2;1;0")); + } + + static class Version { + int id; + String name; + + Version(int id, String name) { + this.id = id; + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + Version version = (Version) o; + return id == version.id && Objects.equals(name, version.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + } + + public static class VersionConverter implements Converter { + + @Override + public Version convert(String value) { + return new Version(Integer.parseInt(value.substring(0, 1)), value.substring(2)); + } + } +} diff --git a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigRecorder.java b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigRecorder.java index c232571d6c513..92f52f136395d 100644 --- a/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigRecorder.java +++ b/extensions/arc/runtime/src/main/java/io/quarkus/arc/runtime/ConfigRecorder.java @@ -1,5 +1,6 @@ package io.quarkus.arc.runtime; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -31,7 +32,7 @@ public void validateConfigProperties(Set properties) { for (ConfigValidationMetadata property : properties) { Class propertyClass = load(property.getType(), cl); // For parameterized types and arrays, we only check if the property config exists without trying to convert it - if (propertyClass.isArray() || propertyClass.getTypeParameters().length > 0) { + if (propertyClass.isArray() || (propertyClass.getTypeParameters().length > 0 && propertyClass != Map.class)) { propertyClass = String.class; }