【问题标题】:Deserialize Generic Type using ReferenceTypeDeserializer with Jackson & Spring使用带有 Jackson 和 Spring 的 ReferenceTypeDeserializer 反序列化通用类型
【发布时间】:2019-08-05 13:49:01
【问题描述】:

我认为我在这里遗漏了一些明显的东西,但我似乎无法使用 Spring/Kotlin/Jackson 反序列化一个简单的通用容器。

有问题的数据类型很简单:

@JsonDeserialize(using = PatchableDeserializer::class)
sealed class Patchable<T> {
    class Undefined<T>: Patchable<T>()
    class Null<T>: Patchable<T>()
    data class Present<T>(val content: T): Patchable<T>()
    // …
}

解串器扩展 ReferenceTypeDeserializer,就像 jdk8 模块的 OptionalDeserializer

class PatchableDeserializer(javaType: JavaType, vi: ValueInstantiator, typeDeser: TypeDeserializer, deser: JsonDeserializer<*> ):
        ReferenceTypeDeserializer<Patchable<*>>(javaType, vi, typeDeser, deser) {
    // …
}

我假设 Jackson 会在此处填写 PatchableDeserializer 的构造函数参数。但是,情况似乎并非如此:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'my.namespace.PatchableDeserializer': Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.fasterxml.jackson.databind.JavaType' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

我会假设 Jackson 提供了 javaType 的值,因为我无法在编译时知道它。

这是我用来测试的代码,它会生成上述异常:

@RunWith(SpringRunner::class)
@JsonTest
class PatchableTest {
    @Autowired
    lateinit var objectMapper: ObjectMapper

    @Test
    fun patchableDeserialisesStringValue() {
        val value: Patchable<String> = objectMapper.readValue("\"null\"", object: TypeReference<Patchable<String>>() {})
        assertTrue(value.isPresent())
        assertEquals("null", value.unsafeGetValue())
    }
}

我错过了什么?另外,我很难在网上寻找一些关于如何反序列化泛型类型的信息,所以如果有人能指出如何为泛型类型编写自定义反序列化器,我将不胜感激。

【问题讨论】:

    标签: java json serialization kotlin jackson


    【解决方案1】:

    我最终为我的反序列化器实现了一个不同的接口。

    class PatchableDeserializer(private val valueType: Class<*>?): JsonDeserializer<Patchable<*>>(), ContextualDeserializer {
        override fun createContextual(ctxt: DeserializationContext?, property: BeanProperty?): JsonDeserializer<*> {
            val wrapperType = property?.type
    
            val rawClass = wrapperType?.containedType(0)?.rawClass
            return PatchableDeserializer(rawClass)
        }
    
        override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Patchable<*> =
            Patchable.of(p!!.readValueAs(valueType))
    
        override fun getNullValue(ctxt: DeserializationContext?): Patchable<Any> =
                if (ctxt?.parser?.currentToken == JsonToken.VALUE_NULL)
                    Patchable.ofNull()
                else
                    Patchable.undefined()
    }
    

    这按预期工作,但杰克逊需要解析器中的上下文信息才能使其工作,即上述测试代码不起作用。但是,如果您明确指定要反序列化到的 DTO,并且它具有正确的类型注释,它确实有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-01
      • 2012-10-18
      • 2012-07-24
      • 2018-06-15
      • 2014-03-11
      • 2012-07-24
      相关资源
      最近更新 更多