This is an automated email from the ASF dual-hosted git repository.

reschke pushed a commit to branch OAK-12298
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git

commit a5f27495f8075ad2b5b715b136561c48932c3711
Author: Julian Reschke <[email protected]>
AuthorDate: Mon Jul 6 12:20:37 2026 +0100

    OAK-12298: SystemPropertySupplier: allow to signal that propery is not 
present (implies default value)
---
 .../commons/properties/SystemPropertySupplier.java | 54 ++++++++++++----------
 .../oak/commons/properties/package-info.java       |  2 +-
 .../properties/SystemPropertySupplierTest.java     | 10 ++++
 3 files changed, 40 insertions(+), 26 deletions(-)

diff --git 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/properties/SystemPropertySupplier.java
 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/properties/SystemPropertySupplier.java
index 0521172842..c1d16ae127 100644
--- 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/properties/SystemPropertySupplier.java
+++ 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/properties/SystemPropertySupplier.java
@@ -23,6 +23,7 @@ import java.util.function.Predicate;
 import java.util.function.Supplier;
 
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -49,26 +50,34 @@ public class SystemPropertySupplier<T> implements 
Supplier<T> {
     private final String propName;
     private final T defaultValue;
     private final Function<String, T> parser;
-
     private Logger log = LOG;
     private String successLogLevel = "INFO";
     private boolean hideValue = false;
-    private Predicate<T> validator = (a) -> true;
+    private Predicate<T> validator = a -> true;
     private Function<String, String> sysPropReader = System::getProperty;
     private BiFunction<String, T, String> setMessageFormatter = (a, b) -> 
String.format("System property %s found to be '%s'", a,
             hideValue ? HIDDEN_REPLACEMENT : b);
 
-    private SystemPropertySupplier(@NotNull String propName, @NotNull T 
defaultValue) {
+    private SystemPropertySupplier(@NotNull String propName, @Nullable T 
defaultValue, @Nullable Class<T> clazz) {
         this.propName = Objects.requireNonNull(propName, "propertyName must be 
non-null");
-        this.defaultValue = Objects.requireNonNull(defaultValue, "defaultValue 
must be non-null");
-        this.parser = getValueParser(defaultValue);
+        this.defaultValue = defaultValue;
+        this.parser = getValueParser(defaultValue, clazz);
     }
 
     /**
      * Create it for a given property name and default value.
      */
     public static <U> SystemPropertySupplier<U> create(@NotNull String 
propName, @NotNull U defaultValue) {
-        return new SystemPropertySupplier<>(propName, defaultValue);
+        return new SystemPropertySupplier<>(propName,
+                Objects.requireNonNull(defaultValue, "defaultValue must not be 
null"), null);
+    }
+
+    /**
+     * Create it for a given property name and no default value (but expected 
{@linkplain Class}).
+     */
+    public static <U> SystemPropertySupplier<U> create(@NotNull String 
propName, @NotNull Class<U> clazz) {
+        return new SystemPropertySupplier<>(propName, null,
+                Objects.requireNonNull(clazz, "clazz must not be null"));
     }
 
     /**
@@ -100,18 +109,10 @@ public class SystemPropertySupplier<T> implements 
Supplier<T> {
      * Specify logging level to use for "success" message (defaults to "INFO")
      */
     public SystemPropertySupplier<T> logSuccessAs(String successLogLevel) {
-        String newLevel;
-        switch (Objects.requireNonNull(successLogLevel)) {
-            case "DEBUG":
-            case "ERROR":
-            case "INFO":
-            case "TRACE":
-            case "WARN":
-                newLevel = successLogLevel;
-                break;
-            default:
-                throw new IllegalArgumentException("unsupported log level: " + 
successLogLevel);
-        }
+        String newLevel = switch (Objects.requireNonNull(successLogLevel)) {
+            case "DEBUG", "ERROR", "INFO", "TRACE", "WARN" -> successLogLevel;
+            default -> throw new IllegalArgumentException("unsupported log 
level: " + successLogLevel);
+        };
         this.successLogLevel = newLevel;
         return this;
     }
@@ -191,18 +192,21 @@ public class SystemPropertySupplier<T> implements 
Supplier<T> {
     }
 
     @SuppressWarnings("unchecked")
-    private static <T> Function<String, T> getValueParser(T defaultValue) {
-        if (defaultValue instanceof Boolean) {
+    private static <T> Function<String, T> getValueParser(T defaultValue, 
Class<T> type) {
+        Class<?> clazz = (defaultValue != null) ? defaultValue.getClass() : 
type;
+
+        if (clazz == null) {
+            throw new IllegalArgumentException("Cannot determine type: 
defaultValue is null and no type provided.");
+        } else if (Boolean.class.isAssignableFrom(clazz)) {
             return v -> (T) Boolean.valueOf(v);
-        } else if (defaultValue instanceof Integer) {
+        } else if (Integer.class.isAssignableFrom(clazz)) {
             return v -> (T) Integer.valueOf(v);
-        } else if (defaultValue instanceof Long) {
+        } else if (Long.class.isAssignableFrom(clazz)) {
             return v -> (T) Long.valueOf(v);
-        } else if (defaultValue instanceof String) {
+        } else if (String.class.isAssignableFrom(clazz)) {
             return v -> (T) v;
         } else {
-            throw new IllegalArgumentException(
-                    String.format("expects a defaultValue of Boolean, Integer, 
Long, or String, but got: %s", defaultValue.getClass()));
+            throw new IllegalArgumentException("Unsupported type: " + 
clazz.getName());
         }
     }
 }
diff --git 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/properties/package-info.java
 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/properties/package-info.java
index 474329ac53..9c197aeb22 100644
--- 
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/properties/package-info.java
+++ 
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/properties/package-info.java
@@ -18,7 +18,7 @@
  * <em>For Oak internal use only. Do not use outside Oak components.</em>
  */
 @Internal(since = "1.1.0")
-@Version("2.1.0")
+@Version("2.2.0")
 package org.apache.jackrabbit.oak.commons.properties;
 
 import org.apache.jackrabbit.oak.commons.annotations.Internal;
diff --git 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/properties/SystemPropertySupplierTest.java
 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/properties/SystemPropertySupplierTest.java
index 69ed32d9d4..fea034e08c 100755
--- 
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/properties/SystemPropertySupplierTest.java
+++ 
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/properties/SystemPropertySupplierTest.java
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.commons.properties;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import org.apache.jackrabbit.oak.commons.junit.LogCustomizer;
@@ -137,4 +138,13 @@ public class SystemPropertySupplierTest {
         } catch (IllegalArgumentException expected) {
         }
     }
+
+    @Test
+    public void testCheckNullDefault() {
+        try {
+            assertNull(SystemPropertySupplier.create("foo", Boolean.class).
+                    usingSystemPropertyReader((n) -> null).get());
+        } catch (IllegalArgumentException expected) {
+        }
+    }
 }

Reply via email to