본문 바로가기

책 요약하기/Do it! 코틀린 프로그래밍

#07-2. 애노테이션 클래스 2021-05-16

애노테이션 위치

@Fancy class MyClass {
    @Fancy fun myMethod(@Fancy myProperty: Int): Int {
    	return (@Fancy 1)
    }
}

앞에서 정의한 @Fancy라는 애노테이션을 클래스의 앞, 메서드 앞, 프로퍼티 앞에 사용할 수 있고, 반환할 때에는 값 앞에 표기하거나 소괄호로 감쌉니다. :)

class Foo @Fancy constructor(dependency: MyDependency) { ... }

생성자 앞에 사용 시 constructor생력 불가!!

class Foo {
    var x: MyDependency? = null
    @Fancy set
}

프로퍼티의 게터/세터에도 사용 가능합니다 :)

 

애노테이션의 매개변수와 생성자

annotation class Special(val why: String) // 애노테이션 클래스의 정의
@Special("example") class Foo { } // 애노테이션에 매개변수를 지정
- 자바의 기본형과 연동하는 자료형(Int형, Long형 등)
- 문자열
- 클래스(클래스 이름::class)
- 열거형
- 기타 애노테이션
- 위의 목록을 가지는 배열

 

애노테이션이 또 다른 애노테이션을 가지고 사용할 때는 @ 기호를 사용하지 않아도 됩니다.

annotation class ReplaceWith(val expression: String) // 첫 번째 애노테이션 클래스 정의

annotation class Deprecated( // 두 번째 애노테이션 클래스 정의
    val message: String,
    val replaceWith: ReplaceWith = ReplaceWith(""))
...
// ReplaceWith는 @ 기호가 생략됨.
@Deprecated("This function is deprecated, use === instead", ReplaceWith("this === other"))

 

애노테이션의 인자로 특정 클래스가 필요하면, 코틀린의 KClass를 사용해야 합니다. 그러면 코틀린 컴파일러가 자동적으로 자바 클래스로 변환할 것입니다. 이후에 자바 코드에서도 애노테이션 인자를 사용할 수 있게 됩니다.

import kotlin.reflect.KClass
annotation class Ann(val arg1: KCall<*>, val arg2: KClass<out Any>)
...
@Ann(String::class, Int::class) class MyClass

String::class와 Int::class는 코틀린의 리플렉션 표현입니다. 이것은 KClass<T>를 반환합니다.

 

표준 애노테이션

코틀린 표준 라이브러리가 가지고 있는 애노테이션들 중 일부

@JvmName("filterStrings")
fun filter(list: List<String>): Unit

@JvmName("filterInts")
fun filter(list: List<Int>): Unit

 

@JvmName은 filter()라는 이름을 자바에서 각각 filterStrings()와 filterInts()로 바꿔주는 것입니다. 자바로 바뀌면 해당 애노테이션에 의해 다음과 같이 표현됩니다.

public static final void filterStrings(java.util.List<java.lang.String>);
...
public static final void filterInts(java.util.List<java.lang.Integer>);
...

그 외에 @JvmStatic은 자바의 정적 메서드로 생성할 수 있게 해주고, @Throw는 코틀린의 throw 구문이 자바에서도 포함되도록 합니다. 예를 들어 코틀린의 코드에서 다음과 같이 찾을 수 없는 예외를 발생시키려고 합니다.

class File(val path: String) {
    @Throws(FileNotFouneException::class)
    fun exists(): Boolean {
        if(!Paths.get(path).toFile().exists())
        throw FileNotFoundException("$path does not exist")
        return true
    }
}

// Java
public void checkFile() throws FileNotFoundException {
    boolean exists = new File("somefile.txt").exists();
    System.out.println("File exists")
}

 

마지막으로 @JvmOverloads는 코틀린에서 기본값을 적용한 인자에 함수를 모두 오버로딩해 줍니다. 이렇게 표준 애노테이션은 자바와 원활하게 연동하는 데 목적을 두고 있습니다.