繁体   English   中英

Jackson 2.2.x:递归反序列化失败,为什么?

[英]Jackson 2.2.x: recursive deserialization fails, why?

确切地说,这是杰克逊2.2.3。

反序列化过程非常复杂,因为根据我反序列化的JSON值的类型,该类会更改:

  • 基本的抽象类是JsonMergePatch ;
  • 当JSON值不是JSON对象时,我反序列NonObjectMergePatch
  • 否则,我递归反序列化为ObjectMergePatch

这是代码(为简洁起见,省略了导入);首先,是JsonMergePatch

@JsonDeserialize(using = JsonMergePatchDeserializer.class)
public abstract class JsonMergePatch
    implements JsonSerializable
{
    public abstract JsonNode apply(final JsonNode input)
        throws JsonPatchException;
}

NonObjectMergePatch

final class NonObjectMergePatch
    extends JsonMergePatch
{
    private final JsonNode node;

    NonObjectMergePatch(@Nonnull final JsonNode node)
    {
        this.node = Preconditions.checkNotNull(node);
    }

    @Override
    public JsonNode apply(final JsonNode input)
        throws JsonPatchException
    {
        return null; // TODO!
    }

    @Override
    public void serialize(final JsonGenerator jgen,
        final SerializerProvider provider)
        throws IOException, JsonProcessingException
    {
        jgen.writeTree(node);
    }

    @Override
    public void serializeWithType(final JsonGenerator jgen,
        final SerializerProvider provider, final TypeSerializer typeSer)
        throws IOException, JsonProcessingException
    {
        serialize(jgen, provider);
    }
}

ObjectMergePatch

final class ObjectMergePatch
    extends JsonMergePatch
{
    private final Set<String> removedMembers;
    private final Map<String, JsonMergePatch> modifiedMembers;

    ObjectMergePatch(final Set<String> removedMembers,
        final Map<String, JsonMergePatch> modifiedMembers)
    {
        this.removedMembers = ImmutableSet.copyOf(removedMembers);
        this.modifiedMembers = ImmutableMap.copyOf(modifiedMembers);
    }

    @Override
    public JsonNode apply(final JsonNode input)
        throws JsonPatchException
    {
        return null;
    }

    @Override
    public void serialize(final JsonGenerator jgen,
        final SerializerProvider provider)
        throws IOException, JsonProcessingException
    {
        jgen.writeStartObject();

        /*
         * Write removed members as JSON nulls
         */
        for (final String member: removedMembers)
            jgen.writeNullField(member);

        /*
         * Write modified members; delegate to serialization for writing values
         */
        for (final Map.Entry<String, JsonMergePatch> entry:
            modifiedMembers.entrySet()) {
            jgen.writeFieldName(entry.getKey());
            entry.getValue().serialize(jgen, provider);
        }

        jgen.writeEndObject();
    }

    @Override
    public void serializeWithType(final JsonGenerator jgen,
        final SerializerProvider provider, final TypeSerializer typeSer)
        throws IOException, JsonProcessingException
    {
        serialize(jgen, provider);
    }
}

最后,自定义解串器:

final class JsonMergePatchDeserializer
    extends JsonDeserializer<JsonMergePatch>
{
    @Override
    public JsonMergePatch deserialize(final JsonParser jp,
        final DeserializationContext ctxt)
        throws IOException, JsonProcessingException
    {
        /* FAILS HERE */
        final JsonNode node = jp.readValueAsTree();
        /*
         * Not an object: the simple case
         */
        if (!node.isObject())
            return new NonObjectMergePatch(node);

        /*
         * The complicated case...
         *
         * We have to build a set of removed members, plus a map of modified
         * members.
         */

        final Set<String> removedMembers = Sets.newHashSet();
        final Map<String, JsonMergePatch> modifiedMembers = Maps.newHashMap();
        final Iterator<Map.Entry<String, JsonNode>> iterator = node.fields();

        Map.Entry<String, JsonNode> entry;

        while (iterator.hasNext()) {
            entry = iterator.next();
            if (entry.getValue().isNull())
                removedMembers.add(entry.getKey());
            else {
                final JsonMergePatch value 
                    = deserialize(entry.getValue().traverse(), ctxt);
                modifiedMembers.put(entry.getKey(), value);
            }            
        }

        return new ObjectMergePatch(removedMembers, modifiedMembers);
    }

    /*
     * This method MUST be overriden... The default is to return null, which is
     * not what we want.
     */
    @Override
    public JsonMergePatch getNullValue()
    {
        return new NonObjectMergePatch(NullNode.getInstance());
    }
}

我编写了编码测试,只要要反序列化的JSON不是对象,它就可以正常工作。 当它是一个对象时,我递归调用deserialize()方法来反序列化对象成员值...但是从解析器中读取值失败(标记为/* FAILS HERE */上面),但有以下例外:

java.lang.IllegalStateException: No ObjectCodec defined for the parser, can not deserialize JSON into JsonNode tree
    at com.fasterxml.jackson.core.JsonParser.readValueAsTree(JsonParser.java:1352)
    at com.github.fge.jsonpatch.rfc7386.JsonMergePatchDeserializer.deserialize(JsonMergePatchDeserializer.java:67)
    at com.github.fge.jsonpatch.rfc7386.JsonMergePatchDeserializer.deserialize(JsonMergePatchDeserializer.java:92)
    at com.github.fge.jsonpatch.rfc7386.JsonMergePatchDeserializer.deserialize(JsonMergePatchDeserializer.java:36)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2888)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2034)
    at com.github.fge.jsonpatch.rfc7386.SerializationTest.objectSerDeserWorksCorrectly(SerializationTest.java:102)

为什么? 我怎么解决这个问题?

乌维尔(Uhwell),在四处搜寻时,偶然发现了我的上一个问题,并给出了答案。 但是我的话很难看...

如异常所提到的,问题在于JsonParser实例没有关联的ObjectCodec 因此,我们必须给它喂一个; 这里的问题是为什么这不会自动完成...

因此,在自定义反序列化器中,我这样声明了一个新的ObjectCodec

// JacksonUtils is a class of mine; the method returns an ObjectMapper,
// which extends ObjectCodec
private static final ObjectCodec CODEC = JacksonUtils.newMapper();

.deserialize()方法中,我这样做:

jp.setCodec(CODEC);

而且有效。

但这很丑。 糟透了 它是可怕的。 我想要一个更好的解决方案:/

暂无
暂无

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

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