안녕하세요.
이번 포스팅에서는 어노테이션이 리플렉션을 통해
어떻게 사용될 수 있는지 적어보려고 합니다.
리플렉션이란 클래스의 정보를 알아내는 것인데 동적으로
클래스 정보를 얻을 수 있는 프로그래밍 방법입니다.
클래스만 알고 있다면 해당 클래스의 변수나 메소드 등을 알 수 있습니다.
이 리플렉션을 통해 클래스에 어떤 어노테이션이 적용 되었고
해당 어노테이션에 대한 정보 또한 알 수 있습니다.
코드는 코틀린 기준으로 작성되었으며 이를 기준으로 설명드리겠습니다.
일단 프로젝트에 코틀린에서 리플렉션을 사용하기 위한 라이브러리를 설치합니다.
implementation "org.jetbrains.kotlin:kotlin-reflect:1.5.20"
어노테이션과 이를 적용할 data class를 선언하겠습니다.
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME) //AnnotationRetention.SOURCE => null
@Target(
AnnotationTarget.PROPERTY
)
annotation class MyIntRange(
val from: Int,
val to: Int
)
data class ReflectionData(
@MyIntRange(1000, 10000)
val bbb: Int,
@MyIntRange(10, 20)
val ccc: Int,
@MyIntRange(1, 100)
val aaa: Int
)
MyIntRange라는 어노테이션을 만들었는데
이전 포스팅에서 설명 드렸던 타겟과 리텐션을 정의한 것을 알 수 있습니다.
https://dog-footprint.tistory.com/42
이제 어노테이션이 적용된 데이터클래스를 작성하였다면
이를 런타임에 어떻게 처리할 수 있는지에 대한 코드를 작성해보겠습니다.
fun validate(data: ReflectionData){
data::class.declaredMemberProperties.forEach { it->
val myAnnotation = it.findAnnotation<MyIntRange>()
if(myAnnotation!=null){
val value = it.getter.call(data) as Int
println("${it.javaField?.name} : ${myAnnotation}")
println("value : ${value}, from : ${myAnnotation.from}, to : ${myAnnotation.to}")
}
println()
}
}
declaredMemberProperties라는 코틀린 리플렉션 메소드를 사용해서
ReflectionData에 있는 프로퍼티 정보들을 가져 옵니다.
이후
findAnnotation<MyIntRange>() 을 이용해 @MyIntRange 이 붙은 프로퍼티를 찾고
해당 어노테이션이 붙은 정보를 출력하게 했습니다.
fun main(){
val data = ReflectionData(10000, 10,100)
validate(data)
}
메인 함수를 실행하면 아래와 같이 어노테이션과 프로퍼티에 대한 정보를 볼 수 있습니다.
aaa : @MyIntRange(from=1, to=100)
value : 100, from : 1, to : 100
bbb : @MyIntRange(from=1000, to=10000)
value : 10000, from : 1000, to : 10000
ccc : @MyIntRange(from=10, to=20)
value : 10, from : 10, to : 20
그러나 이 리플렉션을 이용하는 것은 런타임에 매번 동작하기 때문에 부담이커 이 방법이 아닌 다른 방법으로
어노테이션을 다루는 경우가 많습니다.
Code Generator를 활용하는 것인데 이것은 다음 포스팅에서 진행하겠습니다.
감사합니다.
전체코드
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.jvm.javaField
fun main(){
val data = ReflectionData(10000, 10,100)
validate(data)
}
fun validate(data: ReflectionData){
data::class.declaredMemberProperties.forEach { it->
val myAnnotation = it.findAnnotation<MyIntRange>()
if(myAnnotation!=null){
val value = it.getter.call(data) as Int
println("${it.javaField?.name} : ${myAnnotation}")
println("value : ${value}, from : ${myAnnotation.from}, to : ${myAnnotation.to}")
}
println()
}
}
data class ReflectionData(
@MyIntRange(1000, 10000)
val bbb: Int,
@MyIntRange(10, 20)
val ccc: Int,
@MyIntRange(1, 100)
val aaa: Int
)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME) //AnnotationRetention.SOURCE => null
@Target(
AnnotationTarget.PROPERTY
)
annotation class MyIntRange(
val from: Int,
val to: Int
)
'기타 > 자바 중급' 카테고리의 다른 글
자바 어노테이션(1) (0) | 2021.06.18 |
---|
댓글