개발/TIL

RestController 의 응답 객체가 직렬화되는 방법

ebang 2025. 7. 21. 22:09

정리 :

Spring Controller에서 리턴하는 객체는 Jackson을 사용하여 HttpMessageConverter가 JSON 문자열로 자동 변환함. 

이 과정에서 사용되는 Jackson은 Java Bean 규약 기반으로 직렬화하므로, 필드에 접근하기 위한 방법(getter/@JsonProperty)이 필요하다. 

 

1. Spring의 직렬화 흐름 개요

예시 컨트롤러:

@RestController
public class WorryController {

    @GetMapping("/worries")
    public WorryResponse getWorry() {
        return new WorryResponse(1L, "걱정");
    }
}

실행 흐름:

  1. @RestController → 내부적으로 @ResponseBody 붙은 것과 같음
  2. 리턴 값은 HttpMessageConverter에 의해 HTTP 응답 본문으로 변환됨
  3. 기본적으로 Spring Boot는 MappingJackson2HttpMessageConverter 사용 → 내부적으로 Jackson 사용
  4. Jackson은 Java 객체 → JSON 문자열로 변환하기 위해 BeanSerializer를 생성

 

🔍 2. Jackson의 직렬화 조건과 Bean 규칙

Jackson이 Java 객체를 직렬화하기 위해 사용하는 기본 규칙은 다음과 같다. 

Jackson의 직렬화 대상 조건

조건설명
public 클래스여야 함 내부적으로 reflection으로 접근할 수 있어야 함
필드에 대해 getter가 있거나, getXxx() 또는 isXxx()
@JsonProperty가 명시되어 있어야 함 명시적으로 JSON에 포함될 필드라는 것을 선언
 

즉, getter나 @JsonProperty가 없으면  InvalidDefinitionException 발생

직렬화 실패 클래스

public class WorryResponse {
    private Long id;
    private String content;

    public WorryResponse(Long id, String content) {
        this.id = id;
        this.content = content;
    }

    // getter 없음
}

 

→ No serializer found... 예외 발생
→ Jackson은 접근 가능한 속성이 없다고 판단

@JsonProperty로 명시해서 직렬화

public class WorryResponse {
    @JsonProperty
    private Long id;

    @JsonProperty
    private String content;

    public WorryResponse(Long id, String content) {
        this.id = id;
        this.content = content;
    }
}

→ @JsonProperty 덕분에 getter 없이도 직렬화 가능

 3. 왜 getter 혹은 @JsonProperty가 필요한가?

Jackson은 기본적으로 "Java Bean" 패턴을 따른다. 

Java Bean = private 필드 + public getter/setter

 

Jackson이 필드를 읽으려면:

  • 접근 가능한 public 메서드(getter)
  • 혹은 명시적으로 필드에 @JsonProperty 어노테이션이 붙어 있어야
  • 그렇지 않으면 보안상 private 필드에는 접근하지 않음

즉, 기본 정책이 안전과 표준을 위한 제한이기 때문에 명시적 정보가 필요하다. 

 

참고: 직렬화 커스터마이징 옵션

방법설명
@JsonProperty 특정 필드나 메서드를 JSON에 포함
@JsonIgnore 특정 필드 제외
@JsonInclude(Include.NON_NULL) null인 필드는 제외
@JsonNaming snake_case 등 네이밍 전략 변경