杰克逊双向关系(一对多)不起作用

时间:2017-01-21 10:44:19

标签: hibernate spring-mvc jackson one-to-many circular-reference

我在这个Web服务项目中使用Spring(xml + annotations),Hibernate(注释)。数据库关系图,模型,预期和实际输出如下,

Database Table relationship

Customer.java

@Entity
@Table(name="customer")
public class Customer implements Serializable{
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="customer_id", unique=true, nullable =false)
    long customerId;
    @Column(name="name")
    String name;
    @Column(name="secondary_name")
    String secondaryName;
    @Column(name="date")
    Date date;
    @Column(name="address")
    String address;
    @Column(name="post")
    String post;
    @Column(name="pin")
    String pin;
    @Column(name="phone")
    String phone;
    @OneToMany(fetch=FetchType.LAZY, mappedBy="customer", cascade=CascadeType.ALL)
    @JsonManagedReference
    Set<Loan> loans = new HashSet<Loan>();
    //constructors, getters and setters
}

Loan.java

public class Loan implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="loan_id", nullable=false, unique=true)
    long loanId;
    @ManyToOne(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    @JoinColumn(name="customer_id", nullable = false)
    @JsonBackReference
    Customer customer;
    @Column(name="date", nullable=false)
    Date date;
    @Column(name="amount", nullable=false)
    double amount;
    @OneToMany(fetch=FetchType.LAZY, mappedBy="loan", cascade=CascadeType.ALL)
    @JsonManagedReference
    List<Item> items = new ArrayList<Item>();
    //constructors, getters, setters
}

Item.java

public class Item implements Serializable{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="item_id", nullable=false, unique=true)
    long itemId;
    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
    @JoinColumn(name="loan_id", nullable = false)
    @JsonBackReference
    Loan loan;
    @Column(name="name", nullable=false)
    String name;
    @Column(name="weight", nullable=false)
    double weight;
    //constructors, setters, getters
}

实际输出:此处未显示客户详细信息

{  
   "loanId":4,
   "date":1484937000000,
   "amount":10000.0,
   "items":[  
      {  
         "itemId":3,
         "name":"Item1",
         "weight":10.0
      },
      {  
         "itemId":4,
         "name":"Item2",
         "weight":20.0
      }
   ]
}

预期产出:在寻找贷款时也需要显示客户详细信息

{  
   "loanId":4,
   "customer":{  
      "customerId":2,
      "name":"Prem",
      "address":"Street,State"
   },
   "date":1484937000000,
   "amount":10000.0,
   "items":[  
      {  
         "itemId":3,
         "name":"Item1",
         "weight":10.0
      },
      {  
         "itemId":4,
         "name":"Item2",
         "weight":20.0
      }
   ]
}

我可以从数据库中获取客户详细信息,但无法使用Jackson Json加载它。 如果我删除@JsonManagedReference,我最终会得到循环循环。 如果我删除@JsonBackReference,则输出中没有效果。 完整代码:https://github.com/liwevire/TM_Service 提前谢谢。

3 个答案:

答案 0 :(得分:5)

因为您在@JsonBackReference实体的Customer属性上使用Loan,所以Customer对象不会包含在序列化中。将@JsonManagedReference用于Customer对象中的Loan,并使用@JsonBackReference实体中Loan属性的Customer

这将序列化Customer实体的Loan属性。但Customer对象序列化不包含Loan属性。你需要选择关系的一面来序列化。

要允许双方,请在您的实体中使用@JsonIdentityInfo注释,然后移除@JsonBackReference@JsonManagedReference。你的实体将是这样的:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "customerId")
public class Customer implements Serializable {
    ...
}

property的{​​{1}}引用您的实体ID属性,对于@JsonIdentityInfo,这将是Customer。对customerIdLoan执行此操作。

答案 1 :(得分:1)

这里有点冗长。但需要在您的应用程序中进行一些设计修改。 我遇到了类似的问题,并且为每个实体类创建了单独的pojos。

在服务层中,我使用这些pojos代替实体对象作为参数,并且使用适当的getter / setter设置实体类的属性/从实体类获取属性。 这样,您可以获取/设置所需的属性,避免不必要的属性。但是,我在DAO层中实现了其他方法来获取相关实体。这是一个很冗长的方法,但是为我解决了这个问题。

答案 2 :(得分:0)

这似乎很老了,但让我也把硬币放到这里;我将实体和模型分开。手段;

> Client <-> Application : Models
> 
> Application <-> Database : Entities

服务层或处理数据的任何层都应在实体和模型之间进行转换。

  1. 通过按需返回数据来摆脱递归。
  2. 您将定义分为两个不同的通信渠道。这样,您可以决定向客户显示什么以及如何向客户显示。这样也可以避免直接暴露您的数据库架构。
  3. 您可以根据需要扩展模型,而无需接触数据库后端。