Search

Annotations

주석은 코드에 메타데이터를 첨부하는 수단이다.
annotation class Fancy
Kotlin
복사
주석을 선언하려면 클래스 앞에 annotation 수식어를 붙인다.
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION) @Retention(AnnotationRetention.SOURCE) @MustBeDocumented annotation class Fancy
Kotlin
복사
주석 클래스에 메타 주석을 사용하여 추가 속성을 지정할 수 있다.
@Target
주석이 적용될 수 있는 요소의 종류를 지정한다.
클래스, 함수, 프로퍼티, 표현식 등
@Retention
주석이 컴파일된 클래스 파일에 저장되는지, 런타임에 리플렉션을 통해 볼 수 있는지를 지정한다.
기본값은 둘 다 true이다.
@Repeatable
동일한 주석을 하나의 요소에 여러 번 사용할 수 있게 한다.
@MustBeDocumented
주석이 공용 API의 일부로 생성된 API 문서에 클래스나 메서드 서명에 포함되어야 함을 명시한다.

사용 예시

@Fancy class Foo { @Fancy fun baz(@Fancy foo: Int): Int { return (@Fancy 1) } }
Kotlin
복사
클래스의 기본 생성자에 주석을 달아야 할 경우 생성자 선언에 constructor 키워드를 추가하고 주석을 그 앞에 붙인다.
class Foo @Inject constructor(dependency: MyDependency) { ... }
Kotlin
복사
프로퍼티 접근자에도 주석을 달 수 있다.
class Foo { var x: MyDependency? = null @Inject set }
Kotlin
복사

생성자

주석은 매개변수를 갖는 생성자를 가질 수 있다.
annotation class Special(val why: String) @Special("example") class Foo {}
Kotlin
복사
허용된 매개변수 타입
Java 기본 유형(Int, Long 등)
Strings
Classes (Foo::class)
Enums
다른 annotations
위 타입의 배열들
주석의 매개변수는 nullable 타입을 가질 수 없다.
JVM이 주석 속성의 값으로 null을 저장하는 것을 지원하지 않기 때문이다.
annotation class ReplaceWith(val expression: String) annotation class Deprecated( val message: String, val replaceWith: ReplaceWith = ReplaceWith("")) @Deprecated("이 함수는 더 이상 사용되지 않습니다. === 대신 사용하세요", ReplaceWith("this === other"))
Kotlin
복사
다른 주석의 매개변수로 주석을 사용할 경우 이름 앞에 @ 문자를 붙이지 않는다.
import kotlin.reflect.KClass annotation class Ann(val arg1: KClass<*>, val arg2: KClass<out Any>) @Ann(String::class, Int::class) class MyClass
Kotlin
복사
주석의 인자로 클래스를 지정하려면 Kotlin 클래스를 사용해야 하며 Kotlin 컴파일러가 이를 Java 클래스로 자동 변환하여 Java 코드에서 주석과 인자를 정상적으로 접근할 수 있게 한다.

인스턴스화

annotation class InfoMarker(val info: String) fun processInfo(marker: InfoMarker): Unit = TODO() fun main(args: Array<String>) { if (args.isNotEmpty()) processInfo(getAnnotationReflective(args)) else processInfo(InfoMarker("default")) }
Kotlin
복사
Java에서 주석 타입은 인터페이스의 일종이므로 이를 구현하고 인스턴스를 사용할 수 있다.
Kotlin에서는 주석 클래스의 생성자를 임의의 코드에서 호출하고 결과 인스턴스를 사용하는 방법을 제공한다.

람다

annotation class Suspendable val f = @Suspendable { Fiber.sleep(10) }
Kotlin
복사
주석은 람다에도 사용할 수 있다.
주석은 람다의 본체가 생성되는 invoke() 메서드에 적용된다.
이는 Quasar와 같은 프레임워크에서 동시성 제어를 위해 주석을 사용할 때 유용하다.

주석 사용 위치 타겟

사용 위치 타겟의 종류
file
property (이 타겟을 가진 주석은 Java에서 볼 수 없음)
field
get (프로퍼티 getter)
set (프로퍼티 setter)
receiver (확장 함수 또는 프로퍼티의 수신자 매개변수)
param (생성자 매개변수)
setparam (프로퍼티 setter 매개변수)
delegate (위임된 프로퍼티의 delegate 인스턴스를 저장하는 필드)
주석 사용 위치 타겟을 지정하지 않으면 @Target 주석의 타겟 중 아래의 순서대로 타겟이 선택된다.
param
property
field
class Example(@field:Ann val foo, // Java 필드에 주석 @get:Ann val bar, // Java getter에 주석 @param:Ann val quux) // Java 생성자 매개변수에 주석
Kotlin
복사
프로퍼티나 기본 생성자 매개변수를 주석으로 달 때 여러 Java 요소가 해당 Kotlin 요소에서 생성되므로 Java 바이트코드에서 주석이 생성될 수 있는 위치가 여러 개 있다.
@file:JvmName("Foo") package org.jetbrains.demo
Kotlin
복사
파일 전체를 주석으로 달 때 파일이 기본 패키지인 경우 파일의 최상위에 주석을 두고 패키지 지시문이나 모든 import 문 앞에 둔다.
class Example { @set:[Inject VisibleForTesting] var collaborator: Collaborator }
Kotlin
복사
같은 타겟을 가진 여러 개의 주석이 있는 경우 타겟을 반복하지 않도록 괄호를 추가하고 그 안에 모든 주석을 넣을 수 있다.
fun @receiver:Fancy String.myExtension() { ... }
Kotlin
복사
확장 함수의 수신자 매개변수에 주석을 달려면 위처럼 사용한다.

Java 주석

Java 주석은 Kotlin 과 100% 호환된다.
import org.junit.Test import org.junit.Assert.* import org.junit.Rule import org.junit.rules.* class Tests { // @Rule 주석을 프로퍼티 getter에 적용 @get:Rule val tempFolder = TemporaryFolder() @Test fun simple() { val f = tempFolder.newFile() assertEquals(42, getTheAnswer()) } }
Kotlin
복사
Java에서 작성된 주석의 매개변수 순서가 정의되어 있지 않기 때문에 인자를 전달하기 위해 일반 함수 호출 구문을 사용할 수 없다.
// Java public @interface Ann { int intValue(); String stringValue(); } // Kotlin @Ann(intValue = 1, stringValue = "abc") class C
Kotlin
복사
대신 이름이 지정된 인자 구문을 사용해야 한다.
// Java public @interface AnnWithValue { String value(); } // Kotlin @AnnWithValue("abc") class C
Kotlin
복사
Java에서 특별한 경우로 value 매개변수가 있는 경우 명시적인 이름 없이 값을 지정할 수 있다.
// Java public @interface AnnWithArrayValue { String[] value(); } // Kotlin @AnnWithArrayValue("abc", "foo", "bar") class C
Kotlin
복사
Java에서 value 매개변수가 배열 타입인 경우 Kotlin 에서는 vararg 매개변수로 변환된다.
// Java public @interface AnnWithArrayMethod { String[] names(); } // Kotlin @AnnWithArrayMethod(names = ["abc", "foo", "bar"]) class C
Kotlin
복사
다른 인자가 배열 타입인 경우 배열 리터럴 구문이나 arrayOf(…) 를 사용해야 한다.
// Java public @interface Ann { int value(); } // Kotlin fun foo(ann: Ann) { val i = ann.value }
Kotlin
복사
주석 인스턴스의 값은 Kotlin에서 프로퍼티로 노출된다.

JVM 1.8+ 주석 타겟 생성 방지 기능

Kotlin 주석이 TYPE을 포함하는 경우 해당 주석은 Java 주석 타겟 목록에서 java.lang.annotation.ElementType.TYPE_USE 에 매핑된다.
이는 Kotlin의 TYPE_PARAMETER가 java.lang.annotation.ElementType.TYPE_PARAMETER 에 매핑되는 방식과 동일하다.
TYPE_USE 와 TYPE_PARAMETER 주석 타겟 생성을 피하려면 새로운 컴파일러 인자 -Xno-new-java-annotation-targets 를 사용하라.

반복 가능한 주석

Java와 마찬가지로 Kotlin에도 반복 가능한 주석이 있으며 이는 단일 코드 요소에 여러 번 적용될 수 있다.
주석을 반복 가능하게 만드려면 그 선언에 @kotlin.annotation.Repeatable 메타 주석을 붙인다.
이렇게 하면 Kotlin과 Java 모두에서 반복 가능해지며 Java의 반복 가능한 주석도 Kotlin 측에서 지원된다.
@Repeatable annotation class Tag(val name: String) // 컴파일러가 @Tag.Container 포함 주석을 생성합니다
Kotlin
복사
Java에서 사용되는 스킴과의 주요 차이점은 containing 주석이 없다는 것이다.
Kotlin 컴파일러는 자동으로 미리 정의된 이름으로 containing 주석을 생성한다.
@Tag 주석에 대해 @Tag.Container 라는 containing 주석이 생성된다.
@JvmRepeatable(Tags::class) annotation class Tag(val name: String) annotation class Tags(val value: Array<Tag>)
Kotlin
복사
사용자가 지정한 containing 주석 이름을 설정하려면 @kotlin.jvm.JvmRepeatable 메타 주석을 적용하고 명시적으로 선언된 containing 주석 클래스를 인자로 전달하면 된다.
KAnnotatedElement.findAnnotations()
Kotlin
복사
Kotlin 또는 Java 의 반복 가능한 주석을 리플렉션을 통해 추출하려면 위 함수를 사용하라.