2
votes

Is it possible to leverage Spring-Boot's YAML configuration outside a spring-boot application? i.e Can we use just the YAML config feature adding the spring-boot dependency?

My usecase is a small utility project which needs configuration and YAML approach is apt. If I wire this to the master project (which is a Spring-Boot app), all is fine. But if I want to test this utility project separately (simple java-app) it doesn't get the configuration wired. Any thoughts? may be I'm missing something basic here.

Sample code snippet below. The below package is part of the component-scan.

@Component
@ConfigurationProperties(prefix="my.profile")
public class TestConfig {

    private List<String> items;

    public List<String> getItems() {
        return items;
    }

    public void setItems(List<String> items) {
        this.items = items;
    }
}

YAML Config

my:
    profile:
        items:
            - item1
            - item2
1
Yaml and @ConfigurationProperties are 2 separate things. Yaml support is available in Spring itself, @ConfigurationProperties is a feature of spring boot.M. Deinum
However the same code which works when run as a Spring-Boot application doesn't read the yaml config when run as non-Spring Boot application. Any thoughts?Jebuselwyn Martin
I said that yaml support is available, I didn't say it is available out-of-the-box. You would have to explicitly add the YamlPropertiesFactoryBean to have a yaml file read and to be available as properties. It is also available as of Spring 4.1 so it wouldn't work on earlier versions.M. Deinum
Thanks for the response.. May be I should have rephrased the question a bit.. In short, the out-of-box ability by spring-boot to read & bind yml is not available for non-spring-boot applications,.. I was wondering may be there is a way to just use this one feature without running this as a spring-boot application (reason - simple,, i like Spring-boot, but not always you have flexibility to migrate everything to it). And I already looked at the YamlPropertiesFactory, and what it provides is rather primitive and doesnt exactly match with that of spring-boot out of box ability.Jebuselwyn Martin
Then the answer is quite short and is no... You would have to use a part of spring boot and migrate that to non spring boot.M. Deinum

1 Answers

0
votes

The key is YamlPropertiesFactoryBean, as M. Deinum mentioned.

import org.springframework.beans.factory.config.YamlProcessor;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.core.io.ClassPathResource;

import java.util.Properties;

public class PropertyLoader {

    private static Properties properties;
    
    private PropertyLoader() {}

    public static Properties load(String... activeProfiles) {
        if (properties == null) {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(new ClassPathResource("application.yml"));
            factory.setDocumentMatchers((profile) -> YamlProcessor.MatchStatus.FOUND); // TODO filter on active profiles
            factory.afterPropertiesSet();
            
            properties = factory.getObject();
        }
        return properties;
    }

    public static <T> T value(String property, Class<T> target) {
        load();
        ConfigurationPropertySource propertySource = new MapConfigurationPropertySource(properties);
        Binder binder = new Binder(propertySource);
        return binder.bind(property.toLowerCase(), target).get();
    }
}

PropertyLoader#value can then be used like so:

List<String> items = PropertyLoader.value("my.profile.items", List.class);