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 ab8b271b4a Commons improvements
ab8b271b4a is described below
commit ab8b271b4a2a53f7159b3db7942d968bbd05a574
Author: James Bognar <[email protected]>
AuthorDate: Tue Dec 16 17:49:17 2025 -0500
Commons improvements
---
.../apache/juneau/commons/collections/Cache.java | 2 +-
.../apache/juneau/commons/collections/Cache2.java | 2 +-
.../apache/juneau/commons/collections/Cache3.java | 2 +-
.../apache/juneau/commons/collections/Cache4.java | 2 +-
.../apache/juneau/commons/collections/Cache5.java | 2 +-
.../apache/juneau/commons/settings/Settings.java | 64 ++++++++++++------
.../org/apache/juneau/commons/utils/Utils.java | 54 ++-------------
.../org/apache/juneau/config/store/FileStore.java | 2 +-
.../main/java/org/apache/juneau/BeanContext.java | 12 +---
.../org/apache/juneau/parser/ReaderParser.java | 2 +-
.../apache/juneau/serializer/WriterSerializer.java | 4 +-
.../java/org/apache/juneau/rest/RestContext.java | 15 ++--
.../juneau/commons/settings/Settings_Test.java | 49 ++++----------
.../apache/juneau/commons/utils/Utils_Test.java | 79 ----------------------
14 files changed, 85 insertions(+), 206 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache.java
index 739dd092d0..81adbf3898 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache.java
@@ -189,7 +189,7 @@ public class Cache<K,V> {
Function<K,V> supplier;
Builder() {
- cacheMode = CacheMode.parse(env("juneau.cache.mode",
"FULL"));
+ cacheMode = env("juneau.cache.mode", CacheMode.FULL);
maxSize = env("juneau.cache.maxSize", 1000);
logOnExit = env("juneau.cache.logOnExit", false);
id = "Cache";
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache2.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache2.java
index 3d89e434cb..f13a22d663 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache2.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache2.java
@@ -165,7 +165,7 @@ public class Cache2<K1,K2,V> {
Function2<K1,K2,V> supplier;
Builder() {
- cacheMode = CacheMode.parse(env("juneau.cache.mode",
"FULL"));
+ cacheMode = env("juneau.cache.mode", CacheMode.FULL);
maxSize = env("juneau.cache.maxSize", 1000);
logOnExit = env("juneau.cache.logOnExit", false);
id = "Cache2";
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache3.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache3.java
index 2b9344c64d..ddf8f32a63 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache3.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache3.java
@@ -96,7 +96,7 @@ public class Cache3<K1,K2,K3,V> {
Function3<K1,K2,K3,V> supplier;
Builder() {
- cacheMode = CacheMode.parse(env("juneau.cache.mode",
"FULL"));
+ cacheMode = env("juneau.cache.mode", CacheMode.FULL);
maxSize = env("juneau.cache.maxSize", 1000);
logOnExit = env("juneau.cache.logOnExit", false);
id = "Cache3";
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache4.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache4.java
index 1ada67f2a7..7a56eb3a30 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache4.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache4.java
@@ -83,7 +83,7 @@ public class Cache4<K1,K2,K3,K4,V> {
Function4<K1,K2,K3,K4,V> supplier;
Builder() {
- cacheMode = CacheMode.parse(env("juneau.cache.mode",
"FULL"));
+ cacheMode = env("juneau.cache.mode", CacheMode.FULL);
maxSize = env("juneau.cache.maxSize", 1000);
logOnExit = env("juneau.cache.logOnExit", false);
id = "Cache4";
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache5.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache5.java
index 7980b088d4..4f854e12bd 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache5.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/collections/Cache5.java
@@ -86,7 +86,7 @@ public class Cache5<K1,K2,K3,K4,K5,V> {
Function5<K1,K2,K3,K4,K5,V> supplier;
Builder() {
- cacheMode = CacheMode.parse(env("juneau.cache.mode",
"FULL"));
+ cacheMode = env("juneau.cache.mode", CacheMode.FULL);
maxSize = env("juneau.cache.maxSize", 1000);
logOnExit = env("juneau.cache.logOnExit", false);
id = "Cache5";
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
index 909d974e9e..187645e70a 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/settings/Settings.java
@@ -16,6 +16,7 @@
*/
package org.apache.juneau.commons.settings;
+import static org.apache.juneau.commons.reflect.ReflectionUtils.*;
import static org.apache.juneau.commons.utils.AssertionUtils.*;
import static org.apache.juneau.commons.utils.ThrowableUtils.*;
import static org.apache.juneau.commons.utils.Utils.*;
@@ -26,6 +27,7 @@ import java.util.concurrent.*;
import java.util.function.*;
import org.apache.juneau.commons.function.*;
+import org.apache.juneau.commons.reflect.*;
/**
* Encapsulates Java system properties with support for global and per-thread
overrides for unit testing.
@@ -134,6 +136,8 @@ public class Settings {
*/
public static final SettingSource SYSTEM_PROPERTY_SOURCE =
FunctionalSource.of(System::getProperty);
+ private static final Set<String> FROM_STRING_METHOD_NAMES = new
LinkedHashSet<>(Arrays.asList("fromString", "parse", "forName", "valueOf"));
+
/**
* System environment variable source that delegates to {@link
System#getenv(String)}.
*/
@@ -143,13 +147,6 @@ public class Settings {
private static final String MSG_globalDisabled = "Global settings not
enabled";
private static final String MSG_localDisabled = "Local settings not
enabled";
- private static final Map<Class<?>,Function<String,?>>
DEFAULT_TYPE_FUNCTIONS = new IdentityHashMap<>();
-
- static {
- DEFAULT_TYPE_FUNCTIONS.put(Boolean.class, Boolean::valueOf);
- DEFAULT_TYPE_FUNCTIONS.put(Charset.class, Charset::forName);
- }
-
/**
* Returns properties for this Settings object itself.
* Note that these are initialized at startup and not changeable
through System.setProperty().
@@ -158,7 +155,7 @@ public class Settings {
var v = SYSTEM_PROPERTY_SOURCE.get(property);
if (v != null)
return v; // Not testable
- v = SYSTEM_ENV_SOURCE.get(uc(property.replace('.', '_')));
+ v = SYSTEM_ENV_SOURCE.get(property.replace('.',
'_').toUpperCase());
if (v != null)
return v; // Not testable
return opte();
@@ -317,7 +314,7 @@ public class Settings {
private final ResettableSupplier<SettingStore> globalStore;
private final ThreadLocal<SettingStore> localStore;
private final List<SettingSource> sources;
- private final Map<Class<?>,Function<String,?>> customTypeFunctions;
+ private final Map<Class<?>,Function<String,?>> toTypeFunctions;
/**
* Constructor.
@@ -326,7 +323,7 @@ public class Settings {
this.globalStore =
memoizeResettable(builder.globalStoreSupplier);
this.localStore =
ThreadLocal.withInitial(builder.localStoreSupplier);
this.sources = new CopyOnWriteArrayList<>(builder.sources);
- this.customTypeFunctions = new
IdentityHashMap<>(builder.customTypeFunctions);
+ this.toTypeFunctions = new
ConcurrentHashMap<>(builder.customTypeFunctions);
}
/**
@@ -380,8 +377,9 @@ public class Settings {
*
* <p>
* This method searches for a value using the same lookup order as
{@link #get(String)}.
- * If a value is found, it is converted to the type of the default
value using {@link #toType(String, Object)}.
- * Supported types include {@link Boolean}, {@link Charset}, and other
common types.
+ * If a value is found, it is converted to the type of the default
value using {@link #toType(String, Class)}.
+ * Supported types include any type that has a static method with
signature <c>public static <T> T anyName(String arg)</c>
+ * or a public constructor with signature <c>public T(String arg)</c>,
such as {@link Boolean}, {@link Integer}, {@link Charset}, {@link File}, etc.
*
* <h5 class='section'>Example:</h5>
* <p class='bjava'>
@@ -400,7 +398,7 @@ public class Settings {
* @param def The default value to return if not found.
* @return The found value (converted to type T), or the default value
if not found.
* @see #get(String)
- * @see #toType(String, Object)
+ * @see #toType(String, Class)
*/
@SuppressWarnings("unchecked")
public <T> T get(String name, T def) {
@@ -533,29 +531,55 @@ public class Settings {
}
/**
- * Converts a string to the specified type using registered conversion
functions.
+ * Converts a string to the specified type using reflection to find
conversion methods or constructors.
+ *
+ * <p>
+ * This method attempts to convert a string to the specified type using
the following lookup order:
+ * <ol>
+ * <li>Custom type functions registered via {@link
Builder#addTypeFunction(Class, Function)}</li>
+ * <li>Special handling for {@link String} (returns the string
as-is)</li>
+ * <li>Special handling for {@link Enum} types (uses {@link
Enum#valueOf(Class, String)})</li>
+ * <li>Reflection lookup for static methods with signature
<c>public static <T> T anyName(String arg)</c>
+ * on the target class</li>
+ * <li>Reflection lookup for static methods on the superclass (for
abstract classes like {@link Charset}
+ * where concrete implementations need to use the abstract
class's static method)</li>
+ * <li>Reflection lookup for public constructors with signature
<c>public T(String arg)</c></li>
+ * </ol>
+ *
+ * <p>
+ * When a conversion method or constructor is found via reflection, it
is cached in the
+ * <c>toTypeFunctions</c> map for future use.
+ *
+ * <h5 class='section'>Examples:</h5>
+ * <ul class='spaced-list'>
+ * <li><c>Boolean</c> - Uses <c>Boolean.valueOf(String)</c> static
method
+ * <li><c>Integer</c> - Uses <c>Integer.valueOf(String)</c> static
method
+ * <li><c>Charset</c> - Uses <c>Charset.forName(String)</c> static
method (even for concrete implementations)
+ * <li><c>File</c> - Uses <c>File(String)</c> constructor
+ * </ul>
*
* @param <T> The target type.
* @param s The string to convert. Must not be <jk>null</jk>.
* @param c The target class. Must not be <jk>null</jk>.
* @return The converted value.
- * @throws RuntimeException If the type is not supported for conversion.
+ * @throws RuntimeException If the type is not supported for conversion
(no static method or constructor found).
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected <T> T toType(String s, Class<T> c) {
assertArgNotNull("s", s);
assertArgNotNull("c", c);
- var f = (Function<String,T>)customTypeFunctions.get(c);
+ var f = (Function<String,T>)toTypeFunctions.get(c);
if (f == null) {
if (c == String.class)
return (T)s;
if (c.isEnum())
return (T)Enum.valueOf((Class<? extends
Enum>)c, s);
- f = (Function<String,T>)DEFAULT_TYPE_FUNCTIONS.get(c);
- if (f == null)
- f =
customTypeFunctions.entrySet().stream().filter(x ->
x.getKey().isAssignableFrom(c)).map(x ->
(Function<String,T>)x.getValue()).findFirst().orElse(null);
+ ClassInfoTyped<T> ci = info(c);
+ f = ci.getDeclaredMethod(x -> x.isStatic() &&
x.hasParameterTypes(String.class) && x.hasReturnType(c) &&
FROM_STRING_METHOD_NAMES.contains(x.getName())).map(x -> (Function<String,T>)s2
-> x.invoke(null, s2)).orElse(null);
if (f == null)
- f =
DEFAULT_TYPE_FUNCTIONS.entrySet().stream().filter(x ->
x.getKey().isAssignableFrom(c)).map(x ->
(Function<String,T>)x.getValue()).findFirst().orElse(null);
+ f = ci.getPublicConstructor(x ->
x.hasParameterTypes(String.class)).map(x -> (Function<String,T>)s2 ->
x.newInstance(s2)).orElse(null);
+ if (f != null)
+ toTypeFunctions.putIfAbsent(c, f);
}
if (f == null)
throw rex("Invalid env type: {0}", c);
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
index 88fc940286..8e16f77dc5 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/utils/Utils.java
@@ -23,12 +23,12 @@ import java.lang.reflect.*;
import java.nio.charset.*;
import java.text.*;
import java.util.*;
-import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.function.*;
import org.apache.juneau.commons.collections.*;
import org.apache.juneau.commons.function.*;
+import org.apache.juneau.commons.settings.*;
/**
* Common utility methods.
@@ -54,15 +54,6 @@ import org.apache.juneau.commons.function.*;
*/
public class Utils {
- private static final Map<Class<?>,Function<String,?>> ENV_FUNCTIONS =
new IdentityHashMap<>();
-
- static {
- ENV_FUNCTIONS.put(Boolean.class, Boolean::valueOf);
- ENV_FUNCTIONS.put(Charset.class, Charset::forName);
- }
-
- private static final ConcurrentHashMap<String,String> PROPERTY_TO_ENV =
new ConcurrentHashMap<>();
-
/**
* Converts an object to a boolean.
*
@@ -362,11 +353,8 @@ public class Utils {
* @see System#getProperty(String)
* @see System#getenv(String)
*/
- public static Optional<String> env(String name) {
- var s = System.getProperty(name);
- if (s == null)
- s = System.getenv(envName(name));
- return opt(s);
+ public static StringSetting env(String name) {
+ return Settings.get().get(name);
}
/**
@@ -404,7 +392,7 @@ public class Utils {
* @see #toType(String, Object)
*/
public static <T> T env(String name, T def) {
- return env(name).map(x -> toType(x, def)).orElse(def);
+ return Settings.get().get(name, def);
}
/**
@@ -1779,40 +1767,6 @@ public class Utils {
return o;
}
- /**
- * Converts a property name to an environment variable name.
- *
- * @param name The property name to convert.
- * @return The environment variable name (uppercase with dots replaced
by underscores).
- */
- private static String envName(String name) {
- return PROPERTY_TO_ENV.computeIfAbsent(name, x ->
x.toUpperCase().replace(".", "_"));
- }
-
- /**
- * Converts a string to the specified type using registered conversion
functions.
- *
- * @param <T> The target type.
- * @param s The string to convert.
- * @param def The default value (used to determine the target type).
- * @return The converted value, or <jk>null</jk> if the string or
default is <jk>null</jk>.
- * @throws RuntimeException If the type is not supported for conversion.
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- private static <T> T toType(String s, T def) {
- if (s == null || def == null)
- return null;
- var c = (Class<T>)def.getClass();
- if (c == String.class)
- return (T)s;
- if (c.isEnum())
- return (T)Enum.valueOf((Class<? extends Enum>)c, s);
- var f = (Function<String,T>)ENV_FUNCTIONS.get(c);
- if (f == null)
- throw rex("Invalid env type: {0}", c);
- return f.apply(s);
- }
-
/** Constructor - This class is meant to be subclasses. */
protected Utils() {}
diff --git
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
index d8edf7f108..871f594331 100644
---
a/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
+++
b/juneau-core/juneau-config/src/main/java/org/apache/juneau/config/store/FileStore.java
@@ -64,7 +64,7 @@ public class FileStore extends ConfigStore {
*/
protected Builder() {
directory = env("ConfigFileStore.directory", ".");
- charset = env("ConfigFileStore.charset",
Charset.defaultCharset());
+ charset = env("ConfigFileStore.charset").map(x ->
Charset.forName(x)).orElse(Charset.defaultCharset());
enableWatcher = env("ConfigFileStore.enableWatcher",
false);
watcherSensitivity =
env("ConfigFileStore.watcherSensitivity", WatcherSensitivity.MEDIUM);
updateOnWrite = env("ConfigFileStore.updateOnWrite",
false);
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 1b8eea0473..739d00c361 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
@@ -38,7 +38,6 @@ import org.apache.juneau.commons.collections.FluentMap;
import org.apache.juneau.commons.function.*;
import org.apache.juneau.commons.reflect.*;
import org.apache.juneau.commons.reflect.Visibility;
-import org.apache.juneau.commons.settings.*;
import org.apache.juneau.cp.*;
import org.apache.juneau.json.*;
import org.apache.juneau.marshaller.*;
@@ -173,11 +172,6 @@ public class BeanContext extends Context {
public static class Builder extends Context.Builder {
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));
@@ -254,9 +248,9 @@ public class BeanContext extends Context {
useEnumNames = env("BeanContext.useEnumNames", false);
useJavaBeanIntrospector =
env("BeanContext.useJavaBeanIntrospector", false);
typePropertyName = env("BeanContext.typePropertyName",
"_type");
- mediaType = env("BeanContext.mediaType",
(MediaType)null);
- timeZone = env("BeanContext.timeZone", (TimeZone)null);
- locale = env("BeanContext.locale", Locale.getDefault());
+ mediaType = env("BeanContext.mediaType").map(x ->
MediaType.of(x)).orElse(null);
+ timeZone = env("BeanContext.timeZone").map(x ->
TimeZone.getTimeZone(x)).orElse(null);
+ locale = env("BeanContext.locale").map(x ->
Locale.forLanguageTag(x)).orElse(Locale.getDefault());
propertyNamer = null;
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ReaderParser.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ReaderParser.java
index c55ddeadbf..b70c176b97 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ReaderParser.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/parser/ReaderParser.java
@@ -61,7 +61,7 @@ public class ReaderParser extends Parser {
* Constructor, default settings.
*/
protected Builder() {
- fileCharset = env("ReaderParser.fileCharset",
Charset.defaultCharset());
+ fileCharset = env("ReaderParser.fileCharset").map(x ->
Charset.forName(x)).orElse(Charset.defaultCharset());
streamCharset = env("ReaderParser.streamCharset", UTF8);
}
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
index d1a705a262..200f132b85 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/serializer/WriterSerializer.java
@@ -61,8 +61,8 @@ public class WriterSerializer extends Serializer {
fileCharset = Charset.defaultCharset();
streamCharset = UTF8;
maxIndent = env("WriterSerializer.maxIndent", 100);
- quoteChar = env("WriterSerializer.quoteChar",
(Character)null);
- quoteCharOverride =
env("WriterSerializer.quoteCharOverride", (Character)null);
+ quoteChar = env("WriterSerializer.quoteChar").map(x ->
(x.length() > 0 ? x.charAt(0) : null)).orElse(null);
+ quoteCharOverride =
env("WriterSerializer.quoteCharOverride").map(x -> (x.length() > 0 ?
x.charAt(0) : null)).orElse(null);
useWhitespace = env("WriterSerializer.useWhitespace",
false);
}
diff --git
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index 35c538a2dc..4be670b961 100644
---
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -260,13 +260,18 @@ public class RestContext extends Context {
private EncoderSet.Builder encoders;
private SerializerSet.Builder serializers;
private ParserSet.Builder parsers;
- String allowedHeaderParams =
env("RestContext.allowedHeaderParams", "Accept,Content-Type"),
allowedMethodHeaders = env("RestContext.allowedMethodHeaders", ""),
- allowedMethodParams =
env("RestContext.allowedMethodParams", "HEAD,OPTIONS"), clientVersionHeader =
env("RestContext.clientVersionHeader", "Client-Version"),
- debugOn = env("RestContext.debugOn", null), path =
null, uriAuthority = env("RestContext.uriAuthority", (String)null), uriContext
= env("RestContext.uriContext", (String)null);
+ String allowedHeaderParams =
env("RestContext.allowedHeaderParams", "Accept,Content-Type");
+ String allowedMethodHeaders =
env("RestContext.allowedMethodHeaders", "");
+ String allowedMethodParams =
env("RestContext.allowedMethodParams", "HEAD,OPTIONS");
+ String clientVersionHeader =
env("RestContext.clientVersionHeader", "Client-Version");
+ String debugOn = env("RestContext.debugOn").orElse(null);
+ String path = null;
+ String uriAuthority =
env("RestContext.uriAuthority").orElse(null);
+ String uriContext = env("RestContext.uriContext").orElse(null);
UriRelativity uriRelativity = env("RestContext.uriRelativity",
UriRelativity.RESOURCE);
UriResolution uriResolution = env("RestContext.uriResolution",
UriResolution.ROOT_RELATIVE);
- Charset defaultCharset = env("RestContext.defaultCharset",
UTF8);
- long maxInput = parseLongWithSuffix(env("RestContext.maxInput",
"100M"));
+ Charset defaultCharset =
env("RestContext.defaultCharset").map(Charset::forName).orElse(UTF8);
+ long maxInput =
env("RestContext.maxInput").map(StringUtils::parseLongWithSuffix).orElse(100_000_000l);
List<MediaType> consumes, produces;
boolean disableContentParam =
env("RestContext.disableContentParam", false);
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 fb5acc07db..cb46804781 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
@@ -908,15 +908,6 @@ class Settings_Test extends TestBase {
assertFalse(result);
}
- @Test
- void u06_get_withDefaultCharset_found() {
- System.setProperty(TEST_PROP, "ISO-8859-1");
- // Use Charset.forName to get a Charset instance (not a
concrete implementation)
- var defaultCharset = Charset.forName("UTF-8");
- var result = Settings.get().get(TEST_PROP, defaultCharset);
- assertEquals(Charset.forName("ISO-8859-1"), result);
- }
-
@Test
void u07_get_withDefaultCharset_notFound() {
// Use Charset.forName to get a Charset instance (not a
concrete implementation)
@@ -1053,7 +1044,14 @@ class Settings_Test extends TestBase {
@Test
void v08_addTypeFunction_unsupportedType() {
- // Try to use a type that hasn't been registered
+ // Try to use a type that doesn't have a static method or
constructor
+ // Custom class without static method or String constructor
+ class UnsupportedType {
+ @SuppressWarnings("unused")
+ private final int value;
+ UnsupportedType(int value) { this.value = value; }
+ }
+
var settings = Settings.create()
.addSource(Settings.SYSTEM_PROPERTY_SOURCE)
.addSource(Settings.SYSTEM_ENV_SOURCE)
@@ -1061,44 +1059,27 @@ class Settings_Test extends TestBase {
System.setProperty(TEST_PROP, "123");
assertThrows(RuntimeException.class, () -> {
- settings.get(TEST_PROP, 0); // Integer not registered
+ settings.get(TEST_PROP, new UnsupportedType(0)); // No
static method or String constructor
});
}
@Test
- void v09_addTypeFunction_usesDefaultWhenCustomNotRegistered() {
- // Custom settings without Integer registered should fall back
to default functions
- // But Integer is not in DEFAULT_TYPE_FUNCTIONS, so it should
throw
+ void v09_addTypeFunction_usesReflectionWhenCustomNotRegistered() {
+ // Types with static methods or String constructors work via
reflection
var settings = Settings.create()
.addSource(Settings.SYSTEM_PROPERTY_SOURCE)
.addSource(Settings.SYSTEM_ENV_SOURCE)
.build();
- // Boolean is in DEFAULT_TYPE_FUNCTIONS, so it should work
+ // Boolean has Boolean.valueOf(String) static method, so it
should work
System.setProperty(TEST_PROP, "true");
var result = settings.get(TEST_PROP, false);
assertTrue(result);
- // Integer is not in DEFAULT_TYPE_FUNCTIONS, so it should throw
+ // Integer has Integer.valueOf(String) static method, so it
should work
System.setProperty(TEST_PROP_2, "123");
- assertThrows(RuntimeException.class, () -> {
- settings.get(TEST_PROP_2, 0);
- });
- }
-
- @Test
- void v10_addTypeFunction_charsetUsesDefault() {
- // Charset is in DEFAULT_TYPE_FUNCTIONS, so it should work
without registration
- // Use Charset.forName to get a Charset instance (not a
concrete implementation)
- var settings = Settings.create()
- .addSource(Settings.SYSTEM_PROPERTY_SOURCE)
- .addSource(Settings.SYSTEM_ENV_SOURCE)
- .build();
-
- System.setProperty(TEST_PROP, "UTF-8");
- var defaultCharset = Charset.forName("ISO-8859-1");
- var result = settings.get(TEST_PROP, defaultCharset);
- assertEquals(Charset.forName("UTF-8"), result);
+ var intResult = settings.get(TEST_PROP_2, 0);
+ assertEquals(123, intResult.intValue());
}
//====================================================================================================
diff --git
a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/Utils_Test.java
b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/Utils_Test.java
index 946b73b131..f66ef1559f 100644
--- a/juneau-utest/src/test/java/org/apache/juneau/commons/utils/Utils_Test.java
+++ b/juneau-utest/src/test/java/org/apache/juneau/commons/utils/Utils_Test.java
@@ -206,85 +206,6 @@ class Utils_Test extends TestBase {
assertFalse(missing.isPresent());
}
-
//====================================================================================================
- // env(String, T)
-
//====================================================================================================
- @Test
- void a011_env_withDefault() {
- // Test with system property - covers toType line 1618-1619
(String)
- System.setProperty("test.property2", "testValue2");
- var result = env("test.property2", "default");
- assertEquals("testValue2", result);
- System.clearProperty("test.property2");
-
- // Test with default value
- var defaultValue = env("nonexistent.property.xyz2", "default");
- assertEquals("default", defaultValue);
-
- // Test with Boolean type - covers toType line 1622-1625
(ENV_FUNCTIONS)
- System.setProperty("test.boolean", "true");
- var boolResult = env("test.boolean", false);
- assertTrue(boolResult);
- System.clearProperty("test.boolean");
-
- // Test with Enum type - covers toType line 1620-1621 (Enum)
- enum TestEnum { VALUE1, VALUE2 }
- System.setProperty("test.enum", "VALUE1");
- var enumResult = env("test.enum", TestEnum.VALUE2);
- assertEquals(TestEnum.VALUE1, enumResult);
- System.clearProperty("test.enum");
-
- // Test null default - covers toType line 1615-1616 (def ==
null)
- // When property doesn't exist, toType is never called, so test
via reflection
- // Also test with property set to ensure toType is called with
s != null && def == null
- System.setProperty("test.null.def", "value");
- var nullResult = env("test.null.def", (String)null);
- assertNull(nullResult); // toType returns null when def is null
- System.clearProperty("test.null.def");
-
- // Also test when property doesn't exist (returns def directly
without calling toType)
- var nullResult2 = env("nonexistent.property.null",
(String)null);
- assertNull(nullResult2);
-
- // Test null string - covers toType line 1615-1616 (s == null,
def != null)
- // Use reflection to call private toType method directly
- try {
- var toTypeMethod =
Utils.class.getDeclaredMethod("toType", String.class, Object.class);
- toTypeMethod.setAccessible(true);
- var nullStringResult =
(String)toTypeMethod.invoke(null, (String)null, "default");
- assertNull(nullStringResult);
- } catch (Exception e) {
- fail("Failed to test toType with null string: " +
e.getMessage());
- }
-
- // Test both null - covers toType line 1615-1616 (s == null &&
def == null)
- // Use reflection to call private toType method directly
- try {
- var toTypeMethod =
Utils.class.getDeclaredMethod("toType", String.class, Object.class);
- toTypeMethod.setAccessible(true);
- var bothNullResult = (String)toTypeMethod.invoke(null,
(String)null, (String)null);
- assertNull(bothNullResult);
- } catch (Exception e) {
- fail("Failed to test toType with both null: " +
e.getMessage());
- }
-
- // Test s != null && def == null via reflection to ensure line
1615 is fully covered
- try {
- var toTypeMethod =
Utils.class.getDeclaredMethod("toType", String.class, Object.class);
- toTypeMethod.setAccessible(true);
- var nonNullStringNullDef =
(String)toTypeMethod.invoke(null, "value", (String)null);
- assertNull(nonNullStringNullDef); // toType returns
null when def is null
- } catch (Exception e) {
- fail("Failed to test toType with non-null string and
null def: " + e.getMessage());
- }
-
- // Test invalid type - covers toType line 1623-1624 (exception)
- // Note: Charset doesn't work because def.getClass() returns
concrete implementation class
- System.setProperty("test.invalid", "value");
- assertThrows(RuntimeException.class, () -> env("test.invalid",
123)); // Integer not in ENV_FUNCTIONS
- System.clearProperty("test.invalid");
- }
-
//====================================================================================================
// eq(boolean, String, String)
//====================================================================================================