This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new b8016fec25 Commons improvements
b8016fec25 is described below
commit b8016fec25107ded079d7e2ae0796d8f174b9231
Author: James Bognar <[email protected]>
AuthorDate: Tue Dec 16 15:15:09 2025 -0500
Commons improvements
---
.../main/java/org/apache/juneau/BeanContext.java | 4 +
.../commons/function/OptionalSupplier_Test.java | 342 +++++++++++++++++++++
.../commons/function/ResettableSupplier_Test.java | 269 ++++++++++++++++
.../juneau/commons/settings/Settings_Test.java | 193 ++++++++++++
4 files changed, 808 insertions(+)
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
index 2e022728d6..8ff5b036fc 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanContext.java
@@ -175,6 +175,10 @@ public class BeanContext extends Context {
private static final Cache<HashKey,BeanContext> CACHE =
Cache.of(HashKey.class, BeanContext.class).build();
private static final Settings SETTINGS = Settings.get();
+ private static <T> T env(String property, T def) {
+ return SETTINGS.get(property, def)
+; }
+
private static Set<Class<?>> classSet() {
return new TreeSet<>(comparing(Class::getName));
}
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/function/OptionalSupplier_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/function/OptionalSupplier_Test.java
new file mode 100644
index 0000000000..447348fbda
--- /dev/null
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/function/OptionalSupplier_Test.java
@@ -0,0 +1,342 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau.commons.function;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.juneau.*;
+import org.junit.jupiter.api.*;
+
+class OptionalSupplier_Test extends TestBase {
+
+
//====================================================================================================
+ // Static factory methods
+
//====================================================================================================
+ @Test
+ void a01_of() {
+ AtomicInteger callCount = new AtomicInteger();
+ OptionalSupplier<String> supplier = OptionalSupplier.of(() -> {
+ callCount.incrementAndGet();
+ return "value";
+ });
+
+ assertEquals("value", supplier.get());
+ assertEquals(1, callCount.get());
+ assertEquals("value", supplier.get());
+ assertEquals(2, callCount.get()); // Called again (not cached)
+ }
+
+ @Test
+ void a02_of_nullSupplier() {
+ assertThrows(IllegalArgumentException.class, () ->
OptionalSupplier.of(null));
+ }
+
+ @Test
+ void a03_ofNullable() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertEquals("value", supplier.get());
+ }
+
+ @Test
+ void a04_ofNullable_null() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ assertNull(supplier.get());
+ }
+
+ @Test
+ void a05_empty() {
+ OptionalSupplier<String> supplier = OptionalSupplier.empty();
+ assertNull(supplier.get());
+ }
+
+
//====================================================================================================
+ // isPresent() / isEmpty()
+
//====================================================================================================
+ @Test
+ void b01_isPresent_true() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertTrue(supplier.isPresent());
+ assertFalse(supplier.isEmpty());
+ }
+
+ @Test
+ void b02_isPresent_false() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ assertFalse(supplier.isPresent());
+ assertTrue(supplier.isEmpty());
+ }
+
+
//====================================================================================================
+ // map()
+
//====================================================================================================
+ @Test
+ void c01_map_present() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("hello");
+ OptionalSupplier<Integer> mapped = supplier.map(String::length);
+ assertEquals(5, mapped.get());
+ }
+
+ @Test
+ void c02_map_empty() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ OptionalSupplier<Integer> mapped = supplier.map(String::length);
+ assertNull(mapped.get());
+ }
+
+ @Test
+ void c03_map_nullMapper() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertThrows(IllegalArgumentException.class, () ->
supplier.map(null));
+ }
+
+ @Test
+ void c04_map_returnsNull() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ OptionalSupplier<String> mapped = supplier.map(s -> null);
+ assertNull(mapped.get());
+ }
+
+
//====================================================================================================
+ // flatMap()
+
//====================================================================================================
+ @Test
+ void d01_flatMap_present() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("hello");
+ OptionalSupplier<Integer> mapped = supplier.flatMap(s ->
OptionalSupplier.ofNullable(s.length()));
+ assertEquals(5, mapped.get());
+ }
+
+ @Test
+ void d02_flatMap_empty() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ OptionalSupplier<Integer> mapped = supplier.flatMap(s ->
OptionalSupplier.ofNullable(s.length()));
+ assertNull(mapped.get());
+ }
+
+ @Test
+ void d03_flatMap_returnsEmpty() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("hello");
+ OptionalSupplier<Integer> mapped = supplier.flatMap(s ->
OptionalSupplier.empty());
+ assertNull(mapped.get());
+ }
+
+ @Test
+ void d04_flatMap_returnsNull() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("hello");
+ OptionalSupplier<Integer> mapped = supplier.flatMap(s -> null);
+ assertNull(mapped.get());
+ }
+
+ @Test
+ void d05_flatMap_nullMapper() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertThrows(IllegalArgumentException.class, () ->
supplier.flatMap(null));
+ }
+
+
//====================================================================================================
+ // filter()
+
//====================================================================================================
+ @Test
+ void e01_filter_matches() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("hello");
+ OptionalSupplier<String> filtered = supplier.filter(s ->
s.length() > 3);
+ assertEquals("hello", filtered.get());
+ }
+
+ @Test
+ void e02_filter_noMatch() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("hi");
+ OptionalSupplier<String> filtered = supplier.filter(s ->
s.length() > 3);
+ assertNull(filtered.get());
+ }
+
+ @Test
+ void e03_filter_empty() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ OptionalSupplier<String> filtered = supplier.filter(s ->
s.length() > 3);
+ assertNull(filtered.get());
+ }
+
+ @Test
+ void e04_filter_nullPredicate() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertThrows(IllegalArgumentException.class, () ->
supplier.filter(null));
+ }
+
+
//====================================================================================================
+ // orElse()
+
//====================================================================================================
+ @Test
+ void f01_orElse_present() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertEquals("value", supplier.orElse("default"));
+ }
+
+ @Test
+ void f02_orElse_empty() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ assertEquals("default", supplier.orElse("default"));
+ }
+
+ @Test
+ void f03_orElse_nullDefault() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ assertNull(supplier.orElse(null));
+ }
+
+
//====================================================================================================
+ // orElseGet()
+
//====================================================================================================
+ @Test
+ void g01_orElseGet_present() {
+ AtomicInteger callCount = new AtomicInteger();
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ String result = supplier.orElseGet(() -> {
+ callCount.incrementAndGet();
+ return "default";
+ });
+ assertEquals("value", result);
+ assertEquals(0, callCount.get()); // Should not be called
+ }
+
+ @Test
+ void g02_orElseGet_empty() {
+ AtomicInteger callCount = new AtomicInteger();
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ String result = supplier.orElseGet(() -> {
+ callCount.incrementAndGet();
+ return "default";
+ });
+ assertEquals("default", result);
+ assertEquals(1, callCount.get());
+ }
+
+ @Test
+ void g03_orElseGet_nullSupplier() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertThrows(IllegalArgumentException.class, () ->
supplier.orElseGet(null));
+ }
+
+
//====================================================================================================
+ // orElseThrow()
+
//====================================================================================================
+ @Test
+ void h01_orElseThrow_present() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertEquals("value", supplier.orElseThrow(() -> new
RuntimeException("should not throw")));
+ }
+
+ @Test
+ void h02_orElseThrow_empty() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ assertThrows(RuntimeException.class, () ->
supplier.orElseThrow(() -> new RuntimeException("expected")));
+ }
+
+ @Test
+ void h03_orElseThrow_nullSupplier() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertThrows(IllegalArgumentException.class, () ->
supplier.orElseThrow(null));
+ }
+
+
//====================================================================================================
+ // ifPresent()
+
//====================================================================================================
+ @Test
+ void i01_ifPresent_present() {
+ AtomicInteger callCount = new AtomicInteger();
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ supplier.ifPresent(s -> callCount.incrementAndGet());
+ assertEquals(1, callCount.get());
+ }
+
+ @Test
+ void i02_ifPresent_empty() {
+ AtomicInteger callCount = new AtomicInteger();
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ supplier.ifPresent(s -> callCount.incrementAndGet());
+ assertEquals(0, callCount.get());
+ }
+
+ @Test
+ void i03_ifPresent_nullAction() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertThrows(IllegalArgumentException.class, () ->
supplier.ifPresent(null));
+ }
+
+
//====================================================================================================
+ // ifPresentOrElse()
+
//====================================================================================================
+ @Test
+ void j01_ifPresentOrElse_present() {
+ AtomicInteger presentCount = new AtomicInteger();
+ AtomicInteger emptyCount = new AtomicInteger();
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ supplier.ifPresentOrElse(
+ s -> presentCount.incrementAndGet(),
+ () -> emptyCount.incrementAndGet()
+ );
+ assertEquals(1, presentCount.get());
+ assertEquals(0, emptyCount.get());
+ }
+
+ @Test
+ void j02_ifPresentOrElse_empty() {
+ AtomicInteger presentCount = new AtomicInteger();
+ AtomicInteger emptyCount = new AtomicInteger();
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ supplier.ifPresentOrElse(
+ s -> presentCount.incrementAndGet(),
+ () -> emptyCount.incrementAndGet()
+ );
+ assertEquals(0, presentCount.get());
+ assertEquals(1, emptyCount.get());
+ }
+
+ @Test
+ void j03_ifPresentOrElse_nullAction() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertThrows(IllegalArgumentException.class, () ->
supplier.ifPresentOrElse(null, () -> {}));
+ }
+
+ @Test
+ void j04_ifPresentOrElse_nullEmptyAction() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ assertThrows(IllegalArgumentException.class, () ->
supplier.ifPresentOrElse(s -> {}, null));
+ }
+
+
//====================================================================================================
+ // toOptional()
+
//====================================================================================================
+ @Test
+ void k01_toOptional_present() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable("value");
+ Optional<String> optional = supplier.toOptional();
+ assertTrue(optional.isPresent());
+ assertEquals("value", optional.get());
+ }
+
+ @Test
+ void k02_toOptional_empty() {
+ OptionalSupplier<String> supplier =
OptionalSupplier.ofNullable(null);
+ Optional<String> optional = supplier.toOptional();
+ assertFalse(optional.isPresent());
+ }
+}
+
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/function/ResettableSupplier_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/function/ResettableSupplier_Test.java
index 2cbabfb92c..4204802a15 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/function/ResettableSupplier_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/function/ResettableSupplier_Test.java
@@ -257,5 +257,274 @@ class ResettableSupplier_Test extends TestBase {
assertEquals("computed", supplier.get());
assertEquals(1, callCount.get());
}
+
+
//------------------------------------------------------------------------------------------------------------------
+ // isSupplied()
+
//------------------------------------------------------------------------------------------------------------------
+ @Test void b01_isSupplied_notCalled() {
+ var supplier = new ResettableSupplier<>(() -> "value");
+ assertTrue(supplier.isSupplied()); // Not called yet
+ }
+
+ @Test void b02_isSupplied_afterGet() {
+ var supplier = new ResettableSupplier<>(() -> "value");
+ supplier.get();
+ assertFalse(supplier.isSupplied()); // Has been called
+ }
+
+ @Test void b03_isSupplied_afterReset() {
+ var supplier = new ResettableSupplier<>(() -> "value");
+ supplier.get();
+ supplier.reset();
+ assertTrue(supplier.isSupplied()); // Reset, so not supplied
anymore
+ }
+
+ @Test void b04_isSupplied_afterSet() {
+ var supplier = new ResettableSupplier<>(() -> "value");
+ supplier.set("injected");
+ assertFalse(supplier.isSupplied()); // Has a value (even if set
directly)
+ }
+
+
//------------------------------------------------------------------------------------------------------------------
+ // copy()
+
//------------------------------------------------------------------------------------------------------------------
+ @Test void c01_copy_notCalled() {
+ var callCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> {
+ callCount.incrementAndGet();
+ return "value" + callCount.get();
+ });
+ var copy = supplier.copy();
+
+ // Copy should use original supplier
+ assertEquals("value1", copy.get());
+ assertEquals(1, callCount.get());
+ }
+
+ @Test void c02_copy_afterGet() {
+ var callCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> {
+ callCount.incrementAndGet();
+ return "value" + callCount.get();
+ });
+ supplier.get(); // Cache the value
+ var copy = supplier.copy();
+
+ // Copy should use cached value
+ assertEquals("value1", copy.get());
+ assertEquals(1, callCount.get()); // Original supplier not
called again
+ }
+
+ @Test void c03_copy_independent() {
+ var supplier = new ResettableSupplier<>(() -> "value");
+ var copy = supplier.copy();
+
+ // Copy is independent
+ supplier.reset();
+ assertEquals("value", copy.get()); // Copy still has cached
value
+ }
+
+
//------------------------------------------------------------------------------------------------------------------
+ // map() - overridden to return ResettableSupplier
+
//------------------------------------------------------------------------------------------------------------------
+ @Test void d01_map_present() {
+ var supplier = new ResettableSupplier<>(() -> "hello");
+ var mapped = supplier.map(String::length);
+ assertEquals(5, mapped.get());
+ }
+
+ @Test void d02_map_empty() {
+ @SuppressWarnings("cast")
+ var supplier = new ResettableSupplier<>(() -> (String)null);
+ var mapped = supplier.map(String::length);
+ assertNull(mapped.get());
+ }
+
+ @Test void d03_map_cached() {
+ var callCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> {
+ callCount.incrementAndGet();
+ return "hello";
+ });
+ var mapped = supplier.map(String::length);
+
+ // First call
+ assertEquals(5, mapped.get());
+ assertEquals(1, callCount.get());
+
+ // Second call - should use cached value from original supplier
+ assertEquals(5, mapped.get());
+ assertEquals(1, callCount.get()); // Original supplier not
called again
+ }
+
+ @Test void d04_map_independent() {
+ var supplier = new ResettableSupplier<>(() -> "hello");
+ var mapped = supplier.map(String::length);
+
+ // Reset original
+ supplier.reset();
+ // Mapped should still have cached value
+ assertEquals(5, mapped.get());
+ }
+
+
//------------------------------------------------------------------------------------------------------------------
+ // filter() - overridden to return ResettableSupplier
+
//------------------------------------------------------------------------------------------------------------------
+ @Test void e01_filter_matches() {
+ var supplier = new ResettableSupplier<>(() -> "hello");
+ var filtered = supplier.filter(s -> s.length() > 3);
+ assertEquals("hello", filtered.get());
+ }
+
+ @Test void e02_filter_noMatch() {
+ var supplier = new ResettableSupplier<>(() -> "hi");
+ var filtered = supplier.filter(s -> s.length() > 3);
+ assertNull(filtered.get());
+ }
+
+ @Test void e03_filter_empty() {
+ @SuppressWarnings("cast")
+ var supplier = new ResettableSupplier<>(() -> (String)null);
+ var filtered = supplier.filter(s -> s.length() > 3);
+ assertNull(filtered.get());
+ }
+
+ @Test void e04_filter_cached() {
+ var callCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> {
+ callCount.incrementAndGet();
+ return "hello";
+ });
+ var filtered = supplier.filter(s -> s.length() > 3);
+
+ // First call
+ assertEquals("hello", filtered.get());
+ assertEquals(1, callCount.get());
+
+ // Second call - should use cached value
+ assertEquals("hello", filtered.get());
+ assertEquals(1, callCount.get());
+ }
+
+
//------------------------------------------------------------------------------------------------------------------
+ // OptionalSupplier methods
+
//------------------------------------------------------------------------------------------------------------------
+ @Test void f01_isPresent() {
+ var supplier = new ResettableSupplier<>(() -> "value");
+ assertTrue(supplier.isPresent());
+ assertFalse(supplier.isEmpty());
+ }
+
+ @Test void f02_isEmpty() {
+ var supplier = new ResettableSupplier<>(() -> null);
+ assertFalse(supplier.isPresent());
+ assertTrue(supplier.isEmpty());
+ }
+
+ @Test void f03_orElse() {
+ var supplier = new ResettableSupplier<>(() -> "value");
+ assertEquals("value", supplier.orElse("default"));
+ }
+
+ @Test void f04_orElse_empty() {
+ var supplier = new ResettableSupplier<>(() -> null);
+ assertEquals("default", supplier.orElse("default"));
+ }
+
+ @Test void f05_orElseGet() {
+ var callCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> "value");
+ var result = supplier.orElseGet(() -> {
+ callCount.incrementAndGet();
+ return "default";
+ });
+ assertEquals("value", result);
+ assertEquals(0, callCount.get());
+ }
+
+ @Test void f06_orElseGet_empty() {
+ var callCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> null);
+ var result = supplier.orElseGet(() -> {
+ callCount.incrementAndGet();
+ return "default";
+ });
+ assertEquals("default", result);
+ assertEquals(1, callCount.get());
+ }
+
+ @Test void f07_orElseThrow() {
+ var supplier = new ResettableSupplier<>(() -> "value");
+ assertEquals("value", supplier.orElseThrow(() -> new
RuntimeException("should not throw")));
+ }
+
+ @Test void f08_orElseThrow_empty() {
+ var supplier = new ResettableSupplier<>(() -> null);
+ assertThrows(RuntimeException.class, () ->
supplier.orElseThrow(() -> new RuntimeException("expected")));
+ }
+
+ @Test void f09_ifPresent() {
+ var callCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> "value");
+ supplier.ifPresent(s -> callCount.incrementAndGet());
+ assertEquals(1, callCount.get());
+ }
+
+ @Test void f10_ifPresent_empty() {
+ var callCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> null);
+ supplier.ifPresent(s -> callCount.incrementAndGet());
+ assertEquals(0, callCount.get());
+ }
+
+ @Test void f11_ifPresentOrElse() {
+ var presentCount = new AtomicInteger();
+ var emptyCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> "value");
+ supplier.ifPresentOrElse(
+ s -> presentCount.incrementAndGet(),
+ () -> emptyCount.incrementAndGet()
+ );
+ assertEquals(1, presentCount.get());
+ assertEquals(0, emptyCount.get());
+ }
+
+ @Test void f12_ifPresentOrElse_empty() {
+ var presentCount = new AtomicInteger();
+ var emptyCount = new AtomicInteger();
+ var supplier = new ResettableSupplier<>(() -> null);
+ supplier.ifPresentOrElse(
+ s -> presentCount.incrementAndGet(),
+ () -> emptyCount.incrementAndGet()
+ );
+ assertEquals(0, presentCount.get());
+ assertEquals(1, emptyCount.get());
+ }
+
+ @Test void f13_toOptional() {
+ var supplier = new ResettableSupplier<>(() -> "value");
+ var optional = supplier.toOptional();
+ assertTrue(optional.isPresent());
+ assertEquals("value", optional.get());
+ }
+
+ @Test void f14_toOptional_empty() {
+ var supplier = new ResettableSupplier<>(() -> null);
+ var optional = supplier.toOptional();
+ assertFalse(optional.isPresent());
+ }
+
+ @Test void f15_flatMap() {
+ var supplier = new ResettableSupplier<>(() -> "hello");
+ var mapped = supplier.flatMap(s ->
OptionalSupplier.ofNullable(s.length()));
+ assertEquals(5, mapped.get());
+ }
+
+ @Test void f16_flatMap_empty() {
+ @SuppressWarnings("cast")
+ var supplier = new ResettableSupplier<>(() -> (String)null);
+ var mapped = supplier.flatMap(s ->
OptionalSupplier.ofNullable(s.length()));
+ assertNull(mapped.get());
+ }
}
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/settings/Settings_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/settings/Settings_Test.java
index e0bce38301..fb5acc07db 100644
---
a/juneau-utest/src/test/java/org/apache/juneau/commons/settings/Settings_Test.java
+++
b/juneau-utest/src/test/java/org/apache/juneau/commons/settings/Settings_Test.java
@@ -23,6 +23,7 @@ import java.io.File;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Paths;
+import java.util.concurrent.atomic.AtomicInteger;
import org.apache.juneau.*;
import org.apache.juneau.commons.function.*;
@@ -1099,5 +1100,197 @@ class Settings_Test extends TestBase {
var result = settings.get(TEST_PROP, defaultCharset);
assertEquals(Charset.forName("UTF-8"), result);
}
+
+
//====================================================================================================
+ // StringSetting.filter()
+
//====================================================================================================
+ @Test
+ void r01_stringSetting_filter_returnsStringSetting() {
+ System.setProperty(TEST_PROP, "hello");
+ var setting = Settings.get().get(TEST_PROP);
+ var filtered = setting.filter(s -> s.length() > 3);
+ assertEquals("hello", filtered.get());
+ }
+
+ @Test
+ void r02_stringSetting_filter_noMatch() {
+ System.setProperty(TEST_PROP, "hi");
+ var setting = Settings.get().get(TEST_PROP);
+ var filtered = setting.filter(s -> s.length() > 3);
+ assertNull(filtered.get());
+ }
+
+ @Test
+ void r03_stringSetting_filter_empty() {
+ var setting = Settings.get().get("nonexistent.property");
+ var filtered = setting.filter(s -> s.length() > 3);
+ assertNull(filtered.get());
+ }
+
+ @Test
+ void r04_stringSetting_filter_cached() {
+ var callCount = new AtomicInteger();
+ var settings = Settings.create()
+ .addSource(Settings.SYSTEM_PROPERTY_SOURCE)
+ .addSource(Settings.SYSTEM_ENV_SOURCE)
+ .build();
+ System.setProperty(TEST_PROP, "hello");
+ var setting = settings.get(TEST_PROP);
+ var filtered = setting.filter(s -> {
+ callCount.incrementAndGet();
+ return s.length() > 3;
+ });
+
+ // First call
+ assertEquals("hello", filtered.get());
+ assertEquals(1, callCount.get());
+
+ // Second call - should use cached value
+ assertEquals("hello", filtered.get());
+ assertEquals(1, callCount.get());
+ }
+
+ @Test
+ void r05_stringSetting_filter_independent() {
+ System.setProperty(TEST_PROP, "hello");
+ var setting = Settings.get().get(TEST_PROP);
+ var filtered = setting.filter(s -> s.length() > 3);
+
+ // Reset original
+ setting.reset();
+ // Filtered should still have cached value
+ assertEquals("hello", filtered.get());
+ }
+
+
//====================================================================================================
+ // StringSetting.mapString()
+
//====================================================================================================
+ @Test
+ void s01_stringSetting_mapString_returnsStringSetting() {
+ System.setProperty(TEST_PROP, "hello");
+ var setting = Settings.get().get(TEST_PROP);
+ var mapped = setting.mapString(String::toUpperCase);
+ assertEquals("HELLO", mapped.get());
+ }
+
+ @Test
+ void s02_stringSetting_mapString_empty() {
+ var setting = Settings.get().get("nonexistent.property");
+ var mapped = setting.mapString(String::toUpperCase);
+ assertNull(mapped.get());
+ }
+
+ @Test
+ void s03_stringSetting_mapString_cached() {
+ var callCount = new AtomicInteger();
+ var settings = Settings.create()
+ .addSource(Settings.SYSTEM_PROPERTY_SOURCE)
+ .addSource(Settings.SYSTEM_ENV_SOURCE)
+ .build();
+ System.setProperty(TEST_PROP, "hello");
+ var setting = settings.get(TEST_PROP);
+ var mapped = setting.mapString(s -> {
+ callCount.incrementAndGet();
+ return s.toUpperCase();
+ });
+
+ // First call
+ assertEquals("HELLO", mapped.get());
+ assertEquals(1, callCount.get());
+
+ // Second call - should use cached value
+ assertEquals("HELLO", mapped.get());
+ assertEquals(1, callCount.get());
+ }
+
+ @Test
+ void s04_stringSetting_mapString_independent() {
+ System.setProperty(TEST_PROP, "hello");
+ var setting = Settings.get().get(TEST_PROP);
+ var mapped = setting.mapString(String::toUpperCase);
+
+ // Reset original
+ setting.reset();
+ // Mapped should still have cached value
+ assertEquals("HELLO", mapped.get());
+ }
+
+ @Test
+ void s05_stringSetting_mapString_returnsNull() {
+ System.setProperty(TEST_PROP, "hello");
+ var setting = Settings.get().get(TEST_PROP);
+ var mapped = setting.mapString(s -> null);
+ assertNull(mapped.get());
+ }
+
+
//====================================================================================================
+ // Setting.asOptional()
+
//====================================================================================================
+ @Test
+ void t01_setting_asOptional_present() {
+ System.setProperty(TEST_PROP, "value");
+ var setting = Settings.get().get(TEST_PROP);
+ var optional = setting.asOptional();
+ assertTrue(optional.isPresent());
+ assertEquals("value", optional.get());
+ }
+
+ @Test
+ void t02_setting_asOptional_empty() {
+ var setting = Settings.get().get("nonexistent.property");
+ var optional = setting.asOptional();
+ assertFalse(optional.isPresent());
+ }
+
+ @Test
+ void t03_setting_asOptional_snapshot() {
+ var settings = Settings.create()
+ .addSource(Settings.SYSTEM_PROPERTY_SOURCE)
+ .addSource(Settings.SYSTEM_ENV_SOURCE)
+ .build();
+ System.setProperty(TEST_PROP, "value1");
+ var setting = settings.get(TEST_PROP);
+ var optional1 = setting.asOptional();
+ assertTrue(optional1.isPresent());
+ assertEquals("value1", optional1.get());
+
+ // Change the value
+ System.setProperty(TEST_PROP, "value2");
+ setting.reset(); // Force recomputation
+
+ // Original Optional should still have old value (snapshot)
+ assertTrue(optional1.isPresent());
+ assertEquals("value1", optional1.get());
+
+ // New Optional should have new value
+ var optional2 = setting.asOptional();
+ assertTrue(optional2.isPresent());
+ assertEquals("value2", optional2.get());
+ }
+
+ @Test
+ void t04_setting_asOptional_resetDoesNotAffect() {
+ var settings = Settings.create()
+ .addSource(Settings.SYSTEM_PROPERTY_SOURCE)
+ .addSource(Settings.SYSTEM_ENV_SOURCE)
+ .build();
+ System.setProperty(TEST_PROP, "value1");
+ var setting = settings.get(TEST_PROP);
+ var optional = setting.asOptional();
+ assertTrue(optional.isPresent());
+ assertEquals("value1", optional.get());
+
+ // Reset the setting
+ setting.reset();
+
+ // Optional should still have the original value (snapshot)
+ assertTrue(optional.isPresent());
+ assertEquals("value1", optional.get());
+
+ // Getting a new Optional after reset should get the current
value
+ var optional2 = setting.asOptional();
+ assertTrue(optional2.isPresent());
+ assertEquals("value1", optional2.get()); // Still value1 since
system property hasn't changed
+ }
}