Пользовательская десериализация типов Generi c в Jackson Kotlin / Java - PullRequest
5 голосов
/ 13 февраля 2020

С этой моделью данных ...

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

Я видел решение здесь и пробовал это, но точки останова в моем методе "десериализации", кажется, никогда не достигают.

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'

1 Ответ

0 голосов
/ 17 февраля 2020

Есть два способа справиться с этим.

  1. Было бы проще не использовать пользовательский сериализатор, а полагаться на значение по умолчанию Джексона Jdk8Module (см. здесь )

  2. Если вы хотите свой собственный десериализатор, вам нужно указать нулевой шаблон доступа, иначе десериализатор не будет вызываться для значений null:

Код для 2:

// In OptionalDeserializer

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