Class Settings
This class provides a thread-safe way to access system properties that can be overridden at both the global level and per-thread level, making it useful for unit tests that need to temporarily change system property values without affecting other tests or threads.
Settings instances are created using the Settings.Builder pattern. Use create() to create a new builder,
or get() to get the singleton instance (which is created using default builder settings).
Lookup Order:
When retrieving a property value, the lookup order is:
- Per-thread store (if set via
setLocal(String, String)) - Global store (if set via
setGlobal(String, String)) - Sources added at runtime through
addSource(PropertySource), newest first - The system-default
Config , when juneau-config is on the classpath (SPI order 100) - Command-line args (SPI order 50)
- Java system properties (SPI order 40)
- Environment variables, verbatim (SPI order 30)
- The
.env file (SPI order 20) - The jar manifest (SPI order 10)
- Environment variables, relaxed spelling (registered first, so checked last)
If SPI registered no system-property source (a shaded jar that does not merge
Sources vs Stores:
- Sources (
PropertySource) - Provide read-only access to property values. Examples:FunctionalPropertySource - Stores (
PropertyStore) - Provide read/write access to property values. Examples:MapStore,FunctionalPropertyStore - Stores can be used as sources (they extend
PropertySource), so you can add stores viaSettings.Builder.addSource(PropertySource)
Features:
- System property access - read Java system properties with type conversion via
StringSetting - Global overrides - override system properties globally for all threads (stored in a
PropertyStore) - Per-thread overrides - override system properties for specific threads (stored in a per-thread
PropertyStore) - Custom sources - add arbitrary property sources (e.g., Spring properties, environment variables, config files) via the
Settings.Builder - Disable override support - system property to prevent new global overrides from being set
- Type-safe accessors - type conversion methods on
StringSettingfor common types: Integer, Long, Boolean, Double, Float, File, Path, URI, Charset - Resettable suppliers - settings are returned as
StringSettinginstances that can be reset to force recomputation
Usage Examples:
System Properties:
juneau.settings.disableGlobal (system property) orJUNEAU_SETTINGS_DISABLEGLOBAL (system env) - If set totrue , prevents new global overrides from being set viasetGlobal(String, String). Existing global overrides will still be returned byget(String)until explicitly removed.Note: This property is read once at class initialization time when creating the singleton instance and cannot be changed at runtime. Changing the system property after the class has been loaded will have no effect on the singleton instance. However, you can create custom Settings instances using
create()that ignore this property.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classBuilder for creating Settings instances. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final PropertySourceSYSTEM_ENV_SOURCEwrapped withrelaxed binding, so a single logical key resolves from any of the common environment-variable spellings (e.g.static final PropertySourceSystem environment variable source that delegates toSystem.getenv(String).static final PropertySourceSystem property source that delegates toSystem.getProperty(String). -
Method Summary
Modifier and TypeMethodDescriptionaddSource(PropertySource source) Adds a property source after this settings instance has been built.voidcleanup()Cleans up thread-local storage for the current thread.Clears all global overrides.Clears all per-thread overrides for the current thread.static Settings.Buildercreate()Creates a new builder for constructing a Settings instance.static Settingsget()Returns the singleton instance of Settings.Returns aStringSettingfor the specified system property.<T> TLooks up a system property, returning a default value if not found.getOverride(String name) Returns the override value for the specified property, consulting only the per-thread (local) and global stores — not the sources list.booleanisOverridden(String name) Returnstrue if the specified property has an override in either the per-thread (local) or global store.booleanremoveSource(PropertySource source) Removes a previously-added property source.Sets a global override for the specified property.Sets a per-thread override for the specified property.intReturns the number ofPropertySources currently registered with thisSettingsinstance.<T> TConverts a string to the specified type using reflection to find conversion methods or constructors.voidunsetGlobal(String name) Removes a global override for the specified property.voidunsetLocal(String name) Removes a per-thread override for the specified property.
-
Field Details
-
SYSTEM_PROPERTY_SOURCE
System property source that delegates toSystem.getProperty(String). -
SYSTEM_ENV_SOURCE
System environment variable source that delegates toSystem.getenv(String). -
RELAXED_SYSTEM_ENV_SOURCE
SYSTEM_ENV_SOURCEwrapped withrelaxed binding, so a single logical key resolves from any of the common environment-variable spellings (e.g.my.prop/myProp/MySection/myKeyall satisfied byMY_PROP/MY_SECTION_MY_KEY).This is the env source used by the default
singleton. It is verbatim-first, so exact-match behavior is unchanged — a relaxed variant is only probed when the exact name misses.Its runtime class is a
CachingPropertySourcewrapping the relaxed source. The environment is immutable inside the JVM, so caching is safe, and every chain that uses this constant shares one cache.- Since:
- 10.0.0
-
-
Method Details
-
create
Creates a new builder for constructing a Settings instance.This method provides a convenient way to create custom Settings instances with specific configuration. The builder allows you to configure stores, sources, and other settings before building the final Settings instance.
Example:
// Create a custom Settings instance Settingscustom = Settings.create () .globalStore(() ->new MapStore()) .localStore(() ->new MapStore()) .addSource(FunctionalPropertySource.of (System::getProperty)) .build();- Returns:
- A new Builder instance.
-
get
Returns the singleton instance of Settings.- Returns:
- The singleton Settings instance.
-
addSource
Adds a property source after this settings instance has been built.- Parameters:
source- The property source to add. Must not benull .- Returns:
- This object for method chaining.
-
sourceCount
Returns the number ofPropertySources currently registered with thisSettingsinstance.Intended primarily for tests that need to verify nothing has leaked extra sources into the process-wide
Settings.get()singleton — the historical failure mode documented where a per-RestContextconfig bridge added aConfigPropertySourceper cachedRestContextviaaddSource(PropertySource)and never removed it.- Returns:
- The current source count. Always
>= 0.
-
removeSource
Removes a previously-added property source.The match is by identity (
==), not equality. Callers that mutate the singletonSettings.get()from a test should capture the exact reference returned to/passed intoaddSource(PropertySource)and pass it back here in their teardown to avoid cross-test bleed.- Parameters:
source- The property source to remove. Must not benull .- Returns:
true if the source was present and removed,false otherwise.
-
get
Returns aStringSettingfor the specified system property.The returned
StringSettingis a resettable supplier that caches the lookup result. Use theStringSetting.asInteger(),StringSetting.asBoolean(), etc. methods to convert to different types.The lookup order is:
- Per-thread override (if set via
setLocal(String, String)) - Global override (if set via
setGlobal(String, String)) - Sources added at runtime through
addSource(PropertySource), newest first - The system-default
Config , when juneau-config is on the classpath (SPI order 100) - Command-line args (SPI order 50)
- Java system properties (SPI order 40)
- Environment variables, verbatim (SPI order 30)
- The
.env file (SPI order 20) - The jar manifest (SPI order 10)
- Environment variables, relaxed spelling (registered first, so checked last)
If SPI registered no system-property source (a shaded jar that does not merge
META-INF/services , for example), a fallback system-property source sits just above the relaxed environment source.- Parameters:
name- The property name. Must not benull .- Returns:
- A
StringSettingthat provides the resolved property value.
- Per-thread override (if set via
-
getOverride
Returns the override value for the specified property, consulting only the per-thread (local) and global stores — not the sources list.Intended for callers (notably the
@Valueresolution path) that interleave a caller-scoped property source between the Settings override stores and the sources list. Using this method, the caller can honor the "local/globaloverride wins" contract before consulting its own scoped sources, and still fall through toget(String)(which checks the sources list) afterwards without the override stores accidentally being consulted twice.Lookup order honored by this method:
- Per-thread (local) store
- Global store
If a store is present with an empty value (i.e. an explicit null override), the returned
OptionalisOptional.empty()butisOverridden(String)would returntrue. Callers needing to distinguish "absent" from "explicit null" should useisOverridden(String)alongside this method.- Parameters:
name- The property name. Must not benull .- Returns:
- The override value, or
Optional.empty()if neither store carries an override. - See Also:
-
isOverridden
Returnstrue if the specified property has an override in either the per-thread (local) or global store.Distinguishes the "explicit null override" case — where
getOverride(String)returnsOptional.empty()because the override value itself wasnull— from the "no override" case.- Parameters:
name- The property name. Must not benull .- Returns:
true if either store carries an override (even with anullvalue).
-
get
Looks up a system property, returning a default value if not found.This method searches for a value using the same lookup order as
get(String). If a value is found, it is converted to the type of the default value usingtoType(String, Class). Supported types include any type that has a static method with signaturepublic static <T> T anyName(String arg) or a public constructor with signaturepublic T(String arg) , such asBoolean,Integer,Charset,File, etc.Example:
// System property: -Dmy.property=true Booleanflag = get("my.property" ,false );// true // Environment variable: MY_PROPERTY=UTF-8 Charsetcharset = get("my.property" , Charset.defaultCharset());// UTF-8 // Not found, returns default Stringvalue = get("nonexistent" ,"default" );// "default" - Type Parameters:
T- The type to convert the value to.- Parameters:
name- The property name. Must not benull .def- The default value to return if not found. Must not benull .- Returns:
- The found value (converted to type T), or the default value if not found.
- See Also:
-
setGlobal
Sets a global override for the specified property.This override will apply to all threads and takes precedence over system properties. However, per-thread overrides (set via
setLocal(String, String)) will still take precedence over global overrides.If the
juneau.settings.disableGlobal system property is set totrue , this method will throw an exception. This allows system administrators to prevent applications from overriding system properties globally.Setting a value to
null will store an empty optional, effectively overriding the system property to return empty. UseunsetGlobal(String)to completely remove the override.- Parameters:
name- The property name. Must not benull .value- The override value, ornull to set an empty override.- Returns:
- This object for method chaining.
- See Also:
-
unsetGlobal
Removes a global override for the specified property.After calling this method, the property will fall back to the system property value (or per-thread override if one exists).
- Parameters:
name- The property name. Must not benull .- See Also:
-
setLocal
Sets a per-thread override for the specified property.This override will only apply to the current thread and takes precedence over global overrides and system properties. This is particularly useful in unit tests where you need to temporarily change a system property value without affecting other threads or tests.
Setting a value to
null will store an empty optional, effectively overriding the property to return empty for this thread. UseunsetLocal(String)to completely remove the override.- Parameters:
name- The property name. Must not benull .value- The override value, ornull to set an empty override.- Returns:
- This object for method chaining.
- See Also:
-
unsetLocal
Removes a per-thread override for the specified property.After calling this method, the property will fall back to the global override (if set) or the system property value for the current thread.
- Parameters:
name- The property name. Must not benull .- See Also:
-
clearLocal
Clears all per-thread overrides for the current thread.After calling this method, all properties will fall back to global overrides (if set) or system property values for the current thread.
This is typically called in a
@AfterEach or@After test method to clean up thread-local overrides after a test completes.- Returns:
- This object for method chaining.
- See Also:
-
cleanup
Cleans up thread-local storage for the current thread.This method should be called when a thread is finished using this Settings instance to prevent memory leaks in thread pool environments where threads are reused.
-
clearGlobal
Clears all global overrides.After calling this method, all properties will fall back to resolver values (or per-thread overrides if they exist).
- Returns:
- This object for method chaining.
- See Also:
-
toType
Converts a string to the specified type using reflection to find conversion methods or constructors.This method attempts to convert a string to the specified type using the following lookup order:
- Custom type functions registered via
Settings.Builder.addTypeFunction(Class, Function) - Special handling for
String(returns the string as-is) - Special handling for
Enumtypes (usesEnum.valueOf(Class, String)) - Reflection lookup for static methods with signature
public static <T> T anyName(String arg) on the target class - Reflection lookup for static methods on the superclass (for abstract classes like
Charsetwhere concrete implementations need to use the abstract class's static method) - Reflection lookup for public constructors with signature
public T(String arg)
When a conversion method or constructor is found via reflection, it is cached in the
toTypeFunctions map for future use.Examples:
Boolean - UsesBoolean.valueOf(String) static methodInteger - UsesInteger.valueOf(String) static methodCharset - UsesCharset.forName(String) static method (even for concrete implementations)File - UsesFile(String) constructor
- Type Parameters:
T- The target type.- Parameters:
s- The string to convert. Must not benull .c- The target class. Must not benull .- Returns:
- The converted value.
- Throws:
RuntimeException- If the type is not supported for conversion (no static method or constructor found).
- Custom type functions registered via
-