我正在使用 Jackson with Kotlin序列化和反序列化各种 Kotlin 数据类
es。
我的 data class
es 是非常简单的对象,可以使用标准的 Jackson ObjectMapper
轻松序列化和反序列化,except 我想确保一些后验证作为反序列化的一部分完成。例如,我想确保 Thing.someField >= 0
:
data class InnerThing(
val foo: String
);
data class Thing(
val someField: Int, // must not be negative
val innerThing: InnerThing
);
实现这一点的最简单方法似乎是覆盖相关类的 StdDeserializer
。
class ThingDeserializer : StdDeserializer<Thing>(Thing::class.java) {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Thing {
// Defer to the superclass to do the actual deserialization
// DOES NOT WORK because StdDeserializer.deserialize() is abstract
val t: Thing = super.deserialize(p, ctxt);
if (thing.someField < 0) {
throw RuntimeException("someField value must be >= 0");
}
return t;
}
}
... 但是那不起作用 因为StdDeserializer.deserialize()
是抽象的。这导致我 this related question .从自定义反序列化器中推迟到默认反序列化行为似乎非常困难。
据我所知,推迟默认反序列化行为的最直接方法是创建一个完全单独的ObjectMapper
(!!!),使用那个阅读类(class),然后进行后期验证。
把我带到这个……
class ThingDeserializer : StdDeserializer<Thing>(Thing::class.java) {
// Create a whole separate ObjectMapper that doesn't override
// the deserializer for Thing:
private val defaultMapper = jacksonObjectMapper();
init {
// Need to reregister modules for things like ISO8601
// timestamp parsing:
defaultMapper.registerModule(JavaTimeModule());
}
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Thing {
// Use the non-overridden ObjectMapper to deserialize the object:
val t: Thing = defaultMapper.readValue(p, Thing::class.java);
// ... and then do validation afterwards
if (thing.someField < 0) {
throw RuntimeException("someField value must be >= 0");
}
return t;
}
}
fun main(args: Array<String>) {
val mapper = jacksonObjectMapper();
mapper.registerModule(JavaTimeModule());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.registerModule(
SimpleModule().apply {
addDeserializer(Thing::class.java, ThingDeserializer())
}
);
val test: Thing = mapper.readValue("""{
"someField": -1,
"innerThing": { "foo": "bar" }
}""");
}
这确实有效;它为测试用例中不需要的 someField
值抛出 RuntimeException
。
这似乎是错误的
以上真的是进行此验证的合理方法吗?
它有一种非常糟糕的代码味道。我正在创建一个全新的 ObjectMapper
,我必须重新注册模块以进行时间戳反序列化。
问题
感觉必须一种更明智、更少冗余的方法来反序列化 Kotlin 数据类
(或 Java POJO),然后对对象,而无需完全重写反序列化机制。
有吗?我想不出一种简单的方法来从反序列化器中推迟 ObjectMapper
的默认反序列化行为。
最佳答案
已请求用于做事验证的通用工具:
https://github.com/FasterXML/jackson-databind/issues/2045
虽然还没有实现。据推测,这将不仅限于基于注释,而且将允许可插入的后处理(加上无论如何都可以通过子类化 AnnotationIntrospector
来“伪造”注释)。
除此之外(尚不可用),如果您可以通过它传递所有属性(构造函数或工厂方法),对于 POJO 使用 @JsonCreator
效果很好。但对于验证第 3 方类型来说不是很好。
关于json - jackson :反序列化后如何进行验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64760102/