Como fornecer valor a uma anotação de um java constante

146

Eu estou pensando que isso pode não ser possível em Java porque a anotação e seus parâmetros são resolvidos em tempo de compilação. Eu tenho uma interface da seguinte maneira,

public interface FieldValues {
   String[] FIELD1 = new String[]{"value1", "value2"};
}

e outra classe como,

@SomeAnnotation(locations = {"value1", "value2"})
public class MyClass {
   ....
}

Marquei muitas classes com a anotação e gostaria de saber se posso evitar especificar as strings em todas as anotações que preferiria usar

@SomeAnnotation(locations = FieldValues.FIELD1)
public class MyClass {
   ....
}

No entanto, isso gera erros de compilação, como o valor da anotação, que deve ser um inicializador de matriz etc. Alguém sabe como eu posso usar uma constante String ou uma constante String [] para fornecer valor a uma anotação?

Kannan Ekanath
fonte

Respostas:

126

As constantes de compilação podem ser apenas primitivas e Strings :

15.28 Expressões constantes

Uma expressão constante em tempo de compilação é uma expressão que denota um valor do tipo primitivo ou uma String que não é concluída abruptamente e é composta usando apenas o seguinte:

  • Literais do tipo primitivo e literais do tipo String
  • Transmite para tipos primitivos e transmite para tipo String
  • [...] operadores [...]
  • Expressões entre parênteses cuja expressão contida é uma expressão constante.
  • Nomes simples que se referem a variáveis ​​constantes.
  • Nomes qualificados do formulário TypeName . Identificador que se refere a variáveis ​​constantes.

Na verdade, em java, não há como proteger itens em uma matriz. Em tempo de execução, alguém sempre pode fazer FieldValues.FIELD1[0]="value3", portanto, a matriz não pode ser realmente constante se olharmos mais profundamente.

irreputável
fonte
14
Enums também! :) :)
TacB0sS
1
@ TacB0sS, enums não são expressões constantes.
jaco0646
Bem ... talvez você deve dar uma chance e deixe-me saber ... Eu usá-los o tempo todo :)
TacB0sS
4
Uma especificação mais relevante está em Anotações . Além de uma expressão constante, um valor de anotação pode ser um inicializador de matriz , classe literal ou constante de enumeração .
Java0646
3
@ TacB0sS você pode usar enumem anotações, mas elas não são constantes em tempo de compilação. A diferença se torna aparente quando você escreve static final EnumType VARIABLE = EnumType.ENUM_CONSTANT;e tenta usar VARIABLEem uma anotação; não vai funcionar. Você pode usar apenas o EnumType.ENUM_CONSTANTque não é uma expressão constante, mas é especificamente permitido em anotações (e switchinstruções).
Holger
37

Você pode usar uma constante (ou seja, uma variável final estática) como parâmetro para uma anotação. Como um exemplo rápido, eu uso algo assim com bastante frequência:

import org.junit.Test;
import static org.junit.Assert.*;

public class MyTestClass
{
    private static final int TEST_TIMEOUT = 60000; // one minute per test

    @Test(timeout=TEST_TIMEOUT)
    public void testJDK()
    {
        assertTrue("Something is very wrong", Boolean.TRUE);
    }
}

Observe que é possível passar a TEST_TIMEOUTconstante diretamente para a anotação.

Imediatamente, não me lembro de ter tentado isso com uma matriz, então você pode estar enfrentando alguns problemas com pequenas diferenças em como as matrizes são representadas como parâmetros de anotação em comparação com variáveis ​​Java? Mas, quanto à outra parte da sua pergunta, você pode definitivamente usar uma String constante sem problemas.

EDIT: Eu apenas tentei isso com uma matriz String, e não correr para o problema que você mencionou - no entanto o compilador que me dizer que o "valor do atributo deve ser constante", apesar da matriz que está sendo definido como public static final String[]. Talvez não goste do fato de que matrizes são mutáveis? Hmm...

Andrzej Doyle
fonte
1
Sorte difícil para mim! Ah, sim, eu era capaz de passar Strings / Numbers, mas não arrays. Vou gastar um pouco mais tempo com isso e, se nada der certo vai aceitar a resposta :)
Kannan Ekanath
Sim, meu palpite seria que a mutabilidade da matriz FIELD1 é o problema aqui. Você pode declarar a matriz com um inicializador, porque nada mais pode ter acesso a essa matriz e, portanto, não pode ser alterado posteriormente.
colind
Isso resolve meu problema. Só era necessário compartilhar uma constante String entre anotações e código. Obrigado!
simon
1
variável final estática não é o único pré-requisito. Se você tentar calcular dinamicamente a variável, receberá a mesma mensagem de erro.
precisa
11

Você não está fornecendo uma matriz no seu exemplo. O seguinte compila bem:

public @interface SampleAnnotation {
    String[] sampleValues();
}

public class Values {
    public static final String val0 = "A";
    public static final String val1 = "B";

    @SampleAnnotation(sampleValues={ val0, val1 })
    public void foo() {
    }
}
Steve B.
fonte
4
Ele está sendo fornecido com uma matriz no exemplo, mas não uma criada diretamente na declaração de anotação.
colind
7

Alguém sabe como eu posso usar uma constante String ou constante String [] para fornecer valor a uma anotação?

Infelizmente, você não pode fazer isso com matrizes. Com variáveis ​​que não são da matriz, o valor deve ser estático final.

Kevin
fonte
5

Eu estou pensando que isso pode não ser possível em Java porque a anotação e seus parâmetros são resolvidos em tempo de compilação.

Com o Seam 2 http://seamframework.org/, você conseguiu resolver os parâmetros de anotação em tempo de execução, com a linguagem de expressão entre aspas duplas.

No Seam 3 http://seamframework.org/Seam3/Solder , esse recurso é o módulo Seam Solder

jorgwel
fonte
3
Não, você não resolveu os parâmetros em tempo de execução. O parâmetro foi resolvido no tempo de compilação. O fato de eles terem sido usados ​​para fazer algo em tempo de execução não tem nada a ver com quando seus valores foram definidos.
Fund Monica's Lawsuit
1

Você pode usar enum e referenciá-lo no campo de anotação

Kaustubh Thawari
fonte
1
Você deve adicionar um exemplo.
m02ph3u5 6/04