본문 바로가기
IT

JSON 동적 필드 처리 – Jackson @JsonAnySetter 완전 이해하기

by urosie 2025. 12. 10.
반응형

API 연동을 하다 보면 응답 JSON의 구조가 일정하지 않은 경우가 많다.
예를 들어 아래처럼 DATA 안의 필드가 매번 달라지는 스타일이다.

{
  "DATA": [
    {
      "A": "10",
      "B": "20",
      "X1": "100",
      "X2": "abc"
    }
  ]
}
 

이런 형태는 DTO에 필드를 고정으로 박아 둘 수 없다.
그래서 동적 필드(dynamic fields)를 Map으로 수집하는 방식이 필요하고,
Jackson에서는 이를 위해 @JsonAnySetter라는 강력한 기능을 제공한다.


1. @JsonAnySetter로 동적 필드 수집하기

가장 간단한 DTO는 아래처럼 만든다.

@Getter
@Setter
public class MyDto {

    private final Map<String, Object> fields = new HashMap<>();

    @JsonAnySetter
    public void setFields(String key, Object value) {
        fields.put(key, value);
    }
}
 

동작 방식 핵심

  • JSON에서 MyDto 클래스에 존재하지 않는 필드가 들어오면
    Jackson은 setFields(key, value)를 호출한다.
  • 그래서 DATA 안에 어떤 이름의 필드가 오든 모두 fields Map에 들어간다.
  • DTO에 필드가 하나도 없어도 문제 없다.
    Jackson은 "모르는 키"를 전부 이 Map에 넣어준다.

결과적으로 MyDto는 완전한 동적 구조를 가진 DTO가 된다.
API 응답의 스키마가 달라져도 DTO를 수정할 필요가 없다.


2. 배열(DATA) 매핑 – TypeReference 필수

DATA가 배열이라면 아래처럼 변환한다.

ObjectMapper mapper = new ObjectMapper();

List<MyDto> list = mapper.readValue(
        dataArray.toString(),
        new TypeReference<List<MyDto>>() {}
);
 

여기서 중요한 건 TypeReference<List<MyDto>>() {} 부분이다.

왜 TypeReference가 필요한가?

자바는 제네릭 정보를 런타임에 삭제한다(Type Erasure).
그래서 단순히 List.class만 넘기면 Jackson은
“리스트 안에 뭐가 들어가는지” 판단할 수 없다.

결과적으로 List<Map> 형태로 만들어버린다.

TypeReference<List<MyDto>>() {}는 런타임에도
List<MyDto>라는 타입 정보를 보존하는 객체다.

그래서 반드시 이 방식으로 매핑해야 한다.


3. DATA가 빈 배열일 때 처리

DATA가 빈 배열이면 List<MyDto>도 비어 있는 리스트가 된다.

{
  "DATA": []
}
 

이건 정상 동작이다.
문제 없이 아래와 같이 처리되기 때문이다.

if (list.isEmpty()) {
    // DATA 없음 → 원하는 로직만 처리하면 된다.
}
 

예외는 발생하지 않는다.
빈 배열은 그냥 빈 List로 끝난다.


4. 왜 @JsonAnySetter 방식이 실무에서 유용한가?

동적 필드를 그대로 Map에 받는 구조는
API 스키마가 자주 바뀌는 환경에서 특히 강력하다.

  • 필드 추가돼도 DTO 수정 필요 없음
  • 필드 이름이 매번 바뀌어도 문제 없음
  • JSON 구조가 변해도 안정적으로 파싱됨
  • 유지보수 비용이 아주 낮음

실제로 여러 공공 API, 외부 B2B API, 로그성 데이터 파싱에서도
이 패턴이 가장 많이 쓰인다.


정리

오늘 구현한 구조의 핵심은 두 가지다.

  1. @JsonAnySetter → DTO에 없는 필드도 모두 Map으로 안전하게 수집
  2. TypeReference<List<MyDto>> → 동적 DTO 리스트를 정확하게 매핑

이 조합을 쓰면 JSON 구조가 비정형적이어도 DTO를 바꾸지 않고 안정적으로 처리할 수 있다.

API 스키마가 자주 바뀌거나, KEY 숫자가 많거나, 예측 불가능한 응답을 다뤄야 한다면
이 방식이 가장 안전하고 유지보수도 편하다.

반응형

댓글