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?

Kannan Ekanath
fuente

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.

irreputable
fuente
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 ...

Andrzej Doyle
fuente
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() {
    }
}
Steve B.
fuente
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.

Kevin
fuente
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

jorgwel
fuente
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
1

Puede usar enum y referir esa enumeración en el campo de anotación

Kaustubh Thawari
fuente
1
Deberías agregar un ejemplo.
m02ph3u5