Search code examples
springspring-bootsnakeyaml

spring-boot yaml configuration standalone


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

Solution

  • 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);