Spring에서 @RestController를 만들 때, 요청 객체(Request DTO) 안에 init {} 블록으로 유효성 검사를 넣는 경우가 종종 있다.
예를 들어 아래처럼 말이다.
data class MyRequest(
val name: String,
val age: Int
) {
init {
require(name.isNotBlank()) { "이름은 필수입니다." }
require(age > 0) { "나이는 1살 이상이어야 합니다." }
}
}
그리고 이렇게 작성하면 당연히 유효성 실패 시 @RestControllerAdvice에서 잡히겠거니… 했는데?
❗ 안 잡힌다???
🤔 왜 안 잡히는 걸까?
Spring은 요청 본문(@RequestBody)을 JSON → 객체로 바꾸는데 이 작업을
컨트롤러에 진입하기 전에 Jackson 등의 HttpMessageConverter에서 먼저 처리한다.
즉,
- JSON → 객체 변환 (여기서 init {} 실행됨)
- 이때 예외 발생 시 → Spring이 자체적으로 HttpMessageNotReadableException 같은 걸 던짐
- 우리가 만든 예외는 무시되고, @ExceptionHandler(MyCustomException::class)에서는 안 잡힘
✅ 해결 방법 3가지
1. Bean Validation을 쓰자 (@Valid, @NotBlank, etc.)
Spring 공식 추천 방식이다.
요청 객체에 애노테이션만 붙여도 자동 검증이 되고, 예외도 잘 잡힌다.
import jakarta.validation.constraints.*
data class MyRequest(
@field:NotBlank
val name: String,
@field:Min(1)
val age: Int
)
@PostMapping
fun create(@RequestBody @Valid request: MyRequest) {
// 여긴 유효한 요청만 옴
}
@ControllerAdvice에 MethodArgumentNotValidException 잡아서 예외 포맷 통일 가능.
2. 검증 로직은 init 말고 별도 validate() 함수로 빼기
DTO 생성 자체는 허용하되, 검증은 Controller나 Service에서 직접 호출한다.
data class MyRequest(val name: String?, val age: Int?) {
fun validate() {
require(!name.isNullOrBlank()) { "이름은 필수입니다." }
require(age != null && age > 0) { "나이는 1살 이상이어야 합니다." }
}
}
@PostMapping
fun create(@RequestBody request: MyRequest) {
request.validate() // 여기서 실패 시, 우리가 만든 예외 잘 잡힘
}
3. Controller 바깥 계층에서 검증 (도메인 규칙은 service 이후에서)
복잡한 비즈니스 검증은 DTO → 도메인 모델 변환 이후, Service 계층에서 처리하는 게 더 깔끔하다.
Request는 그저 데이터만 옮기는 "메신저" 역할로 두는 것.
🌱 결론
| 방법 | 장점 | 단점 |
| Bean Validation (@Valid) | 간편하고 Spring 기본방식 | 복잡한 조건 처리 어려움 |
| validate() 함수 분리 | 유연하게 검증 가능 | validate 호출 깜빡할 수 있음 |
| Service에서 검증 | 도메인 로직에 충실 | 단순한 필드검증에는 과함 |
🔚 마무리
init {}에서 예외 던지면 @RestControllerAdvice로 못 잡는다.
검증은 Controller 이후에서 하자!
'삽질인가 고찰인가' 카테고리의 다른 글
| [눈길을 끈 신문 사설] "AI 코딩의 오류 수정할 인재가 사라진다" : AI 때문에 취업도 안되고, 기존 개발자도 바보가 되고, 몸값 높은 개발자 되려면 이래야 한다? (1) | 2025.11.08 |
|---|---|
| 주석에 대하여. 코드에 주석을 쓰냐마냐? 아니 제발 쓰자. 잘! (1) | 2025.09.02 |
| 알고리즘 하기 싫어) VS Code 확장팩들 (추가중. 추천 받음) (7) | 2025.07.17 |
| 알고리즘 하기 싫어) 코틀린 개발을 위한 VS Code 환경구축. 레슨1 - Hello World (6) | 2025.07.17 |
| 🌏 타임존을 어떻게 다룰 것인가? 백엔드와 BFF의 책임 분리 전략 (0) | 2025.05.29 |