Class ConfigPropertiesBinder<T>

java.lang.Object
org.apache.juneau.commons.inject.ConfigPropertiesBinder<T>
Type Parameters:
T - The target type.

public final class ConfigPropertiesBinder<T> extends Object
Reusable, prefix-scoped whole-object config binder — usable with or without the @ConfigProperties annotation.

For each non-static, non-synthetic, non-final field on the target, builds relaxed candidate keys of the form prefix.fieldName (via RelaxedPropertySource.candidates(String)), resolves the first candidate present in the given Settings chain, and converts it via Settings.toType(String, Class). A key absent from every candidate leaves the field's initializer value untouched ("bind-only-present" semantics). The same bind-only-present rule governs a nested @ConfigProperties field that starts out null: the nested type is only materialized if at least one key resolves anywhere under its sub-prefix; otherwise the field is left null.

Usage

MyServiceProperties props = ConfigPropertiesBinder.of(new MyServiceProperties(), "MyService").run();

Precedence (candidate-major)

Precedence is candidate-major: each spelling (in RelaxedPropertySource.candidates(String) order — verbatim, upper-underscore, lower-dotted) is resolved through the full Settings source chain before the next spelling is tried. This means a verbatim hit in a lower-precedence source can outrank a relaxed-spelling override set on a higher-precedence source, if that override used a different spelling than the one that hit first.

Caller-scoped sources

When a beanStore(BeanStore) is supplied, its PropertySource-typed beans are consulted ahead of the global Settings chain for each candidate key, but after any local/global test override recorded on settings(Settings) — a Settings.setLocal/setGlobal override always wins over a scoped source, and among the scoped sources the first one that reports the key present wins. This exactly mirrors the @Value resolution path (PropertyVar), letting a caller layer overriding or supplementary sources without mutating the shared singleton. Absent any scoped PropertySource beans, resolution is identical to binding against settings(Settings) alone.

Limitation — raw-type conversion only

Unlike @Value, conversion here is keyed on the field's raw Class (via FieldInfo.getFieldType()), not its full generic Type. Generic container types such as Optional<T> or Supplier<T> are therefore not supported as @ConfigProperties field types; use a plain field type instead.

Nested fields and circular nesting

A field whose type is itself @ConfigProperties-annotated is bound recursively under prefix.fieldName. The set of nested types along the active recursion path is tracked, and re-entering a type already on that path throws a RuntimeException instead of recursing indefinitely. A nested type that needs to be materialized (see the bind-only-present rule above) must expose an accessible no-arg constructor; if it doesn't, materialization throws a RuntimeException naming the offending field.

See Also:
Since:
10.0.0