Skip to content

Instantly share code, notes, and snippets.

@amr
Last active November 11, 2023 18:43
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save amr/897109c2c9a5d3b317e6a97fe74f321f to your computer and use it in GitHub Desktop.
Save amr/897109c2c9a5d3b317e6a97fe74f321f to your computer and use it in GitHub Desktop.
Java simple YAML/JSON/Properties configuration mechanism with environment variable substitution/interpolation

What is this?

Java simple configuration mechanism with environment variable substitution/interpolation.

This is basically like Dropwizard configuration functionality, but standalone.

It uses Jackson for actually reading the config file (like Dropwizard), so you get all the amazing features of Jackson, on top of commons text string substitution functionality to pre-process the config file (also like Dropwizard).

The gist is so small and could probably be missing a feature or two that you desire. The thing is, after trying other dominent libraries, I didn't find anything that gave me the functionality that I got from Jackson + StringSubstitutor in 20 lines of code.

What does it support?

  • Map configurations to POJOs, with all Jackson mapping goodness
  • Supports variable substitution, from environment and you can tweak to add more sources
  • Supports YAML, JSON and all the other formats Jackson supports

How to use it?

  1. Given a config file like this config.yml:
database:
  host: ${DB_HOST:-localhost}
  user: ${DB_USER:-defaultuser}
  password: ${DB_PASSWORD}
  
... other config here ...
  1. You write POJOs reflecting your config. I'm demonstrating nested objects so it will be 2 POJOs, I'm also using Lombok here for brevity:
@Getter
public class AppConfiguration {
  private DatabaseConfiguration database;
  
  // ... other config fields here ...
}

@Getter
public class DatabaseConfiguration {
  private String host;
  private String user;
  private String password;
}
  1. Now load your configuration into those POJOs:
ConfigurationLoader configLoader = new ConfigurationLoader();
AppConfiguration config =
        configLoader.loadConfiguration(
            new File("config.yml"), AppConfiguration.class);

Done

public class ConfigurationLoader {
private final ObjectMapper objectMapper;
private final StringSubstitutor stringSubstitutor;
ConfigurationLoader() {
this.objectMapper = new ObjectMapper(new YAMLFactory());
this.stringSubstitutor =
new StringSubstitutor(StringLookupFactory.INSTANCE.environmentVariableStringLookup());
}
<T> T loadConfiguration(File config, Class<T> cls) {
try {
String contents =
this.stringSubstitutor.replace(new String(Files.readAllBytes(config.toPath())));
return this.objectMapper.readValue(contents, cls);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
@tyagiakhilesh
Copy link

Good stuff.

@jdimeo
Copy link

jdimeo commented Jun 13, 2020

Huge fan of this approach. Closes an important gap with HOCON while still offering the "standard" syntax of YAML. Lombok, Jackson, Dropwizard, and Apache Commons are awesome libraries I use daily.

@michael-o
Copy link

I'd prefer to have ${{env.NAME}}. This would allow to chain substitutors. An application may define wellknown placeholders.

@CodeGeek32
Copy link

Thank you! I was looking for simple solution for environment variables resolution in yaml files NOT IN SPRING. AND I FOUND IT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment