使用匿名 类 的 Jackson 反序列化

Jackson deserialization with anonymous classes

我整天都在寻找能回答这个问题的东西,但到目前为止我运气不太好。

我的问题很简单:如何使用 Jackson 正确反序列化匿名对象。

private interface Interface1
{
    int getValue();
}

public static void testAnonymousObject() throws IOException
{
    ObjectMapper mapper = new ObjectMapper();

    mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
    mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
    mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);

    Interface1 testObject = new Interface1()
    {
        private final int value = 5;

        @Override
        public int getValue()
        {
           return value;
        }
    };

    String json = mapper.writeValueAsString(testObject);
    System.out.println("JSON = " + json);

    Interface1 received = (Interface1) mapper.readValue(json, Object.class);
    System.out.println(received);
}

这个输出是:JSON = ["com.foo.test.JacksonTest",{"value":5}] 在我得到异常之前:

线程"main"com.fasterxml.jackson.databind.JsonMappingException中的异常:无法将Classcom.foo.test.JacksonTest$1(类型local/anonymous)反序列化为Bean .

EDIT 澄清一下,Jackson 和 XStream 都能够序列化该对象。但似乎只有 XStream 能够反序列化对象。所以这个场景可以实现。

问题不仅仅在于它是一个内部 class(这可能有问题也可能没有问题,具体取决于实现是静态的还是非静态的),还在于没有包含类型信息 - - Jackson 看到的都是类型 Interface1。为了能够读回它,必须包含类型信息 ("polymorphic type handling"),或者指定抽象类型和实现之间的映射 class.

鉴于您正在使用匿名内部 class,您将能够通过启用所谓的 "default typing" 来支持这种用法(请参阅 ObjectMapper javadocs 了解 enableDefaultTyping() 之类的)。 但如果您不想为所有非最终类型启用类型包含,您可能还需要实施特定策略。

要查看是否包含类型 ID,您可以使用默认选项之一启用默认类型,并查看正在生成的 JSON:应该有一个额外的类型 ID ("@class " 属性 当 class 名称用作 id 时)。

截至我撰写本文时,Jackson 似乎没有正确序列化内部 类 或匿名 类。但是,XStream 和 Kryo 等其他软件包可以。

因为内部 classes 没有默认的零参数构造函数(它们有对 outer/parent class 的隐藏引用)Jackson 无法实例化它们。

你可以检查这个link

使用嵌套 类:

的通用 JSON 反序列化为 Java POJO 的现成代码片段
static class MyJSON {

    private Map<String, Object> content = new HashMap<>();

    @JsonAnySetter
    public void setContent(String key, Object value) {
        content.put(key, value);
    }
}

String json = "{\"City\":\"Prague\"}";

try {

    MyPOJO myPOJO = objectMapper.readValue(json, MyPOJO.class);

    String jsonAttVal = myPOJO.content.get("City").toString();

    System.out.println(jsonAttVal);

} catch (IOException e) {
    e.printStackTrace();
}

@JsonAnySetter 确保通用 JSON-解析和填充。