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

如何用Jackson注解避免双向OneToOne无限递归并获取关联实体指定属性

解决双向@OneToOne关联的JSON序列化需求

你可以通过以下几种方式实现期望的JSON输出,同时避免无限递归:

方法一:在Certificate中添加只读序列化字段(最直接)

直接在Certificate类中新增一个仅用于序列化的方法,屏蔽原有的Student关联字段,同时返回包含studentId的嵌套结构:

修改后的Certificate类:

@Entity
@Table(name = "certificate")    
public class Certificate {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int certificateId;

    @Column(name = "aknowledgment")
    private String aknowledgment;

    @OneToOne() 
    @JoinColumn(name="student_id", nullable= false)   
    @JsonIgnore // 屏蔽整个Student对象,避免递归
    private Student student;

    // 自定义序列化字段,返回仅含studentId的结构
    @JsonProperty("student")
    public Map<String, Integer> serializeStudentId() {
        Map<String, Integer> studentMap = new HashMap<>();
        studentMap.put("studentId", student.getStudentId());
        return studentMap;
    }

    // 省略原有getter、setter,注意不要给serializeStudentId添加setter
}

同时去掉Student类中的@JsonManagedReference注解,因为已经通过@JsonIgnore阻断了递归路径。

方法二:使用@JsonIdentityInfo识别对象身份

让Jackson通过对象ID识别重复引用,自动在重复序列化时只输出ID:

修改Student类:

@Entity
@Table(name = "student")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "studentId")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int studentId;

    @Column(name = "age")
    private int age;

    @Column(name = "mean")
    private double mean;

    @OneToOne(mappedBy="student" ,cascade = CascadeType.ALL)
    private Certificate certificate;

    // 省略getter、setter
}

修改Certificate类:

@Entity
@Table(name = "certificate")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "certificateId")
public class Certificate {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int certificateId;

    @Column(name = "aknowledgment")
    private String aknowledgment;

    @OneToOne() 
    @JoinColumn(name="student_id", nullable= false)   
    private Student student;

    // 省略getter、setter
}

序列化Student时,嵌套的Certificate中的Student会自动只输出studentId,符合你的期望结构。

方法三:使用@JsonView控制序列化范围

先定义视图接口:

public class SerializationViews {
    public static class BasicView {}
}

修改Student类,标记需要序列化的字段:

@Entity
@Table(name = "student")
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    @JsonView(SerializationViews.BasicView.class)
    private int studentId;

    @Column(name = "age")
    @JsonView(SerializationViews.BasicView.class)
    private int age;

    @Column(name = "mean")
    @JsonView(SerializationViews.BasicView.class)
    private double mean;

    @OneToOne(mappedBy="student" ,cascade = CascadeType.ALL)
    @JsonView(SerializationViews.BasicView.class)
    private Certificate certificate;

    // 省略getter、setter
}

修改Certificate类,自定义student字段的序列化:

@Entity
@Table(name = "certificate")    
public class Certificate {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    @JsonView(SerializationViews.BasicView.class)
    private int certificateId;

    @Column(name = "aknowledgment")
    @JsonView(SerializationViews.BasicView.class)
    private String aknowledgment;

    @OneToOne() 
    @JoinColumn(name="student_id", nullable= false)   
    private Student student;

    @JsonView(SerializationViews.BasicView.class)
    @JsonProperty("student")
    public Map<String, Integer> getStudentId() {
        Map<String, Integer> studentMap = new HashMap<>();
        studentMap.put("studentId", student.getStudentId());
        return studentMap;
    }

    // 省略其他getter、setter
}

最后在Controller接口上指定视图:

@GetMapping("/students/{id}")
@JsonView(SerializationViews.BasicView.class)
public Student getStudent(@PathVariable int id) {
    return studentRepository.findById(id).orElse(null);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 04:35:28