You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+Hibernate多对多关联返回JSON时触发StackOverflowException

解决Spring Boot+Hibernate多对多关联JSON序列化循环引用及完整双向数据返回问题

方案1:使用@JsonIdentityInfo识别对象身份

这个注解让Jackson在序列化时识别对象的唯一ID,遇到循环引用时会用ID代替重复的对象实例,双向关联的字段都能被正常序列化。

在GiftCertificate和Tag实体类上都添加该注解:

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class GiftCertificate {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @ManyToMany(mappedBy = "giftCertificates")
    private Set<Tag> tags = new HashSet<>();
    
    // getter、setter、构造方法
}
@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Tag {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @ManyToMany
    @JoinTable(
        name = "gift_certificate_tag",
        joinColumns = @JoinColumn(name = "tag_id"),
        inverseJoinColumns = @JoinColumn(name = "gift_certificate_id")
    )
    private Set<GiftCertificate> giftCertificates = new HashSet<>();
    
    // getter、setter、构造方法
}

特点:实现简单,无需额外类;但序列化后的JSON中,重复出现的对象会被替换为ID,适合能接受这种格式的场景。

方案2:使用DTO(数据传输对象)解耦实体与返回结构

这是更规范的做法,通过定义专门的DTO类控制返回的JSON结构,彻底避免循环引用,同时灵活定制返回字段。

首先创建DTO类:

public class GiftCertificateDTO {
    private Long id;
    private String name;
    private Set<TagDTO> tags;
    
    // 构造方法、getter、setter
}

public class TagDTO {
    private Long id;
    private String name;
    private Set<GiftCertificateDTO> giftCertificates;
    
    // 构造方法、getter、setter
}

然后在业务层或控制器中完成实体到DTO的转换:

// 示例转换方法
public GiftCertificateDTO convertToDTO(GiftCertificate certificate) {
    GiftCertificateDTO dto = new GiftCertificateDTO();
    dto.setId(certificate.getId());
    dto.setName(certificate.getName());
    dto.setTags(certificate.getTags().stream()
        .map(tag -> {
            TagDTO tagDTO = new TagDTO();
            tagDTO.setId(tag.getId());
            tagDTO.setName(tag.getName());
            // 按需处理关联字段,避免无限循环
            tagDTO.setGiftCertificates(tag.getGiftCertificates().stream()
                .map(cert -> {
                    GiftCertificateDTO certDTO = new GiftCertificateDTO();
                    certDTO.setId(cert.getId());
                    certDTO.setName(cert.getName());
                    return certDTO;
                }).collect(Collectors.toSet()));
            return tagDTO;
        }).collect(Collectors.toSet()));
    return dto;
}

在控制器中返回DTO:

@GetMapping("/certificates/{id}")
public ResponseEntity<GiftCertificateDTO> getCertificate(@PathVariable Long id) {
    GiftCertificate certificate = certificateRepository.findById(id).orElseThrow();
    return ResponseEntity.ok(convertToDTO(certificate));
}

特点:完全解耦数据库实体与API返回结构,灵活度高;需要额外编写DTO和转换代码,适合复杂API场景。

方案3:使用@JsonIgnoreProperties忽略对方的关联字段

在双向关联的字段上指定忽略对方的关联属性,Jackson序列化时不会递归处理对方的关联集合,既避免循环引用,又保留自身的关联字段。

修改实体类:

@Entity
public class GiftCertificate {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @ManyToMany(mappedBy = "giftCertificates")
    @JsonIgnoreProperties("giftCertificates") // 忽略Tag中的giftCertificates字段
    private Set<Tag> tags = new HashSet<>();
    
    // getter、setter、构造方法
}
@Entity
public class Tag {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @ManyToMany
    @JoinTable(
        name = "gift_certificate_tag",
        joinColumns = @JoinColumn(name = "tag_id"),
        inverseJoinColumns = @JoinColumn(name = "gift_certificate_id")
    )
    @JsonIgnoreProperties("tags") // 忽略GiftCertificate中的tags字段
    private Set<GiftCertificate> giftCertificates = new HashSet<>();
    
    // getter、setter、构造方法
}

特点:实现简单,无需额外代码;序列化后的JSON会包含双方的关联字段,但不会递归深入,适合需要完整双向关联字段但不需要无限递归的场景。

内容的提问来源于stack exchange,提问作者Redoge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 13:17:31