Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java Jackson의 @JsonManagedReference와 @JsonBackReference 어노테이션 활용 가이드

Java에서 객체 간 양방향(bidirectional) 관계를 JSON으로 직렬화할 때, 순환 참조로 인해 무한 루프가 발생하거나 원치 않는 데이터가 출력되는 문제가 자주 생깁니다. 이럴 때 유용하게 쓸 수 있는 것이 바로 Jackson 라이브러리의 @JsonManagedReference@JsonBackReference 어노테이션입니다.

두 어노테이션의 역할

@JsonManagedReference순방향 참조(forward reference)를 나타내며, 직렬화 과정에서 해당 필드가 정상적으로 포함됩니다. 반면 @JsonBackReference역방향 참조(back reference)를 나타내며, 직렬화 시 이 필드는 생략(omitted)됩니다. 즉, 부모-자식 관계처럼 서로를 참조하는 구조에서 한쪽 방향만 JSON에 노출시켜 무한 재귀를 방지할 수 있습니다.

예제 코드

아래 예제를 통해 두 어노테이션의 실제 동작을 확인해 보겠습니다.

import java.util.*;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
public class ManagedReferenceBackReferenceTest {
    public static void main(String args[]) throws JsonProcessingException {
        BackReferenceBeanTest testBean = new BackReferenceBeanTest(110, "Sai Chaitanya");
        ManagedReferenceBeanTest bean = new ManagedReferenceBeanTest(135, "Adithya Ram", testBean);
        testBean.addEmployees(bean);
        ObjectMapper mapper = new ObjectMapper();
        String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(bean);
        System.out.println(jsonString);
    }
}
class ManagedReferenceBeanTest {
    public int empId = 115;
    public String empName = "Raja Ramesh";
    @JsonManagedReference
    public BackReferenceBeanTest manager;
    public ManagedReferenceBeanTest(int empId, String empName, BackReferenceBeanTest manager) {
        this.empId = empId;
        this.empName = empName;
        this.manager = manager;
    }
}
class BackReferenceBeanTest {
    public int empId = 125;
    public String empName = "Jai Dev";
    @JsonBackReference
    public List<ManagedReferenceBeanTest> list;
    public BackReferenceBeanTest(int empId, String empName) {
        this.empId = empId;
        this.empName = empName;
        list = new ArrayList<ManagedReferenceBeanTest>();
    }
    public void addEmployees(ManagedReferenceBeanTest managedReferenceBeanTest) {
        list.add(managedReferenceBeanTest);
    }
}

실행 결과

{
    "empId" : 135,
    "empName" : "Adithya Ram",
    "manager" : {
        "empId" : 110,
        "empName" : "Sai Chaitanya"
    }
}

결과 분석

출력 결과를 보면 직원(Employee) 객체인 beanmanager 필드(@JsonManagedReference 적용)를 통해 관리자 정보를 정상적으로 포함하고 있습니다. 하지만 관리자 객체 내부의 list 필드(@JsonBackReference 적용), 즉 다시 직원 목록을 참조하는 부분은 JSON에서 제외된 것을 확인할 수 있습니다.

만약 두 어노테이션을 사용하지 않았다면, 직원 → 관리자 → 직원 → 관리자... 로 이어지는 무한 순환 참조가 발생해 StackOverflowError가 발생하거나 비정상적으로 거대한 JSON이 생성되었을 것입니다.

정리

  • @JsonManagedReference: 직렬화 시 포함되는 순방향 참조 (부모 쪽 필드)
  • @JsonBackReference: 직렬화 시 생략되는 역방향 참조 (자식 쪽 필드)

양방향 관계가 있는 엔티티를 REST API 응답 등으로 변환할 때 이 두 어노테이션을 함께 사용하면, 순환 참조 문제를 깔끔하게 해결하고 의도한 JSON 구조를 만들 수 있습니다.