繁体   English   中英

如何在自定义解串器中使用 jackson ObjectMapper?

[英]How use jackson ObjectMapper inside custom deserializer?

我尝试编写自定义 jackson 解串器。 我想“查看”一个字段并对 class 执行自动反序列化,请参见下面的示例:

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

波霍斯:

public class MyFailure implements MyInterface {}

public class MySuccess implements MyInterface {}

@JsonDeserialize(using = MyDeserializer.class)
public interface MyInterface {}

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

直接的问题似乎是@JsonDeserialize(using=...)被用于MyInterface和MyInterface本身的实现:因此无限循环。

你可以解决这个问题,重写每个实现中的设置:

@JsonDeserialize(using=JsonDeserializer.None.class)
public static class MySuccess implements MyInterface {
}

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

mapper.registerModule(new SimpleModule() {{
    addDeserializer(MyInterface.class, new MyDeserializer());
}});

另外,您还可以考虑扩展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);
}

对这个自定义反序列化器有很多改进,特别是关于跟踪反序列化等的上下文,但是这应该提供你要求的功能。

这对我有用:

ctxt.readValue(node, MyFailure.class)

为了使用自己ObjectMapper自定义解串器里面,您可以使用杰克逊混合式注解 DefaultJsonDeserializer 接口 )从动态删除自定义解串器POJO类,避免StackOverflowError ,否则将被抛出的结果objectMapper.readValue(JsonParser, Class<T>)

public class MyDeserializer extends JsonDeserializer<MyInterface> {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    static {
        objectMapper.addMixIn(MySuccess.class, DefaultJsonDeserializer.class);
        objectMapper.addMixIn(MyFailure.class, DefaultJsonDeserializer.class);
    }

    @Override
    public MyInterface deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        if (jp.getCodec().<JsonNode>readTree(jp).has("custom_field")) {
            return objectMapper.readValue(jp, MyFailure.class);
        } else {
            return objectMapper.readValue(jp, MySuccess.class);
        }           
    }

    @JsonDeserialize
    private interface DefaultJsonDeserializer {
        // Reset default json deserializer
    }

}

我找到了在自定义反序列化中使用 object 映射器的解决方案

public class DummyDeserializer extends JsonDeserializer<Dummy> {

    @Override
    public Dummy deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        ObjectMapper om = new ObjectMapper();
        om.addMixIn(NexusAccount.class, DefaultJsonDeserializer.class);
        ObjectCodec oc = jsonParser.getCodec();
        JsonNode node = oc.readTree(jsonParser);
        String serviceType = node.path("serviceType").asText();
        switch (serviceType) {
            case "Dummy1":
                return om.treeToValue(node, Dumm1.class);
            case "Dummy2":
                return om.treeToValue(node, Dummy2.class);
            case "Dummy3":
                return om.treeToValue(node, Dummy3.class);
            default:
                throw new IllegalArgumentException("Unknown Dummy type");
        }
    }
 
    @JsonDeserialize
    private interface DefaultJsonDeserializer {
        // Reset default json deserializer
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM