Anotações de Kotlin
1. Visão geral
Neste tutorial, daremos uma visão geral das anotações do Kotlin.
Vamos demonstrar como aplicá-los, como criar e personalizar os nossos próprios. Em seguida, discutiremos brevemente a interação entre anotações e palavras-chave em Java e Kotlin.
Finalmente, daremos um exemplo simples de validação de classe que ilustra como podemos processar as anotações.
2. Aplicando anotações
No Kotlin, aplicamos uma anotação colocando seu nome prefixado com o símbolo @ na frente de um elemento de código. Por exemplo, se quisermos aplicar uma anotação chamadaPositive, devemos escrever o seguinte:
@Positive val amount: Float
Muitas vezes, as anotações têm parâmetros. The annotation parameters must be compile-time constants and must be of the following types:
-
Tipos primitivos Kotlin (Int, Byte, Short, Float, Double, Char, Boolean)
-
enumerações
-
referências de classe
-
anotações
-
matrizes dos tipos mencionados acima
Se uma anotação exigir um parâmetro, forneceremos seu valor entre parênteses, como em uma chamada de função:
@SinceKotlin(version="1.3")
No caso, quando um parâmetro de anotação também é uma anotação, devemos omitir o símbolo @:
@Deprecated(message="Use rem(other) instead", replaceWith=ReplaceWith("rem(other)"))
Se um parâmetro de anotação for um objeto de classe, devemos adicionar::class ao nome da classe, por exemplo:
@Throws(IOException::class)
Se precisarmos especificar que um parâmetro de anotação pode ter vários valores, basta passar uma matriz desses valores:
@Throws(exceptionClasses=arrayOf(IOException::class, IllegalArgumentException::class))
A partir do Kotlin 1.2, também podemos usar a seguinte sintaxe:
@Throws(exceptionClasses=[IOException::class, IllegalArgumentException::class])
3. Declarações de anotações
Para declarar uma anotação, definimos uma classe e colocamos a palavra-chaveannotation antes declass one. Por sua natureza,declarations of annotation cannot contain any code.
A anotação mais simples não possui parâmetros:
annotation class Positive
A declaração de uma anotação que requer um parâmetro é como uma classe com um construtor primário:
annotation class Prefix(val prefix: String)
Quando declaramos nossas anotações personalizadas, devemos especificar a quais elementos de código eles podem ser aplicados e onde devem ser armazenados. As anotações usadas para definir esta meta-informação são chamadasmeta-annotations.
Nas próximas seções, vamos discuti-los brevemente. Para as informações mais recentes, podemos sempre verificar oofficial documentation.
3.1. @Target
Esta meta-anotação especifica a quais elementos de código essa anotação pode se referir. It has a required parameter that must be an instance of the AnnotationTarget enumeration or an array thereof. Portanto, podemos especificar que queremos aplicar nossa anotação aos seguintes elementos:
-
CLASSE
-
ANNOTATION_CLASS
-
TYPE_PARAMETER
-
PROPRIEDADE
-
CAMPO
-
LOCAL_VARIABLE
-
VALUE_PARAMETER
-
CONSTRUTOR
-
FUNÇÃO
-
PROPERTY_GETTER
-
PROPERTY_SETTER
-
TYPE
-
EXPRESSÃO
-
FILE
-
TYPEALIAS
Se não especificarmos explicitamente, a anotação correspondente poderá ser aplicada aos seguintes elementos por padrão:
CLASS, PROPERTY, FIELD, LOCAL_VARIABLE, VALUE_PARAMETER, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER
3.2. @Retention
Esta meta-anotação especifica se a anotação deve ser armazenada no arquivo.class e se deve ser visível para uma reflexão. Its required parameter must be an instance of the AnnotationRetention enumeration que possui os seguintes elementos:
-
FONTE
-
BINÁRIO
-
TEMPO DE EXECUÇÃO
Ao contrário do Java, o valor padrão para@Retention em Kotlin éRUNTIME.
3.3. @Repeatable
@Repeatable especifica se um elemento pode ter várias anotações do mesmo tipo. Esta meta-anotação não aceita parâmetros.
3.4. @MustBeDocumented
@MustBeDocumented especifica se a documentação da anotação deve ser incluída na documentação gerada. Essa meta-anotação também não aceita parâmetros.
4. Interoperabilidade Java com anotações
Kotlin é geralmente mais conciso em relação ao Java. Por exemplo, ele cria automaticamente métodos adicionais para nós, como quando declaramos uma propriedade:
val name: String?;
o compilador cria automaticamente um campo privado e um getter e setter para essa propriedade. Como resultado, surge uma pergunta: se adicionarmos uma anotação à propriedade, onde ela será aplicada? Para o getter, setter ou para o próprio campo?
Em Kotlin, se decorarmos uma propriedade com uma anotação definida em um código Java, ela é aplicada ao campo correspondente.
Agora podemos enfrentar um problema se a anotação requer que um campo seja público, por exemplo, com a anotação@Rule de JUnit. Para evitar ambiguidade, o Kotlin possui a chamada declaração de destino do site de uso.
4.1. Declarações de destino do site de uso
Os destinos do site de uso são opcionais. Nós os colocamos entre o símbolo@ e o nome da anotação, usando o sinal de dois pontos como separador. A sintaxe nos permite especificar vários nomes de anotação ao mesmo tempo:
No caso de colocar@get:Positive em um campo Kotlin, isso significaria que a anotação deveria realmente ter como alvo o getter gerado para aquele campo.
O Kotlin suporta os seguintes valores dos destinos do site de uso que correspondem a:
-
delegate - um campo que armazena uma propriedade delegada
-
field - um campo gerado para uma propriedade
-
file - uma classe que contém funções de nível superior e propriedades definidas naquele arquivo
-
get/set - a propriedade getter / setter
-
param - um parâmetro do construtor
-
property - a propriedade do Kotlin, não é acessível a partir do código Java
-
receiver - o parâmetro receptor de uma função de extensão ou propriedade
4.2. Anotações relacionadas à JVM
As seguintes anotações do Kotlin permitem personalizar como elas podem ser usadas no código Java:
-
@JvmName - permite alterar o nome do método ou campo Java gerado
-
@JvmStatic - permite-nos especificar que o método ou campo Java gerado deve ser estático
-
@JvmOverloads - indica que o compilador Kotlin deve gerar funções de sobrecarga substituindo os parâmetros padrão
-
@JvmField - indica que o campo Java gerado deve ser público sem getter / setter
Algumas anotações Java tornam-se palavras-chave do Kotlin e vice-versa:
Java | Kotlin |
---|---|
@Sobrepor |
sobrepor |
volátil |
@Volátil |
strictfp |
@Strictfp |
sincronizado |
@synchronized |
transitório |
@Transient |
joga |
@Throws |
5. Anotações de processamento
Para demonstrar como podemos processar anotações, vamos criar um validador simples. Aqui apresentamos apenas a ideia enquanto o código completo está disponível em nossorepository no Github.
Suponha que devamos decidir se uma instância deItem é válida:
class Item(val amount: Float, val name: String)
Assumimos que uma instânciaItem é válida se o valor deamount for positivo e o valor dename forAlice ouBob.
Para este fim, vamos decorar as propriedades da classeItem com nossas anotações personalizadas:PositiveeAllowedNames:
class Item(
@Positive val amount: Float,
@AllowedNames(["Alice", "Bob"]) val name: String)
Em nossa implementação ingênua, apenas obtemos as propriedades deItem:
val fields = item::class.java.declaredFields
for (field in fields) {...}
e itere sobre todas as anotações de cada propriedade:
for (annotation in field.annotations) {...}
para encontrar aqueles com os quais decoramos as propriedades deItem.
Por exemplo, podemos detectar seAllowedNames está presente em uma propriedade por meio do comando:
field.isAnnotationPresent(AllowedNames::class.java)
Depois que a anotação estiver presente, poderemos decidir facilmente se a propriedade tem um valor válido apenas comparando-o com os valores permitidos:
val allowedNames = field.getAnnotation(AllowedNames::class.java)?.names
We should be aware that annotations use the Java Reflection API. Como resultado, o desempenho do código pode sofrer se dependermos fortemente de anotações.
6. Conclusão
Neste artigo, consideramos as anotações Kotlin e suas contrapartes Java. Descrevemos como aplicar anotações Kotlin, como criar anotações personalizadas e, em seguida, como processá-las.
Como podemos ver, as anotações do Kotlin são bastante semelhantes às do Java. No entanto, nosso tutorialCreating a Custom Annotation in Java também pode ser útil.
Como sempre, o código completo está disponível emin our GitHub repository.