如何解决Jackson将字符串映射解析为已声明的类,作为字符串映射与映射如何使它创建声明的类的对象?
我正在使用jackson-module-kotlin:2.11.2解析一些YAML。我试图产生包含映射的对象,其值是我声明的类的对象。相反,此地图包含的值是HashMaps。
这是我的声明:
import com.fasterxml.jackson.module.kotlin.readValue
object Parser {
// ObjectMapper is thread safe as long as we don't mess with the config after this declaration.
val mapper: ObjectMapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
.registerModule(JavaTimeModule())
.registerModule(nullMapDeserialiserModule)
.registerModule(SimpleModule().setDeserializerModifier(ValidatingDeserializerModifier()))
// When parsing timestamps,we don't want to lose the offset information
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
// We would prefer an error if we're trying to store a float in an int
.disable(DeserializationFeature.ACCEPT_FLOAT_AS_INT)
// If a primitive field (like Int) is non-nullable (as in the Kotlin meaning),then we don't want nulls being converted to 0
.enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
// Because enums could change order in future versions (if we keep them in lexicographic order,for example),// we don't want the client to expect that they can give us the ordinal value of the enum.
.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)
// When serialising schedule expressions,don't include null values
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
@Throws(JsonProcessingException::class)
inline fun <reified T: Any> deserialise(yaml: String): T = mapper.readValue(yaml)
}
data class ListValue (
val listValueKey: String,val someOtherValue: Int
)
data class ExpectedValue (
val expectedValueKey: String,val list: List<ListValue>
)
data class TestClass (
val testClassKey: String,@param:JsonDeserialize(contentAs = ExpectedValue::class)
val testMap: Map<String,ExpectedValue>
)
这是我的测试用例:
@Test
fun `map parse test`() {
val testObj: TestClass? = RuleParser.deserialise(
//language=YAML
"""
testClassKey: the-key
testMap:
key1:
expectedValueKey: subKey1
list:
- listValueKey: someKey1
someOtherValue: 5
- listValueKey: anotherKey1
someOtherValue: 6
key2:
expectedValueKey: subKey2
list:
- listValueKey: someKey2
someOtherValue: 7
- listValueKey: anotherKey2
someOtherValue: 8
"""
)
assertTrue(testObj is TestClass)
assert(testObj.testMap is HashMap)
assertNotNull(testObj.testMap["key1"])
assert(testObj.testMap["key1"] is ExpectedValue)
assertEquals(
ExpectedValue(
expectedValueKey = "subKey1",list = listOf(ListValue("someKey1",5),ListValue("anotherKey1",6))
),testObj.testMap["key1"]
)
}
当前,该测试在最终断言上失败,并出现以下错误
Expected :ExpectedValue(expectedValueKey=subKey1,list=[ListValue(listValueKey=someKey1,someOtherValue=5),ListValue(listValueKey=anotherKey1,someOtherValue=6)])
Actual :{expectedValueKey=subKey1,list=[{listValueKey=someKey1,someOtherValue=5},{listValueKey=anotherKey1,someOtherValue=6}]}
这显然不是我所期望的。如果我改为解析一个声明的类的列表,则此方法可以正常工作(示例测试如下)。
@Test
fun `list parse test`() {
val testObj: ExpectedValue? = RuleParser.deserialise(
//language=YAML
"""
expectedValueKey: subKey1
list:
- listValueKey: someKey1
someOtherValue: 5
- listValueKey: anotherKey1
someOtherValue: 6
"""
)
assertTrue(testObj is ExpectedValue)
assertTrue(testObj.list[0] is ListValue)
assertEquals(
ListValue("someKey1",testObj.list[0]
)
}
因此,我有可能以这种方式解析通用列表,但无法解析地图,对此我感到有些惊讶。如何让Jackson创建我期望的地图值而不是HashMaps?
解决方法
您的解串器功能错误。您必须在readValue
方法中使用经过修饰的通用类型:
inline fun <reified T: Any> deserialise(yaml: String): T = mapper.readValue(yaml,T::class.java)
,
虽然根本不需要注释是很奇怪的(因为声明类型的列表不需要注释),但是按如下方式使用注释也可以工作:
@field:JsonDeserialize(`as` = HashMap::class,contentAs = ExpectedValue::class)
一开始并不清楚,因为contentAs
的javadoc没有提到as
也是必需的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。