【问题标题】:How to solve circular reference in json serializer caused by Many TO Many hibernate bidirectional mapping?如何解决由Many TO Many hibernate双向映射引起的json序列化器中的循环引用?
【发布时间】:2011-07-17 18:52:38
【问题描述】:

我正在尝试将 POJO 序列化为 JSON,但陷入循环引用问题。我知道如何使用@JsonBackReference@JsonManagedReference 处理一对多和反向关系。

我的问题是双向多对多关系(例如,一个学生可以有很多课程,每门课程可以有很多学生注册),父母参考孩子和孩子参考回到父母,我的序列化器在这里死了。根据我的理解,我不能在这里使用@JsonBackReference,因为属性的值类型必须是 bean:它不能是 Collection、Map、Array 或枚举。

有人可以告诉我如何处理这种情况吗?

【问题讨论】:

    标签: json hibernate spring many-to-many circular-reference


    【解决方案1】:

    @Bozho 已经回答使用@JsonIgnoreProperties,试试这个,它对我有用。

    以下是我使用@JsonIgnoreProperties 的模型:

    @Entity
    public class Employee implements Serializable{
        @ManyToMany(fetch=`enter code here`FetchType.LAZY)
        @JoinTable(name="edm_emp_dept_mappg", 
            joinColumns={@JoinColumn(name="emp_id", referencedColumnName="id")},
            inverseJoinColumns={@JoinColumn(name="dept_id", referencedColumnName="id")})
        @JsonIgnoreProperties(value="employee")
        Set<Department> department = new HashSet<Department>();
    }
    
    
    @Entity
    public class Department implements Serializable {
        @ManyToMany(fetch=FetchType.LAZY, mappedBy="department")
        @JsonIgnoreProperties(value="department")
        Set<Employee> employee = new HashSet<Employee>();
    }
    

    在@JsonIgnoreProperties的value属性中,我们需要提供counter(related)模型的集合类型属性。

    【讨论】:

    • 不错的答案,但我会修复 fetch='enter code here,并且使用复数表示属性会更清楚:departmentsemployees
    【解决方案2】:

    正在阐述@Bozho 已经提到的内容...

    我现在坚持使用 Jackson 1,因为我使用的是 Google Cloud Endpoints,所以即使 Jackson 2 已经发布了一段时间,这仍可能对某些人有所帮助。虽然我不需要反序列化整个对象,但是引用还是很有必要的。

    我将@JsonIgnore 放在导致循环引用的字段上,然后为每个字段创建一个新的getter,以便在我的API 中仍然返回一个平面引用。

    @JsonIgnore
    private FooClass foo;
    
    public String getFooKey()
    ...
    

    使用 Cloud Endpoints,这会导致在 GET 负载中返回一个扁平的“fooKey”,同时省略“foo”。

    【讨论】:

      【解决方案3】:

      您还可以使用 Dozer 映射将 POJO 转换为 Map 并排除字段。例如,如果我们有两个具有双向关系的类 PojoA 和 PojoB,我们可以这样定义映射

      <mapping map-id="mapA" map-null="false">
        <class-a>com.example.PojoA</class-a>
        <class-b>java.util.Map</class-b>
        <field>
          <a>fieldA</a>
          <b>this</b>
        </field>  
        <field map-id="mapB">
            <a>pojoB</a>
            <b>this</b>
            <b-hint>java.util.Map</b-hint>
        </field>
      </mapping>
      
      <mapping map-id="mapB" map-null="false">
        <class-a>com.example.PojoB</class-a>
        <class-b>java.util.Map</class-b>
        <field-exclude>
          <a>pojoA</a>
          <b>this</b>
        </field-exclude>
      </mapping>
      

      然后你定义一个bean,将上面的dozer映射文件设置为一个属性。

      <bean id="mapper" class="org.dozer.DozerBeanMapper">
         <property name="mappingFiles">
          <list>
             <value>dozerMapping.xml</value>
          </list>
         </property>
      </bean>
      

      然后在你要序列化的类中

      public class TestClass
      {
           @Autowired
           DozerBeanMapper mapper;
      
           public Map<String,Object> serializeObject(PojoA pojoA)
           {
                return ((Map<String, Object>) mapper.map(pojoA, Map.class, "mapA"));
           }
      }
      

      Dozer manual here.

      【讨论】:

        【解决方案4】:

        如果你有集合对象,那就让它成为吧

        collection<object> listobj 
        
        var jsonObj = from c in listobj
                          select new
                         {
                           Prop1 = c.Prop1
                            ...
                         }
        

        这应该可以工作,你现在得到的对象可以被 json 序列化并且它是干净的

        【讨论】:

          【解决方案5】:

          您可以在关系的一侧使用@JsonIgnoreProperties("someField")(注释是类级别的)。或@JsonIgnore

          【讨论】:

          • 这个,加上我将在下面提到的一些补充,为我很好地解决了类似的问题。
          猜你喜欢
          • 2011-03-21
          • 1970-01-01
          • 1970-01-01
          • 2016-09-30
          • 2015-02-13
          • 2019-07-26
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多