Class Settings

java.lang.Object
org.apache.juneau.commons.settings.Settings

public class Settings extends Object
Encapsulates Java system properties with support for global and per-thread overrides for unit testing.

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:

  1. Per-thread store (if set via setLocal(String, String))
  2. Global store (if set via setGlobal(String, String))
  3. Sources added at runtime through addSource(PropertySource), newest first
  4. The system-default Config, when juneau-config is on the classpath (SPI order 100)
  5. Command-line args (SPI order 50)
  6. Java system properties (SPI order 40)
  7. Environment variables, verbatim (SPI order 30)
  8. The .env file (SPI order 20)
  9. The jar manifest (SPI order 10)
  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.

Sources vs Stores:
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 StringSetting for common types: Integer, Long, Boolean, Double, Float, File, Path, URI, Charset
  • Resettable suppliers - settings are returned as StringSetting instances that can be reset to force recomputation
Usage Examples:

// Get a system property as a StringSetting (using singleton instance) StringSetting setting = Settings.get().get("my.property"); String value = setting.get(); // Get the string value // Get with type conversion using StringSetting methods Setting<Integer> intSetting = Settings.get().get("my.int.property").asInteger(); Setting<Long> longSetting = Settings.get().get("my.long.property").asLong(); Setting<Boolean> boolSetting = Settings.get().get("my.bool.property").asBoolean(); Setting<Double> doubleSetting = Settings.get().get("my.double.property").asDouble(); Setting<Float> floatSetting = Settings.get().get("my.float.property").asFloat(); Setting<File> fileSetting = Settings.get().get("my.file.property").asFile(); Setting<Path> pathSetting = Settings.get().get("my.path.property").asPath(); Setting<URI> uriSetting = Settings.get().get("my.uri.property").asURI(); Setting<Charset> charsetSetting = Settings.get().get("my.charset.property").asCharset(); // Use custom type conversion Setting<MyCustomType> customSetting = Settings.get().get("my.custom.property").asType(MyCustomType.class); // Reset a setting to force recomputation setting.reset(); // Override for current thread (useful in unit tests) Settings.get().setLocal("my.property", "test-value"); // ... test code that uses the override ... Settings.get().unsetLocal("my.property"); // Remove specific override // OR Settings.get().clearLocal(); // Clear all thread-local overrides // Set global override (applies to all threads) Settings.get().setGlobal("my.property", "global-value"); // ... code that uses the global override ... Settings.get().unsetGlobal("my.property"); // Remove specific override // OR Settings.get().clearGlobal(); // Clear all global overrides // Create a custom Settings instance with custom sources (e.g., Spring properties) MapStore springSource = new MapStore(); springSource.set("spring.datasource.url", "jdbc:postgresql://localhost/db"); Settings custom = Settings.create() .addSource(springSource) .addSource(FunctionalPropertySource.of(System::getProperty)) .build();

System Properties:
  • juneau.settings.disableGlobal (system property) or JUNEAU_SETTINGS_DISABLEGLOBAL (system env) - If set to true, prevents new global overrides from being set via setGlobal(String, String). Existing global overrides will still be returned by get(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.

  • Field Details

  • Method Details

    • create

      public static Settings.Builder 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 Settings custom = Settings.create() .globalStore(() -> new MapStore()) .localStore(() -> new MapStore()) .addSource(FunctionalPropertySource.of(System::getProperty)) .build();

      Returns:
      A new Builder instance.
    • get

      public static Settings 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 be null.
      Returns:
      This object for method chaining.
    • sourceCount

      public int sourceCount()
      Returns the number of PropertySources currently registered with this Settings instance.

      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-RestContext config bridge added a ConfigPropertySource per cached RestContext via addSource(PropertySource) and never removed it.

      Returns:
      The current source count. Always &gt;= 0.
    • removeSource

      public boolean removeSource(PropertySource source)
      Removes a previously-added property source.

      The match is by identity (==), not equality. Callers that mutate the singleton Settings.get() from a test should capture the exact reference returned to/passed into addSource(PropertySource) and pass it back here in their teardown to avoid cross-test bleed.

      Parameters:
      source - The property source to remove. Must not be null.
      Returns:
      true if the source was present and removed, false otherwise.
    • get

      public StringSetting get(String name)
      Returns a StringSetting for the specified system property.

      The returned StringSetting is a resettable supplier that caches the lookup result. Use the StringSetting.asInteger(), StringSetting.asBoolean(), etc. methods to convert to different types.

      The lookup order is:

      1. Per-thread override (if set via setLocal(String, String))
      2. Global override (if set via setGlobal(String, String))
      3. Sources added at runtime through addSource(PropertySource), newest first
      4. The system-default Config, when juneau-config is on the classpath (SPI order 100)
      5. Command-line args (SPI order 50)
      6. Java system properties (SPI order 40)
      7. Environment variables, verbatim (SPI order 30)
      8. The .env file (SPI order 20)
      9. The jar manifest (SPI order 10)
      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 be null.
      Returns:
      A StringSetting that provides the resolved property value.
    • 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 @Value resolution 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 / global override wins" contract before consulting its own scoped sources, and still fall through to get(String) (which checks the sources list) afterwards without the override stores accidentally being consulted twice.

      Lookup order honored by this method:

      1. Per-thread (local) store
      2. Global store

      If a store is present with an empty value (i.e. an explicit null override), the returned Optional is Optional.empty() but isOverridden(String) would return true. Callers needing to distinguish "absent" from "explicit null" should use isOverridden(String) alongside this method.

      Parameters:
      name - The property name. Must not be null.
      Returns:
      The override value, or Optional.empty() if neither store carries an override.
      See Also:
    • isOverridden

      public boolean isOverridden(String name)
      Returns true 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) returns Optional.empty() because the override value itself was null — from the "no override" case.

      Parameters:
      name - The property name. Must not be null.
      Returns:
      true if either store carries an override (even with a null value).
    • get

      public <T> T get(String name, T def)
      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 using toType(String, Class). Supported types include any type that has a static method with signature public static <T> T anyName(String arg) or a public constructor with signature public T(String arg), such as Boolean, Integer, Charset, File, etc.

      Example:

      // System property: -Dmy.property=true Boolean flag = get("my.property", false); // true // Environment variable: MY_PROPERTY=UTF-8 Charset charset = get("my.property", Charset.defaultCharset()); // UTF-8 // Not found, returns default String value = get("nonexistent", "default"); // "default"

      Type Parameters:
      T - The type to convert the value to.
      Parameters:
      name - The property name. Must not be null.
      def - The default value to return if not found. Must not be null.
      Returns:
      The found value (converted to type T), or the default value if not found.
      See Also:
    • setGlobal

      public Settings setGlobal(String name, String value)
      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 to true, 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. Use unsetGlobal(String) to completely remove the override.

      Parameters:
      name - The property name. Must not be null.
      value - The override value, or null to set an empty override.
      Returns:
      This object for method chaining.
      See Also:
    • unsetGlobal

      public void unsetGlobal(String name)
      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 be null.
      See Also:
    • setLocal

      public Settings setLocal(String name, String value)
      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. Use unsetLocal(String) to completely remove the override.

      Parameters:
      name - The property name. Must not be null.
      value - The override value, or null to set an empty override.
      Returns:
      This object for method chaining.
      See Also:
    • unsetLocal

      public void unsetLocal(String name)
      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 be null.
      See Also:
    • clearLocal

      public Settings 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

      public void 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

      public <T> T toType(String s, Class<T> c)
      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:

      1. Custom type functions registered via Settings.Builder.addTypeFunction(Class, Function)
      2. Special handling for String (returns the string as-is)
      3. Special handling for Enum types (uses Enum.valueOf(Class, String))
      4. Reflection lookup for static methods with signature public static <T> T anyName(String arg) on the target class
      5. Reflection lookup for static methods on the superclass (for abstract classes like Charset where concrete implementations need to use the abstract class's static method)
      6. 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 - Uses Boolean.valueOf(String) static method
      • Integer - Uses Integer.valueOf(String) static method
      • Charset - Uses Charset.forName(String) static method (even for concrete implementations)
      • File - Uses File(String) constructor
      Type Parameters:
      T - The target type.
      Parameters:
      s - The string to convert. Must not be null.
      c - The target class. Must not be null.
      Returns:
      The converted value.
      Throws:
      RuntimeException - If the type is not supported for conversion (no static method or constructor found).