Hibernate 和 JSON - 是否有循环依赖的明确解决方案?

tig*_*k89 7 java json hibernate jackson gson

这些天我正在努力处理 Hibernate 实体和 JSON,尽管存在很多关于该对象的问题,但我还无法在存在循环依赖项的情况下进行序列化。我尝试了 Gson 和 Jackson,但没有取得太大进展。这是我的对象的摘录。这是“父”类。

@Entity
public class User extends RecognizedServerEntities implements java.io.Serializable
{
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer id;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "user", orphanRemoval = false)
    @Cascade({CascadeType.SAVE_UPDATE})
    private Set<Thread> threads = new HashSet<Thread>(0);
    //...other attributes, getters and setters
}
Run Code Online (Sandbox Code Playgroud)

这是“儿童”班

@Entity
@Table(name = "thread")
public class Thread extends RecognizedServerEntities implements java.io.Serializable
{
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    private Integer id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "author", nullable = true)
    private User user;
    //...other attributes, getters and setters
}
Run Code Online (Sandbox Code Playgroud)

我编写了一个简单的类来测试 gson 和 jackson 功能;如前所述,他们都提出了例外。

public class MyJsonsTest
{
    private static User u;
    public static void main(String[] args)
    {
        u = new User("mail", "password", "nickname", new Date());
        u.setId(1); // Added with EDIT 1
    //  testGson();
        testJackson();
    }

    private static void testJackson()
    {
        Thread t = new Thread("Test", u, new Date(), new Date());
        t.setId(1); // Added with EDIT 1
        u.getThreads().add(t);

        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        try
        {
            mapper.writeValue(new File("result.json"), u);
        }
        catch {/[various exceptions catched, but a JsonMappingException was thrown]}
    }

    private static void testGson()
    {
        Gson gson = new Gson();
        System.out.println(u.toString());
        System.out.println(gson.toJson(u, User.class));

        Thread t = new Thread("Test", u, new Date(), new Date());
        u.getThreads().add(t);

        //This raise an exception overflow
        System.out.println(gson.toJson(u, User.class));
    }
}
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,在jackson这边,我尝试使用这个注释

@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
Run Code Online (Sandbox Code Playgroud)

在 User 和 Thread 类上。然而,它并不能解决问题。在 gson 方面,我阅读了有关 GraphAdapterBuilder 类的信息,但我无法正确使用它。我没有找到任何 jar,所以我从这里复制/粘贴了源代码。然而,这一行有一个编译时错误

 private final ConstructorConstructor constructorConstructor = new ConstructorConstructor();
Run Code Online (Sandbox Code Playgroud)

因为 ConstructorConstructor() 未定义;正确的语法应该是

ConstructorConstructor(Map<Type>, InstanceCreator<?> instanceCreators)
Run Code Online (Sandbox Code Playgroud)

那么,这个问题有没有一个明确的解决方案呢?显然,我不能使用transient变量。

编辑1

我终于找到了杰克逊的问题。在测试类中,我忘记初始化id字段(在实际场景中它是由数据库初始化的),这就是异常的原因。当我最终设置 id 时,一切正常。这是输出

{
  "id" : 1,
  "email" : "mail",
  "password" : "password",
  "nick" : "nickname",
  "registeredDate" : 1414703168409,
  "threads" : [ {
    "id" : 1,
    "thread" : null,
    "user" : 1,
    "title" : "Test",
    "lastModifiedDate" : 1414703168410,
    "createdDate" : 1414703168410,
    "messages" : [ ],
    "threads" : [ ]
  } ],
  "messages" : [ ]
}
Run Code Online (Sandbox Code Playgroud)

tig*_*k89 5


杰克逊

如前所述,我能够使用解决问题

@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id", scope=MyEntity.class)` 
Run Code Online (Sandbox Code Playgroud)

对于此处建议的每个实体。该scope属性对于确保名称“id”在范围内是唯一的是必需的。实际上,如果没有该属性,正如您在此处scope看到的那样,它会抛出一个异常

com.fasterxml.jackson.databind.JsonMappingException: Already had POJO for id java.lang.String) [com.fasterxml.jackson.annotation.ObjectIdGenerator$IdKey@3372bb3f] (through reference chain: ParentEntity["children"]->java.util.ArrayList[0]->ChildEntity["id"])
...stacktrace...
Caused by: java.lang.IllegalStateException: Already had POJO for id (java.lang.String) [com.fasterxml.jackson.annotation.ObjectIdGenerator$IdKey@3372bb3f]
...stacktrace...
Run Code Online (Sandbox Code Playgroud)

格森

我仍然没有找到一种干净的方法来序列化循环依赖项。