I’ve a use case where I need to bind configuration properties based on two prefixes, one of which is determined at runtime. Let’s say the constant prefix is foo
and the runtime prefix is bar
.
Given a new instance of Java Bean class FooBar
, the code should bind all environment variables FOO_
, then overwrite with all environment variables BAR_
.
There’s a way to dynamically bind a prefix to a class, as I had stated in this ticket (sample code shown below). However, what’s missing is the merging of the results.
var bindable = Bindable.of(FooBar.class); var properties = ConfigurationPropertySources.get(env); new Binder(properties) .bind("prefix", bindable) .orElse(new FooBar());
Example:
public class FooBar { private Duration latency = Duration.ofMillis(500L); // other properties // getters, setters }
If there are no environment variables FOO_LATENCY
or BAR_LATENCY
, FooBar.getLatency()
is 500 ms. If only one of FOO_LATENCY
and BAR_LATENCY
is present, FooBar.getLatency()
takes its value. If both FOO_LATENCY
and BAR_LATENCY
are present, FooBar.getLatency()
takes the value of BAR_LATENCY
.
Any idea how can this be done?
Advertisement
Answer
UPDATED
Just call bind
again. It only assigns values that are found in the configuration properties, and last prefix bound will win, on a property-by-property basis.
Example
class FooBar { private String a; private String b = "B"; private String c; private String d; private String e = "E"; // Getter, setters, and toString here }
Properties (YAML)
x.a: Hello x.b: World z.a: Goodbye z.c: Test
Test
Binder binder = Binder.get(env); FooBar fooBar = new FooBar(); System.out.println(fooBar); fooBar = binder.bind("x", Bindable.ofInstance(fooBar)).orElse(fooBar); System.out.println(fooBar); fooBar = binder.bind("y", Bindable.ofInstance(fooBar)).orElse(fooBar); System.out.println(fooBar); fooBar = binder.bind("z", Bindable.ofInstance(fooBar)).orElse(fooBar); System.out.println(fooBar);
Output
FooBar[a=null, b=B, c=null, d=null, e=E] FooBar[a=Hello, b=World, c=null, d=null, e=E] FooBar[a=Hello, b=World, c=null, d=null, e=E] FooBar[a=Goodbye, b=World, c=Test, d=null, e=E]
As you can see, the third binding overrides the values from the first, but only for properties that are actually configured, which is why the second binding does nothing.
I also simplified the logic to skip the use of ConfigurationPropertySources.get()
.