Repository: quarkusio/quarkus
Issue: Using @ConfigProperty with Optional<List<String>> throw an exception

**Describe the bug**
Using:
```
    @ConfigProperty(name = "items3")
    Optional<List<String>> getItems3();
```

**Expected behavior**
Return an empty list when unset

**Actual behavior**
Throws an exception:
```
java.lang.IllegalArgumentException: No Converter registered for interface java.util.List

	at io.smallrye.config.SmallRyeConfig.lambda$getConverter$1(SmallRyeConfig.java:202)
	at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1705)
	at io.smallrye.config.SmallRyeConfig.getConverter(SmallRyeConfig.java:199)
```

**To Reproduce**
Reproducer:
https://github.com/ia3andy/check-list-config-empty

**Environment (please complete the following information):**
 - Quarkus version or git rev: 1.3.1.Final


Changed files:
extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/ClassWithAllPublicFieldsConfigPropertiesTest.java
extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ConfigPropertiesUtil.java
extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ClassConfigPropertiesUtil.java
extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/InterfaceConfigPropertiesUtil.java
extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/TypicalInterfaceConfigPropertiesTest.java

diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ClassConfigPropertiesUtil.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ClassConfigPropertiesUtil.java
index 5262640498e..9d8643ea1f5 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ClassConfigPropertiesUtil.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ClassConfigPropertiesUtil.java
@@ -268,11 +268,27 @@ private static ResultHandle populateConfigObject(ClassLoader classLoader, ClassI
                             field.declaringClass().name());
 
                     // config.getOptionalValue
-                    ResultHandle setterValue = methodCreator.invokeInterfaceMethod(
-                            MethodDescriptor.ofMethod(Config.class, "getOptionalValue", Optional.class, String.class,
-                                    Class.class),
-                            config, methodCreator.load(fullConfigName), methodCreator.loadClass(genericType.name().toString()));
-                    createWriteValue(methodCreator, configObject, field, setter, useFieldAccess, setterValue);
+                    if (genericType.kind() != Type.Kind.PARAMETERIZED_TYPE) {
+                        ResultHandle setterValue = methodCreator.invokeInterfaceMethod(
+                                MethodDescriptor.ofMethod(Config.class, "getOptionalValue", Optional.class, String.class,
+                                        Class.class),
+                                config, methodCreator.load(fullConfigName),
+                                methodCreator.loadClass(genericType.name().toString()));
+                        createWriteValue(methodCreator, configObject, field, setter, useFieldAccess, setterValue);
+                    } else {
+                        // convert the String value and populate an Optional with it
+                        ReadOptionalResponse readOptionalResponse = createReadOptionalValueAndConvertIfNeeded(fullConfigName,
+                                genericType, field.declaringClass().name(), methodCreator, config);
+                        createWriteValue(readOptionalResponse.getIsPresentTrue(), configObject, field, setter, useFieldAccess,
+                                readOptionalResponse.getIsPresentTrue().invokeStaticMethod(
+                                        MethodDescriptor.ofMethod(Optional.class, "of", Optional.class, Object.class),
+                                        readOptionalResponse.getValue()));
+
+                        // set Optional.empty if the value isn't set
+                        createWriteValue(readOptionalResponse.getIsPresentFalse(), configObject, field, setter, useFieldAccess,
+                                readOptionalResponse.getIsPresentFalse().invokeStaticMethod(
+                                        MethodDescriptor.ofMethod(Optional.class, "empty", Optional.class)));
+                    }
                 } else {
                     /*
                      * We want to support cases where the Config class defines a default value for fields
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ConfigPropertiesUtil.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ConfigPropertiesUtil.java
index a17e0b939d9..76982cd50e5 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ConfigPropertiesUtil.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/ConfigPropertiesUtil.java
@@ -94,7 +94,7 @@ static ReadOptionalResponse createReadOptionalValueAndConvertIfNeeded(String pro
         return new ReadOptionalResponse(value, isPresentTrue, isPresentBranch.falseBranch(), effectiveTypeResponse);
     }
 
-    private static EffectiveTypeResponse getEffectiveResultType(Type resultType, DotName declaringClass) {
+    static EffectiveTypeResponse getEffectiveResultType(Type resultType, DotName declaringClass) {
         if (DotNames.LIST.equals(resultType.name()) || DotNames.COLLECTION.equals(resultType.name())
                 || DotNames.SET.equals(resultType.name())) {
             /*
diff --git a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/InterfaceConfigPropertiesUtil.java b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/InterfaceConfigPropertiesUtil.java
index bd02a980f34..9d2fa1b4204 100644
--- a/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/InterfaceConfigPropertiesUtil.java
+++ b/extensions/arc/deployment/src/main/java/io/quarkus/arc/deployment/configproperties/InterfaceConfigPropertiesUtil.java
@@ -1,6 +1,7 @@
 package io.quarkus.arc.deployment.configproperties;
 
 import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.createReadMandatoryValueAndConvertIfNeeded;
+import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.createReadOptionalValueAndConvertIfNeeded;
 import static io.quarkus.arc.deployment.configproperties.ConfigPropertiesUtil.determineSingleGenericType;
 
 import java.lang.reflect.Modifier;
@@ -134,12 +135,32 @@ static String generateImplementationForInterfaceConfigProperties(ClassInfo origi
 
                             Type genericType = determineSingleGenericType(returnType,
                                     method.declaringClass().name());
-                            ResultHandle result = methodCreator.invokeInterfaceMethod(
-                                    MethodDescriptor.ofMethod(Config.class, "getOptionalValue", Optional.class, String.class,
-                                            Class.class),
-                                    config, methodCreator.load(fullConfigName),
-                                    methodCreator.loadClass(genericType.name().toString()));
-                            methodCreator.returnValue(result);
+
+                            if (genericType.kind() != Type.Kind.PARAMETERIZED_TYPE) {
+                                ResultHandle result = methodCreator.invokeInterfaceMethod(
+                                        MethodDescriptor.ofMethod(Config.class, "getOptionalValue", Optional.class,
+                                                String.class,
+                                                Class.class),
+                                        config, methodCreator.load(fullConfigName),
+                                        methodCreator.loadClass(genericType.name().toString()));
+                                methodCreator.returnValue(result);
+                            } else {
+                                // convert the String value and populate an Optional with it
+                                ConfigPropertiesUtil.ReadOptionalResponse readOptionalResponse = createReadOptionalValueAndConvertIfNeeded(
+                                        fullConfigName,
+                                        genericType, method.declaringClass().name(), methodCreator, config);
+
+                                // return Optional.empty() if no config value was read
+                                readOptionalResponse.getIsPresentFalse()
+                                        .returnValue(readOptionalResponse.getIsPresentFalse().invokeStaticMethod(
+                                                MethodDescriptor.ofMethod(Optional.class, "empty", Optional.class)));
+
+                                // return Optional.of() using the converted value
+                                readOptionalResponse.getIsPresentTrue()
+                                        .returnValue(readOptionalResponse.getIsPresentTrue().invokeStaticMethod(
+                                                MethodDescriptor.ofMethod(Optional.class, "of", Optional.class, Object.class),
+                                                readOptionalResponse.getValue()));
+                            }
                         } else {
                             if (defaultValueStr != null) {
                                 /*
diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/ClassWithAllPublicFieldsConfigPropertiesTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/ClassWithAllPublicFieldsConfigPropertiesTest.java
index 65d79dff90e..9a81c7c7998 100644
--- a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/ClassWithAllPublicFieldsConfigPropertiesTest.java
+++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/ClassWithAllPublicFieldsConfigPropertiesTest.java
@@ -27,7 +27,7 @@ public class ClassWithAllPublicFieldsConfigPropertiesTest {
             .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
                     .addClasses(DummyBean.class, DummyProperties.class)
                     .addAsResource(new StringAsset(
-                            "dummy.name=quarkus\\ndummy.numbers=1,2,3,4\\ndummy.bool-with-default=true\\ndummy.optional-int=100"),
+                            "dummy.name=quarkus\\ndummy.numbers=1,2,3,4\\ndummy.bool-with-default=true\\ndummy.optional-int=100\\ndummy.optional-int-list=1,2"),
                             "application.properties"));
 
     @Inject
@@ -42,6 +42,9 @@ public void testConfiguredValues() {
         assertTrue(dummyBean.getOptionalInt().isPresent());
         assertEquals(100, dummyBean.getOptionalInt().get());
         assertFalse(dummyBean.getOptionalString().isPresent());
+        assertFalse(dummyBean.getOptionalStringList().isPresent());
+        assertTrue(dummyBean.getOptionalIntList().isPresent());
+        assertEquals(Arrays.asList(1, 2), dummyBean.getOptionalIntList().get());
     }
 
     @Singleton
@@ -72,6 +75,14 @@ Optional<Integer> getOptionalInt() {
         Optional<String> getOptionalString() {
             return dummyProperties.optionalString;
         }
+
+        Optional<List<String>> getOptionalStringList() {
+            return dummyProperties.optionalStringList;
+        }
+
+        Optional<List<Integer>> getOptionalIntList() {
+            return dummyProperties.optionalIntList;
+        }
     }
 
     @ConfigProperties(prefix = "dummy")
@@ -83,5 +94,7 @@ public static class DummyProperties {
         public List<Integer> numbers;
         public Optional<Integer> optionalInt;
         public Optional<String> optionalString;
+        public Optional<List<String>> optionalStringList;
+        public Optional<List<Integer>> optionalIntList;
     }
 }
diff --git a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/TypicalInterfaceConfigPropertiesTest.java b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/TypicalInterfaceConfigPropertiesTest.java
index ba31954273c..c91f9e09a4f 100644
--- a/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/TypicalInterfaceConfigPropertiesTest.java
+++ b/extensions/arc/deployment/src/test/java/io/quarkus/arc/test/configproperties/TypicalInterfaceConfigPropertiesTest.java
@@ -6,6 +6,7 @@
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.List;
 import java.util.Optional;
 
 import javax.inject.Inject;
@@ -28,7 +29,7 @@ public class TypicalInterfaceConfigPropertiesTest {
             .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
                     .addClasses(DummyBean.class, DummyProperties.class)
                     .addAsResource(new StringAsset(
-                            "dummy.name=quarkus\\ndummy.numbers=1,2,3,4\\ndummy.boolWD=true\\ndummy.optional-int=100"),
+                            "dummy.name=quarkus\\ndummy.numbers=1,2,3,4\\ndummy.boolWD=true\\ndummy.optional-int=100\\ndummy.optionalStringList=a,b"),
                             "application.properties"));
 
     @Inject
@@ -44,6 +45,9 @@ public void testConfiguredValues() {
         assertTrue(dummyBean.getOptionalInt().isPresent());
         assertEquals(100, dummyBean.getOptionalInt().get());
         assertFalse(dummyBean.getOptionalString().isPresent());
+        assertFalse(dummyBean.getIntListOptional().isPresent());
+        assertTrue(dummyBean.getStringListOptional().isPresent());
+        assertEquals(Arrays.asList("a", "b"), dummyBean.getStringListOptional().get());
     }
 
     @Singleton
@@ -76,6 +80,14 @@ Optional<String> getOptionalString() {
             return dummyProperties.stringOptional();
         }
 
+        Optional<List<String>> getStringListOptional() {
+            return dummyProperties.stringListOptional();
+        }
+
+        Optional<List<Integer>> getIntListOptional() {
+            return dummyProperties.intListOptional();
+        }
+
         String nameWithSuffix() {
             return dummyProperties.nameWithSuffix();
         }
@@ -100,6 +112,12 @@ public interface DummyProperties {
         @ConfigProperty(name = "optionalString")
         Optional<String> stringOptional();
 
+        @ConfigProperty(name = "optionalStringList")
+        Optional<List<String>> stringListOptional();
+
+        @ConfigProperty(name = "optionalIntList")
+        Optional<List<Integer>> intListOptional();
+
         default String nameWithSuffix() {
             return getFirstName() + "!";
         }