How to use YamlPropertiesFactoryBean to load YAML files using Spring Framework 4.1?
Solution 1
With XML config I've been using this construct:
<context:annotation-config/>
<bean id="yamlProperties" class="org.springframework.beans.factory.config.YamlPropertiesFactoryBean">
<property name="resources" value="classpath:test.yml"/>
</bean>
<context:property-placeholder properties-ref="yamlProperties"/>
Of course you have to have the snakeyaml dependency on your runtime classpath.
I prefer XML config over the java config, but I recon it shouldn't be hard to convert it.
edit:
java config for completeness sake
@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
yaml.setResources(new ClassPathResource("default.yml"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
Solution 2
`
package com.yaml.yamlsample;
import com.yaml.yamlsample.config.factory.YamlPropertySourceFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;
@SpringBootApplication
@PropertySource(value = "classpath:My-Yaml-Example-File.yml", factory = YamlPropertySourceFactory.class)
public class YamlSampleApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(YamlSampleApplication.class, args);
}
@Value("${person.firstName}")
private String firstName;
@Override
public void run(String... args) throws Exception {
System.out.println("first Name :" + firstName);
}
}
package com.yaml.yamlsample.config.factory;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
import java.io.IOException;
import java.util.List;
public class YamlPropertySourceFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource createPropertySource(String name, EncodedResource resource) throws IOException {
if (resource == null) {
return super.createPropertySource(name, resource);
}
List<PropertySource<?>> propertySourceList = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource());
if (!propertySourceList.isEmpty()) {
return propertySourceList.iterator().next();
}
return super.createPropertySource(name, resource);
}
}
My-Yaml-Example-File.yml
person:
firstName: Mahmoud
middleName:Ahmed
Reference my example on github spring-boot-yaml-sample So you can load yaml files and inject values using @Value()
Solution 3
To read .yml file in Spring you can use next approach.
For example you have this .yml file:
section1:
key1: "value1"
key2: "value2"
section2:
key1: "value1"
key2: "value2"
Then define 2 Java POJOs:
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "section1")
public class MyCustomSection1 {
private String key1;
private String key2;
// define setters and getters.
}
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "section2")
public class MyCustomSection1 {
private String key1;
private String key2;
// define setters and getters.
}
Now you can autowire these beans in your component. For example:
@Component
public class MyPropertiesAggregator {
@Autowired
private MyCustomSection1 section;
}
In case you are using Spring Boot everything will be auto scaned and instantiated:
@SpringBootApplication
public class MainBootApplication {
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(MainBootApplication.class)
.bannerMode(OFF)
.run(args);
}
}
If you'are using JUnit there is a basic test setup for loading YAML file:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(MainBootApplication.class)
public class MyJUnitTests {
...
}
If you're using TestNG there is a sample of test configuration:
@SpringApplicationConfiguration(MainBootApplication.class)
public abstract class BaseITTest extends AbstractTestNGSpringContextTests {
....
}
Solution 4
I spend 5 to 6 hours in understanding why external configuration of yml/yaml file(not application.yml) are so different.I read various articles, stack overflow questions but didn't get correct answer.
I was stuck in between like I was able to use custom yml file value using YamlPropertySourceLoader but not able to use @Value because it is giving me error like Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'fullname.firstname' in value "${fullname.firstname}"
fullname is a property in yml.
Then I used "turtlesallthewaydown" given above solution, then at last I was able to use @Value without any issues for yaml files and I removed YamlPropertySourceLoader.
Now I understand the difference between YamlPropertySourceLoader and PropertySourcesPlaceholderConfigurer, a big thanks, however I have added these changes in my git repo.
Git Repo: https://github.com/Atishay007/spring-boot-with-restful-web-services
Class Name: SpringMicroservicesApplication.java
Solution 5
If one will seek how to load yaml file into Properties in Spring, then there is a solution:
public Properties loadYaml(String fileName){
// fileName for eg is "my-settings.yaml"
YamlPropertySourceLoader ypsl = new YamlPropertySourceLoader();
PropertySource ps = ypsl.load(fileName, new ClassPathResource(fileName)).get(0);
Properties props = new Properties();
props.putAll((Map)ps.getSource());
return props;
}
ktulinho
Software Engineer with 12 years of experience developing, deploying and maintaining client and server applications. Ability to design and develop applications using Object Oriented concepts, Software Engineering concepts and methodologies such as Scrum and Agile. Specialties: Java EE, Java SE, Maven, Git, SQL, IntelliJ, Databases and a bit of DevOps. Continuously improving skills and knowledge through courses, articles and technical conferences. Interested by: Serverless, Cloud and Server-Side Applications; Desktop and mobile application design, development, usability and improving user experience; New technologies such as IoT, Machine Learning, VR and video games!
Updated on July 09, 2022Comments
-
ktulinho almost 2 years
I have a spring application that is currently using *.properties files and I want to have it using YAML files instead.
I found the class YamlPropertiesFactoryBean that seems to be capable of doing what I need.
My problem is that I'm not sure how to use this class in my Spring application (which is using annotation based configuration). It seems I should configure it in the PropertySourcesPlaceholderConfigurer with the setBeanFactory method.
Previously I was loading property files using @PropertySource as follows:
@Configuration @PropertySource("classpath:/default.properties") public class PropertiesConfig { @Bean public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
How can I enable the YamlPropertiesFactoryBean in the PropertySourcesPlaceholderConfigurer so that I can load YAML files directly? Or is there another way of doing this?
Thanks.
My application is using annotation based config and I'm using Spring Framework 4.1.4. I found some information but it always pointed me to Spring Boot, like this one.
-
turtlesallthewaydown almost 9 yearsIf my comment answers your initial question, could you accept it? Or if there is anything else I can add, let me now.
-
ktulinho almost 9 years@turtlesallthewaydown Thanks for your answer and sorry for the delay in the response.
-
-
ktulinho almost 9 yearsThanks for your answer. How can I now inject a value from the
default.yml
into my Java class? So if my yml contains a propertyvalue: 60
, can I simple do this in my code:@Value("${value}") private String value;
? -
turtlesallthewaydown almost 9 yearsYou can use the properties loaded from the yaml file as you would use the regular .properties file. So in any Spring managed class you can indeed use your exact example of
@Value("${value}") private String value
, and it'll be injected. -
Timur Milovanov almost 8 yearsSorry, but your example relates to Spring Boot. The question is about plain Spring Framework 4.1
-
niaomingjian about 7 years@ayurchuk my file name is 'myconfig.yaml'. This method doesn't work. What should I do?
-
spandey about 6 yearshow to load multiple files?
-
turtlesallthewaydown about 6 yearssetResources() takes a varargs argument, so you can add multiple in the same call. Don't call the method multiple times with different arguments, since it overwrites the resources on each call.
-
Ahmed Kooli about 6 yearsWhere are you putting your yml file? How spring boot is loading it ? You should mention it some where ?
-
TheJeff about 6 yearsIs there a way to inject these properties into a <util:properties> tag? Currently I can only find examples with location. EG: <util:properties id="env" location="classpath:env_dev.properties"/>
-
turtlesallthewaydown almost 6 years@TheJeff the xsd schema only allows for a location attribute, which states:
The location of the properties file, as a Spring resource location: a URL, a "classpath:" pseudo URL, or a relative file path. Multiple locations may be specified, separated by commas.
. You can probably use the non shorthand notation to customise the configuration. -
Simon Logic about 5 yearsHow can I map yaml block to Map attribute via @Value annotation ?
-
prnjn over 4 yearswhat should i give the path if the file is located externally outside src/main/resources , say in external config folder?
-
turtlesallthewaydown over 4 years@prnjn You can use any of the following, depending on your preferred method: PathResource, FileSystemResource, or InputStreamResource.
-
prnjn over 4 years@turtlesallthewaydown i used FileSystemResource and it worked, But now i am facing issue that it is working fine in eclipse , but in intelijIdea i am getting exception java.io.FileNotFoundException: ./conf/myFile.yml
-
gorjanz about 4 yearsThe question is regarding core spring application, and this answer is relying on spring boot being used, hence the down-vote.