[Kotlin Tutorial] Annotation 과 Reflection #1 - Chap 10. Annotations and reflection |
참조 : Kotlin in action
10.1. Declaring and applying annotations.
10.1.1. Applying annotations
-
Annotation 사용법은 Java 와 동일하다. @ 를 prefix 로 하고 annotation name 을 써주면 된다.
-
@Deprecated 의 경우 Kotlin 은 Java 의 것에서 향상되었다.
replaceWith parameter 가 추가되어, 새로운 version 의 API 에 연결될 수 있다.
@Deprecated(“Use removeAt(index) instead.”, ReplaceWith(“removeAt(index)"))
fun remove(index: Int){ … }
이렇게 명시해주면 어떤 function 을 써줘야 함을 표기함은 물론 quick fix 도 제공된다.
-
annotation 은 parameter 로 다음 type 들만 가질 수 있다.
primitive type, string, enum, class reference, 다른 annotation, 그리고 이것들의 array
-
annotation syntax 는 java 와 약간 다르다.
클래스 이름을 명시할 때는 ::class 형태로 한다. @MyAnnotation(MyClass::class)
다른 annotation 을 argument 로 할 때는 @ 를 쓰지 않는다.
array 를 argument 로 쓸 때는 arrayOf function 을 써야 한다. @RequestMapping(path=arrayOf(“/foo”, “/bar”)). Annotation 이 Java 에 정의되어 있다면 "value" 라는 parameter 가 자동으로 vararg 형태로 필요하면 자동으로 생성이 되기 때문에 arrayOf 없이 사용할 수도 있다.
Annotation argument 는 compile time 에 알 수 있어야 한다.
그래서 property 를 annotation argument 로 쓰려면 const modifier 를 써줘야 한다.
const val TEST_TIMEOUT = 100L // top-level 또는 object 안에 있어야 하며, primitive type 과 string 만 올 수 있다.
@Test(timeout = TEST_TIMEOUT) fun testMethod(){ … }
10.1.2. Annotation targets
-
annotation 은 use-site target declaration 으로 명시할 수 있다.
@get:Rule // @get 은 Use-site target, Rule 은 Annotation name
-
class HasTempFolder{
@get:Rule // property 가 아닌 getter 에 annotation 이 된다.
val folder = TemporaryFolder()
@Test
fun testUsingTempFolder(){
val createdFile = folder.newFile(“myfile.txt”)
val createFolder = folder.newFolder("subfolder”)
...
}
}
-
Java 에서 정의된 annotation 을 Kotlin 의 property 에 적용하면 기본적으로 해당 field 에 적용된다고 보면 된다.
Kotlin 에서는 property 자체에 적용가능한 annotation 도 정의 가능하다.
-
use-site 를 지원하는 target 들은..
property ( Java annotation 은 적용 불가 )
field ( property 로 생성되는 field )
get ( property getter )
set ( property setter )
receiver ( extension function 이나 extension property 의 receiver param )
param ( constructor param )
setparam ( property setter parameter )
delegate ( delegate property 를 위한 delegate instance 를 저장하는 field )
file ( top-level function 이나 property 를 가진 class, package directive 전에 정의되어야 함 )
-
file 에 가장 많이 쓰이는 annotation 은 @JvmName, 이 녀석은 class 이름을 변경한다.
-
Java 와 달리 Kotlin 에서는 임의의 expression 에도 annotation 을 적용할 수 있다. ( class, function, type 뿐만 아니라 )
대표적 예는 @Suppress annotation 이다.
fun test(list: List<*>){
@Suppress(“UNCHECKED_CAST”)
val strings = list as List<String>
// ...
}
-
Kotlin 에서 정의한 annotation 도 마찬가지로 bytecode 가 되어 Java 에서 볼 수 있다.
@Volatile 이나 @Strictfp 와 같은 경우는 Java 의 volatile 과 strictfp keyword (부동소수 어쩌구 저쩌구.. )로 변형된다.
다른 것들은 Kotlin 의 정의가 Java caller 에게 어떻게 보일까를 결정한다.
@JvmName 은 Kotlin 에서 정의한 Java method 나 field 이름을 변경한다.
@JvmStatic 은 object 선언이나 companion object 를 Java 에서 static method 로 보이도록 한다.
@JvmOverloads 는 Kotlin compiler 에게 default parameter 를 가진 function 을 overload 함수를 생성하도록 한다.
@JvmField 는 property 를 getter 나 setter 없이 public field 로 노출시킨다.
10.1.3. Using annotations to customize JSON serialization
-
JKid 라는 JSON serialization lib 이 있다.
data class Person(val name:String, val age: Int)
val person = Person(“Alice”, 29)
println(serialize(person)) // {“age”:29, “name”: “Alice” }
val json = “””{“name”:”Alice”, “age”: 29}”””
println(deserialize<Person>(json)) // Person(name=Alice, age=29)
serialize 를 할 때 기본적으로 모든 property 를 그 이름 자체로 key 로 해서 serialize 한다.
@JsonExclue, @JsonName 을 통해 exclude 를 할 수도 있고, 이름을 바꿀 수도 있다.
10.1.4. Declaring annotations
-
annotation class JsonExclude
syntax 는 class 정의와 비슷하나, annotation 이 앞에 붙는다.
-
annotation class JsonName(val name:String)
parameter 가 있는 annotation.
parameter 는 필수적으로 val 이다.
Java 코드는 아래와 같다.
public @interface JsonName{
String value();
}
여기서 value 는 그냥 1개의 param 을 받는다는 의미이고, 만약에 다른 param 을 추가하려면 해당 getter 를 추가로 써줘야 한다.
-
Kotlin 에서의 annotation 은 named-argument 를 쓸 수 있다.
@JsonName(name=“first_name”)
@JsonName(“first_name”)
Java 에서 정의한 annotation 을 사용할 때는 value 를 제외한 모든 경우 named-argument 를 사용해야 한다.
10.1.5. Meta-annotations: controlling how an annotation is processed
-
Java 처럼 Kotlin annotation 은 그 자신을 annotation 할 수 있다.
annotation 에 annotation 되는 class 를 meta-annotations 라고 부른다.
-
standard lib 에 정의된 가장 잘 쓰이는 녀석은 @Target 이다.
@Target(AnnotationTarget.PROPERTY)
annotation class JsonExclue
@Target 은 annotation 이 어디에 적용될 수 있는지 명시하는 것이다.
명시되지 않으면 모든 target 에 적용될 수 있다.
Target 으로 지정할 수 있는 enum 은..
class, file, function, property, property accessor, type, expression 등이다.
, 를 통해 여러개의 target 을 지정할 수도 있다.
@Target(AnnotationTarget.CLASS, AnnotationTarget.METHOD)
-
meta-annotation 을 만들기 위해서는 target 을 ANNOTATION_CLASS 로 지정해줘야 한다.
@Target(AnnotationTarget.ANNOTATION_CLASS)
annotation class BindingAnnotation
@BindingAnnotation
annotation class MyBinding
-
Property target 을 하고 있는 annotation 은 Java 코드에서 사용할 수 없다.
Java 에도 사용하게 하려면 FIELD target 도 추가해주어야 한다.
-
Java 는 기본적으로 annotation 을 .class files 로 만들지만, runtime 에는 접근 가능하지 않게 한다.
@Retension annotation 을 사용하면 .class 로 만들지, runtime 에도 접근하게 할지를 control 할 수 있다.
Kotlin 에서는 기본이 RUNTIME retension 이다.
10.1.6. Classes as annotation parameters
-
annotation 에 class reference 를 넣을 수도 있다.
annotation class DeserializeInterface(val targetClass: KClass<out Any>)
// 여기서 out 이 없다면 Any::class 밖에 안 된다.
interface Company{
val name: String
}
data class CompanyImpl(override val name: String) : Company
data class Person(val name:String, @DeserializeInterface(CompanyImpl::class) val company: Company)
-
KClass 는 Java 의 java.lang.Class type 과 매칭되는 녀석이다.
10.1.7. Generic classes as annotation parameters
-
Jkid 는 primitive type 이 아닌 property 들은 nested object 로 serialize 한다.
이 로직을 @CustomSerializer annotation 을 써서 변경할 수 있다.
interface ValueSerializer<T>{
fun toJsonValue(value: T): Any?
fun fromJsonValue(jsonValue: Any?) : T
}
annotation class CustomSerializer{
val serializerClass: KClass<out ValueSerializer<*>>
}
data class Person{
val name: String,
@CustomSerializer(DateSerializer::class) val birthDate: Date
}
'프로그래밍 놀이터 > Kotlin, Coroutine' 카테고리의 다른 글
[Kotlin] Linkage Error 버그? (0) | 2017.09.13 |
---|---|
[Kotlin Tutorial] Annotation 과 Reflection #2 (0) | 2017.09.12 |
[Kotlin Tutorial] Generics - Chap9. Generics (2) | 2017.09.05 |
[Kotlin Tutorial] 한 차원 높은 함수 : 람다를 parameter 와 return value 로 - Chap8. Higher-order functions: lambdas as parameters and return values (0) | 2017.08.31 |
[Kotlin Tutorial] Operator overload 와 convention #2 (0) | 2017.08.29 |
댓글