【问题标题】:Jackson JsonDeserializer delegate deserialization of a field back to default deserializer of that field typeJackson JsonDeserializer 将字段的反序列化委托回该字段类型的默认反序列化器
【发布时间】:2018-08-20 19:17:57
【问题描述】:

给定

public class ConstraintMatch {
    protected String constraintName;
    protected Score score;
    ...
}

我在杰克逊有以下序列化程序:

public class ConstraintMatchJacksonJsonSerializer extends JsonSerializer<ConstraintMatch> {

    @Override
    public void serialize(ConstraintMatch constraintMatch, JsonGenerator generator, SerializerProvider serializers)
            throws IOException {
        generator.writeStartObject();
        generator.writeStringField("constraintName", constraintMatch.getConstraintName());
        generator.writeFieldName("score");
        // Delegate to serialization to the default Score serializer
        serializers.findValueSerializer(Score.class)
                 .serialize(constraintMatch.getScore(), generator, serializers);
        generator.writeEndObject();
    }

}

如何编写一个也委托给默认反序列化器的反序列化器?

public class ConstraintMatchJacksonJsonDeserializer extends JsonDeserializer<ConstraintMatch> {

    @Override
    public ConstraintMatch deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        JsonNode tree = parser.readValueAsTree();

        String constraintName = tree.get("constraintName").asText();

        JsonNode scoreNode = tree.get("score");
        Score score = ...; // How do I delegate to the default deserializer?
        return new ConstraintMatch(constraintName, score);
    }

}

我查看了findContextualValueDeserializer() 等,但无法创建BeanProperty 实例。

【问题讨论】:

    标签: java jackson jackson2 jackson-databind


    【解决方案1】:

    在类似的情况下,我实际上发现有两个问题需要解决。首先,正如您所说,需要委托回正常的反序列化器。但是我遇到的另一个问题是如何将 JsonNode(下面的 TreeNode)提供给下一个反序列化(JsonParser,...)。

    以下是该情况下的一个工作示例,我想提前找出子类。

    希望这里的节点是你的 scoreNode。听起来 objectClass 对你来说只是 Score.class。

    @Override
    public T deserialize(JsonParser parser, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        ObjectMapper mapper = (ObjectMapper) parser.getCodec();
        TreeNode node = parser.readValueAsTree();
    
        // Select the subclass to deserialize as
        Class<? extends T> objectClass = deduceClass(node);
    
        // This based on ObjectMapper._convert()
        // - the problem here was the JsonParser (parser) had gone past the current node
        TokenBuffer buf = new TokenBuffer(mapper, false);
        SerializationConfig config = mapper.getSerializationConfig()
                .without(SerializationFeature.WRAP_ROOT_VALUE);
        DefaultSerializerProvider serializerProvider = ((DefaultSerializerProvider) mapper
                .getSerializerProvider()).createInstance(config,
                        mapper.getSerializerFactory());
        serializerProvider.serializeValue(buf, node);
        JsonParser nestedParser = buf.asParser();
        nestedParser.nextToken();
        JsonDeserializer<Object> deserializer = ctxt
                .findRootValueDeserializer(
                        mapper.getTypeFactory().constructType(objectClass));
        @SuppressWarnings("unchecked")
        T obj = (T) deserializer.deserialize(nestedParser, ctxt);
    
        return obj;
    
    }
    

    (以防万一,这是 Jackson 2.7.9)

    我很高兴听到有关从节点创建 JsonParser 的更简单方法。

    【讨论】:

    • 有趣,不过我找到了一种方法,但是没有使用readValueAsTree(),所以可以传入原始解析器。请参阅我的其他答案。
    【解决方案2】:

    序列化:

        constraintMatch.getConstraintPackage());
        generator.writeStringField("constraintName", constraintMatch.getConstraintName());
    
        generator.writeFieldName("score");
        // Delegate to PolymorphicScoreJacksonJsonSerializer
        JsonSerializer<Object> scoreSerializer = serializers.findValueSerializer(Score.class);
        scoreSerializer.serialize(constraintMatch.getScore(), generator, serializers);
        generator.writeEndObject();
    

    可以用这个反序列化:

        parser.nextToken();
        if (!"constraintName".equals(parser.getCurrentName())) {
            throw new IllegalStateException(...);
        }
        parser.nextToken();
        String constraintName = parser.getValueAsString();
    
        parser.nextToken();
        if (!"score".equals(parser.getCurrentName())) {
            throw new IllegalStateException(...);
        }
        parser.nextToken();
        JsonDeserializer<Object> scoreDeserializer = context.findNonContextualValueDeserializer(context.constructType(Score.class));
        Score score = (Score) scoreDeserializer.deserialize(parser, context);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-31
      • 2021-12-27
      • 2022-10-15
      • 2016-02-13
      • 2019-10-21
      • 2016-02-12
      • 2018-03-06
      • 2017-01-02
      相关资源
      最近更新 更多