8

Is it possible to load spring-boot config from a .json file as opposed to .yaml or .properties? From looking at the documentation, this isn't supported out of the box - I'm wondering if it's possible and if so how one would go about doing it?

Andy W
  • 380
  • 1
  • 5
  • 13

4 Answers4

11

As noted in docs and on GitHub

YAML is a superset of JSON

So you can just create the following class in your Spring Boot project:

public class JsonPropertySourceLoader extends YamlPropertySourceLoader {
    @Override
    public String[] getFileExtensions() {
        return new String[]{"json"};
    }
}

Then create a file:

/src/main/resources/META-INF/spring.factories with the following content:

org.springframework.boot.env.PropertySourceLoader=\
io.myapp.JsonPropertySourceLoader

And your Spring application is ready to load JSON configurations from application.json. The priority will be: .properties -> .yaml -> .json

If you have multiple apps, you can create a jar with the shared PropertySourceLoader and spring.factories file in order to include it to any project you need.

Kirill
  • 6,762
  • 4
  • 51
  • 81
6

The spring boot way:

@EnableAutoConfiguration
@Configuration
@PropertySource(value = { "classpath:/properties/config.default.json" }, factory=SpringBootTest.JsonLoader.class )
public class SpringBootTest extends SpringBootServletInitializer {

    @Bean
    public Object test(Environment e) {
        System.out.println(e.getProperty("test"));
        return new Object();
    }


    public static void main(String[] args) {
        SpringApplication.run(SpringBootTest.class);
    }

    public static class JsonLoader implements PropertySourceFactory {

        @Override
        public org.springframework.core.env.PropertySource<?> createPropertySource(String name,
                EncodedResource resource) throws IOException {
            Map readValue = new ObjectMapper().readValue(resource.getInputStream(), Map.class);
            return new MapPropertySource("json-source", readValue);
        }

    }
}

Define your own PropertySourceFactory and hook it in via the @PropertySource annotation. Read the resource, set the properties, use them anywhere.

Only thing is, how do you translate nested properties. The Spring way to do that (by the way you can define Json also as a variable for properties, see: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html) is to translate nested properties as such:

{"test": { "test2" : "x" } }

Becomes:

test.test2.x

Hope that helps,

Artur

pandaadb
  • 6,306
  • 2
  • 22
  • 41
2

The SPRING_APPLICATION_JSON properties can be supplied on the command line with an environment variable. For example, you could use the following line in a UN*X shell:

$ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar

In the preceding example, you end up with acme.name=test in the Spring Environment. You can also supply the JSON as spring.application.json in a System property, as shown in the following example:

$ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar

You can also supply the JSON by using a command line argument, as shown in the following example:

$ java -jar myapp.jar --spring.application.json='{"name":"test"}'

You can also supply the JSON as a JNDI variable, as follows:

java:comp/env/spring.application.json.

Reference documentation: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

Ashu
  • 2,066
  • 3
  • 19
  • 33
0

2 steps

public String asYaml(String jsonString) throws JsonProcessingException, IOException {
    // parse JSON
    JsonNode jsonNodeTree = new ObjectMapper().readTree(jsonString);
    // save it as YAML
    String jsonAsYaml = new YAMLMapper().writeValueAsString(jsonNodeTree);
    return jsonAsYaml;
}

Got from the post

and

public class YamlFileApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
  @Override
  public void initialize(ConfigurableApplicationContext applicationContext) {
    try {
        Resource resource = applicationContext.getResource("classpath:file.yml");
        YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader();
        PropertySource<?> yamlTestProperties = yamlTestProperties = sourceLoader.load("yamlTestProperties", resource, null);
        applicationContext.getEnvironment().getPropertySources().addFirst(yamlTestProperties);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
  }
}

Got from the post

So you can combine both. Load your json as resource and convert to yaml and then add to Environment all the found properties

StanislavL
  • 56,971
  • 9
  • 68
  • 98