如何配置Jackson ObjectMapper将Foo类型的所有字段反序列化为SubclassOfFoo的实例?

时间:2016-11-02 21:52:33

标签: java json jackson deserialization subclass

我反序列化一个大的json值。深深嵌套在该值中的是一个json对象,如下所示:

{
  "fieldOne": "valueOne",
  "fieldTwo": {
    "innerField": "innerValue"
  }
}

我使用Jackson ObjectMapper将大型json值反序列化为第三方类。深深嵌套在第三方课程中的是另一个第三方课程:

public class DeepThirdPartyClass {
    public String fieldOne;
}

遗憾的是缺少fieldTwo属性。我可以创建自己的类,添加缺少的字段:

public class MyClass extends DeepThirdPartyClass {
    public MySubObject fieldTwo;
}

如何配置jackson,以便每当它尝试将值反序列化为DeepThirdPartyClass时,它会反序列化为MyClass

2 个答案:

答案 0 :(得分:1)

当我必须过滤所有String值中的任何不允许的字符时,我有类似的要求。 要创建Object Mapper:

public class CustomObjectMapper extends ObjectMapper {
    public CustomObjectMapper() {
        super();

        SimpleModule module = new SimpleModule("HTML XSS Serializer", new Version(1, 0, 0, "FINAL", "com.crowdoptic", "web"));
        module.addSerializer(String.class, new JsonHtmlXssSerializer());
        module.addDeserializer(String.class, new JsonHtmlXssDeserializer());

        this.registerModule(module);
    }
}

public class JsonHtmlXssDeserializer extends StdScalarDeserializer<String> {
    private static final Logger LOG = LogManager.getLogger(JsonHtmlXssDeserializer.class);

    public JsonHtmlXssDeserializer() { super(String.class); }

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String value = StringDeserializer.instance.deserialize(p, ctxt);
        LOG.trace("in deserialize for value: " + value);
        String encodedValue = StringEscapeUtils.escapeHtml4(value);
        return encodedValue;
    }
    @Override
    public String deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException {
        return StringDeserializer.instance.deserializeWithType(jp, ctxt, typeDeserializer);
    }

    @Override
    public boolean isCachable() { return StringDeserializer.instance.isCachable(); }
}

在您的情况下,您可以注册您的类反序列化器,调用对象反序列化器的超级方法。然后,不是返回DeepThirdPartyClass,而是创建MyClass的对象,从DeepThirdPartyClass设置字段1并添加第二个字段。有关实现细节和可用属性,请参阅StringDeserializer和其他人。

如果有帮助,请告诉我。

答案 1 :(得分:0)

我重写了@ olga-khylkouskaya的解决方案,以解决我的问题:

@Test
public void newDeserializer() throws Exception {
    ObjectMapper objectMapper = new ObjectMapper();
    SimpleModule module = new SimpleModule("DeepThirdPartyClass subclass override", new Version(1, 0, 0, "FINAL", "com.example", "deep-third-party-class-override"));
    module.addDeserializer(DeepThirdPartyClass.class, new JsonDeserializer<DeepThirdPartyClass>() {
        @Override
        public DeepThirdPartyClass deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            return p.readValueAs(MyClass.class);
        }
    });
    objectMapper.registerModule(module);
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    String json = "{\n" +
            "  \"middle\": {\n" +
            "    \"fieldOne\": \"valueOne\",\n" +
            "    \"fieldTwo\": {\n" +
            "      \"fieldThree\": \"valueThree\"\n" +
            "    }\n" +
            "  }\n" +
            "}\n";

    ThirdPartyClass thirdPartyClass = objectMapper.readValue(json, ThirdPartyClass.class);
}

public class ThirdPartyClass {
    public DeepThirdPartyClass middle;
}

public class InnerClass {
    public String fieldThree;
}