Repository: smallrye/smallrye-config
Issue: 1.3.10 started returning Optional[false] for non existent boolean properties

In 1.3.9, `config.getOptionalValue("NON_EXISTENT_PROPERTY", Boolean.class)`, returns `Optional.empty`

In 1.3.10, the same call started returning `Optional[false]` instead. This is a backward incompatible change in behavior and is not consistent with the behavior for types other than boolean, for which this call still returns `Optional.empty`.

Changed files:
implementation/src/test/java/io/smallrye/config/ConvertersTestCase.java, implementation/src/main/java/io/smallrye/config/Converters.java

diff --git a/implementation/src/main/java/io/smallrye/config/Converters.java b/implementation/src/main/java/io/smallrye/config/Converters.java
index 6ffc789b..f5bac62e 100644
--- a/implementation/src/main/java/io/smallrye/config/Converters.java
+++ b/implementation/src/main/java/io/smallrye/config/Converters.java
@@ -55,7 +55,7 @@ public final class Converters {
 
     @SuppressWarnings("unchecked")
     static final Converter<Boolean> BOOLEAN_CONVERTER = BuiltInConverter.of(1, (Converter & Serializable) value -> {
-        if (value != null) {
+        if (value != null && !value.isEmpty()) {
             return "TRUE".equalsIgnoreCase(value)
                     || "1".equalsIgnoreCase(value)
                     || "YES".equalsIgnoreCase(value)
@@ -72,19 +72,19 @@ public final class Converters {
 
     @SuppressWarnings("unchecked")
     static final Converter<Double> DOUBLE_CONVERTER = BuiltInConverter.of(2,
-            (Converter & Serializable) value -> value != null ? Double.valueOf(value) : null);
+            (Converter & Serializable) value -> value != null && !value.isEmpty() ? Double.valueOf(value) : null);
 
     @SuppressWarnings("unchecked")
     static final Converter<Float> FLOAT_CONVERTER = BuiltInConverter.of(3,
-            (Converter & Serializable) value -> value != null ? Float.valueOf(value) : null);
+            (Converter & Serializable) value -> value != null && !value.isEmpty() ? Float.valueOf(value) : null);
 
     @SuppressWarnings("unchecked")
     static final Converter<Long> LONG_CONVERTER = BuiltInConverter.of(4,
-            (Converter & Serializable) value -> value != null ? Long.valueOf(value) : null);
+            (Converter & Serializable) value -> value != null && !value.isEmpty() ? Long.valueOf(value) : null);
 
     @SuppressWarnings("unchecked")
     static final Converter<Integer> INTEGER_CONVERTER = BuiltInConverter.of(5,
-            (Converter & Serializable) value -> value != null ? Integer.valueOf(value) : null);
+            (Converter & Serializable) value -> value != null && !value.isEmpty() ? Integer.valueOf(value) : null);
 
     @SuppressWarnings("unchecked")
     static final Converter<Class<?>> CLASS_CONVERTER = BuiltInConverter.of(6, (Converter & Serializable) value -> {
@@ -121,7 +121,7 @@ public final class Converters {
 
     @SuppressWarnings("unchecked")
     static final Converter<Character> CHARACTER_CONVERTER = BuiltInConverter.of(11, (Converter & Serializable) value -> {
-        if (value != null) {
+        if (value != null && !value.isEmpty()) {
             if (value.length() == 1) {
                 return Character.valueOf(value.charAt(0));
             }
diff --git a/implementation/src/test/java/io/smallrye/config/ConvertersTestCase.java b/implementation/src/test/java/io/smallrye/config/ConvertersTestCase.java
index ab5e63e6..add365a5 100644
--- a/implementation/src/test/java/io/smallrye/config/ConvertersTestCase.java
+++ b/implementation/src/test/java/io/smallrye/config/ConvertersTestCase.java
@@ -26,6 +26,9 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.NoSuchElementException;
 import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
 
 import org.eclipse.microprofile.config.spi.Converter;
 import org.junit.Test;
@@ -203,6 +206,103 @@ public class ConvertersTestCase {
         assertEquals(LocalDate.of(1950, 1, 1), config.getValue("when", dateConv4));
     }
 
+    @Test
+    public void testEmpty() {
+        SmallRyeConfig config = buildConfig("int.key", "1234", "boolean.key", "true", "empty.key", "");
+        assertTrue(config.getOptionalValue("int.key", Integer.class).isPresent());
+        assertEquals(1234, config.getOptionalValue("int.key", Integer.class).get().intValue());
+        assertTrue(config.getValue("int.key", OptionalInt.class).isPresent());
+        assertFalse(config.getValue("int.missing.key", OptionalInt.class).isPresent());
+        assertFalse(config.getValue("empty.key", OptionalInt.class).isPresent());
+        assertEquals(1234, config.getValue("int.key", OptionalInt.class).getAsInt());
+        assertFalse(config.getOptionalValue("int.missing.key", Integer.class).isPresent());
+        assertFalse(config.getOptionalValue("empty.key", Integer.class).isPresent());
+
+        try {
+            config.getValue("empty.key", Integer.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+        try {
+            config.getValue("int.missing.key", Integer.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+
+        assertTrue(config.getOptionalValue("int.key", Long.class).isPresent());
+        assertEquals(1234, config.getOptionalValue("int.key", Long.class).get().intValue());
+        assertTrue(config.getValue("int.key", OptionalLong.class).isPresent());
+        assertEquals(1234, config.getValue("int.key", OptionalLong.class).getAsLong());
+        assertFalse(config.getValue("int.missing.key", OptionalLong.class).isPresent());
+        assertFalse(config.getValue("empty.key", OptionalLong.class).isPresent());
+        assertFalse(config.getOptionalValue("int.missing.key", Long.class).isPresent());
+        assertFalse(config.getOptionalValue("empty.key", Long.class).isPresent());
+
+        try {
+            config.getValue("empty.key", Long.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+        try {
+            config.getValue("int.missing.key", Long.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+
+        assertTrue(config.getOptionalValue("int.key", Double.class).isPresent());
+        assertEquals(1234, config.getOptionalValue("int.key", Double.class).get().intValue());
+        assertTrue(config.getValue("int.key", OptionalDouble.class).isPresent());
+        assertEquals(1234, config.getValue("int.key", OptionalDouble.class).getAsDouble(), 0.0);
+        assertFalse(config.getValue("int.missing.key", OptionalDouble.class).isPresent());
+        assertFalse(config.getValue("empty.key", OptionalDouble.class).isPresent());
+        assertFalse(config.getOptionalValue("int.missing.key", Double.class).isPresent());
+        assertFalse(config.getOptionalValue("empty.key", Double.class).isPresent());
+
+        try {
+            config.getValue("empty.key", Double.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+        try {
+            config.getValue("int.missing.key", Double.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+
+        assertTrue(config.getOptionalValue("int.key", Float.class).isPresent());
+        assertEquals(1234, config.getOptionalValue("int.key", Float.class).get().intValue());
+
+        try {
+            config.getValue("empty.key", Float.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+        try {
+            config.getValue("int.missing.key", Float.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+
+        assertTrue(config.getOptionalValue("boolean.key", Boolean.class).isPresent());
+        assertTrue(config.getValue("boolean.key", Boolean.class).booleanValue());
+        assertFalse(config.getOptionalValue("boolean.missing.key", Boolean.class).isPresent());
+        assertFalse(config.getOptionalValue("empty.key", Boolean.class).isPresent());
+        try {
+            config.getValue("empty.key", Boolean.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+        try {
+            config.getValue("boolean.missing.key", Boolean.class);
+            fail("Expected exception");
+        } catch (NoSuchElementException expected) {
+        }
+
+        assertFalse(config.getOptionalValue("empty.key", String.class).isPresent());
+
+        assertFalse(config.getOptionalValue("empty.key", Character.class).isPresent());
+    }
+
     @SafeVarargs
     private static <T> T[] array(T... items) {
         return items;