如何在自定义反序列化器中使用jackson ObjectMapper?

Che*_*rry 15 java json jackson json-deserialization

我尝试编写自定义jackson反序列化器.我希望"查看"一个字段并对类执行自动反序列化,请参阅下面的示例:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.mypackage.MyInterface;
import com.mypackage.MyFailure;
import com.mypackage.MySuccess;

import java.io.IOException;

public class MyDeserializer extends JsonDeserializer<MyInterface> {

    @Override
    public MyInterface deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        ObjectCodec codec = jp.getCodec();
        JsonNode node = codec.readTree(jp);
        if (node.has("custom_field")) {
            return codec.treeToValue(node, MyFailure.class);
        } else {
            return codec.treeToValue(node, MySuccess.class);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

的POJO:

public class MyFailure implements MyInterface {}

public class MySuccess implements MyInterface {}

@JsonDeserialize(using = MyDeserializer.class)
public interface MyInterface {}
Run Code Online (Sandbox Code Playgroud)

我得到了StackOverflowError.在了解codec.treeToValue调用相同的反序列化器.有没有办法使用codec.treeToValueObjectMapper.readValue(String,Class<T>)内部客户deseralizer?

ara*_*nid 8

眼前的问题似乎@JsonDeserialize(using=...)是您的MyInterface以及MyInterface本身的实现都在使用;因此循环不断。

您可以通过在每个实现中覆盖的设置来解决此问题:

@JsonDeserialize(using=JsonDeserializer.None.class)
public static class MySuccess implements MyInterface {
}
Run Code Online (Sandbox Code Playgroud)

或通过使用模块而不是注释来配置反序列化(并从MyInterface中删除注释):

mapper.registerModule(new SimpleModule() {{
    addDeserializer(MyInterface.class, new MyDeserializer());
}});
Run Code Online (Sandbox Code Playgroud)

在旁注中,您可能还考虑扩展StdNodeBasedDeserializer以基于JsonNode实现反序列化。例如:

@Override
public MyInterface convert(JsonNode root, DeserializationContext ctxt) throws IOException {
    java.lang.reflect.Type targetType;
    if (root.has("custom_field")) {
        targetType = MyFailure.class;
    } else {
        targetType = MySuccess.class;
    }
    JavaType jacksonType = ctxt.getTypeFactory().constructType(targetType);
    JsonDeserializer<?> deserializer = ctxt.findRootValueDeserializer(jacksonType);
    JsonParser nodeParser = root.traverse(ctxt.getParser().getCodec());
    nodeParser.nextToken();
    return (MyInterface) deserializer.deserialize(nodeParser, ctxt);
}
Run Code Online (Sandbox Code Playgroud)

此自定义反序列化器有很多改进,特别是在跟踪反序列化的上下文等方面,但这应该提供您所要求的功能。