【问题标题】:Custom Deserialization of Generic Types in Jackson Kotlin/JavaJackson Kotlin/Java 中泛型类型的自定义反序列化
【发布时间】:2020-05-28 14:07:05
【问题描述】:

有了这个数据模型...

TestClass.kt

data class TestClass (val bar: Optional<Double>?)

我的目标是反序列化以下 json 值:

{"foo": 3.5}  --> foo = 3.5
{"foo": null} --> foo = Optional.empty() // This is currently my problem. foo is null and I can't seem to fix it
{}            --> foo = null

我见过solution here 并尝试过这个,但我的“反序列化”方法中的断点似乎从未命中。

OptionalDeserializer.java

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import java.io.IOException;
import java.util.Optional;

public class OptionalDeserializer extends JsonDeserializer<Optional<?>> implements ContextualDeserializer {
    private JavaType valueType;

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext context, BeanProperty property) {
        this.valueType = property.getType().containedType(0);
        return this;
    }

    @Override
    public Optional<?> deserialize(final JsonParser parser, final DeserializationContext context) throws IOException {
        final JsonNode node = parser.getCodec().readTree(parser);

        return node.isNull()
                ? Optional.empty()
                : Optional.of(context.readValue(parser, valueType));
    }

}

TestDeserialization.kt

fun main(): {
    val objectMapper = ObjectMapper().registerModule(KotlinModule())

    val module = SimpleModule()
    module.addDeserializer(Optional::class.java, OptionalDeserializer())
    objectMapper.registerModule(module)

    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)

    objectMapper.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true)
    objectMapper.configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true)
    objectMapper.nodeFactory = JsonNodeFactory.withExactBigDecimals(true)

    val inputJson = """{"foo" : null}"""

    val expectedObject = TestClass(foo = Optional.empty())

    val actualObject = objectMapper.readValue(inputJson, TestClassBravo::class.java)

    assertEquals(expectedObject, actualObject)
}

build.gradle(用于版本信息)

compile 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
compile 'com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8'

【问题讨论】:

  • IMO,Optional&lt;Decimal&gt;? 是代码异味。考虑更改此类,问题可能会消失。
  • 糟糕。不小心把十进制留在了那里。我的最终目标是区分空属性和缺失属性,并最终准确地重新创建输入 json。因此,尽管看起来很“臭”,但这是我找到的唯一合理的解决方案。

标签: java json kotlin jackson optional


【解决方案1】:

有两种方法可以解决这个问题。

  1. 不使用自定义序列化程序会更容易,而是依赖杰克逊默认的Jdk8Module(参见here

  2. 如果您想要自定义反序列化器,则需要指定空访问模式,否则将不会为 null 值调用反序列化器:

2 的代码:

// In OptionalDeserializer

@Override
public AccessPattern getNullAccessPattern() {
    return AccessPattern.CONSTANT;
}

【讨论】:

  • 我尝试了两种解决方案。不幸的是,Jdk8Module 不适用于 Kotlin 数据类。我尝试了添加和不添加 KotlinModule。非常适合 Java 类,但我有一个包含大约 50 个类的域模型,我想利用 Kotlin 的数据类特性。至于选项 2,我试过了,但我的重写方法 getNullAccessPattern 甚至从未被调用过。
猜你喜欢
  • 1970-01-01
  • 2019-04-29
  • 2012-10-18
  • 2016-07-09
  • 2012-07-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多