-
Notifications
You must be signed in to change notification settings - Fork 41.5k
Description
This year I'm upgrading my application from Java 8 to OpenJDK 11.0.2 so that necessitated upgrading Spring Boot from v1.5.3 to 2.1.4. After I did that the POJO to store my YAML properties failed.
For convenience I had created a simple POJO to hold any key and value type, this allowed for complex YAML tag configurations without having to create a lot of specialized POJO classes.
public class GenericProperty <K,V> {
private K key;
private V value;
public GenericProperty() {
//Default
}
/**
* Creates an instance of SimpleProperty
* @param aKey Represents a property key
* @param aValue Represents a property value
*/
public GenericProperty(K aKey, V aValue) {
key = aKey;
value = aValue;
}
}
examples:
# Map<Integer, GenericProperty<Integer,String>>
pojo-map: {14: {key: 23, value: "hello"}, 98: {key: 85, value: "world"}}
# Maping with Boolean as Key, and Value is list of Objects
# Map<Boolean,List<GenericProperty<String,String>>>
pojo-map-list: {
true: [
{key: "hello", value: "hola"},
{key: "night", value: "nochas"}
],
false: [
{key: "blue", value: "azul"},
{key: "white", value: "blanco"}
]
}
In v1.5.3 this worked fine when the YAML was mapped to attributes on a POJO like this:
@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix="examples")//Root level within .yml config file
public class YamlPojo {
private Map<Integer,GenericProperty<Integer,String>> pojoMap;
/** Only with SpringBoot 1.5.x can reuse GenericProperty again */
private Map<Boolean,List<GenericProperty<String,String>>> pojoMapList;
public YamlPojo() {
//Default
}
}
# To String Output after YAML loaded and mapped to Object
YamlPojo[
Pojo Map:,
98=GenericProperty[Key=85,Value=world],
14=GenericProperty[Key=23,Value=hello],
Pojo Map2:,
false=[GenericProperty[Key=blue,Value=azul], GenericProperty[Key=white,Value=blanco]],
true=[GenericProperty[Key=hello,Value=hola], GenericProperty[Key=night,Value=nochas]]]
]
But when switching to v2.1.4 reusing the same GenericPropery.java
on a different attribute failed. I think that's because the library used a binder on the first attribute, pojoMap
, for <Integer,String>
and did not create another binder for <String,String>
on the second attribute, pojoMapList
.
Caused by: org.springframework.boot.context.properties.ConfigurationPropertiesBindException:
Error creating bean with name 'yamlPojo':
Could not bind properties to 'YamlPojo' :
prefix=examples, ignoreInvalidFields=false, ignoreUnknownFields=true;
nested exception is org.springframework.boot.context.properties.bind.BindException:
Failed to bind properties under
'examples.pojo-map-list[true][0].key' to java.lang.Integer
at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.bind(ConfigurationPropertiesBindingPostProcessor.java:110) ~[spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor.postProcessBeforeInitialization(ConfigurationPropertiesBindingPostProcessor.java:93) ~[spring-boot-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:414) ~[spring-beans-5.1.6.RELEASE.jar:5.1.6.RELEASE]
My only workaround is to create another Class to handle mapping the second attribute. I've attached a project (yaml-generics.zip) so you can test the scenario. My pom.xml
is using the latest code, so if you try both JUnit classes then the test case that tries to reuse GenericProperty.java
twice will fail. If you modify the pom.xml to revert to the older release, v1.5, then both JUnit cases work. Was that just a "happy accident" under v1.5 that using generics with a Collection was handled, or is this a bug with the latest version?