Java 에서 Kotlin, Validation 문제 해결기

gimseonjin616·2024년 3월 29일
0

들어가며

안녕하세요, Kerry입니다! 최근에 저는 Splab에 합류하게 되었습니다! 센드타임과 우모를 만드는 SaaS 분야의 스타트업으로 이 회사에 오고 싶었던 만큼, 지금의 기대감은 정말 크답니다.

하지만, 작지만 중요한 한 가지 문제가 있습니다. Splab은 Kotlin 기반의 Spring Boot 환경에서 개발을 진행하는데, 저는 지금까지 Java와 Spring Boot만 사용해왔거든요. 그래서 이 새로운 개발 환경이 저에게는 상당히 낯설게 느껴집니다.

이에 입사하기 전, 이전에 했던 기술 과제 중 일부를 Kotlin으로 변환하면서, Spring Boot에서 Kotlin을 어떻게 활용할 수 있는지 간단히 학습해보기로 했습니다. 또한, 이 과정에서 겪은 몇 가지 문제와 해결 과정을 공유하려고 합니다.


문제 발생

우선 이전 과제에서 Integration Test와 Unit Test를 작성해두었기 때문에 이를 기반으로 각 레이어별로 migration을 수행하려고 했습니다. 그래서 맨 처음에는 Controller layer 들을 수정했습니다.

수정하면서 테스트로 검증하는 와중에 아래와 같은 에러를 맞이했습니다.

에러 메시지를 더 디테일하게 읽어보니, 방금 전에 수정한 CreateMemberRequest 부분에서 Non-null 한 곳에 null이 매핑되서 생긴 문제라는 것을 인식했습니다.


해결책

위의 코드는 문제가 발생한 CreateMemberRequest class입니다. 여기서 Null Point Exception을 발생시킬만한 곳은 크게 두 군데로 1) @field:NotBlank 등등, 2) val name: String 처럼 non-null 필드들 입니다.

정확한 문제 원인 파악을 위해 각 부분을 주석처리 한 후, 테스트를 돌려봤습니다.

1) @field:NotBlank 주석 처리

여전히 똑같은 에러가 발생합니다.

2) 필드들을 Nullable하게 수정

필드들을 nullable하게 하니 테스트가 통과하는 것을 볼 수 있습니다.

결론 : 필드들을 nullable하게 하지 않아 생긴 문제다.


문제 원인 파악

그렇다면 왜 필드들을 nullable하게 해야하는가? 어차피 Notnull로 받을 값인데???

관련 내용을 리서치 하였고 아래 블로그에서 다음과 같은 내용를 볼 수 있었습니다.

코틀린에서는 변수 선언할 때 nullable한 type으로 선언할 수 있습니다. 코틀린으로 Validation 적용하려면 (특히 NotNull 적용시) nullable type으로 선언해야 합니다. @field:NotNull 적용한 필드에 확정형 타입을 선언했다면 요청시 해당 필드를 입력하지 않았을 때 Validation 이용한 원하는 방식의 에러 핸들링을 기대하기 힘듭니다.
예를 들어 이렇게 확정형 타입에 NotNull을 적용한 경우 api 요청시 number 필드에 대한 내용을 입력하지 않았을 때 nullable에 대한 Type Mismatch 에러를 반환하게 됩니다. 이런 경우 Valid에 지정해놓은 default message 등을 무시하게 되고 기타 Validation 관련 원하는 형태의 에러 반환값을 기대할 수 없게 됩니다.

출처 - https://beaniejoy.tistory.com/72

정리하자면 NotNull 어노테이션 검증보다, nullable에 대한 Type Mismatch 검증이 우선적으로 이뤄진다는 것입니다.

그렇다면 nullable type mismatch 검증이 먼저 이뤄지는 이유가 뭘까요??

Reflection

그 이유는 jakarta validation이 사용하는 Java Reflection에 있습니다. Java Refelction은 쉽게 얘기하면 런타임 환경에서 만들어진 객체를 통해, 해당 클래스의 정보에 접근할 수 있는 기술입니다.

jakarta validation은 직렬화를 통해 만들어진 객체(RequestBody, Model 등등)들을 Reflection을 통해 메타데이터를 읽어와서 그에 맞게 검증하는 식의 로직으로 동작합니다.

그렇기 때문에 validation을 하기 위해선 우선 객체가 만들어져야합니다!

다시 처음으로 돌아가서, 아래 기존 CreateMemberRequest의 경우, 필드 값으로 null이 들어오는 경우, 필드가 non-nullable 하기 때문에 객체 자체가 만들어지지 않아, NPE가 발생하게 된 것입니다.

결론

이 사례에서 배울 수 있는 핵심은, Kotlin에서 Jakarta Validation 같은 라이브러리를 사용할 때, @NotNull과 같은 어노테이션을 적용하기 위해서는 필드를 nullable하게 선언해야 한다는 것입니다.

이렇게 하지 않으면, Kotlin의 타입 시스템 때문에 null 값으로 초기화하려 할 때 타입 불일치 에러가 발생하여, 객체 자체가 정상적으로 생성되지 않아 검증 절차까지 도달할 수 없습니다.

이는 Kotlin의 non-nullable 타입과 Java 기반 라이브러리의 상호작용에서 자주 볼 수 있는 문제 유형 중 하나로, nullable 타입 선언을 통해 초기 객체 생성 시 null 입력을 허용하고, 이후 Jakarta Validation을 통한 명시적인 검증 절차를 진행하는 것이 올바른 접근 방식입니다.

따라서, Kotlin과 Spring Boot 환경에서 robust한 애플리케이션을 개발하고자 할 때, 이러한 언어와 라이브러리 간의 상호작용을 이해하는 것이 중요합니다.

이 방법을 통해 개발자는 Kotlin의 강력한 타입 시스템과 Spring Boot의 편리한 기능을 효과적으로 활용할 수 있습니다.

profile
to be data engineer

0개의 댓글

관련 채용 정보