杰克逊与双向一对多关系混淆

时间:2012-04-10 23:22:08

标签: json jackson

我通过MappingJacksonHttpMessageConverter使用带有Hibernate / Spring MVC的jackson 1.9.2。

杰克逊无法序列化双向一对多关系并进行无限循环。

我正在使用的课程是:

  • 包含一组SMS实例的对话。

  • 每个SMS实例都有一组PhoneNumbers

  • 每个PhoneNumber都有一个父联系人(这是双向的多对一关系)

我要做的是序列化对话。

如果我不使用 @JsonManagedReference @JsonBackReference ,那么jackson会因无限循环而崩溃。但是当我使用它们时, 联系 不会序列化为 PhoneNumber

Class Contact {
  @JsonManagedReference
  List<PhoneNumber> phoneNumber ;
}
Class PhoneNumber {
  @JsonBackReference 
  Contact contact;
}

输出结果为:

{    <--------------------- Conversation
    "id": 51,
    "smsSet": [
      {
        "id": 53,
        "origin": 0123465,
        "destination": "06533844XY",
        "message": "Hello world!",
        "phoneNumbers": [
          {
            "id": 64,
            "num": "06533844XY",
            "creationDate": 1333992533000,
          }
        ],
      }
    ],
    "creationDate": 1333992534000
  }

而不是

{    <---------- conversation
    "id": 51,
    "smsSet": [
      {
        "id": 53,
        "origin": 0123465,
        "destination": "06533844XY",
        "message": "Hello world!",
        "phoneNumbers": [
          {
            "id": 64,
            "num": "06533844XY",
            "creationDate": 1333992533000,
            "contact":  <--------------------- Missing part
             {
                "id": 12,
                "name": "Samuel Jackson",
                "primaryNumber": "06533844XY"
             }
          }
        ],
      }
    ],
    "creationDate": 1333992534000
  }

4 个答案:

答案 0 :(得分:7)

我最近遇到了类似的问题:杰克逊 - 具有双向关系的实体的序列化(避免循环)

因此,解决方案是升级到Jackson 2.0,并向类中添加以下注释:

@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, 
                  property = "@id")
public class SomeEntityClass ...

然后问题是Spring不能与Jackson 2.0一起使用。这已通过以下方式解决:

<bean id="jacksonMessageConverter"
          class="own.implementation.of.MappingJacksonHttpMessageConverter"/>

<bean class="org.springframework.web.servlet.mvc
             .annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <ref bean="jacksonMessageConverter"/>
            </list>
        </property>
        <property name="requireSession" value="false"/>
    </bean>

self.implementation.of.MappingJacksonHttpMessageConverter基于此:

http://www.jarvana.com/jarvana/view/org/springframework/spring-web/3.0.0.RELEASE/spring-web-3.0.0.RELEASE-sources.jar!/org/springframework/http/converter/json/MappingJacksonHttpMessageConverter.java?format=ok

但是使用杰克逊2.0中的ObjectMapper和其他Jackson课程而不是Jackson 1。*

答案 1 :(得分:1)

作为第一个解决方案,我保留了这些注释并创建了另一个类:ContactWithouPhoneNumber并将其作为字段添加到PhoneNumber类中。

现在,在渲染之前,我会复制除PhoneNumber之外的所有字段,从联系人到contactWithoutPhoneNumber。输出JSON包含我需要的所有东西。

这是DTO设计模式。

答案 2 :(得分:0)

你的班级def有一件事是使用无类型的List;你应该宁愿:

List<PhoneNumber> phoneNumber ;

因为杰克逊不知道反序列化时的类型是什么;甚至在序列化时它可能会导致问题(因为基本类型不确定)。 所以我先解决这个问题。

但另外你的依赖可能是错误的方式:@JsonManagedReference必须始终是序列化的第一件事。如果不是这种情况,则无法使用这些注释。 如果没有看到您尝试序列化的对象,很难确定(POJO定义和JSON似乎略微偏离)。

答案 3 :(得分:0)

您可以将@JsonIgnore添加到字段中,映射器将在序列化期间跳过它们。它的功能类似于@Transient。

它位于jackson-core-asl。