Reputation: 1997
I am using custom 'YamlPropertySourceFactory' to load yaml configuration in Spring boot. When configs are loaded as Map it loads wrong key-value pair value for below scenerio.
SpringBoot 'PropertySourceFactory' assumes value of keys'CORE_3_1' and 'CORE_31' OR 'CORE-3-1' and 'CORE-31'same.
Below is the sample code to replicate this issue.
Yaml Config - response-mapping.yaml
mappings:
response-code:
mappings:
CORE_3_1: "30"
CORE_31: "31"
CORE_32: "32"
OR
Yaml Config - response-mapping.yaml
mappings:
response-code:
mappings:
CORE-3-1: "30"
CORE-31: "31"
CORE-32: "32"
Custom YamlPropertySourceFactory
import java.util.Properties;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
public final class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertiesPropertySource createPropertySource(@SuppressWarnings("unused") final String name, final EncodedResource encodedResource) {
final YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(encodedResource.getResource());
final Properties properties = factory.getObject();
return new PropertiesPropertySource(encodedResource.getResource().getFilename(), properties);
}
}
Response Config Class
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* It is used to load response codes from YAML configuration.
*/
@Configuration
@ConfigurationProperties(prefix = "mappings.response-code")
@PropertySource(value = "classpath:response-mapping.yaml", factory = YamlPropertySourceFactory.class)
public class ResponseCode {
private Map<String, String> mappings;
public Map<String, String> getMappings() {
return this.mappings;
}
public String getMapping( final String errorCode) {
return this.mappings.get(errorCode);
}
public void setMappings(final Map<String, String> value) {
this.mappings = value;
}
@Override
public String toString() {
return "ResponseCode{" + "mappings=" + this.mappings + '}';
}
}
Simple Controller to test it. - http://localhost:8080/code
package de.fiserv.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@Autowired
private ResponseCode responseCode;
@GetMapping(value = "/code")
public ResponseEntity<String> code() {
return new ResponseEntity<>(this.responseCode.getMappings().toString(), HttpStatus.OK);
}
}
I have found the workaround by replacing '-' OR '_' with '.' in key and it works but it would break whole design of error code mapping.
Reference: https://www.baeldung.com/spring-yaml-propertysource
Upvotes: 1
Views: 1372
Reputation: 1997
Updated Yaml Config - response-mapping.yaml
mappings:
response-code:
mappings:
"[CORE_3_1]": "30"
CORE_31: "31"
Why this was happening?
Spring Boot uses some relaxed rules for binding Environment properties to @ConfigurationProperties beans, so there does not need to be an exact match between the Environment property name and the bean property name. Common examples where this is useful include dash-separated environment properties (for example, context-path binds to contextPath), and capitalized environment properties (for example, PORT binds to port).
Upvotes: 1