Spring Boot에서 Java record를 활용한 DTO 설계법 (feat. JSON 직렬화)
2025. 5. 18. 19:08
728x90

Spring Boot에서 Java record를 DTO로 사용하는 방법

Spring Boot 프로젝트에서 데이터를 주고받는 DTO(Data Transfer Object)를 정의할 때, Java 16부터 정식 도입된 record를 활용하면 더 간결하고 명확한 코드를 작성할 수 있습니다. 본 글에서는 record란 무엇인지, DTO로 사용할 때의 장점과 주의사항을 정리합니다.


record란 무엇인가?

record는 Java에서 불변 데이터 구조를 간결하게 표현할 수 있도록 도입된 키워드입니다. 흔히 DTO처럼 데이터를 담기만 하는 클래스에 적합합니다.

public record UserDTO(String name, int age) {}

위 한 줄의 코드는 다음과 같은 클래스와 동일한 기능을 합니다:

public class UserDTO {
    private final String name;
    private final int age;

    public UserDTO(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String name() { return name; }
    public int age() { return age; }

    @Override
    public String toString() { return ... }
    @Override
    public boolean equals(Object o) { return ... }
    @Override
    public int hashCode() { return ... }
}

Spring Boot에서 DTO로 record를 사용할 때의 장점

항목 설명
코드 간결성 생성자, getter, equals, hashCode 등을 자동 생성
불변성 보장 모든 필드는 final, setter 없음
직렬화 호환 Spring에서 @RequestBody, @ResponseBody에 기본적으로 잘 작동
유지보수 용이 DTO의 구조를 직관적으로 파악 가능

실전 예제: 회원 가입 요청 DTO로 사용하기

1. record 기반 Request DTO 정의

public record RegisterUserRequest(String email, String password, String name) {}

2. Controller에서 사용

@PostMapping("/register")
public ResponseEntity<String> register(@RequestBody RegisterUserRequest request) {
    userService.register(request.email(), request.password(), request.name());
    return ResponseEntity.ok("회원가입 완료");
}

주의할 점

1. Setter가 없다

record는 불변(immutable) 객체이므로 setter가 없습니다. 필드 수정이 필요한 경우 class를 사용하세요.

2. 기본 생성자 없음

기본 생성자가 없기 때문에 Jackson이 JSON → Object 변환 시 모든 필드를 정확히 매칭해야 합니다. 아래 JSON과 필드명이 달라지면 오류가 발생합니다:

{
  "email": "test@example.com",
  "password": "secure123",
  "name": "John Doe"
}

3. Lombok과 혼용 불가

@Builder, @NoArgsConstructor 같은 Lombok 어노테이션은 record에 사용할 수 없습니다. 생성자나 빌더가 필요한 경우 class를 사용하세요.


언제 record를 DTO에 쓰면 좋은가?

추천 사용처:

  • Controller의 입력/출력 DTO
  • 조회 전용 Query DTO
  • 변형 없이 전달만 하는 계층 간 데이터

지양할 곳:

  • 상태 변화가 필요한 Command 객체
  • 빌더 패턴이 필요한 복잡한 생성 구조

실무에서는 record를 사용할까?

 사용되는 경우

  • 조회 전용 응답 DTO
    • REST API의 출력 전용 데이터에 적합
    • ex) ProductSummary, UserProfileView
  • 단순 요청 DTO
    • 수정이 필요 없는 @RequestBody용 객체

 사용이 어려운 경우

  • 상태 변경이 필요한 객체 (Command 등)
  • 복잡한 생성자나 Lombok @Builder가 필요한 경우
  • 엔티티(Entity) → JPA에서 record는 지원되지 않음

 실제 기업 사례

  • Java 17 이상을 도입한 기업에서는 점진적으로 도입 중
  • 쿠팡, 배달의민족 등 일부 기업에서 조회 응답 DTO 위주로 활용

 정리

상황 record 사용 여부 비고
REST API 응답 DTO 사용 권장 간결하고 직관적
단순 요청(Request) DTO 조건부 사용 JSON 필드 일치 필요
DB Entity 사용 지양 JPA 미지원
상태 변경이 필요한 객체 사용 지양 불변성 문제
Builder 패턴 필요한 경우 사용 불가 일반 class 사용

 


마치며

Spring Boot에서 DTO를 정의할 때 record는 불변성과 간결함을 동시에 잡을 수 있는 좋은 도구입니다. 다만, 모든 상황에 적합한 것은 아니며 쓰임새에 따라 class와 record를 적절히 나누어 사용하는 것이 중요합니다.

Spring Boot + Java 17 이상 환경이라면, DTO 작성의 기본값으로 record를 도입해보는 것도 추천드립니다.

728x90