使用带有Jackson和Spring的ReferenceTypeDeserializer反序列化通用类型

时间:2019-03-14 15:29:27

标签: java json serialization kotlin jackson

我想我这里缺少明显的东西,但是我似乎无法使用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())
    }
}

我想念什么?另外,我在网上很难找到有关如何反序列化泛型类型的信息,因此,如果有人有指针如何为泛型类型编写自定义反序列化器,我将非常感激。

1 个答案:

答案 0 :(得分:0)

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

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()
}

这可以按预期工作,但是Jackson需要解析器中的上下文信息以使其起作用,即上述测试代码不起作用。但是,如果您明确指定要反序列化的DTO(如果它具有正确的类型注释),它将起作用。