Аннотации
Объявление аннотации
Аннотации служат для добавления метаданных к коду. Чтобы объявить аннотацию, поместите модификатор annotation перед классом:
annotation class Fancy
Дополнительные атрибуты аннотации можно указать, добавив мета-аннотации к классу аннотации:
-
@Targetопределяет возможные типы элементов, которые могут быть аннотированы этой аннотацией (классы, функции, свойства, выражения и т. д.); -
@Retentionопределяет, хранится ли аннотация в скомпилированных файлах класса и доступна ли она через рефлексию во время выполнения (по умолчанию, оба значения — true); -
@Repeatableпозволяет использовать одну и ту же аннотацию для одного элемента несколько раз; -
@MustBeDocumentedуказывает, что аннотация является частью публичного API и должна быть включена в сигнатуру класса или метода, показанную в документации API.
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class Fancy
Использование
@Fancy class Foo {
@Fancy fun baz(@Fancy foo: Int): Int {
return (@Fancy 1)
}
}
Если вам нужно аннотировать первичный конструктор класса, добавьте ключевое слово constructor к объявлению конструктора и поместите аннотации перед ним:
class Foo @Inject constructor(dependency: MyDependency) { ... }
Вы также можете аннотировать аксессоры свойств:
class Foo {
var x: MyDependency? = null
@Inject set
}
Конструкторы
Аннотации могут иметь конструкторы, которые принимают параметры.
annotation class Special(val why: String)
@Special("example") class Foo {}
Разрешенные типы параметров:
- типы, соответствующие примитивным типам Java (Int, Long и т. д.);
- строки;
- классы (
Foo::class); - перечисления;
- другие аннотации;
- массивы перечисленных выше типов.
Параметры аннотации не могут иметь типы с возможностью null, так как JVM не поддерживает хранение null в качестве значения атрибута аннотации.
Если аннотация используется в качестве параметра другой аннотации, ее имя не предваряется символом @:
annotation class ReplaceWith(val expression: String)
annotation class Deprecated(
val message: String,
val replaceWith: ReplaceWith = ReplaceWith(""))
@Deprecated("This function is deprecated, use === instead", ReplaceWith("this === other"))
Если вам нужно указать класс в качестве аргумента аннотации, используйте Kotlin-класс (KClass). Компилятор Kotlin автоматически преобразует его в Java-класс, чтобы Java-код мог нормально обращаться к аннотациям и аргументам.
import kotlin.reflect.KClass annotation class Ann(val arg1: KClass<*>, val arg2: KClass<out Any>) @Ann(String::class, Int::class) class MyClass
Лямбды
Аннотации также могут использоваться для лямбд. Они будут применены к invoke() методу, в который генерируется тело лямбды. Это полезно для фреймворков, таких как Quasar, которые используют аннотации для управления конкурентностью.
annotation class Suspendable
val f = @Suspendable { Fiber.sleep(10) }
Цели применения аннотаций
При аннотировании свойства или параметра первичного конструктора, из соответствующего Kotlin-элемента генерируется несколько Java-элементов, а значит, есть несколько возможных мест для аннотации в сгенерированном Java-байткоде. Чтобы указать, как именно должна быть сгенерирована аннотация, используйте следующий синтаксис:
class Example(@field:Ann val foo, // annotate Java field
@get:Ann val bar, // annotate Java getter
@param:Ann val quux) // annotate Java constructor parameter
Тот же синтаксис можно использовать для аннотации всего файла. Для этого поместите аннотацию с целевым file на верхнем уровне файла, перед директивой пакета или перед всеми импортами, если файл находится в пакете по умолчанию:
@file:JvmName("Foo")
package org.jetbrains.demo
Если у вас есть несколько аннотаций с той же целью, вы можете избежать повторения цели, добавив скобки после цели и поместив все аннотации внутри скобок:
class Example {
@set:[Inject VisibleForTesting]
var collaborator: Collaborator
}
Полный список поддерживаемых целей применения аннотаций:
-
file; -
property(аннотации с этой целью не видны для Java); -
field; -
get(получатель свойства); -
set(установщик свойства); -
receiver(параметр получателя расширенной функции или свойства); -
param(параметр конструктора); -
setparam(параметр установщика свойства); -
delegate(поле, хранящее экземпляр делегата для делегированного свойства).
Для аннотации параметра получателя расширенной функции используйте следующий синтаксис:
fun @receiver:Fancy String.myExtension() { ... }
Если вы не указываете цель применения аннотации, цель выбирается в соответствии с @Target аннотацией используемой аннотации. Если применимо несколько целей, используется первая применимая цель из следующего списка:
-
param; -
property; -
field.
Аннотации Java
Аннотации Java полностью совместимы с Kotlin:
import org.junit.Test
import org.junit.Assert.*
import org.junit.Rule
import org.junit.rules.*
class Tests {
// apply @Rule annotation to property getter
@get:Rule val tempFolder = TemporaryFolder()
@Test fun simple() {
val f = tempFolder.newFile()
assertEquals(42, getTheAnswer())
}
}
Так как порядок параметров для аннотации, написанной на Java, не определен, вы не можете использовать обычный синтаксис вызова функции для передачи аргументов. Вместо этого вам нужно использовать синтаксис именованных аргументов:
// Java
public @interface Ann {
int intValue();
String stringValue();
}
// Kotlin @Ann(intValue = 1, stringValue = "abc") class C
Как и в Java, особый случай — параметр value; его значение можно указать без явного имени:
// Java
public @interface AnnWithValue {
String value();
}
// Kotlin
@AnnWithValue("abc") class C
Массивы как параметры аннотаций
Если аргумент value в Java имеет тип массива, он становится параметром типа vararg в Kotlin:
// Java
public @interface AnnWithArrayValue {
String[] value();
}
// Kotlin
@AnnWithArrayValue("abc", "foo", "bar") class C
Для других аргументов, имеющих тип массива, вам нужно использовать синтаксис литералов массива (с Kotlin 1.2) или arrayOf(...):
// Java
public @interface AnnWithArrayMethod {
String[] names();
}
// Kotlin 1.2+:
@AnnWithArrayMethod(names = ["abc", "foo", "bar"])
class C
// Older Kotlin versions:
@AnnWithArrayMethod(names = arrayOf("abc", "foo", "bar"))
class D
Доступ к свойствам экземпляра аннотации
Значения экземпляра аннотации доступны как свойства в Kotlin-коде:
// Java
public @interface Ann {
int value();
}
// Kotlin
fun foo(ann: Ann) {
val i = ann.value
}
© 2010–2020 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/reference/annotations.html