Spring Boot DTO 설계 및 JSON 역직렬화 가이드

KUKJIN LEE • 2일 전 작성
Spring Boot에서는 클라이언트가 보내는 JSON 데이터를 Java 객체(DTO)로 자동 변환하여 처리합니다. 이 과정을 JSON 역직렬화(deserialization)라고 합니다. 기본적으로 Spring Boot는 Jackson 라이브러리를 사용하여 이 작업을 수행합니다.
문제 상황: 역직렬화 오류
Spring Boot 애플리케이션에서 JSON 데이터를 DTO로 변환할 때 다음과 같은 오류가 발생
Cannot construct instance of `com.example.dto.SignIn`: no default constructor found.
이 오류의 원인은 다음 두 가지입니다:
-
DTO 클래스에 기본 생성자가 없음
-
DTO 클래스의 필드가 final로 선언되어 Jackson이 기본 생성자를 생성하지 못함
역직렬화의 기본 작동 방식
Spring Boot는 요청된 JSON 데이터를 다음과 같은 과정으로 Java 객체로 변환
-
JSON 데이터를 읽고 분석(parse)
-
분석한 데이터를 바탕으로 DTO 객체의 인스턴스를 생성
-
생성된 객체의 필드에 JSON 데이터 값을 매핑
이때, 객체 생성을 위해 기본 생성자(No-Args Constructor)를 사용합니다. 따라서 DTO 설계 시 주의
올바른 DTO 설계를 위한 가이드라인
방법 1: 기본적인 DTO 설계
가장 간단한 방법으로, DTO 클래스에 기본 생성자를 제공하고 final 필드를 사용하지 않는 방식
@Getter
@NoArgsConstructor // 기본 생성자 추가
@AllArgsConstructor
public class SignIn {
private String userId;
private String password;
private String remember;
}
장점: 구현이 간단하고 명확합니다.
단점: 객체의 불변성을 보장하지 못합니다.
final
필드는 Java에서 초기화 이후 값을 변경할 수 없는 필드. 즉, 객체가 한번 생성되면 그 값이 고정되어 변경이 불가능한(불변, immutable) 상태
setter로 값을 바꿀 수 없다는 게 final
필드의 핵심
방법 2: 불변성 유지 및 역직렬화 지원 (@JsonCreator 사용)
DTO 객체의 불변성을 유지하면서 역직렬화를 지원하려면 Jackson의 @JsonCreator
와 @JsonProperty
를 명시적으로 사용
@Getter
public class SignIn {
private final String userId;
private final String password;
private final String remember;
@JsonCreator
public SignIn(
@JsonProperty("userId") String userId,
@JsonProperty("password") String password,
@JsonProperty("remember") String remember
) {
this.userId = userId;
this.password = password;
this.remember = remember;
}
}
장점: 객체 불변성을 유지할 수 있습니다.
단점: JSON 속성을 생성자 파라미터와 정확히 매칭시켜야 합니다.
Spring Boot에서 DTO 클래스를 설계할 때 JSON 역직렬화 요구 사항을 항상 고려해야 합니다. 다음의 핵심 원칙을 기억하세요:
-
DTO 클래스에는 기본 생성자를 제공하거나 명시적 생성자(@JsonCreator)를 사용합니다.
-
불변성을 유지하려면 final 필드를 사용하되, 이 경우 반드시
@JsonCreator
와@JsonProperty
를 명시합니다. -
Lombok 사용 시 final 필드와 기본 생성자의 충돌을 주의합니다.