•
Kotlin 표준 라이브러리는 특정 API 요소 사용 시 명시적인 동의를 요구하는 메커니즘을 제공한다.
•
이 메커니즘을 통해 라이브러리 개발자는 사용자가 실험적인 상태에 있는 API를 사용할 때 발생할 수 있는 문제점에 대해 경고하고 API의 사용이 미래에 변경될 가능성이 있음을 알릴 수 있다.
•
문제가 발생하는 것을 방지하기 위해 컴파일러는 이러한 API 사용에 대해 경고를 하고 사용자가 동의한 후에만 API를 사용할 수 있도록 요구한다.
API 사용에 대한 동의
•
라이브러리 작성자가 라이브러리 API의 선언에 대해 사용자가 동의해야 한다고 표시한 경우 코드에서 이를 사용하려면 명시적으로 동의해야 한다.
•
동의하는 방법은 여러 가지가 있으며 기술적인 제한 없이 상황에 맞게 선택할 수 있다.
동의 전파
// 라이브러리 코드
@RequiresOptIn(message = "이 API는 실험적입니다. 예고 없이 변경될 수 있습니다.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class MyDateTime // 동의 요구 주석
@MyDateTime
class DateProvider // 동의를 요구하는 클래스
// 클라이언트 코드
fun getYear(): Int {
val dateProvider: DateProvider // 오류: DateProvider는 동의를 요구합니다.
// ...
}
@MyDateTime
fun getDate(): Date {
val dateProvider: DateProvider // OK: 이 함수도 동의를 요구합니다.
// ...
}
fun displayDate() {
println(getDate()) // 오류: getDate()는 동의를 요구합니다.
}
Kotlin
복사
•
다른 사용자들이 사용할 라이브러리 코드에서 해당 API를 사용해야 하는 경우 동의 요구를 자신이 작성하는 API로 전파할 수 있다.
•
이를 위해 사용하는 API의 동의 요구 주석인 @RequiresOptIn 을 자신의 선언에 추가하면 된다.
•
이를 통해 해당 API 요소를 사용하면서도 동의 요구를 API 사용자에게 전달할 수 있다.
// 클라이언트 코드
fun getDate(dateProvider: DateProvider): Date { // 오류: DateProvider는 동의를 요구합니다.
// ...
}
fun displayDate() {
println(getDate()) // 경고: getDate()의 시그니처에 DateProvider가 포함되어 있으며, 이는 동의를 요구합니다.
}
Kotlin
복사
•
동의가 필요한 API를 암묵적으로 사용하는 경우에도 동의가 필요하다.
•
API 요소에 동의 요구 주석이 없더라도 해당 API의 시그니처에 동의를 요구하는 타입이 포함되어 있다면 경고가 발생한다.
•
여러 동의 요구가 있는 API를 사용할 경우 해당 요구 주석들을 모두 선언에 추가해야 한다.
동의 요구를 전파하지 않기
// 라이브러리 코드
@RequiresOptIn(message = "이 API는 실험적입니다. 예고 없이 변경될 수 있습니다.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class MyDateTime // 동의 요구 주석
@MyDateTime
class DateProvider // 동의를 요구하는 클래스
// 클라이언트 코드
@OptIn(MyDateTime::class)
fun getDate(): Date { // DateProvider를 사용하지만 동의 요구를 전파하지 않음
val dateProvider: DateProvider
// ...
}
fun displayDate() {
println(getDate()) // OK: 동의가 필요하지 않음
}
Kotlin
복사
•
라이브러리처럼 외부에 API를 노출하지 않는 모듈에서는 동의 요구를 전파하지 않고도 API를 사용할 수 있다.
•
이 경우 선언에 @OptIn 주석을 추가하고 동의 요구 주석을 인수로 전달하면 된다.
@OptIn(MyDateTime::class)
fun getDate(dateProvider: DateProvider): Date { // DateProvider가 시그니처에 포함되어 동의 요구가 전파됨
// ...
}
fun displayDate() {
println(getDate()) // 경고: getDate()는 동의를 요구합니다.
}
Kotlin
복사
•
그러나 함수 시그니처에 동의를 요구하는 타입이 포함된 경우에는 여전히 동의 요구가 전파된다.
@file:OptIn(MyDateTime::class)
Kotlin
복사
•
모든 함수와 클래스에서 동의 요구를 사용하려면 파일 상단에 파일 레벨 주석인 @file:OptIn 을 추가할 수 있다.
모듈 전체 동의
// Gradle을 사용하는 경우 다음과 같이 설정할 수 있다.
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
tasks.named<KotlinCompilationTask<*>>("compileKotlin").configure {
compilerOptions.freeCompilerArgs.add("-opt-in=org.mylibrary.OptInAnnotation")
}
Kotlin
복사
•
모듈 전체에서 동의를 요구하는 API를 사용하려면 -opt-in 컴파일 옵션을 사용하여 전체 모듈에 동의할 수 있다.
•
이를 통해 모듈 내 모든 선언이 @OptIn 주석을 사용하는 것과 동일한 효과를 얻는다.
API에 대해 동의 요구하기
동의 요구 주석 만들기
@RequiresOptIn
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class MyDateTime
Kotlin
복사
•
모듈 API 사용에 대해 명시적인 동의를 요구하려면 동의 요구 주석으로 사용할 주석 클래스를 생성해야 한다.
•
이 클래스는 @RequiresOptIn 으로 주석 처리되어야 한다.
•
동의 요구 주석은 몇 가지 요구 사항을 충족해야 한다.
◦
BINARY 또는 RUNTIME 유지
◦
EXPRESSION, FILE, TYPE 또는 TYPE_PARAMETER는 대상에 포함되지 않아야함
◦
매개변수를 가질 수 없음
•
동의 요구는 두 가지 심각도 수준 중 하나를 가질 수 있다.
◦
RequiresOptIn.Level.ERROR
▪
기본값
▪
동의가 필수이다.
▪
동의하지 않으면 해당 API를 사용하는 코드가 컴파일되지 않는다.
◦
RequiresOptIn.Level.WARNING
▪
동의가 필수가 아니지만 권장된다.
▪
동의하지 않으면 컴파일러가 경고를 발생시킨다.
@RequiresOptIn(level = RequiresOptIn.Level.WARNING, message = "이 API는 실험적입니다. 향후 호환되지 않게 변경될 수 있습니다.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
annotation class ExperimentalDateTime
Kotlin
복사
•
원하는 수준을 설정하려면 @RequiresOptIn 주석의 level 매개변수를 지정하면 된다.
•
추가적으로 API 사용자가 API 사용 시 특별한 조건에 대해 알릴 수 있는 메세지를 제공할 수 있다.
•
이 메세지는 동의 없이 API를 사용하는 사용자에게 컴파일러가 표시한다.
•
여러 독립적인 기능을 배포할 경우 각 기능에 대해 동의 요구 주석을 선언하는 것이 좋다.
•
이렇게 하면 클라이언트가 명시적으로 수용한 기능만 사용할 수 있으므로 API 사용이 더 안전해진다.
•
또한 각 기능에 대한 동의 요구를 독립적으로 제거할 수 있다.
API 요소에 주석 추가하기
@MyDateTime
class DateProvider
@MyDateTime
fun getTime(): Time {}
Kotlin
복사
•
API 요소 사용에 대해 동의를 요구하려면 해당 선언에 동의 요구 주석을 추가한다.
•
일부 언어 요소에 대해서는 동의 요구 주석을 적용할 수 없다는 점에 유의해야 한다.
◦
프로퍼티의 백킹 필드나 getter에는 주석을 달 수 없고 프로퍼티 자체에만 주석을 달 수 있다.
◦
로컬 변수나 값 매개변수에는 주석을 달 수 없다.
안정화 이전 API에 대한 동의 요구
@Deprecated("이 동의 요구는 더 이상 사용되지 않습니다. 코드에서 제거하십시오.")
@RequiresOptIn
annotation class ExperimentalDateTime
Kotlin
복사
•
안정되지 않은 기능에 대해 동의 요구를 사용하는 경우 API의 졸업 과정을 신중하게 처리하여 클라이언트 코드가 깨지지 않도록 해야 한다.
•
예비 안정 상태에 있는 API가 졸업하여 안정 상태로 출시되면 해당 선언에서 동의 요구 주석을 제거해야 한다.
•
그러면 클라이언트는 제한 없이 이를 사용할 수 있다.
•
그러나 기존 클라이언트 코드와의 호환성을 유지하기 위해 주석 클래스는 모듈에 남겨 두어야 한다.
•
API 사용자에게 모듈을 업데이트하도록 알리려면(주석을 제거하고 다시 컴파일) 주석을 @Deprecated 로 표시하고 폐기 메세지에 설명을 제공해야 한다.
•
이렇게 하면 동의 요구가 사라진 경우에도 클라이언트 코드가 여전히 호환성을 유지할 수 있다.