Go (Con)Figure
Another post about Lightweight Config, a library I’ve recently built from the ground up, after creating various versions of it in previous projects.
Where previously, I’d tried to be clever and prepare the library for lots of possibilities, I took the opposite approach this time. I created a simple monolithic library to solve the core problem, and then in a later version added some new ideas that the simple idea opened up for me.
The Basic Challenge
In a service that has no specific injection framework, like Spring or DropWizard, and especially in a test, what’s the nicest way to load some configuration into an object.
E.g.
1 2 3 4 5 | username: user password: foo urls: - http: //foo.com - http: //bar.com |
We’d like to load this into an object:
1 2 3 4 5 6 7 | public class Config { private String user; private String password; private List<String> urls; // getters and setters } |
This is easily achieved in one line with ConfigLoader.loadYmlConfigFromResource("config.yml", Config.class)
This assumes config.yml
is in the appropriate resources.
Placeholders
What if we wanted to interpolate runtime values from environment variables or system properties? Well, that’s really the point of this framework. It’s intended to externalise the setting of values:
1 2 3 4 5 | username: ${USERNAME} password: ${PASSWORD} urls: - http: //foo.com - http: //bar.com |
Imports
If we have some common snippets of configuration to share between various configuration objects, then an import syntax would be nice. Even better if we can drive the import by a placeholder:
1 2 | # config.yml # import ${PROFILE}-config.yml |
And then:
1 2 3 4 5 | # dev-config.yml username: username password: foo urls: - http: //www.dev.com |
And so on. Now we can load the config.yml
but set PROFILE
to determine which child config is also loaded. We can even put some common properties in the parent and it’ll all mash together into the load operation.
Plugins
What if we’re using a password/secret manager to load certain values dynamically? Let’s say we want to express that a certain value may be loaded from a secret:
1 2 | username: !secret ${SECRET_ID}.user password: !secret ${SECRET_ID}.password |
We can add our custom tag – secret
– to the loader:
1 2 3 | Config myConfig = new ConfigLoader() .withTag( "secret" , secretPath -> secretsManager.load(secretPath)) .loadAs( "config.yml" , Config. class ); |
Conclusion
With a little hindsight and a little code, I’ve put together a version of this framework I’m pleased to share with the open source community.
Published on Java Code Geeks with permission by Ashley Frieze, partner at our JCG program. See the original article here: Go (Con)Figure Opinions expressed by Java Code Geeks contributors are their own. |