Cómo suministrar valor a una anotación desde un Java constante


146

Estoy pensando que esto puede no ser posible en Java porque la anotación y sus parámetros se resuelven en tiempo de compilación. Tengo una interfaz de la siguiente manera,

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

y otra clase como,

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

Marco muchas clases con la anotación y me gustaría saber si puedo evitar especificar las cadenas en cada anotación que preferiría usar

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

Sin embargo, esto genera errores de compilación como que el valor de anotación debe ser un inicializador de matriz, etc. ¿Alguien sabe cómo puedo usar una constante de cadena o una constante de cadena [] para proporcionar valor a una anotación?

Respuestas:


127

Las constantes de compilación solo pueden ser primitivas y cadenas :

15.28. Expresiones constantes

Una expresión constante en tiempo de compilación es una expresión que denota un valor de tipo primitivo o una cadena que no se completa abruptamente y se compone utilizando solo lo siguiente:

  • Literales de tipo primitivo y literales de tipo String
  • Lanzamientos a tipos primitivos y lanzamientos a tipo String
  • [...] operadores [...]
  • Expresiones entre paréntesis cuya expresión contenida es una expresión constante.
  • Nombres simples que se refieren a variables constantes.
  • Nombres calificados de la forma TypeName . Identificador que se refiere a variables constantes.

En realidad, en Java no hay forma de proteger los elementos en una matriz. En tiempo de ejecución, alguien siempre puede hacer FieldValues.FIELD1[0]="value3", por lo tanto, la matriz no puede ser realmente constante si miramos más profundamente.


14
¡Enums también! :) :)
TacB0sS

1
@ TacB0sS, las enumeraciones no son expresiones constantes.
jaco0646

Bueno ... tal vez deberías
intentarlo

44
Una especificación más relevante está en Anotaciones . Además de una expresión constante, un valor de anotación puede ser un inicializador de matriz , literal de clase o constante de enumeración .
jaco0646

3
@ TacB0sS puede usar enumen anotaciones, pero no son constantes en tiempo de compilación. La diferencia se hace evidente cuando escribe static final EnumType VARIABLE = EnumType.ENUM_CONSTANT;e intenta usar VARIABLEen una anotación; No funcionará. Solo puede usar lo EnumType.ENUM_CONSTANTque no es una expresión constante, sino que se permite específicamente en anotaciones (y switchdeclaraciones).
Holger

37

Puede usar una constante (es decir, una variable final estática) como parámetro para una anotación. Como ejemplo rápido, uso algo como esto con bastante frecuencia:

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);
    }
}

Tenga en cuenta que es posible pasar la TEST_TIMEOUTconstante directamente a la anotación.

Por casualidad, no recuerdo haber intentado esto con una matriz, por lo que es posible que tenga algunos problemas con pequeñas diferencias en la forma en que las matrices se representan como parámetros de anotación en comparación con las variables de Java. Pero en cuanto a la otra parte de su pregunta, definitivamente podría usar una cadena constante sin ningún problema.

EDIT: He acaba de intentar esto con una matriz de cadenas, y no encontrarse con el problema que usted ha mencionado - sin embargo, el compilador no me diga que el "valor del atributo debe ser constante" a pesar de la matriz se define como public static final String[]. ¿Quizás no le gusta el hecho de que las matrices son mutables? Hmm ...


1
¡Suerte dura para mí! Oh, sí, pude pasar cadenas / números pero no matrices. Pasaré un poco más de tiempo en esto y si nada funciona aceptaré la respuesta :)
Kannan Ekanath

Sí, supongo que la mutabilidad de la matriz FIELD1 es el problema aquí. Puede declarar la matriz con un inicializador de matriz porque nada más puede tener acceso a esa matriz y, por lo tanto, no se puede cambiar más adelante.
ColinD

Esto resuelve mi problema. Solo necesitaba compartir una cadena constante entre anotaciones y código. ¡Gracias!
Simon

1
La variable estática final no es el único requisito previo. Si intenta calcular dinámicamente la variable, obtendrá el mismo mensaje de error.
Wolfgang Fahl el

11

No le está proporcionando una matriz en su ejemplo. Lo siguiente compila bien:

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() {
    }
}

44
Se suministra con una matriz en el ejemplo, solo que no se crea directamente en la declaración de anotación.
ColinD

7

¿Alguien sabe cómo puedo usar una constante String o String [] constante para proporcionar valor a una anotación?

Desafortunadamente, no puede hacer esto con matrices. Con variables sin matriz, el valor debe ser estático final.


5

Estoy pensando que esto puede no ser posible en Java porque la anotación y sus parámetros se resuelven en tiempo de compilación.

Con Seam 2 http://seamframework.org/ pudo resolver los parámetros de anotación en tiempo de ejecución, con lenguaje de expresión entre comillas dobles.

En Seam 3 http://seamframework.org/Seam3/Solder , esta característica es el módulo Seam Solder


3
No, no resolvió los parámetros en tiempo de ejecución. El parámetro se resolvió en tiempo de compilación. El hecho de que luego se usaran para hacer algo en tiempo de ejecución literalmente no tiene nada que ver cuando se establecieron sus valores.
Financia la demanda de Mónica el

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.