prefix: stringProp1: propValue1 stringProp2: propValue2 intProp1: 10 listProp: - listValue1 - listValue2 mapProp: key1: mapValue1 key2: mapValue2
These entries can also be described in a traditional application.properties file the following way:
prefix.stringProp1=propValue1 prefix.stringProp2=propValue2 prefix.intProp1=10 prefix.listProp[0]=listValue1 prefix.listProp[1]=listValue2 prefix.mapProp.key1=mapValue1 prefix.mapProp.key2=mapValue2
It has taken me a little while, but I do like the hierarchical look of the properties described in a yaml format.
So now, given this property file a traditional Spring application would have loaded up the properties the following way:
public class SamplePropertyLoadingTest { @Value("${prefix.stringProp1}") private String stringProp1;
Note the placeholder for "prefix.stringProp" key.
This however is not ideal for loading a family of related properties, say in this specific case namespaced by the prefix conveniently named "prefix".
The approach Spring boot takes is to define a bean that can hold all the family of related properties this way:
@ConfigurationProperties(prefix = "prefix") @Component public class SampleProperty { private String stringProp1; private String stringProp2; @Max(99) @Min(0) private Integer intProp1; private List<String> listProp; private Map<String, String> mapProp; ... }
At runtime, all the fields would be bound to the related properties cleanly.
Additionally note the JSR-303 annotations on top of the "intProp1" field that validates that value of the field is between 0 and 99, @ConfigurationProperties will call the validator to ensure that bound bean is validated.
An integration test making use of this is the following:
package prop; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SampleWebApplication.class) public class SamplePropertyLoadingTest { @Autowired private SampleProperty sampleProperty; @Value("${prefix.stringProp1}") private String stringProp1; @Test public void testLoadingOfProperties() { System.out.println("stringProp1 = " + stringProp1); assertThat(sampleProperty.getStringProp1(), equalTo("propValue1")); assertThat(sampleProperty.getStringProp2(), equalTo("propValue2")); assertThat(sampleProperty.getIntProp1(), equalTo(10)); assertThat(sampleProperty.getListProp(), hasItems("listValue1", "listValue2")); assertThat(sampleProperty.getMapProp(), allOf(hasEntry("key1", "mapValue1"), hasEntry("key2", "mapValue2"))); } }
If you are interested in exploring this sample further, I have a github repo with the code checked in here.