【问题标题】:Jackson JSON gives exception on collection of nested classJackson JSON 对嵌套类的集合给出异常
【发布时间】:2016-02-15 21:03:45
【问题描述】:

Jackson JSON 序列化/反序列化这个类没有问题:

public class MyClass {
   public class Nested {
      public String string;
      public Nested() {}
   }
   public Nested nestedVar;
}

但是关于这个:

public class MyClass {
   class Nested {
      public String string;
      public Nested() {}
   }
   public Nested nestedVar;
   public List<Nested> nestedList;
}

反序列化时出现此异常:

com.fasterxml.jackson.databind.JsonMappingException:没有找到适合类型[简单类型,类 test.MyClass$Nested] 的构造函数:无法从 JSON 对象实例化(缺少默认构造函数或创建者,或者可能需要添加/启用类型信息?) 在 [来源:java.io.StringReader@26653222; line: 1, column: 48](通过引用链:test.MyClass["nestedList"]->java.util.ArrayList[0])

在第一种情况下,Jackson 处理嵌套类的实例没有问题,但在第二种情况下则不然。

我必须编写自定义反序列化器吗?

测试代码(Jackson 2.6.3):

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

public class ATest {

   public static void main(String[] args) throws IOException {

      ObjectMapper mapper = new ObjectMapper();

      StringWriter sw = new StringWriter();

      MyClass myClass = new MyClass();

      MyClass.Nested nestedVar = myClass.new Nested();

      List<MyClass.Nested> nestedList = new ArrayList<>();

      nestedList.add(nestedVar);

      myClass.nestedList =nestedList;

      myClass.nestedVar = nestedVar;

      mapper.writeValue(sw, myClass);

      System.out.println(sw.toString());

      StringReader sr = new StringReader(sw.toString());

      MyClass z = mapper.readValue(sr, MyClass.class);
}

}

【问题讨论】:

  • 尝试创建一个 list 对象或至少 set public List nestedList = null;
  • 尝试将内部类设为静态。
  • nestedList = null 不起作用
  • 添加了有问题的测试代码
  • 感谢测试代码。关于嵌套类的static:它将避免您在此处遇到的问题,并且参数“我不想使内部类在外部类之外可访问” 不受@987654325 的影响@。目前Nested 在您的示例中是包私有的,您可以保持这种方式。

标签: java json serialization jackson


【解决方案1】:

看起来非静态内部类的识别是在它们是直接在其包含 bean 上的属性的情况下完成的(BeanDeserializerBase.java 2.6.3 中的第 476 行)。因此,介入的 Collection 反序列化器将超越这一点。自定义反序列化器可能是这里最简单的选择。

请注意,您仍然可以使用 Jackson 来读取 Nested 的属性,并且只需在自定义反序列化器中自己实现它的构造在反序列化 Nested 对象列表时使用.

为此,请像这样注释列表:

    @JsonDeserialize(contentUsing = NestedDeserializer.class)
    public List<Nested> nestedList;

然后使用自定义的反序列化器:

  1. 在调用时查看解析上下文以查找包含 MyClass 的实例。

  2. 封装Nested的默认/根级反序列化器,将反序列化内容的工作委托给。

例如:

public static final class NestedDeserializer extends StdDeserializer<MyClass.Nested>
    implements ResolvableDeserializer {
  private JsonDeserializer<Object> underlyingDeserializer;

  public NestedDeserializer() {
    super(MyClass.Nested.class);
  }

  @Override
  public void resolve(DeserializationContext ctxt) throws JsonMappingException {
    underlyingDeserializer = ctxt
        .findRootValueDeserializer(ctxt.getTypeFactory().constructType(MyClass.Nested.class));
  }

  @Override
  public Nested deserialize(JsonParser p, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
    JsonStreamContext ourContext = p.getParsingContext();
    JsonStreamContext listContext = ourContext.getParent();
    JsonStreamContext containerContext = listContext.getParent();
    MyClass container = (MyClass) containerContext.getCurrentValue();
    MyClass.Nested value = container.new Nested();
    // note use of three-argument deserialize method to specify instance to populate
    underlyingDeserializer.deserialize(p, ctxt, value);
    return value;
  }
}

【讨论】:

  • 看准了!实际上,我最终做了一些不太干净的事情——使用@jsondeserialize,但使用了一个自定义构建器,它只会从临时 MyClass 生成一个嵌套,然后返回它。但这是教科书式的。谢谢!
  • 非常超级的解决方案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 2011-12-06
  • 1970-01-01
  • 2014-04-10
  • 1970-01-01
  • 2017-09-20
相关资源
最近更新 更多