【问题标题】:Jackson: Unresolved forward references when trying to deserialize JSON into java objectsJackson:尝试将 JSON 反序列化为 java 对象时未解析的前向引用
【发布时间】:2019-04-06 14:29:48
【问题描述】:

我已经被Jackson 的问题困扰了很长一段时间了,我很想解决它。我有一个JSON,其中包含通过 ID 相互引用的对象,我需要将其反序列化为对象,但在尝试这样做时我不断收到Unresolved forward references exception。

我曾尝试使用上述有问题的类的Jackson 注释@JsonIdentityInfo,但这并没有产生任何结果。

JSON 示例:

{
  "customer": [
    {
      "id": 1,
      "name": "Jane Gallow",
      "age": 16
    },
    {
      "id": 2,
      "name": "John Sharp",
      "age": 20
    },
  ],
  "shoppingcart": [
    {
      "id": 1,
      "customer": 2,
      "orderDate": "2015-02-19"
    }
  ]
}

客户类


@JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id",scope = Customer.class)
@JsonIdentityReference(alwaysAsId = true)
public class Customer {

    private int id = -1;

    private String name;

    private int age;

    //getters, setters
}

ShoppingCart 类


<!-- language: java -->

@JsonIdentityInfo(generator= ObjectIdGenerators.PropertyGenerator.class, property="id",scope = ShoppingCart.class)
public class ShoppingCart {

    private int id = -1;

    private Customer customer;

    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)
    private LocalDate orderDate = LocalDate.now();

    //getters, setters
}

我希望Jackson 给我一个ShoppinCart 对象,该对象引用了Customer 对象,ID 为2(在本例中为John Sharp)。但是我无法让它工作,当我尝试使用ObjectMapper.readValue() 方法从 JSON 读取时,它给了我"main" com.fasterxml.jackson.databind.deser.UnresolvedForwardReference。

【问题讨论】:

    标签: java json jackson deserialization json-deserialization


    【解决方案1】:

    我在反序列化过程中遇到了与未解决的前向引用相同的问题。我使用https://www.logicbig.com/tutorials/misc/jackson/json-identity-reference.html 上提供的示例来检查并解决我的问题。 有一个非常简单的类:

    public class Order {
      private int orderId;
      private List<Integer> itemIds;
      private Customer customer;
    ....
    }
    

    我在 Customer 类中添加了 @JsonCreator 静态工厂方法,它没有引起任何问题。

    现在,当我向 Order 类添加任何类型的 @JsonCreator(静态方法或构造函数)时,我会立即得到未解析的前向引用。有趣的是,当我添加以下构造函数时,仅存在 @JsonPropery 注释:

     public Order(@JsonProperty("orderId") int orderId, @JsonProperty("itemIds") List<Integer> itemIds, @JsonProperty("customer") Customer customer) {
        this.orderId = orderId;
        this.itemIds = itemIds;
        this.customer = customer;
    }
    

    它还会导致无法解析的前向引用。

    为了解决这个问题,您必须为 Order 类创建无参数构造函数(可以是私有的)。否则你会得到:

    线程“主”com.fasterxml.jackson.databind.exc.InvalidDefinitionException 中的异常:无法构造com.logicbig.example.Order 的实例(没有创建者,如默认构造,不存在):无法从对象值反序列化(没有委托或属性基于创作者)

    并且不得有任何 @JsonCreator 注释的方法和构造函数,或带有 @JsonProperty 注释的构造函数。

    仅此而已。

    【讨论】:

      【解决方案2】:

      您应该在属性上使用JsonIdentityReference。

      @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = ShoppingCart.class)
      class ShoppingCart {
      
          private int id = -1;
      
          @JsonIdentityReference
          private Customer customer;
          private LocalDate orderDate;
      
          // getters, setters, toString
      }
      
      @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope = Customer.class)
      class Customer {
      
          private int id = -1;
          private String name;
          private int age;
      
          // getters, setters, toString
      }
      

      简单示例:

      import com.fasterxml.jackson.annotation.JsonIdentityInfo;
      import com.fasterxml.jackson.annotation.JsonIdentityReference;
      import com.fasterxml.jackson.annotation.JsonProperty;
      import com.fasterxml.jackson.annotation.ObjectIdGenerators;
      import com.fasterxml.jackson.databind.ObjectMapper;
      import com.fasterxml.jackson.databind.SerializationFeature;
      import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
      
      import java.io.File;
      import java.time.LocalDate;
      import java.util.List;
      
      public class JsonApp {
      
          public static void main(String[] args) throws Exception {
              File jsonFile = new File("./resource/test.json").getAbsoluteFile();
      
              ObjectMapper mapper = new ObjectMapper();
              mapper.registerModule(new JavaTimeModule());
              mapper.enable(SerializationFeature.INDENT_OUTPUT);
      
              System.out.println(mapper.readValue(jsonFile, Pojo.class));
          }
      }
      

      为您的JSON 打印:

      Pojo{customers=[Customer{id=1, name='Jane Gallow', age=16}, Customer{id=2, name='John Sharp', age=20}], shoppingCarts=[ShoppingCart{id=1, customer=Customer{id=2, name='John Sharp', age=20}, orderDate=2015-02-19}]}
      

      另见:

      【讨论】:

      • 谢谢,您的回答让我找到了解决方案。我发现您的示例代码有效,但我的应用程序中的代码没有。不同的是,我创建 Pojo 对象的方式有点不同,Jackson 对象引用算法显然不喜欢这种方式。
      猜你喜欢
      • 2012-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-17
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多