Atualizado: 09/11/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

Criação e Uso de Anotações Personalizadas em Java

Além das anotações fornecidas pela linguagem (como @Override, @Deprecated e @FunctionalInterface), o Java permite criar anotações personalizadas — úteis para marcar e configurar elementos do código-fonte.

Essas anotações são definidas com o modificador @interface, que cria uma estrutura semelhante a um interface, mas destinada a armazenar metadados:

// Declaração de uma anotação chamada MyAnnotation
@interface MyAnnotation { }

Assim como interfaces comuns, as anotações são convertidas em bytecode e ficam acessíveis para ferramentas, compiladores e frameworks. Por padrão, todas as anotações estendem implicitamente a interface java.lang.annotation.Annotation.


Aplicando uma anotação

@interface MyAnnotation { }

@MyAnnotation
class Thing {
    @MyAnnotation
    String name;
}

Aqui, a anotação @MyAnnotation foi aplicada tanto à classe quanto ao campo name. Por padrão, sem restrições, uma anotação pode ser usada em qualquer declaração, exceto em parâmetros de tipo ou uso de tipo (genéricos, casts etc.).


Meta-anotações

O Java fornece anotações especiais que servem para configurar o comportamento de outras anotações. Essas são chamadas de meta-anotações, e as mais usadas são:

Meta-anotaçãoDescrição
@TargetDefine onde a anotação pode ser aplicada (classe, método, campo, etc.)
@RetentionDefine até quando a anotação será mantida (em tempo de compilação, classe ou execução)
@DocumentedIndica que a anotação deve aparecer na documentação Javadoc
@InheritedFaz com que subclasses herdem anotações aplicadas à superclasse
@RepeatablePermite aplicar a mesma anotação mais de uma vez ao mesmo elemento

@Target

A meta-anotação @Target define em quais elementos a anotação pode ser usada. Ela recebe um ou mais valores de ElementType, que indicam o tipo de elemento suportado.

Exemplo:

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target({ElementType.FIELD, ElementType.RECORD_COMPONENT, ElementType.TYPE})
@interface MyAnnotation { }

Essa definição permite aplicar @MyAnnotation a campos, classes/interfaces e componentes de records:

@MyAnnotation
class Thing {
    @MyAnnotation
    String name;
}

Aplicações em outros contextos (como métodos) gerariam erro de compilação.


Elementos de anotações

Os elementos de uma anotação são definidos dentro de seu corpo e se comportam como métodos sem parâmetros:

@interface MyAnnotation {
    String value();
    int count();
}

Ao aplicar a anotação, você deve fornecer valores para esses elementos:

@MyAnnotation(value = "Thing", count = 1)
class Thing { }

A sintaxe se assemelha a uma chamada de construtor com argumentos nomeados.


Valores padrão para elementos

Os elementos podem ter valores padrão, definidos com a palavra-chave default:

@interface MyAnnotation {
    String value() default "DefaultValue";
    int count() default 0;
}

Assim, os valores podem ser omitidos ao aplicar a anotação:

@MyAnnotation(value = "TypeA", count = 2)
class TypeA { }

@MyAnnotation(value = "TypeB")   // count usa valor padrão (0)
class TypeB { }

@MyAnnotation(count = 1)         // value usa valor padrão
class TypeC { }

@MyAnnotation                    // ambos usam valores padrão
class TypeD { }

Elementos do tipo array

Elementos também podem ser arrays, com valores padrão entre chaves {}:

@interface MyAnnotation {
    String[] emails() default {"user1@mail.com", "user2@mail.com"};
    String[] tags() default {}; // array vazio
}

Esses valores padrão são avaliados dinamicamente — não são armazenados literalmente na anotação.


@Retention

A meta-anotação @Retention controla quanto tempo a anotação é mantida e onde ela pode ser acessada.

Ela recebe um valor do enum RetentionPolicy:

PolíticaDescrição
SOURCEA anotação existe apenas no código-fonte e é descartada na compilação. Ideal para ferramentas de análise de código.
CLASSA anotação é gravada no bytecode (.class), mas não é acessível em tempo de execução. (Valor padrão)
RUNTIMEA anotação é preservada e pode ser lida via reflexão (Reflection) durante a execução.

Exemplo:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

@Retention(RetentionPolicy.RUNTIME)   // Disponível em tempo de execução
@Target(ElementType.TYPE)              // Aplicável a classes e interfaces
@interface MyAnnotation {
    String value() default "DefaultValue";
}

Com RetentionPolicy.RUNTIME, frameworks e ferramentas podem ler e agir sobre anotações usando a API de reflexão, o que é essencial para tecnologias como Spring, JUnit, Jakarta EE, entre outras.


Resumo

ConceitoFunção
@interfaceDefine uma nova anotação personalizada
@TargetEspecifica onde a anotação pode ser usada
@RetentionDefine até quando a anotação é mantida (código-fonte, bytecode ou execução)
Valores padrãoPermitem omitir parâmetros ao aplicar a anotação
Meta-anotaçõesAnotações que configuram o comportamento de outras anotações

Conclusão

Criar anotações personalizadas em Java é o primeiro passo para explorar o poder dos metadados e da configuração declarativa. Combinadas a meta-anotações como @Target e @Retention, elas se tornam ferramentas fundamentais para o desenvolvimento de frameworks, validações automáticas e injeção de dependências.