Como as diferentes políticas de retenção afetam minhas anotações?

175

Alguém pode explicar de forma clara as diferenças práticas entre os java.lang.annotation.RetentionPolicyconstantes SOURCE, CLASS, e RUNTIME?

Também não sei exatamente o que significa a frase "retendo anotação".

xdevel2000
fonte
5
A documentação ( java.sun.com/j2se/1.5.0/docs/api/java/lang/annotation/… ) é muito clara.
É verdade macia
Sim, eu já li, mas na prática não entendo como funciona. De fato, se eu tentar 'esta frase': "" "" As anotações devem ser registradas no arquivo de classe pelo compilador, mas não precisam ser retidas pela VM no tempo de execução. """ E, em seguida, abrir uma classe decompiled onde eu colocar uma anotação com a classe política de retenção de eu não encontrar nada ...
xdevel2000
2
Então, seu descompilador parece não suportar anotações. jd-gui funciona bem.
musikk
Obrigado o problema foi o meu descompilador dj e jad ... jd-gui me mostre !!
xdevel2000

Respostas:

210
  • RetentionPolicy.SOURCE: Descartar durante a compilação. Essas anotações não fazem sentido após a compilação ser concluída, portanto, elas não são gravadas no bytecode.
    Exemplo: @Override,@SuppressWarnings

  • RetentionPolicy.CLASS: Descartar durante o carregamento da classe. Útil ao executar o pós-processamento no nível de bytecode. Surpreendentemente, esse é o padrão.

  • RetentionPolicy.RUNTIME: Não descarte. A anotação deve estar disponível para reflexão no tempo de execução. Exemplo:@Deprecated

Origem: o URL antigo está morto agora hunter_meta e substituído por hunter-meta-2-098036 . Caso isso aconteça, estou carregando a imagem da página.

Imagem (Clique com o botão direito do mouse e selecione 'Abrir imagem em uma nova guia / janela') Captura de tela do site da Oracle

Favonius
fonte
1
obrigado pela citação, o mais interessante aqui é o caso de uso paraRetentionPolicy.CLASS
Max
2
você pode explicar por que RetentionPolicy.class é interessante / surpreendentemente o padrão?
sudocoder 12/01
1
@sudocoder - Consulte estes links: stackoverflow.com/a/5971247/373861 e stackoverflow.com/a/3849602/373861 . Eu acredito que essa política em particular é necessária para a instrumentação de bytecode. Embora eu nunca tenha usado.
Favonius
No final, diz No próximo artigo desta série, mostrarei como os recursos de reflexão do Java foram aprimorados para ajudá-lo a descobrir anotações em tempo de execução e como a Ferramenta de Processamento de Anotações "apt" permite que você use anotações em tempo de construção. , onde está este artigo?
Sushant
@ Shank: Bem, eu não tenho certeza de onde é :). Embora tenha aptsido descontinuado, consulte este documentos.oracle.com/javase/7/docs/technotes/guides/apt/… . Para descobrir anotações usando reflexão, existem vários tutoriais na Internet. Você pode começar examinando java.lang.Class::getAnno*métodos semelhantes em java.lang.reflect.Methode java.lang.reflect.Field.
Favonius
57

De acordo com seus comentários sobre a descompilação de classes, aqui está como eu acho que deve funcionar:

  • RetentionPolicy.SOURCE: Não aparecerá na classe descompilada

  • RetentionPolicy.CLASS: Aparece na classe descompilada, mas não pode ser inspecionada em tempo de execução com reflexão com getAnnotations()

  • RetentionPolicy.RUNTIME: Aparecem na classe descompilada e podem ser inspecionados em tempo de execução com reflexão com getAnnotations()

ewernli
fonte
Sim, eu também pensava assim, mas na classe descompilada nada está presente !!! e, portanto, eu estou confuso ... Eu vou tentar inspecionar o arquivo de classe com a ferramenta javap
xdevel2000
javap não retorna nada onde são colocados então?
xdevel2000
1
algum caso de uso de RetentionPolicy.CLASS?
Rahul
20

Exemplo mínimo executável

Nível de idioma :

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

@Retention(RetentionPolicy.SOURCE)
@interface RetentionSource {}

@Retention(RetentionPolicy.CLASS)
@interface RetentionClass {}

@Retention(RetentionPolicy.RUNTIME)
@interface RetentionRuntime {}

public static void main(String[] args) {
    @RetentionSource
    class B {}
    assert B.class.getAnnotations().length == 0;

    @RetentionClass
    class C {}
    assert C.class.getAnnotations().length == 0;

    @RetentionRuntime
    class D {}
    assert D.class.getAnnotations().length == 1;
}

Nível de bytecode : usando javap, observamos que a Retention.CLASSclasse anotada recebe um atributo de classe RuntimeInvisible :

#14 = Utf8               LRetentionClass;
[...]
RuntimeInvisibleAnnotations:
  0: #14()

enquanto a Retention.RUNTIMEanotação obtém um atributo de classe RuntimeVisible :

#14 = Utf8               LRetentionRuntime;
[...]
RuntimeVisibleAnnotations:
  0: #14()

e o Runtime.SOURCEanotado .classnão recebe nenhuma anotação.

Exemplos no GitHub para você brincar.

Ciro Santilli adicionou uma nova foto
fonte
Então, alguma idéia de qual é o uso do Runtime.SOURCE e Runtime.CLASS?
Praveen Kamath
@PraveenKamath Não conheço nenhum exemplo de utilidade. Provavelmente só acontece se você estiver fazendo coisas de nível mais baixo da JVM que a maioria dos desenvolvedores nunca faz. Deixe-me saber se você encontrar um aplicativo para eles.
Ciro Santilli escreveu:
5

Política de retenção: uma política de retenção determina em que momento uma anotação é descartada. É especificado usando as anotações internas do Java: @Retention[Sobre]

1.SOURCE: annotation retained only in the source file and is discarded
          during compilation.
2.CLASS: annotation stored in the .class file during compilation,
         not available in the run time.
3.RUNTIME: annotation stored in the .class file and available in the run time.
Ferdous Wahid
fonte
0
  • CLASSE : As anotações devem ser registradas no arquivo de classe pelo compilador, mas não precisam ser retidas pela VM no tempo de execução.
  • RUNTIME : as anotações devem ser registradas no arquivo de classe pelo compilador e retidas pela VM no tempo de execução, para que possam ser lidas reflexivamente.
  • FONTE : As anotações devem ser descartadas pelo compilador.

Documento Oracle

Michael Wong
fonte