개발자로서 살아남기

서버개발자로서 살아남기- spring json 라이브러리 어노테이션 부수기

코드 살인마 2025. 8. 18. 21:27
728x90

아래와 같은 Json 관련 어노테이션이 있다.
아래 어노테이션을 상세분석 해보자

@JsonIgnoreProperties(ignoreUnknown = true)  
@JsonInclude(Include.NON_NULL)  
@JsonAutoDetect  
@JsonPropertyOrder(alphabetic = true)  
@JsonRootName(value = "result")

Jackson 어노테이션 상세 분석

@JsonIgnoreProperties(ignoreUnknown = true)

@JsonIgnoreProperties(ignoreUnknown = true)
  • 목적: JSON 역직렬화 시 알 수 없는 속성을 무시
  • 동작: JSON에 클래스에 정의되지 않은 필드가 있어도 예외를 발생시키지 않고 무시
  • 예시: JSON에 "unknownField": "value"가 있어도 오류 없이 처리

실제 코드 예시

public class StickerView extends BaseView {
    private String name;
    private String category;
}

정상적인 JSON (모든 필드가 클래스에 정의됨)

{
  "name": "cute_cat",
  "category": "animal"
}
// 성공적으로 역직렬화됨
StickerView sticker = objectMapper.readValue(json, StickerView.class);
System.out.println(sticker.getName());     // "cute_cat"
System.out.println(sticker.getCategory()); // "animal"

알 수 없는 필드가 포함된 JSON

{
  "name": "cute_cat",
  "category": "animal",
  "unknownField": "someValue",
  "extraData": {
    "id": 123,
    "metadata": "test"
  },
  "anotherUnknownField": true
}

@JsonIgnoreProperties(ignoreUnknown = true) 있을 때

// ✅ 성공: 알 수 없는 필드들은 무시하고 정상 처리
StickerView sticker = objectMapper.readValue(json, StickerView.class);
System.out.println(sticker.getName());     // "cute_cat"
System.out.println(sticker.getCategory()); // "animal"
// unknownField, extraData, anotherUnknownField는 무시됨

@JsonIgnoreProperties(ignoreUnknown = true) 없을 때

// ❌ 실패: UnrecognizedPropertyException 발생
try {
    StickerView sticker = objectMapper.readValue(json, StickerView.class);
} catch (UnrecognizedPropertyException e) {
    // 에러 메시지: "Unrecognized field 'unknownField'"
    System.err.println("JSON 역직렬화 실패: " + e.getMessage());
}

실용적인 활용 사례

API 버전 호환성

// 구버전 클라이언트가 신규 필드를 포함한 JSON 전송
// 서버는 알 수 없는 필드를 무시하고 정상 처리

외부 API 연동

// 외부 API 응답에 예상하지 못한 필드가 추가되어도
// 필요한 데이터만 추출하여 안정적으로 처리

로그 분석

// 클라이언트가 디버깅 정보나 메타데이터를 추가로 전송해도
// 서버 로직에는 영향을 주지 않음

결론: @JsonIgnoreProperties(ignoreUnknown = true)JSON에 클래스에 정의되지 않은 추가 필드가 있어도 오류 없이 무시하고, 정의된 필드만 정상적으로 매핑하는 역할을 합니다.

 

@JsonInclude(Include.NON_NULL)

@JsonInclude(Include.NON_NULL)
  • 목적: JSON 직렬화 시 null 값인 필드를 제외
  • 동작: 객체를 JSON으로 변환할 때 null 값을 가진 속성은 JSON에 포함하지 않음
  • 효과: JSON 크기 감소 및 불필요한 null 값 제거

해당 어노테이션을 사용하면, 상속받는 객체도 포함하여, non-null 값 필드를 제외한다.

 

BaseView를 상속받는 클래스

public class StickerView extends BaseView {
    private String name;
    private String description;
    private Integer count;

    // getters/setters...
}

객체 생성 및 JSON 변환

StickerView sticker = new StickerView();
sticker.setName("cute_cat");        // non-null
sticker.setDescription(null);       // null
sticker.setCount(10);              // non-null

// JSON 직렬화 결과
{
  "count": 10,
  "name": "cute_cat"
  // description은 null이므로 제외됨
}

 

@JsonAutoDetect

@JsonAutoDetect
  • 목적: 필드, getter/setter 메서드의 자동 감지 설정
  • 기본 동작: public 필드와 getter/setter를 자동으로 JSON 속성으로 인식
  • 장점: 별도의 @JsonProperty 어노테이션 없이도 자동 매핑

 

@JsonPropertyOrder(alphabetic = true)

@JsonPropertyOrder(alphabetic = true)
  • 목적: JSON 출력 시 속성 순서를 알파벳 순으로 정렬
  • 동작: 필드명을 A-Z 순서로 정렬하여 JSON 생성
  • 장점: 일관된 JSON 구조, 테스트 시 예측 가능한 순서

 

@JsonRootName(value = "result")

@JsonRootName(value = "result")
  • 목적: JSON 루트 레벨에 wrapper 객체 생성
  • 동작: JSON을 {"result": {실제객체내용}} 형태로 감쌈
  • 주의: ObjectMapper에서 WRAP_ROOT_VALUE 설정이 활성화되어야 동작

실제 JSON 출력 예시

// BaseView 객체
BaseView view = new BaseView();
view.setName("test");
view.setDescription(null);
view.setAge(25);

// 결과 JSON (@JsonRootName 미적용 시)
{
  "age": 25,
  "name": "test"
  // description은 null이므로 제외됨
  // 필드들이 알파벳 순으로 정렬됨
}

// @JsonRootName 적용 시
{
  "result": {
    "age": 25,
    "name": "test"
  }
}

이러한 어노테이션들은 API 응답의 일관성과 크기 최적화를 위해 사용되며, 특히 REST API에서 표준화된 JSON 응답 형식을 만들 때 유용하다.