요약
코틀린의 프로퍼티는 선언하는 방식에 따라, 자바에서의 여러 요소에 매핑될 수 있다.
따라서 코틀린의 프로퍼티에 어노테이션 사용시에는 use-site target 을 지정해주어야한다.
해당 글에서는 코틀린 프로퍼티와 자바의 필드 사이의 차이점에 대해 다루며, 어노테이션이나, bean validation 에 대해 국한된 내용도 아니고 관련해서 딥다이브 하는 포스트는 아니라서 관련된 내용에 대해서 자세히 다루지 않는다.
문제상황 분석
문제 상황
Bean Validation 기능을 통해 request dto 를 검증하려고 한다.
하지만, 아래의 코드는 동작하지 않는다.
@RestController
class TestController {
private val logger = LoggerFactory.getLogger(javaClass)
@PostMapping("/test")
fun test(
@Valid @RequestBody request: TestRequestDto
) {
logger.info("name: ${request.name}")
}
}
data class TestRequestDto(
@NotEmpty
val name:String,
)
위 코드에서는 TestRequestDto의 name 프로퍼티에 @NotEmpty 어노테이션이 붙어있지만, 실제 동작시에는 어노테이션이 적용되지 않아 유효성 검증이 제대로 동작하지 않는다.
자바로 변환
위의 TestRequestDto 를 자바코드로 디컴파일해보면 아래의 코드가 나온다.
바로 name 프로퍼티의 @NotEmpty 어노테이션이 생성자의 파라미터에 붙어있다.
public final class TestRequestDto {
@NotNull
private final String name;
// @NotEmpty 어노테이션이 생성자에 붙어있다.
public TestRequestDto(@NotEmpty @NotNull String name) {
Intrinsics.checkNotNullParameter(name, "name");
super();
this.name = name;
}
@NotNull
public final String getName() {
return this.name;
}
@NotNull
public final String component1() {
return this.name;
}
@NotNull
public final TestRequestDto copy(@NotEmpty @NotNull String name) {
Intrinsics.checkNotNullParameter(name, "name");
return new TestRequestDto(name);
}
}
Bean Validation 이 기대하는 위치는 필드나 getter 지만, 생성된 코드에는 생성자 파라미터에 어노테이션이 적용되어 제대로 동작하지 않는 것이다.
상황에 대한 이해
위 상황에 대해 이해하기 위해서는 코틀린의 프로퍼티와 어노테이션에 대해 이해해야한다.
코틀린의 프로퍼티는 자바의 필드와 비슷하지만 같지 않다.
코틀린에서 프로퍼티를 선언하면 암묵적으로 field, getter, setter 가 생성된다.
그리고 코틀린의 문법을 통해서 생성자에서 프로퍼티 선언과 동시에 초기화를 할 수 있다.
즉, 코틀린의 생성자에서 프로퍼티를 선언한다면 자바에서는 4개의 element 가 생성된다.
- 생성자 파라미터
- 필드
- getter
- setter (var 의 경우)
그리고 생성자에 프로퍼티를 선언하고 어노테이션을 붙이는 경우, 어노테이션의 Target 리스트 중 아래 순서대로 적용된다.
- parameter
- property
- field
NotEmpty 어노테이션은 아래의 Target 을 지원하므로, parameter 에 어노테이션이 적용되어 버린 것이다.
@Target({ElementType.METHOD,
ElementType.FIELD,
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.PARAMETER,
ElementType.TYPE_USE})
해결법
이 문제를 해결하기 위해서는 어노테이션을 명시적으로 원하는 위치에 붙이도록 use-site target을 지정해주어야 한다.
예를 들어, 필드에 직접 어노테이션을 적용하고자 한다면 아래와 같이 use-site target 을 지정해주어야한다.
data class TestRequestDto(
@field:NotEmpty // or @get:NotEmpty
val name: String,
)
위와 같이 @field:NotEmpty를 사용하면, 어노테이션이 생성된 자바 코드에서 필드에 직접 마킹이 되어서 Bean Validation이 올바르게 동작한다.
결론
코틀린의 언어 특성상, 프로퍼티의 개념이 자바의 필드와는 다르다.
포스트에서는 BeanValidation 에 대해서 다루었지만, ORM 이나 SDK 을 사용할 때에도 마찬가지로 적용이 된다.
따라서 코틀린 프로젝트에서 프로퍼티에 어노테이션을 적용할 때는 어노테이션이 어느 위치에 붙는지 이해해야한다.
'자바와 코틀린' 카테고리의 다른 글
JWT (0) | 2024.11.17 |
---|---|
코루틴 - 코루틴 스레드 양보와 실행 스레드 (0) | 2024.09.17 |
코루틴 - 중단함수 (0) | 2024.09.17 |
코루틴 - 구조화된 동시성 (2) | 2024.09.17 |
코루틴 - 코루틴 빌더와 Job (0) | 2024.09.17 |