코틀린에서 자주 사용하는 어노테이션(Annotation)@ 정리-2
이번 포스팅에서는 저번 포스팅에 이어서 Annotation을 커스텀하는 방법을 알아보겠습니다.
Reflection을 사용한 Custom Annotation
코틀린에서 어노테이션을 커스텀하기 위한 방법으로는 두 가지 방법이 있습니다.
- Reflection을 사용한 커스텀
- Code Generation을 사용한 커스텀
먼저 Reflection이 뭔지 간단히 설명하자면
Reflection이란, 런타임 시 프로그램의 구조(객체, 함수, 프로퍼티)를 분석하는 기법입니다.
즉, 프로그램이 실행중일 때 인스턴스 등을 통해 객체의 내부 구조 등을 파악할 수 있습니다.대신 이렇게 매번 확인하기 때문에 앱의 성능 저하를 일으킬 수 있습니다.
코틀린에서 Reflection을 사용하기 위해선 KClass를 사용해야 합니다.
코틀린 리플렉션(Reflection)에 대한 정보는 여기서 확인할 수 있습니다.
코틀린에서 KClass를 사용하기 위해선 아래와 같은 라이브러리를 추가해줘야 합니다.
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
그리고 다음과 같이 Annotation을 지정해서 annotation class를 만들어보겠습니다.
@Target(AnnotationTarget.PROPERTY)
annotation class StringConstraint(
val minLength: Int,
val maxLength: Int
)
위에서 생성한 StringContraint 어노테이션 클래스는 String 변수의 최소 길이, 최대 길이를 정의하기 위해 만든 어노테이션 클래스입니다.
해당 커스텀 어노테이션을 프로퍼티 값을 갖는 data class에 적용합니다.
data class Data(
// set field value with custom annotation
@StringConstraint(10, 50)
val title: String,
@StringConstraint(100, 500)
val contents: String
)
이제 이 둘을 사용하여 Validation을 확인하는 코드를 작성합니다.
object FieldValidator {
data class ValidationResult(
var isValid: Boolean = true,
val invalidFieldNames: MutableList<String> = mutableListOf()
)
fun validate(data: Data): ValidationResult {
val result = ValidationResult()
// get property information with reflection
data::class.declaredMemberProperties.forEach {
val field = it
val annotation = it.findAnnotation<StringConstraint>()
if (annotation != null && field.getter.visibility == KVisibility.PUBLIC) {
val fieldValue = field.getter.call(data) as String
// set validation with annotation field value
if (fieldValue.length !in annotation.minLength..annotation.maxLength) {
result.isValid = false
result.invalidFieldNames.add(field.name)
}
}
}
return result
}
}
그리고 다음과 같은 코드를 작성하여 실행합니다.
fun main() {
val data = Data(
"극도의 투명함",
"투명함은 단순히 결과가 잘 공유되는 것 이상을 의미합니다. 우리는 결과뿐 아니라 의도와 맥락, 과정까지도 알 수 있을 만큼 공유하는 것을 투명하다고 합니다. 우리가 추구하는 극도의 솔직함은 투명함이 전제되어야만 발현된다고 믿습니다."
)
val validationResult = FieldValidator.validate(data)
// Validation: false / not validated Field: [title]
println("Validation: ${validationResult.isValid} / not validated Field: ${validationResult.invalidFieldNames}")
}
정리
이렇게 커스텀 Annotation과 코틀린 Reflection을 사용하는 방법에 대해 알아봤습니다.
참고로 모든 코드는 다음과 같습니다.
import kotlin.reflect.KVisibility
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.findAnnotation
@Target(AnnotationTarget.PROPERTY)
annotation class StringConstraint(
val minLength: Int,
val maxLength: Int
)
data class Data(
// set field value with custom annotation
@StringConstraint(10, 50)
val title: String,
@StringConstraint(100, 500)
val contents: String
)
object FieldValidator {
data class ValidationResult(
var isValid: Boolean = true,
val invalidFieldNames: MutableList<String> = mutableListOf()
)
fun validate(data: Data): ValidationResult {
val result = ValidationResult()
// get property information with reflection
data::class.declaredMemberProperties.forEach {
val field = it
val annotation = it.findAnnotation<StringConstraint>()
if (annotation != null && field.getter.visibility == KVisibility.PUBLIC) {
val fieldValue = field.getter.call(data) as String
// set validation with annotation field value
if (fieldValue.length !in annotation.minLength..annotation.maxLength) {
result.isValid = false
result.invalidFieldNames.add(field.name)
}
}
}
return result
}
}
fun main() {
val data = Data(
"극도의 투명함",
"투명함은 단순히 결과가 잘 공유되는 것 이상을 의미합니다. 우리는 결과뿐 아니라 의도와 맥락, 과정까지도 알 수 있을 만큼 공유하는 것을 투명하다고 합니다. 우리가 추구하는 극도의 솔직함은 투명함이 전제되어야만 발현된다고 믿습니다."
)
val validationResult = FieldValidator.validate(data)
// Validation: false / not validated Field: [title]
println("Validation: ${validationResult.isValid} / not validated Field: ${validationResult.invalidFieldNames}")
}
다음 포스팅에서는 두 번째 Annotation 커스텀 방법인
Compile Time에 Code Generation을 활용해 Annotation에 로직을 삽입
에 대해 알아보겠습니다!
'코틀린' 카테고리의 다른 글
코틀린에서 abstract 클래스는 무엇이고 어떻게 사용할까? (0) | 2023.03.30 |
---|---|
코틀린으로 알고리즘 문제 풀기 - 입력 받기 꿀팁 (0) | 2023.03.23 |
안드로이트 코틀린 Reflection(리플렉션) 기초 정의 (0) | 2023.03.09 |
코틀린에서 자주 사용하는 어노테이션(Annotation)@ 정리-1 (0) | 2023.03.06 |
코틀린에서 변성(variance)이란 무엇인가 - 상세 설명 (0) | 2023.02.18 |
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."
댓글