当前位置: 首页 > 知识库问答 >
问题:

Jackson反序列化器委托给下一个适用的反序列化器

酆出野
2023-03-14

我有一个外部服务,我用它来查询一些数据。数据将采用两种格式之一(第一种是“遗留”格式,但需要支持):

{
    "foo": "John Smith"
}

{
    "foo": {
        "name": "John Smith",
        "bar": "baz"
    }
}

我想将其映射到以下POJO:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Outer {

    private Foo foo;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Foo {

        String name;
        String bar;

    }

}

第二种格式的数据(foo是一个对象)应该像任何其他POJO一样进行反序列化,但给定第一种格式的数据(foo是字符串),要将其转换为foo的实例,我想调用new foo(

@JsonComponent
public class FooDeserializer extends JsonDeserializer<Outer.Foo> {

    @Override
    public Outer.Foo deserialize(JsonParser parser, DeserializationContext context)
            throws IOException {
        JsonNode node = parser.getCodec().readTree(parser);
        if (node.isTextual()) {
            return new Foo(node.asText(), null);
        }
        return <delegate to next applicable deserializer>;
    }

}

我很难弄清楚如何执行委托到下一个适用的反序列化器部分,因为我尝试过的每个解决方案(例如parser.getCodec(). treeToValue(节点,外部。Foo.class))最终再次使用相同的自定义反序列化器,导致无限递归。这有可能吗?


共有1个答案

祁乐邦
2023-03-14

schummar回答:如何从Jackson中的自定义反序列化程序调用默认反序列化程序。根据上述答案,
1@JsonComponent注释应从自定义序列化程序中删除,因为我们需要使用默认序列化程序构造自定义序列化程序,@JsonComponent不支持此操作
2。使用BeandSerializerModifier将SimpleModule注册到ObjectMapper,并使用使用默认序列化程序构造的自定义序列化程序修改序列化程序
3。在自定义序列化程序的serialize方法中,处理特殊情况,并将序列化委托给正常情况下的默认序列化程序。

下面的代码演示了如何实现以上几点。

主类

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.module.SimpleModule;

public class DelegateDeserializer {
    public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {

        ObjectMapper mapper = new ObjectMapper();

        SimpleModule simpleModule = new SimpleModule();

        simpleModule.setDeserializerModifier(new BeanDeserializerModifier() {
            @Override
            public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc,
                    JsonDeserializer<?> deserializer) {
                if (Outer.Foo.class.isAssignableFrom(beanDesc.getBeanClass())) {
                    return new FooDeserializer(deserializer, beanDesc.getBeanClass());
                }
                return deserializer;
            }
        });

        mapper.registerModule(simpleModule);

        Outer outer1 = mapper.readValue(getType1Json(), Outer.class);
        Outer outer2 = mapper.readValue(getType2Json(), Outer.class);
        System.out.println("deserialize json with object structure:");
        System.out.println(outer1.getFoo().getName());
        System.out.println(outer1.getFoo().getBar());
        System.out.println("deserialize json with string field only:");
        System.out.println(outer2.getFoo().getName());
        System.out.println(outer2.getFoo().getBar());
    }

    private static String getType1Json() {

        return "  {                                                                        "
                + "  \"foo\": {                                                            "
                + "     \"name\": \"John Smith\",                                          "
                + "    \"bar\": \"baz\"                                                    "
                + "   }                                                                    "
                + "}                                                                       ";

    }

    private static String getType2Json() {

        return "  {                                                                        "
                + "  \"foo\": \"John Smith\"                                               "
                + "}                                                                       ";

    }
}

foDeserializer类

import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.ResolvableDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;

import jackson.Outer.Foo;

public class FooDeserializer extends StdDeserializer<Outer.Foo> implements ResolvableDeserializer {

    private static final long serialVersionUID = 1L;
    private final JsonDeserializer<?> defaultDeserializer;

    public FooDeserializer(JsonDeserializer<?> defaultDeserializer, Class<?> clazz) {
        super(clazz);
        this.defaultDeserializer = defaultDeserializer;
    }

    @Override
    public Outer.Foo deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        if (parser.getCurrentToken() == JsonToken.VALUE_STRING) {
            JsonNode node = parser.getCodec().readTree(parser);
            if (node.isTextual()) {
                return new Foo(node.asText(), null);
            }
        }

        return (Foo) defaultDeserializer.deserialize(parser, context);
    }

    @Override
    public void resolve(DeserializationContext ctxt) throws JsonMappingException {
        ((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
    }

}

外层阶级

 public class Outer {
    private Foo foo;

    public Foo getFoo() {
        return foo;
    }

    public void setFoo(Foo foo) {
        this.foo = foo;
    }

    public static class Foo {
        private String bar;
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getBar() {
            return bar;
        }

        public void setBar(String bar) {
            this.bar = bar;
        }

        public Foo() {
        }

        public Foo(String name, String bar) {
            this.name = name;
            this.bar = bar;
        }
    }

}
 类似资料:
  • 情况如下:我已经设法让Jackson反序列化以下通用 作为HTTP客户端,并使用exchange

  • I'va是一个OID接口,可以由许多具体类型实现: 现在我有一个具有两个字段的对象,一个使用抽象接口类型(OID)定义,另一个使用具体类型(MyOID)定义 我想使用jackson以不同的方式序列化/反序列化字段,无论它们是使用抽象接口类型还是具体类型定义的: 注意,被序列化,包括类型信息(多态序列化),而被序列化为文本 为此,我将OID接口注释为: 并为每个具体类型分配了类型id: 最后,对容器

  • 我想反序列化表单中的类: 其中文本是加密的,反序列化应该在重建TestFieldEncryptedMessage实例之前取消对值的加密。 我采用的方法非常类似于:https://github.com/codesqueak/jackson-json-crypto 也就是说,我正在构建一个扩展SimpleModule的模块: 如您所见,设置了两个修饰符:EncryptedSerializerModif

  • 我正在尝试使用RestTemplate使用REST服务。我无法反序列化JSON响应。我正在使用一个自定义反序列化程序,我的JSON有3个节点,但看起来只有一个节点到达反序列化程序。以下是更多详细信息。 以下是JSON的响应: 我正在使用@jsondeselizer对属性Hello的响应类使用自定义反序列化器。 当我执行如下readTree时: 它到达了反序列化方法,看起来它只有一个节点,而不是下面

  • 假设我正在为某个类编写自定义序列化,但希望使用默认方法处理其中一个字段。 那要怎么做? 序列化时,我们有。 但反序列化的相应方法是什么? 请注意以下代码: 如何实现MyOuterDeserializer?

  • 问题内容: 我正在使用JAVA 1.6和Jackson 1.9.9我有一个枚举 我添加了一个@JsonValue,这似乎可以将对象序列化为: 但是当我尝试反序列化时,我得到了 我在这里想念什么? 问题答案: 如果你希望将枚举类与其JSON表示完全脱钩,则@xbakesx指出的序列化器/反序列化器解决方案是一个很好的解决方案。 另外,如果你喜欢一个独立的解决方案,则基于·和·注释的实现会更方便。 因