【发布时间】:2020-08-31 00:06:26
【问题描述】:
我正在使用 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", 5),
testObj.list[0]
)
}
所以我有点惊讶可以以这种方式解析通用列表,但不能解析地图。如何让 Jackson 创建我期望的地图值,而不是 HashMaps?
【问题讨论】:
标签: kotlin jackson jackson-databind