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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32551983/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 20:22:58  来源:igfitidea点击:

How use Hymanson ObjectMapper inside custom deserializer?

javajsonHymansonjson-deserialization

提问by Cherry

I try to write custom Hymanson deserializer. I want "look" at one field and perform auto deserialization to class, see example below:

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

import com.fasterxml.Hymanson.core.JsonParser;
import com.fasterxml.Hymanson.core.JsonProcessingException;
import com.fasterxml.Hymanson.core.ObjectCodec;
import com.fasterxml.Hymanson.databind.DeserializationContext;
import com.fasterxml.Hymanson.databind.JsonDeserializer;
import com.fasterxml.Hymanson.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);
        }
    }
}

Pojos:

波霍斯:

public class MyFailure implements MyInterface {}

public class MySuccess implements MyInterface {}

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

And I got StackOverflowError. In understand that codec.treeToValuecall same deserializer. Is there a way to use codec.treeToValueor ObjectMapper.readValue(String,Class<T>)inside custome deseralizer?

我得到了StackOverflowError。在理解codec.treeToValue调用相同的解串器。有没有办法使用codec.treeToValueObjectMapper.readValue(String,Class<T>)在客户除盐器内使用?

回答by araqnid

The immediate problem seems to be that the @JsonDeserialize(using=...)is being picked up for your implementations of MyInterface as well as MyInterface itself: hence the endless loop.

眼前的问题似乎@JsonDeserialize(using=...)是正在为您的 MyInterface 实现以及 MyInterface 本身获取 :因此是无限循环。

You can fix this my overriding the setting in each implementation:

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

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

Or by using a module instead of an annotation to configure the deserialization (and removing the annotation from MyInterface):

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

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

On a side-note, you might also consider extending StdNodeBasedDeserializerto implement deserialization based on JsonNode. For example:

附带说明一下,您还可以考虑扩展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 HymansonType = ctxt.getTypeFactory().constructType(targetType);
    JsonDeserializer<?> deserializer = ctxt.findRootValueDeserializer(HymansonType);
    JsonParser nodeParser = root.traverse(ctxt.getParser().getCodec());
    nodeParser.nextToken();
    return (MyInterface) deserializer.deserialize(nodeParser, ctxt);
}

There are a bunch of improvements to make to this custom deserializer, especially regarding tracking the context of the deserialization etc., but this should provide the functionality you're asking for.

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

回答by lcnicolau

In order to use your own ObjectMapperinside a custom deserializer, you can use Hymanson Mix-in Annotations(theDefaultJsonDeserializerinterface) to dynamically remove the custom deserializer from the POJOclasses, avoiding the StackOverflowErrorthat would otherwise be thrown as a result of objectMapper.readValue(JsonParser, Class<T>).

为了使用自己ObjectMapper定制的解串器里面,您可以使用Hyman逊混合式注解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
    }

}

回答by Julio

This did the trick for me:

这对我有用:

ctxt.readValue(node, MyFailure.class)