无限递归与Jackson JSON和Hibernate JPA问题


412

当尝试将具有双向关联的JPA对象转换为JSON时,我不断

org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)

我所发现的只是该线程,基本上以建议避免双向关联为结尾。有谁知道这个春季错误的解决方法?

------编辑2010-07-24 16:26:22 -------

代码段:

业务对象1:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class Trainee extends BusinessObject {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "name", nullable = true)
    private String name;

    @Column(name = "surname", nullable = true)
    private String surname;

    @OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Column(nullable = true)
    private Set<BodyStat> bodyStats;

    @OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Column(nullable = true)
    private Set<Training> trainings;

    @OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Column(nullable = true)
    private Set<ExerciseType> exerciseTypes;

    public Trainee() {
        super();
    }

    ... getters/setters ...

业务对象2:

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class BodyStat extends BusinessObject {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "height", nullable = true)
    private Float height;

    @Column(name = "measuretime", nullable = false)
    @Temporal(TemporalType.TIMESTAMP)
    private Date measureTime;

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name="trainee_fk")
    private Trainee trainee;

控制器:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Controller
@RequestMapping(value = "/trainees")
public class TraineesController {

    final Logger logger = LoggerFactory.getLogger(TraineesController.class);

    private Map<Long, Trainee> trainees = new ConcurrentHashMap<Long, Trainee>();

    @Autowired
    private ITraineeDAO traineeDAO;

    /**
     * Return json repres. of all trainees
     */
    @RequestMapping(value = "/getAllTrainees", method = RequestMethod.GET)
    @ResponseBody        
    public Collection getAllTrainees() {
        Collection allTrainees = this.traineeDAO.getAll();

        this.logger.debug("A total of " + allTrainees.size() + "  trainees was read from db");

        return allTrainees;
    }    
}

JPA实施学员DAO:

@Repository
@Transactional
public class TraineeDAO implements ITraineeDAO {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public Trainee save(Trainee trainee) {
        em.persist(trainee);
        return trainee;
    }

    @Transactional(readOnly = true)
    public Collection getAll() {
        return (Collection) em.createQuery("SELECT t FROM Trainee t").getResultList();
    }
}

persistence.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
             version="1.0">
    <persistence-unit name="RDBMS" transaction-type="RESOURCE_LOCAL">
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="hibernate.hbm2ddl.auto" value="validate"/>
            <property name="hibernate.archive.autodetection" value="class"/>
            <property name="dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <!-- <property name="dialect" value="org.hibernate.dialect.HSQLDialect"/>         -->
        </properties>
    </persistence-unit>
</persistence>

添加@TransientTrainee.bodyStats
phil294

截至2017年,@JsonIgnoreProperties是最干净的解决方案。请查看Zammel AlaaEddine的答案以获取更多详细信息。
Utku

春天的毛病怎么了?
内森·休斯

Answers:


293

您可以使用它@JsonIgnore来打破循环。


1
@本:其实我不知道。也许未启用其支持:wiki.fasterxml.com/JacksonJAXBAnnotations
axtavt 2010年

40
从Jackson 1.6开始,有一个更好的解决方案:您可以使用两个新的注释来解决无限递归问题,而不必在序列化过程中忽略getter / setter方法。请参阅下面的详细信息。
Kurt Bourbaki 2014年

1
@axtavt感谢您的完美答案。顺便说一句,我想出了另一种解决方案:您可以简单地避免为此值创建getter,因此Spring在创建JSON时将无法访问它(但我认为这并不适合每种情况,因此您的答案会更好)
Semyon Danilov

11
以上所有解决方案似乎都需要通过添加注释来更改域对象。如果我要序列化第三方类,则无法修改它们。如何避免这个问题?
陈建武

2
此解决方案在某些情况下不起作用。在使用jpa的关系数据库中,如果您放置@JsonIgnore该实体,则在更新实体时您将在“外键”中为null ...
slim 2002年

628

JsonIgnoreProperties [2017更新]:

您现在可以使用JsonIgnoreProperties属性(序列化过程中)的抑制序列,或忽略JSON性能的处理读取(反序列化过程)。如果这不是您想要的,请继续阅读以下内容。

(感谢As Zammel AlaaEddine指出了这一点)。


JsonManagedReference和JsonBackReference

从Jackson 1.6开始,您可以使用两个注释来解决无限递归问题,而不必在序列化过程中忽略getter / setter方法:@JsonManagedReference@JsonBackReference

说明

为了使Jackson正常工作,不应将关系的两个方面之一进行序列化,以避免引起您stackoverflow错误的infite循环。

因此,Jackson接受了引用的前一部分(您Set<BodyStat> bodyStats在Trainee类中),并将其转换为类似json的存储格式;这就是所谓的编组过程。然后,杰克逊寻找引用的Trainee trainee后半部分(即在BodyStat类中),并保持原样,而不是对其进行序列化。关系的这一部分将在前向引用的反序列化(反编组)期间重新构建。

您可以这样更改代码(我跳过了无用的部分):

业务对象1:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class Trainee extends BusinessObject {

    @OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @Column(nullable = true)
    @JsonManagedReference
    private Set<BodyStat> bodyStats;

业务对象2:

@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
public class BodyStat extends BusinessObject {

    @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinColumn(name="trainee_fk")
    @JsonBackReference
    private Trainee trainee;

现在一切都应该正常工作。

如果您需要更多信息,我我的博客Keenformatics上写了一篇有关Json和Jackson Stackoverflow问题的文章。

编辑:

您可以检查的另一个有用的注释是@JsonIdentityInfo:使用它,每次Jackson序列化您的对象时,它都会向其添加一个ID(或您选择的另一个属性),这样就不会每次都完全“扫描”它。当您在更多相互关联的对象之间形成链环时(例如:Order-> OrderLine-> User-> Order and over over),这很有用。

在这种情况下,您必须要小心,因为您可能需要多次读取对象的属性(例如,在一个产品列表中有多个共享同一卖方的产品),并且此注释会阻止您这样做。我建议始终查看Firebug日志,以检查Json响应,并查看代码中发生了什么。

资料来源:


29
感谢您的明确答复。这比@JsonIgnore回引用更方便。
UtkuÖzdemir13年

3
这绝对是正确的方法。如果您在服务器端这样做是因为您在那儿使用Jackson,则在客户端使用什么json映射器都没有关系,您不必将子级设置为父级链接手册。它只是工作。谢谢库尔特
flosk8 2013年

1
精美,详尽的解释,绝对比更好,更具描述性的方法@JsonIgnore
Piotr Nowicki 2015年

2
谢谢!@JsonIdentityInfo适用于循环引用,该循环引用涉及许多重叠循环中的多个实体。
2015年

1
我无法让它为我的一生工作。我想我有一个非常相似的设置,但是我显然出了点问题,因为除了无限递归错误我什么都得不到:
swv

103

新的注释@JsonIgnoreProperties使用其他选项解决了许多问题。

@Entity

public class Material{
   ...    
   @JsonIgnoreProperties("costMaterials")
   private List<Supplier> costSuppliers = new ArrayList<>();
   ...
}

@Entity
public class Supplier{
   ...
   @JsonIgnoreProperties("costSuppliers")
   private List<Material> costMaterials = new ArrayList<>();
   ....
}

在这里查看。它的工作方式类似于文档:http :
//springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html


@tero-同样,通过这种方法,我们不会获得与实体关联的数据。
Pra_A

@PAA嗨,PAA我认为这与实体有关!你为什么这样讲 ?
tero17

1
@ tero17当您有两个以上的类时,如何管理无限递归?例如:A类-> B类-> C类-> A类。我尝试使用JsonIgnoreProperties时没有运气
维拉特

@Villat这是要解决的另一个问题,我建议对此提出新的要求。
tero17

代码示例+1,作为Jackson的新手,使用@JsonIgnoreProperties并不完全清楚
JavaBean

47

另外,使用Jackson 2.0+,您可以使用@JsonIdentityInfo。这对我的休眠类来说要比@JsonBackReference和更好@JsonManagedReference,因为对我来说有问题,但不能解决问题。只需添加如下内容:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@traineeId")
public class Trainee extends BusinessObject {

@Entity
@Table(name = "ta_bodystat", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@bodyStatId")
public class BodyStat extends BusinessObject {

它应该工作。


您能否解释一下“效果更好”?托管参考有问题吗?
UtkuÖzdemir13年

@UtkuÖzdemir我@JsonIdentityInfo在上面的答案中添加了有关的详细信息。
Kurt Bourbaki 2013年

1
这是迄今为止找到的最好的解决方案,因为当我们使用“ @JsonManagedReference”时,get方法成功返回了值,而没有任何stackoverflow错误。但是,当我们尝试使用帖子保存数据时,它返回了错误415(不受支持的媒体错误)
cuser

1
我已将@JsonIdentityInfo注释添加到我的实体中,但不能解决递归问题。只有@JsonBackReference@JsonManagedReference解决的,但他们是从JSON删除映射属性。
Oleg Abrazhaev '16



9

这对我来说很好。在子类上添加注释@JsonIgnore,在其中提及父类的引用。

@ManyToOne
@JoinColumn(name = "ID", nullable = false, updatable = false)
@JsonIgnore
private Member member;

2
我认为@JsonIgnore忽略了从检索到客户端的此属性。如果我需要此属性及其子级(如果有子级)怎么办?
珊,2015年

6

现在有一个专为Jackson 2设计的Jackson模块(专门用于处理序列化时的Hibernate延迟初始化问题)。

https://github.com/FasterXML/jackson-datatype-hibernate

只需添加依赖项(请注意,Hibernate 3和Hibernate 4有不同的依赖项):

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-hibernate4</artifactId>
  <version>2.4.0</version>
</dependency>

然后在初始化Jackson的ObjectMapper时注册该模块:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Hibernate4Module());

文档目前不是很好。请参阅Hibernate4Module代码以获取可用选项。


然后问题解决了,因为它看起来很有趣。我有与OP相同的问题,包括上述所有技巧都无效。
user1567291

6

对我而言 工作正常与杰克逊一起工作时解决Json Infinite Recursion问题

这是我在oneToMany和ManyToOne映射中所做的

@ManyToOne
@JoinColumn(name="Key")
@JsonBackReference
private LgcyIsp Key;


@OneToMany(mappedBy="LgcyIsp ")
@JsonManagedReference
private List<Safety> safety;

我已在春季启动应用程序中使用过休眠映射
Prabu M

嗨,作者,谢谢您的精彩教程和精彩文章。但是,我发现@JsonManagedReference@JsonBackReference并不会为您提供与@OneToMany@ManyToOne场景关联的数据,使用时也会@JsonIgnoreProperties跳过关联的实体数据。如何解决呢?
Pra_A

5

对我而言,最好的解决方案是@JsonView针对每种情况使用并创建特定的过滤器。您也可以使用@JsonManagedReference@JsonBackReference,但是,它仅是一种硬编码的解决方案,在这种情况下,所有者总是引用所有者,而不是相反。如果您有另一种序列化方案,需要以不同的方式重新注释属性,则将无法执行此操作。

问题

现在让我们使用两个班,CompanyEmployee在那里你有它们之间的循环依赖:

public class Company {

    private Employee employee;

    public Company(Employee employee) {
        this.employee = employee;
    }

    public Employee getEmployee() {
        return employee;
    }
}

public class Employee {

    private Company company;

    public Company getCompany() {
        return company;
    }

    public void setCompany(Company company) {
        this.company = company;
    }
}

以及尝试使用ObjectMapperSpring Boot)进行序列化的测试类:

@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class CompanyTest {

    @Autowired
    public ObjectMapper mapper;

    @Test
    public void shouldSaveCompany() throws JsonProcessingException {
        Employee employee = new Employee();
        Company company = new Company(employee);
        employee.setCompany(company);

        String jsonCompany = mapper.writeValueAsString(company);
        System.out.println(jsonCompany);
        assertTrue(true);
    }
}

如果运行此代码,您将获得:

org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError)

使用`@ JsonView`的解决方案

@JsonView使您可以使用过滤器并选择在序列化对象时应包括哪些字段。过滤器只是用作标识符的类引用。因此,让我们首先创建过滤器:

public class Filter {

    public static interface EmployeeData {};

    public static interface CompanyData extends EmployeeData {};

} 

请记住,过滤器是伪类,仅用于通过@JsonView注释指定字段,因此您可以根据需要创建任意多个。让我们来看一下它的作用,但是首先我们需要注释我们的Company类:

public class Company {

    @JsonView(Filter.CompanyData.class)
    private Employee employee;

    public Company(Employee employee) {
        this.employee = employee;
    }

    public Employee getEmployee() {
        return employee;
    }
}

并更改测试以使序列化程序使用视图:

@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional
public class CompanyTest {

    @Autowired
    public ObjectMapper mapper;

    @Test
    public void shouldSaveCompany() throws JsonProcessingException {
        Employee employee = new Employee();
        Company company = new Company(employee);
        employee.setCompany(company);

        ObjectWriter writter = mapper.writerWithView(Filter.CompanyData.class);
        String jsonCompany = writter.writeValueAsString(company);

        System.out.println(jsonCompany);
        assertTrue(true);
    }
}

现在,如果您运行此代码,则可以解决“无限递归”问题,因为您已经明确表示只想序列化使用注释的属性@JsonView(Filter.CompanyData.class)

当到达中的company的后向引用时Employee,它将检查是否未加注释,并忽略序列化。您还具有强大而灵活的解决方案,可以选择要通过REST API发送的数据。

使用Spring,您可以使用所需的@JsonView过滤器注释REST Controllers方法,并将序列化透明地应用于返回的对象。

这是您需要检查的导入文件:

import static org.junit.Assert.assertTrue;

import javax.transaction.Transactional;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;

import com.fasterxml.jackson.annotation.JsonView;

1
这是一个很好的文章,解释许多可选择的解决方案来解决递归:baeldung.com/...
雨果BAES

5

答案就是 @JsonIgnoreProperties

使用这样的东西::

@OneToMany(mappedBy = "course",fetch=FetchType.EAGER)
@JsonIgnoreProperties("course")
private Set<Student> students;

我已经看到Jhipster在其生成的代码中使用了它,因此请放心使用它
ifelse.codes

感谢您的回答。但是,我发现@JsonManagedReference@JsonBackReference并不会为您提供与@OneToMany@ManyToOne场景关联的数据,使用时也会@JsonIgnoreProperties跳过关联的实体数据。如何解决呢?
Pra_A

4

就我而言,将关系从以下位置更改就足够了:

@OneToMany(mappedBy = "county")
private List<Town> towns;

至:

@OneToMany
private List<Town> towns;

另一个关系保持不变:

@ManyToOne
@JoinColumn(name = "county_id")
private County county;

2
我认为最好使用Kurt的解决方案。因为JoinColumn解决方案可以以未引用的数据无效主体结尾。
flosk14 2014年

1
实际上,这是唯一帮助我的事情。高层没有其他解决方案。我仍然不确定为什么...
Deniss M.

4

确保在任何地方都使用com.fasterxml.jackson。我花了很多时间来找出答案。

<properties>
  <fasterxml.jackson.version>2.9.2</fasterxml.jackson.version>
</properties>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>${fasterxml.jackson.version}</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>${fasterxml.jackson.version}</version>
</dependency>

然后使用@JsonManagedReference@JsonBackReference

最后,您可以将模型序列化为JSON:

import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(model);

4

您可以使用@JsonIgnore,但这将忽略由于外键关系而可以访问的json数据。因此,如果您需要重新构造外键数据(大多数时候我们需要),那么@JsonIgnore将无济于事。在这种情况下,请遵循以下解决方案。

您将获得无限递归,因为BodyStat类再次引用了Trainee对象

身体状态

@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name="trainee_fk")
private Trainee trainee;

实习生

@OneToMany(mappedBy = "trainee", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@Column(nullable = true)
private Set<BodyStat> bodyStats;

因此,你必须要评论/省略上面的部分 见习


1
就我而言,它不起作用。您可以看看:github.com/JavaHelper/issue-jackson-boot吗?
Pra_A

3

我也遇到了同样的问题。我使用@JsonIdentityInfoObjectIdGenerators.PropertyGenerator.class生成器类型。

那是我的解决方案:

@Entity
@Table(name = "ta_trainee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id"})})
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Trainee extends BusinessObject {
...

2
好的答案
LAGRIDA

1
我会回答同样的事情!!!尼斯;)
Felipe Desiderati

3

您应该将@JsonBackReference与@ManyToOne实体一起使用,并将@JsonManagedReference与@onetomany包含实体类一起使用。

@OneToMany(
            mappedBy = "queue_group",fetch = FetchType.LAZY,
            cascade = CascadeType.ALL
        )
    @JsonManagedReference
    private Set<Queue> queues;



@ManyToOne(cascade=CascadeType.ALL)
        @JoinColumn(name = "qid")
       // @JsonIgnore
        @JsonBackReference
        private Queue_group queue_group;

如果我在子级中添加@ jsonIgnore批注。当我试图带孩子时,我无法从孩子那里获得父对象。为什么父对象不来,它会被@ jsonignore忽略。告诉我如何从孩子到父母以及从父母到孩子。
Kumaresan Perumal

无需使用@JsonIgnore即可使用上面的注释,并通过使用Getter和setter获取父级和子级的objets。Jsonignore也这样做,但是会产生无限递归。如果您共享您的代码,那么我可以检查为什么您没有得到对象。因为对我来说,两者都来了。
Shubham

我的意思是。当父母。父对象应带有子对象。拿孩子对象时。孩子应该和父母一起来。在这种情况下,它不起作用。请你帮助我好吗?
Kumaresan Perumal

1

您可以使用DTO模式创建类TraineeDTO而无需任何注释休眠,并且可以使用jackson映射器将Trainee转换为TraineeDTO并宾果错误消息disapeare :)


1

如果您不能忽略该属性,请尝试修改该字段的可见性。在我们的例子中,我们有旧代码仍在提交具有关系的实体,因此在我的例子中,这就是解决方法:

    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private Trainee trainee;

如果我在子级中添加@ jsonIgnore批注。当我试图带孩子时,我无法从孩子那里获得父对象。为什么父对象不来,它会被@ jsonignore忽略。告诉我如何从孩子到父母以及从父母到孩子。
Kumaresan Perumal

0

我遇到了这个问题,但是我不想在我的实体中使用注释,因此我通过为我的类创建一个构造函数来解决该构造函数必须不能返回引用该实体的实体的引用。假设这种情况。

public class A{
   private int id;
   private String code;
   private String name;
   private List<B> bs;
}

public class B{
   private int id;
   private String code;
   private String name;
   private A a;
}

如果您尝试将类BA与其一起发送到视图,@ResponseBody则可能导致无限循环。您可以在您的类中编写构造函数,并使用entityManager类似的方法创建查询。

"select new A(id, code, name) from A"

这是带有构造函数的类。

public class A{
   private int id;
   private String code;
   private String name;
   private List<B> bs;

   public A(){
   }

   public A(int id, String code, String name){
      this.id = id;
      this.code = code;
      this.name = name;
   }

}

但是,如您所见,此解决方案有一些限制,在构造函数中,我没有引用List bs,这是因为Hibernate至少在3.6.10.Final版本中不允许这样,所以当我需要时为了在视图中显示两个实体,我执行以下操作。

public A getAById(int id); //THE A id

public List<B> getBsByAId(int idA); //the A id.

此解决方案的另一个问题是,如果添加或删除属性,则必须更新构造函数和所有查询。


0

如果您使用的是Spring Data Rest,则可以通过为循环引用中涉及的每个实体创建存储库来解决问题。


0

我来晚了,已经很长了。但是我也花了几个小时试图弄清楚这一点,并举另一个例子。

我尝试了JsonIgnore,JsonIgnoreProperties和BackReference解决方案,但奇怪的是,好像它们没有被使用。

我使用了Lombok,并认为可能会造成干扰,因为它创建了构造函数并覆盖了toString(在stackoverflowerror堆栈中看到了toString)。

最终,这不是Lombok的错-我使用NetBeans从数据库表自动生成JPA实体,而没有考虑太多-很好,添加到生成的类中的注释之一是@XmlRootElement。一旦删除它,一切便开始工作。那好吧。


0

关键是将@JsonIgnore放置在setter方法中,如下所示。就我而言。

Township.java

@Access(AccessType.PROPERTY)
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name="townshipId", nullable=false ,insertable=false, updatable=false)
public List<Village> getVillages() {
    return villages;
}

@JsonIgnore
@Access(AccessType.PROPERTY)
public void setVillages(List<Village> villages) {
    this.villages = villages;
}

Village.java

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "townshipId", insertable=false, updatable=false)
Township township;

@Column(name = "townshipId", nullable=false)
Long townshipId;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.