Spring @PropertySource using YAML

Spring Download allows us to replace our application.properties files with YAML equivalents. However, I seem to be trapped in my trials. If I annotate my TestConfiguration (simple Java configuration), it expects a properties file.

For example, this does not work: @PropertySource(value = "classpath:application-test.yml")

If I have this in my YAML file:

 db: url: jdbc:oracle:thin:@pathToMyDb username: someUser password: fakePassword 

And I would use these values โ€‹โ€‹something like this:

 @Value("${db.username}") String username 

However, in the end I get an error like this:

 Could not resolve placeholder 'db.username' in string value "${db.username}" 

How can I use the goodness of YAML in my tests?

+87
spring spring-boot
Jan 21 '14 at 23:50
source share
15 answers

Spring-boot has an assistant for this, just add

 @ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class) 

at the top of your test classes or abstract test superclass.

Edit: I wrote this answer five years ago. It does not work with the latest versions of Spring Boot. This is what I am doing now (please translate Kotlin to Java, if necessary):

 @TestPropertySource(locations=["classpath:application.yml"]) @ContextConfiguration( initializers=[ConfigFileApplicationContextInitializer::class] ) 

added on top then

  @Configuration open class TestConfig { @Bean open fun propertiesResolver(): PropertySourcesPlaceholderConfigurer { return PropertySourcesPlaceholderConfigurer() } } 

to context.

+43
Nov 10 '14 at 9:29
source share

As already mentioned, @PropertySource does not load the yaml file. As a workaround, upload the file yourself and add the loaded properties to the Environment .

Running ApplicationContextInitializer :

 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 = sourceLoader.load("yamlTestProperties", resource, null); applicationContext.getEnvironment().getPropertySources().addFirst(yamlTestProperties); } catch (IOException e) { throw new RuntimeException(e); } } } 

Add your initializer to your test:

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = Application.class, initializers = YamlFileApplicationContextInitializer.class) public class SimpleTest { @Test public test(){ // test your properties } } 
+51
May 20 '16 at 14:34
source share

@PropertySource only supports property files (this is a limitation from Spring, not the download itself). Feel free to open a ticket function in JIRA .

+26
Jan 22 '14 at 7:35
source share

@PropertySource can be configured using the factory argument. So you can do something like:

 @PropertySource(value = "classpath:application-test.yml", factory = YamlPropertyLoaderFactory.class) 

Where YamlPropertyLoaderFactory is your custom property loader:

 public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { if (resource == null){ return super.createPropertySource(name, resource); } return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource(), null); } } 

Inspired by https://stackoverflow.com>

+20
Jul 18 '18 at 2:28
source share

From Spring Download 1.4, you can use the new @SpringBootTest annotation to make this easier (and simplify the installation of integration as a whole) by loading your integration tests using Spring Boot Support.

Details in the Spring Blog .

As far as I can tell, this means that you get all the benefits of Spring Boot configuration appearance , as in your production code, including automatically selecting the YAML configuration from the class path.

By default, this annotation will be

... first try loading @Configuration from any inner classes, and if that doesn't work, it will look for your main @SpringBootApplication class.

but if necessary, you can specify other configuration classes.

In this particular case, you can combine @SpringBootTest with @ActiveProfiles( "test" ) , and Spring will get your YAML configuration provided that it complies with the usual loading naming standards (i.e. application-test.yml ).

 @RunWith( SpringRunner.class ) @SpringBootTest @ActiveProfiles( "test" ) public class SpringBootITest { @Value("${db.username}") private String username; @Autowired private MyBean myBean; ... } 

Note: SpringRunner.class is the new name for SpringJUnit4ClassRunner.class

+18
Jan 08 '17 at 17:39 on
source share

Another option is to set spring.config.location via @TestPropertySource :

 @TestPropertySource(properties = { "spring.config.location = classpath:<path-to-your-yml-file>" } 
+13
Sep 26 '16 at 18:42
source share

The approach to loading yaml, IMHO properties can be done in two ways:

but. You can put the configuration in the standard location - application.yml in the root directory of the path - usually src/main/resources , and this yaml property should automatically load when you boot Spring with the name of the smoothed path you specified.

b. The second approach is a bit more extensive, basically defining a class for storing your properties as follows:

 @ConfigurationProperties(path="classpath:/appprops.yml", name="db") public class DbProperties { private String url; private String username; private String password; ... } 

Essentially, this suggests that it loads the yaml file and populates the DbProperties class based on the root db element.

Now, to use it in any class, you will need to do this:

 @EnableConfigurationProperties(DbProperties.class) public class PropertiesUsingService { @Autowired private DbProperties dbProperties; } 

Any of these approaches should work for you using Spring-boot.

+10
Jan 22 '14 at 1:36 on
source share

I found a workaround using @ActiveProfiles("test") and adding the application-test.yml file to src / test / resources.

It ended up like this:

 @SpringApplicationConfiguration(classes = Application.class, initializers = ConfigFileApplicationContextInitializer.class) @ActiveProfiles("test") public abstract class AbstractIntegrationTest extends AbstractTransactionalJUnit4SpringContextTests { } 

The application-test.yml file simply contains the properties that I want to override from application.yml (which can be found in src / main / resources).

+3
Jul 16 '15 at 15:58
source share

in the test block, @value has some problems for the call property from the properties file, so you can use the environment to replace the value

 @Autowired private Environment environment; public void init(){ String username=environment.getRequiredProperty("db.username"); } 

so that you can call the property now in both the production and the test block

+1
Apr 03 '16 at 7:34
source share

because you did not configure snakeyml. spring boot comes with the @EnableAutoConfiguration function. There is also snakeyml config when you invoke this annotation.

this is my way:

 @Configuration @EnableAutoConfiguration public class AppContextTest { } 

here is my test:

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration( classes = { AppContextTest.class, JaxbConfiguration.class, } ) public class JaxbTest { //tests are ommited } 
0
Mar 12 '15 at 7:33
source share

I needed to read some properties in my code, and this works with spring-boot 1.3.0.RELEASE

 @Autowired private ConfigurableListableBeanFactory beanFactory; // access a properties.yml file like properties @Bean public PropertySource properties() { PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer(); YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean(); yaml.setResources(new ClassPathResource("properties.yml")); propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject()); // properties need to be processed by beanfactory to be accessible after propertySourcesPlaceholderConfigurer.postProcessBeanFactory(beanFactory); return propertySourcesPlaceholderConfigurer.getAppliedPropertySources().get(PropertySourcesPlaceholderConfigurer.LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME); } 
0
Dec 10 '15 at 18:56
source share

Upload a custom yml file with multiple profile configurations in Spring Upload.

1) Add a bean property with running SpringBootApplication as follows

 @SpringBootApplication @ComponentScan({"com.example.as.*"}) public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } @Bean @Profile("dev") public PropertySourcesPlaceholderConfigurer propertiesStage() { return properties("dev"); } @Bean @Profile("stage") public PropertySourcesPlaceholderConfigurer propertiesDev() { return properties("stage"); } @Bean @Profile("default") public PropertySourcesPlaceholderConfigurer propertiesDefault() { return properties("default"); } /** * Update custom specific yml file with profile configuration. * @param profile * @return */ public static PropertySourcesPlaceholderConfigurer properties(String profile) { PropertySourcesPlaceholderConfigurer propertyConfig = null; YamlPropertiesFactoryBean yaml = null; propertyConfig = new PropertySourcesPlaceholderConfigurer(); yaml = new YamlPropertiesFactoryBean(); yaml.setDocumentMatchers(new SpringProfileDocumentMatcher(profile));// load profile filter. yaml.setResources(new ClassPathResource("env_config/test-service-config.yml")); propertyConfig.setProperties(yaml.getObject()); return propertyConfig; } } 

2) Configure the Java pojo object as follows

 @Component @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(Include.NON_NULL) @ConfigurationProperties(prefix = "test-service") public class TestConfig { @JsonProperty("id") private String id; @JsonProperty("name") private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 

3) Create a custom yml (and put it in the resource path as follows: YML File name: test-service-config.yml

For example, Config in the yml file.

 test-service: id: default_id name: Default application config --- spring: profiles: dev test-service: id: dev_id name: dev application config --- spring: profiles: stage test-service: id: stage_id name: stage application config 
0
Sep 19 '17 at 21:56 on
source share

Strengthening the response of Mateusz Balbus .

A modified class is YamlFileApplicationContextInitializer wherein the YAML location is determined for each test class. Unfortunately, this does not work on the test.

 public abstract class YamlFileApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { /*** * Return location of a YAML file, eg: classpath:file.yml * * @return YAML file location */ protected abstract String getResourceLocation(); @Override public void initialize(ConfigurableApplicationContext applicationContext) { try { Resource resource = applicationContext.getResource(getResourceLocation()); YamlPropertySourceLoader sourceLoader = new YamlPropertySourceLoader(); PropertySource<?> yamlTestProperties = sourceLoader.load("yamlTestProperties", resource, null); applicationContext.getEnvironment().getPropertySources().addFirst(yamlTestProperties); } catch (IOException e) { throw new RuntimeException(e); } } } 

Using:

Subclass YamlFileApplicationContextInitializer with the defined getResourceLocation() and add this subclass to the @SpringApplicationConfiguration annotation.

I think it is easiest for the test class itself to make this specific subclass, as in the following example.

 @RunWith(SpringRunner.class) @SpringApplicationConfiguration(classes = Application.class, initializers = SimpleTest.class) public class SimpleTest extends YamlFileApplicationContextInitializer { @Override protected String getResourceLocation() { return "classpath:test_specific.yml"; } @Test public test(){ // test your properties } } 
0
Apr 08 '18 at 9:19
source share

You can configure @PropertySource to load YAML files, the @PropertySource class in the factory attribute. I have implemented a version that can also take into account the active profiles of your deployment :).

https://medium.com/@james.tran/how-to-read-profile-based-yaml-configurations-with-propertysource-8131c16b3fc6

0
May 09 '19 at 10:25
source share



no need to add, for example, YamlPropertyLoaderFactory or YamlFileApplicationContextInitializer. You have to transform your idea. just like a common spring project. You know, not using Java configuration.

just * .xml




complete this step:

Just add applicationContext.xml as




 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-autowire="byName"> <context:property-placeholder location="classpath*:*.yml"/> </beans> 



then add

 @ImportResource({"classpath:application*.xml"}) 

to your ApplicationMainClass

Everything works well!

-one
Jan 18 '19 at 2:31
source share



All Articles