Reputation: 759
I have a spring boot application where properties have to be read from a yaml file.
code:
@Component
@PropertySource("classpath:application.yml")
public class ResourceProvider {
@Autowired
private Environment env;
public String getValue(String key) {
return env.getProperty("app.max.size");
}
}
yaml file
app:
max:
size: 10
When I try this it doesn't work. I get value for app.max.size
as null. For size
I get the value as 10.
When I use application.properties. I am able to get the desired result. Am I doing anything incorrectly?
application.properties
app.max.size=10
Upvotes: 7
Views: 65450
Reputation: 11
You can't load yaml files using @ProperySource
annotation. One thing, I found out was you can use the property spring.config.location
where you can define comma separated yaml files location. I have attached the snippet below:
@Data
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "public.config.app", ignoreUnknownFields = false)
@Slf4j
public class AppServiceConfiguration {
private Map<String, Object> ios;
private Map<String, Object> android;
private Map<String, Object> buildNumberForIOS;
private Map<String, Object> buildNumberForAndroid;
@PostConstruct
public void checkIfYamlIsLoaded() {
log.debug("APP YAML configuration loaded successfully!");
}
}
This is how i have defined this property in application.properties:
spring.config.location=src/main/resources/app-application.yaml, src/main/resources/web-application.yaml
Here is my sample yaml file:
public:
config:
app:
ios:
enableMyContent: true
warnUserOnMultipleShippingMethods: true
enableShowScanToOrder: false
android:
enableMyContent: true
warnUserOnMultipleShippingMethods: true
enableShowScanToOrder: false
buildNumberForIOS:
'951': enableCurbsidePickup
buildNumberForAndroid:
'585': enableCurbsidePickup
'595': enableImpulseUpsellOnPDP|enableQuantityLimiter
Upvotes: 1
Reputation: 14819
from the documentation:
YAML files cannot be loaded by using the @PropertySource annotation. So, in the case that you need to load values that way, you need to use a properties file.
Official spring boot documentation reference
Upvotes: 1
Reputation: 1490
Since you'r using application.yml
file, you don't need to manually load the file to the context as it's the default config file for spring
application. You can simply use them in a @Component
decorated class like below;
@Value("${app.max.size}")
private int size;
If you're laoding custom YAML
file, then this is a huge problem in Spring yet. Using @PropertySource
you can't load YAML files simply. It's possible, but little work required. First you need a custom property source factory. In your case, custom YAML property source factory.
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Objects;
import java.util.Properties;
public class YamlPropertySourceFactory implements PropertySourceFactory {
/**
* Create a {@link PropertySource} that wraps the given resource.
*
* @param name the name of the property source
* @param resource the resource (potentially encoded) to wrap
* @return the new {@link PropertySource} (never {@code null})
* @throws IOException if resource resolution failed
*/
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource)
throws IOException {
Properties properties = load(resource);
return new PropertiesPropertySource(name != null ? name :
Objects.requireNonNull(resource.getResource().getFilename(), "Some error message"),
properties);
}
/**
* Load properties from the YAML file.
*
* @param resource Instance of {@link EncodedResource}
* @return instance of properties
*/
private Properties load(EncodedResource resource) throws FileNotFoundException {
try {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return factory.getObject();
} catch (IllegalStateException ex) {
/*
* Ignore resource not found.
*/
Throwable cause = ex.getCause();
if (cause instanceof FileNotFoundException) throw (FileNotFoundException) cause;
throw ex;
}
}
}
And, you need to tell @PropertySource
annotation use this factory instead of default one whenever you use it like below;
@Component
@PropertySource(value = "classpath:config-prop.yml", factory = YamlPropertySourceFactory.class) // Note the file name with the extension unlike a property file. Also, it's not the `application.yml` file.
public class ResourceProvider {
@Value("${app.max.size}")
private int size;
}
You can use your properties shown in above code snippet's size
variable.
Though. If you're using a YAML array declaration to get properties, that would be little peculiar even if you use this way.
Upvotes: 12
Reputation: 602
You can read the value by:
@Value("${app.max.size}")
private String size;
public String getValue(String key) {
return size;
}
Upvotes: -2