Jackson JSON 在嵌套类的集合上给出了异常

2022-09-04 03:19:23

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:没有找到适合类型 [simple type, class test.MyClass$Nested]:无法从 JSON 对象实例化(缺少默认构造函数或创建者,或者可能需要添加/启用类型信息?)位于 [Source: java.io.StringReader@26653222; 行: 1,列: 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);
}

}


答案 1

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

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

为此,请按如下方式对列表进行批注:

    @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;
  }
}

答案 2