Comment fournir une valeur à une annotation à partir d'une constante Java

146

Je pense que cela n'est peut-être pas possible en Java car l'annotation et ses paramètres sont résolus au moment de la compilation. J'ai une interface comme suit,

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

et une autre classe comme,

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

Je marque de nombreuses classes avec l'annotation et j'aimerais savoir si je peux éviter de spécifier les chaînes dans chaque annotation que je préférerais plutôt utiliser

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

Cependant, cela donne des erreurs de compilation comme la valeur d'annotation devrait être un initialiseur de tableau, etc. Est-ce que quelqu'un sait comment je peux utiliser une constante String ou une constante String [] pour fournir une valeur à une annotation?

Kannan Ekanath
la source

Réponses:

127

Les constantes de compilation ne peuvent être que des primitives et des chaînes :

15.28. Expressions constantes

Une expression constante au moment de la compilation est une expression désignant une valeur de type primitif ou une chaîne qui ne se termine pas brusquement et qui est composée uniquement de ce qui suit:

  • Littéraux de type primitif et littéraux de type String
  • Conversion en types primitifs et conversion en type String
  • [...] les opérateurs [...]
  • Expressions entre parenthèses dont l'expression contenue est une expression constante.
  • Noms simples qui font référence à des variables constantes.
  • Noms qualifiés de la forme TypeName . Identifiant faisant référence à des variables constantes.

En fait, en java, il n'y a aucun moyen de protéger les éléments d'un tableau. Au moment de l'exécution, quelqu'un peut toujours le faire FieldValues.FIELD1[0]="value3", donc le tableau ne peut pas être vraiment constant si l'on regarde plus en profondeur.

irréprochable
la source
14
Enums aussi! :) :)
TacB0sS
1
@ TacB0sS, les énumérations ne sont pas des expressions constantes.
jaco0646
Eh bien ... vous devriez peut-être
essayer
4
Une spécification plus pertinente est sous Annotations . En plus d'une expression constante, une valeur d'annotation peut être un initialiseur de tableau , un littéral de classe ou une constante d'énumération .
jaco0646
3
@ TacB0sS que vous pouvez utiliser enumdans les annotations, mais ce n'est pas une constante de compilation. La différence devient apparente lorsque vous écrivez static final EnumType VARIABLE = EnumType.ENUM_CONSTANT;et essayez d'utiliser VARIABLEdans une annotation; ça ne marchera pas. Vous ne pouvez utiliser que EnumType.ENUM_CONSTANTce qui n'est pas une expression constante, mais spécifiquement autorisée dans les annotations (et les switchinstructions).
Holger
37

Vous pouvez utiliser une constante (c'est-à-dire une variable finale statique) comme paramètre pour une annotation. À titre d'exemple rapide, j'utilise assez souvent quelque chose comme ça:

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

Notez qu'il est possible de passer la TEST_TIMEOUTconstante directement dans l'annotation.

De façon désinvolte, je ne me souviens pas avoir déjà essayé cela avec un tableau, vous pouvez donc rencontrer des problèmes avec de légères différences dans la façon dont les tableaux sont représentés en tant que paramètres d'annotation par rapport aux variables Java? Mais comme pour l'autre partie de votre question, vous pouvez certainement utiliser une chaîne constante sans aucun problème.

EDIT: Je viens d'essayer cela avec un tableau String, et je n'ai pas rencontré le problème que vous avez mentionné - cependant le compilateur m'a dit que la "valeur d'attribut doit être constante" malgré le tableau défini comme public static final String[]. Peut-être que cela n'aime pas le fait que les tableaux sont mutables? Hum ...

Andrzej Doyle
la source
1
Tough Luck pour moi! Oh oui, j'ai pu passer des chaînes / nombres mais pas des tableaux. Je passerai un peu plus de temps là-dessus et si rien ne fonctionne, j'accepterai la réponse :)
Kannan Ekanath
Ouais, je suppose que la mutabilité du tableau FIELD1 est le problème ici. Vous êtes autorisé à déclarer le tableau avec un initialiseur de tableau car rien d'autre ne peut avoir accès à ce tableau et il ne peut donc pas être modifié ultérieurement.
ColinD le
Cela résout mon problème. Juste besoin de partager une constante String entre les annotations et le code. Merci!
simon
1
la variable finale statique n'est pas la seule condition préalable. Si vous essayez de calculer dynamiquement la variable, vous obtiendrez le même message d'erreur.
Wolfgang Fahl
11

Vous ne lui fournissez pas un tableau dans votre exemple. Ce qui suit se compile 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.
la source
4
Il est fourni avec un tableau dans l'exemple, mais pas un qui est créé directement dans la déclaration d'annotation.
ColinD le
7

Quelqu'un sait-il comment je peux utiliser une constante String ou String [] pour fournir une valeur à une annotation?

Malheureusement, vous ne pouvez pas faire cela avec des tableaux. Avec les variables non-tableau, la valeur doit être statique finale.

Kevin
la source
5

Je pense que cela n'est peut-être pas possible en Java car l'annotation et ses paramètres sont résolus au moment de la compilation.

Avec Seam 2 http://seamframework.org/, vous avez pu résoudre les paramètres d'annotation au moment de l'exécution, avec un langage d'expression entre guillemets.

Dans Seam 3 http://seamframework.org/Seam3/Solder , cette fonctionnalité est le module Seam Solder

Jorgwel
la source
3
Non, vous n'avez pas résolu les paramètres lors de l'exécution. Le paramètre a été résolu au moment de la compilation. Le fait qu'ils aient ensuite été utilisés pour faire quelque chose au moment de l'exécution n'a littéralement rien à voir avec le moment où leurs valeurs ont été définies.
Fund Monica's Lawsuit
1

Vous pouvez utiliser enum et faire référence à cette énumération dans le champ d'annotation

Kaustubh Thawari
la source
1
Vous devriez ajouter un exemple.
m02ph3u5 le