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

标签 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
}

这是“ child ”类

@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
}

我写了一个简单的类来测试 gson 和 jackson 的特性;如前所述,他们都提出了一个异常(exception)。

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));
    }
}

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

@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")

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

 private final ConstructorConstructor constructorConstructor = new ConstructorConstructor();

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

ConstructorConstructor(Map<Type>, InstanceCreator<?> instanceCreators)

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

编辑 1

我终于找到了 jackson 的问题。在测试类中忘记初始化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" : [ ]
}

最佳答案

在处理循环依赖时,您需要构建父子 JSON 层次结构,因为编码必须从根级联到最内层的子级。

对于双向关联,当Parent有一对多的children集合,child有对Parent的多对一引用时,需要在多对一的一侧注解@JsonIgnore :

@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;

    @org.codehaus.jackson.annotate.JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "author", nullable = true)
    private User user;
    //...other attributes, getters and setters
}

这样你将不再有 Json 序列化时间循环依赖。

关于java - Hibernate 和 JSON - 循环依赖有明确的解决方案吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26657259/

相关文章:

模块化方式的 Java Swing + MVC 模式

java - 如何为在 Java 中运行的 Selenium 测试设置浏览器区域设置?

java - 如何在 JavaFX ChoiceBox 中显示默认选择

json - 在 Go 中将组合对象转换为 json

javascript - 在 json 文件中定义日期

java - 将 `@UsingDataSet` 转换为 `@Sql`

java - 插件的安全限制?

c# - 无法在 C# 中解析 JSON 响应

hibernate - 在一对多 Hibernate 映射中使用部分复合键

java - 返回奇数结果的日期之间的比较