Jackson 库进行 JSON 序列化时遇到了 ‌无限递归(Infinite Recursion)‌ 问题

使用 Jackson 库进行 JSON 序列化时遇到了 ‌无限递归(Infinite Recursion)‌ 问题,这是因为两个实体类 ComPointQuotaEntity 和 ComPointEntity 之间存在双向关联(point 和 pointQuota 相互引用),导致序列化时陷入死循环。以下是解决方案:

解决方案‌

1. 使用 @JsonIgnore 忽略一个方向的引用

在其中一个实体类的关联字段上添加 @JsonIgnore 注解,直接阻止某一方的序列化:

// ComPointQuotaEntity.java
public class ComPointQuotaEntity {
    @ManyToOne
    @JoinColumn(name = "point_id")
    private ComPointEntity point;  // 保留此字段的序列化
    // 其他字段...
}

// ComPointEntity.java
public class ComPointEntity {
    @OneToMany(mappedBy = "point")
    @JsonIgnore  // 忽略此字段的序列化
    private List<ComPointQuotaEntity> pointQuota;
    // 其他字段...
}

2. 使用 @JsonManagedReference@JsonBackReference

通过注解明确父子关系,Jackson 会序列化父级(@JsonManagedReference),但忽略子级(@JsonBackReference):

// ComPointQuotaEntity.java
public class ComPointQuotaEntity {
    @ManyToOne
    @JoinColumn(name = "point_id")
    @JsonManagedReference  // 标记为父级(序列化)
    private ComPointEntity point;
    // 其他字段...
}

// ComPointEntity.java
public class ComPointEntity {
    @OneToMany(mappedBy = "point")
    @JsonBackReference  // 标记为子级(不序列化)
    private List<ComPointQuotaEntity> pointQuota;
    // 其他字段...
}

3. 使用 DTO 替代直接序列化实体

创建 Data Transfer Object (DTO),只暴露需要的字段,避免直接序列化 JPA 实体:

public class ComPointQuotaDTO {
    private Long id;
    private ComPointDTO point;  // 避免双向引用
    // 其他字段...
}

public class ComPointDTO {
    private Long id;
    // 不包含 pointQuota 字段
    // 其他字段...
}

4. 配置 Jackson 忽略循环引用

在 application.properties 或 application.yml 中配置 Jackson:

# application.properties
spring.jackson.serialization.fail-on-empty-beans=false
spring.jackson.serialization.fail-on-self-references=false

或在代码中配置 ObjectMapper:

@Configuration
public class JacksonConfig {
    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper()
            .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
            .configure(SerializationFeature.FAIL_ON_SELF_REFERENCES, false);
    }
}

5. 自定义序列化器(高级)

为关联字段自定义序列化逻辑,跳过循环引用:

public class ComPointQuotaEntity {
    @ManyToOne
    @JoinColumn(name = "point_id")
    @JsonSerialize(using = ComPointEntitySerializer.class)
    private ComPointEntity point;
    // 其他字段...
}

public class ComPointEntitySerializer extends JsonSerializer<ComPointEntity> {
    @Override
    public void serialize(ComPointEntity value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if (value != null) {
            gen.writeStartObject();
            gen.writeNumberField("id", value.getId());
            // 仅序列化需要的字段,跳过 pointQuota
            gen.writeEndObject();
        }
    }
}

总结‌

  • 推荐方案 2(@JsonManagedReference 和 @JsonBackReference)‌:简单且能保持双向关联。
    ‌>- 推荐方案 3(DTO)‌:彻底解耦序列化逻辑与数据库实体,适合复杂场景。
  • 避免直接序列化 JPA 实体,尤其是涉及双向关联时。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王小工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值