애노테이션(Annotation) 적용하기
코틀린은 자바와 같은 방법으로 애노테이션을 사용할 수 있다. 애노테이션은 @
과 이름으로 이뤄지며 함수나 클래스 등 여러 다른 코드 구성 요소에 붙일 수 있다.
@Test
fun testTrue() {
Assert.assertTrue(true)
}
@Deprecated
애노테이션은 자바와 같은 의미이지만 코틀린에서는 replaceWith
파라미터를 사용해 대체할 수 있는 패턴을 제시할 수 있다.
@Deprecated("Use removeAt(index) instead.", ReplaceWith("removeAt(index)"))
fun remove(index: Int)
Intellij IDEA에서는 Kotlin의
@Deprecated
경고에 대해 자동으로 경고 메시지 및 Quick Fix 기능을 제공한다.
애노테이션의 인자로는 원시 타입 값, 문자열, enum, 클래스 참조, 다른 애노테이션, 앞서 말한 요소의 배열을 넣을 수 있다. 애노테이션 인자를 지정하는 문법은 자바와 약간 다르다.
- 클래스를 애노테이션 인자로 지정할 때는 클래스 이름 뒤에
::class
를 넣어야 한다. - 다른 애노테이션을 인자로 지정할 때는 인자로 들어가는 애노테이션 앞에
@
를 붙이지 않는다(@Deprecated
참조). - 배열을 인자로 지정하려면
arrayOf('a', 'b', 'c')
와 같이 사용한다. 다만 자바에서 선언한 애노테이션 클래스를 사용할 때는 가변 길이 인자 형식을 취한다.
애노테이션 인자는 컴파일 시점에 알 수 있어야 한다. 프로퍼티를 애노테이션 인자로 지정하려면 const
변경자를 사용해 상수로 취급해야 한다.
애노테이션 대상
코틀린은 소스코드에서 한 선언을 컴파일한 결과가 여러 자바 선언과 대응되는 경우가 있다. 여러 자바 선언에 각각 다른 애노테이션을 붙여야 할 때가 있을 것이다. 코틀린은 애노테이션을 붙일 때 어느 요소에 붙일 지 정할 수 있다. 사용 지점 대상(Use-site target)을 사용해서 애노테이션을 붙일 요소를 정할 수 있다.
@get:Rule
//@(사용 지점 대상):(애노테이션 이름)
다음은 사용 지점 대상을 지정할 때 사용하는 대상 목록이다.
property
: 프로퍼티 전체. 자바에서 선언된 애노테이션에는 사용할 수 없다.field
: 프로퍼티에 의해 생성되는 필드(뒷받침하는 필드)get
: 프로퍼티 게터set
: 프로퍼티 세터receiver
: 확장 함수나 프로퍼티의 수신 객체 파라미터param
: 생성자 파라미터setparam
: 세터 파라미터delegate
: 위임 프로퍼티의 위임 인스턴스를 담아둔 필드file
: 파일 안에 선언된 최상위 함수와 프로퍼티를 담아둔 필드
file
을 사용하는 애노테이션은 package
선언 앞에서 파일의 최상위 수준에만 적용할 수 있다.
@file:JvmName("StringFunctions")
package string
애노테이션 선언
애노테이션을 선언하려면 클래스 앞에 annotation
키워드를 붙인다.
annotation class JsonExclude
애노테이션 클래스는 오직 선언이나 식과 관련 있는 메타데이터의 구조를 정의하기 때문에 내부에 코드가 들어있을 수 없다.
파라미터가 있는 애노테이션을 정의하려면 애노테이션 클래스의 주 생성자에 파라미터를 선언한다.
annotation class JsonName(val name: String)
일반 클래스와 다른점은 모든 파라미터 앞에 val을 붙여야 한다.
같은 코드를 자바 애노테이션으로 작성하면 다음과 같다.
public @interface JsonName {
String value();
}
자바는 어떤 애노테이션을 적용할 때 value
를 제외한 모든 속성에는 이름을 명시해야 한다. 코틀린은 애노테이션 적용에 일반적인 생성자 호출을 사용한다. 따라서 이름을 붙일 수도 있고 생략할 수도 있다.
메타애노테이션
애노테이션 클래스에 적용할 수 있는 애노테이션을 메타애노테이션(Meta-annotation)이라고 한다. 표준 라이브러리에는 몇 가지 메타애노테이션이 있으며 그런 메타애노테이션들은 컴파일러가 애노테이션을 처리하는 방법을 제어한다(애노테이션을 적용할 수 있는 요소의 유형을 지정할 수 있는 @Target
등).
애노테이션 파라미터로 클래스 사용하기
클래스 참조를 파라미터로 하는 애노테이션 클래스를 선언하려면 다음과 같이 한다.
annotation class DeserializeInterface(val targetClass: KClass<out Any>)
Kclass
는 java.lang.Class
타입과 같은 역할을 하는 코틀린 타입이다. KClass
의 타입 파라미터는 KClass
인스턴스가 가리키는 코틀린 타입을 지정한다. 예를 들어 CompanyImpl::class
의 타입은 KClass<CompanyImpl>
이며 KClass<out Any>
의 하위 타입이다(공변성).
애노테이션 파라미터로 제네릭 클래스 받기
애노테이션 파라미터로 제네릭 클래스를 받으려면 스타 프로젝션을 사용하면 된다.
annotion class CustomSerializer(val serializerClass: KClass<out ValueSerializer<*>>)
위 예제에서는 CustomSerializer
가 ValueSerializer
를 구현하는 클래스만 인자로 받도록 제한하고 있다.