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 d08d2d60019aa..67c0cc07d1a89 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 @@ -37,6 +37,7 @@ import org.jboss.jandex.ClassType; import org.jboss.jandex.DotName; import org.jboss.jandex.FieldInfo; +import org.jboss.jandex.IndexView; import org.jboss.jandex.MethodInfo; import org.jboss.jandex.Type; import org.jboss.jandex.Type.Kind; @@ -80,6 +81,7 @@ public class ConfigBuildStep { private static final DotName LIST_NAME = DotName.createSimple(List.class.getName()); private static final DotName SUPPLIER_NAME = DotName.createSimple(Supplier.class.getName()); private static final DotName CONFIG_VALUE_NAME = DotName.createSimple(io.smallrye.config.ConfigValue.class.getName()); + public static final AnnotationInstance[] EMPTY_ANNOTATION_INSTANCES = {}; @BuildStep void additionalBeans(BuildProducer additionalBeans) { @@ -326,6 +328,7 @@ void generateConfigClasses( void beanConfigClasses( List configClasses, BeanRegistrationPhaseBuildItem beanRegistrationPhase, + CombinedIndexBuildItem combinedIndex, BuildProducer beanConfigurationRegistry) { for (ConfigClassBuildItem configClass : configClasses) { @@ -340,17 +343,53 @@ void beanConfigClasses( new AnnotationValue[] { createStringValue("prefix", configClass.getPrefix()) })); } + collectTypes(combinedIndex, configClass); + beanConfigurationRegistry.produce(new BeanConfiguratorBuildItem( beanRegistrationPhase.getContext() .configure(configClass.getConfigClass()) - .types(configClass.getConfigClass()) - .qualifiers(qualifiers.toArray(new AnnotationInstance[] {})) + .types(collectTypes(combinedIndex, configClass)) + .qualifiers(qualifiers.toArray(EMPTY_ANNOTATION_INSTANCES)) .creator(ConfigMappingCreator.class) .param("type", configClass.getConfigClass()) .param("prefix", configClass.getPrefix()))); } } + private Type[] collectTypes(CombinedIndexBuildItem combinedIndex, ConfigClassBuildItem configClass) { + IndexView index = combinedIndex.getIndex(); + DotName configIfaceName = DotName.createSimple(configClass.getConfigClass().getName()); + ClassInfo configIfaceInfo = index.getClassByName(configIfaceName); + if ((configIfaceInfo == null) || configIfaceInfo.interfaceNames().isEmpty()) { + return new Type[] { Type.create(configIfaceName, Kind.CLASS) }; + } + + Set allIfaces = new HashSet<>(); + allIfaces.add(configIfaceName); + collectInterfacesRec(configIfaceInfo, index, allIfaces); + Type[] result = new Type[allIfaces.size()]; + int i = 0; + for (DotName iface : allIfaces) { + result[i++] = Type.create(iface, Kind.CLASS); + } + return result; + } + + private static void collectInterfacesRec(ClassInfo current, IndexView index, Set result) { + List interfaces = current.interfaceNames(); + if (interfaces.isEmpty()) { + return; + } + for (DotName iface : interfaces) { + ClassInfo classByName = index.getClassByName(iface); + if (classByName == null) { + continue; // just ignore this type + } + result.add(iface); + collectInterfacesRec(classByName, index, result); + } + } + @BuildStep @Record(RUNTIME_INIT) void registerConfigClasses( diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigMappingTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigMappingTest.java index 8620e9ebbc4e5..1f3b5c42377e7 100644 --- a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigMappingTest.java +++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/config/ConfigMappingTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; @@ -60,7 +61,10 @@ public class ConfigMappingTest { "override.server.host=localhost\n" + "override.server.port=8080\n" + "cloud.server.host=cloud\n" + - "cloud.server.port=9000\n"), "application.properties")); + "cloud.server.port=9000\n" + + "cloud.server.port=9000\n" + + "hierarchy.foo=bar"), + "application.properties")); @Inject Config config; @@ -290,4 +294,26 @@ public String convert(final String value) { void converters() { assertEquals("bar", converters.foo()); } + + public interface Base { + + String foo(); + } + + @ConfigMapping(prefix = "hierarchy") + public interface ExtendsBase extends Base { + } + + @Inject + Base base; + + @Inject + ExtendsBase extendsBase; + + @Test + void hierarchy() { + assertSame(base, extendsBase); + assertEquals("bar", extendsBase.foo()); + } + }