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 0521172842f..519fb635ad8 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.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 implements Supplier { private final String propName; private final T defaultValue; private final Function parser; - private Logger log = LOG; private String successLogLevel = "INFO"; private boolean hideValue = false; - private Predicate validator = (a) -> true; + private Predicate validator = a -> true; private Function sysPropReader = System::getProperty; private BiFunction 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 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 SystemPropertySupplier 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 SystemPropertySupplier create(@NotNull String propName, @NotNull Class clazz) { + return new SystemPropertySupplier<>(propName, null, + Objects.requireNonNull(clazz, "clazz must not be null")); } /** @@ -100,18 +109,10 @@ public SystemPropertySupplier formatSetMessage(@NotNull BiFunction 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; } @@ -163,7 +164,7 @@ public T get() { log.error("Ignoring malformed value '{}' for system property {}", displayedValue, propName); } - if (!returnValue.equals(defaultValue)) { + if (!Objects.equals(returnValue, defaultValue)) { String msg = setMessageFormatter.apply(propName, returnValue); switch (successLogLevel) { case "INFO": @@ -191,18 +192,21 @@ public T get() { } @SuppressWarnings("unchecked") - private static Function getValueParser(T defaultValue) { - if (defaultValue instanceof Boolean) { + private static Function getValueParser(T defaultValue, Class 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 474329ac53e..9c197aeb223 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 @@ * For Oak internal use only. Do not use outside Oak components. */ @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 69ed32d9d49..1d484ab94da 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,38 @@ public void testUnsupportedType() { } catch (IllegalArgumentException expected) { } } + + @Test + public void testCheckNullDefault() { + try { + assertNull(SystemPropertySupplier.create("foo", Boolean.class). + usingSystemPropertyReader((n) -> null).get()); + } catch (IllegalArgumentException expected) { + } + } + + @Test + public void testCheckNoDefaultNotSet() { + assertNull(SystemPropertySupplier.create("foo", Boolean.class). + usingSystemPropertyReader((n) -> null).get()); + } + + @Test + public void testCheckNoDefaultSet() { + int value = SystemPropertySupplier.create("foo", Integer.class). + usingSystemPropertyReader((n) -> "4217").get(); + assertEquals(4217, value); + } + + @Test + public void testCheckNoDefaultSetInvalid() { + assertNull(SystemPropertySupplier.create("foo", Integer.class). + usingSystemPropertyReader((n) -> "abcd").get()); + } + + @Test + public void testCheckNoDefaultValidatorRejects() { + assertNull(SystemPropertySupplier.create("foo", String.class). + usingSystemPropertyReader((n) -> "abcd").validateWith(x-> false) .get()); + } }