【问题标题】:Jackson deserialization with anonymous classes使用匿名类的杰克逊反序列化
【发布时间】:2015-04-09 17:04:44
【问题描述】:

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

我的问题很简单:如何使用 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$1",{"value":5}]:

线程“main”com.fasterxml.jackson.databind.JsonMappingException 中的异常:无法将 com.foo.test.JacksonTest$1 类(本地/匿名类型)反序列化为 Bean

编辑 澄清一下,Jackson 和 XStream 都能够序列化对象。但似乎只有 XStream 能够反序列化对象。所以这个场景可以工作。

【问题讨论】:

  • 一个内部类实例需要一个外部类的实例来构造。杰克逊会用什么?它将如何创建外部类实例?顶级类和静态嵌套类有什么问题?
  • 这里被序列化/反序列化的对象只是一个空接口的匿名实现。问题是我正在将已经使用 XStream 序列化的大型代码库转换为使用 Jackson。匿名对象在代码中相当常见。在这种情况下,XStream 能够序列化和反序列化这个对象。 Jackson 只能序列化,不能反序列化。

标签: java json serialization jackson deserialization


【解决方案1】:

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

鉴于您使用的是匿名内部类,您将能够通过启用所谓的“默认类型”来支持这种用法(请参阅ObjectMapper javadocs for enableDefaultTyping() 等)。 但是,如果您不想为所有非最终类型启用类型包含,您可能还需要实施特定策略。

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

【讨论】:

  • 我实际上启用了默认类型,这就是为什么问题中包含的 JSON 包含类名“com.foo.test.JacksonTest$1。但我不知道如何获取要正确反序列化的序列化 JSON(请注意,它确实具有正确的类名)。
  • 啊。那么问题在于匿名内部类不是静态的,并且需要所谓的“隐式”this 指针。这不受支持。
【解决方案2】:

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

【讨论】:

  • 你的意思是杰克逊没有反序列化非静态内部类。支持静态内部类。
【解决方案3】:

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

你可以查看这个link

【讨论】:

    【解决方案4】:

    一个现成的代码-sn-p,用于使用嵌套类将通用 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 解析和填充。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多