So liefern Sie einen Wert für eine Anmerkung aus einem konstanten Java

146

Ich denke, dass dies in Java möglicherweise nicht möglich ist, da Annotation und ihre Parameter zur Kompilierungszeit aufgelöst werden. Ich habe eine Schnittstelle wie folgt:

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

und eine andere Klasse als,

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

Ich markiere viele Klassen mit der Annotation und möchte wissen, ob ich es vermeiden kann, die Zeichenfolgen in jeder Annotation anzugeben, die ich stattdessen lieber verwenden würde

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

Dies führt jedoch zu Kompilierungsfehlern, z. B. sollte der Annotationswert ein Array-Initialisierer usw. sein. Weiß jemand, wie ich eine String-Konstante oder eine String [] -Konstante verwenden kann, um einer Annotation einen Wert zu liefern?

Kannan Ekanath
quelle

Antworten:

126

Kompilierungskonstanten können nur Grundelemente und Zeichenfolgen sein :

15.28. Konstante Ausdrücke

Ein Konstantenausdruck zur Kompilierungszeit ist ein Ausdruck, der einen Wert vom primitiven Typ oder einen String bezeichnet, der nicht abrupt abgeschlossen wird und nur aus den folgenden Komponenten besteht:

  • Literale primitiven Typs und Literale vom Typ String
  • Casts zu primitiven Typen und Casts zu Typ String
  • [...] Operatoren [...]
  • Ausdrücke in Klammern, deren enthaltener Ausdruck ein konstanter Ausdruck ist.
  • Einfache Namen, die sich auf konstante Variablen beziehen.
  • Qualifizierte Namen des Formulars TypeName . Kennung , die sich auf konstante Variablen bezieht.

Tatsächlich gibt es in Java keine Möglichkeit, Elemente in einem Array zu schützen. Zur Laufzeit kann es immer jemand tun FieldValues.FIELD1[0]="value3", daher kann das Array nicht wirklich konstant sein, wenn wir genauer hinschauen.

unwiderlegbar
quelle
14
Aufzählungen auch! :) :)
TacB0sS
1
@ TacB0sS, Aufzählungen sind keine konstanten Ausdrücke.
jaco0646
Nun ... vielleicht solltest du es
versuchen
4
Eine relevantere Spezifikation finden Sie unter Anmerkungen . Zusätzlich zu einem konstanten Ausdruck kann ein Annotationswert ein Array-Initialisierer , ein Klassenliteral oder eine Enum-Konstante sein .
jaco0646
3
@ TacB0sS können Sie enumin Anmerkungen verwenden, aber sie sind keine Konstante für die Kompilierungszeit. Der Unterschied wird deutlich, wenn Sie schreiben static final EnumType VARIABLE = EnumType.ENUM_CONSTANT;und versuchen, ihn VARIABLEin einer Anmerkung zu verwenden. es wird nicht funktionieren. Sie können nur verwenden, EnumType.ENUM_CONSTANTwas kein konstanter Ausdruck ist, sondern speziell in Anmerkungen (und switchAnweisungen) zulässig ist .
Holger
37

Sie können eine Konstante (dh eine statische endgültige Variable) als Parameter für eine Anmerkung verwenden. Als schnelles Beispiel verwende ich so etwas ziemlich oft:

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

Beachten Sie, dass es möglich ist, die TEST_TIMEOUTKonstante direkt in die Annotation zu übergeben.

Ich erinnere mich nicht, dass ich dies jemals mit einem Array versucht habe, sodass Sie möglicherweise auf einige Probleme mit geringfügigen Unterschieden bei der Darstellung von Arrays als Anmerkungsparameter im Vergleich zu Java-Variablen stoßen. Aber für den anderen Teil Ihrer Frage könnten Sie definitiv ohne Probleme einen konstanten String verwenden.

BEARBEITEN: Ich habe dies gerade mit einem String-Array versucht und bin nicht auf das von Ihnen erwähnte Problem gestoßen. Der Compiler hat mir jedoch mitgeteilt, dass der "Attributwert konstant sein muss", obwohl das Array als definiert ist public static final String[]. Vielleicht gefällt es nicht, dass Arrays veränderlich sind? Hmm ...

Andrzej Doyle
quelle
1
Pech für mich! Oh yah, ich konnte Strings / Numbers übergeben, aber keine Arrays. Ich werde ein bisschen mehr Zeit damit verbringen und wenn nichts
klappt
Ja, ich würde vermuten, dass die Veränderlichkeit des FIELD1-Arrays hier das Problem ist. Sie dürfen das Array mit einem Array-Initialisierer deklarieren, da nichts anderes auf dieses Array zugreifen kann und es später nicht mehr geändert werden kann.
ColinD
Dies löst mein Problem. Muss nur eine String-Konstante zwischen Annotationen und Code teilen. Vielen Dank!
Simon
1
Eine statische Endvariable ist nicht die einzige Voraussetzung. Wenn Sie versuchen, die Variable dynamisch zu berechnen, wird dieselbe Fehlermeldung angezeigt.
Wolfgang Fahl
11

Sie liefern in Ihrem Beispiel kein Array. Folgendes kompiliert gut:

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.
quelle
4
Im Beispiel wird es mit einem Array geliefert, das jedoch nicht direkt in der Anmerkungsdeklaration erstellt wird.
ColinD
7

Weiß jemand, wie ich eine String-Konstante oder eine String [] -Konstante verwenden kann, um einer Annotation einen Wert zu geben?

Mit Arrays ist dies leider nicht möglich. Bei Nicht-Array-Variablen muss der Wert endgültig statisch sein.

Kevin
quelle
5

Ich denke, dass dies in Java möglicherweise nicht möglich ist, da Annotation und ihre Parameter zur Kompilierungszeit aufgelöst werden.

Mit Seam 2 http://seamframework.org/ konnten Sie Annotationsparameter zur Laufzeit auflösen, wobei die Ausdruckssprache in doppelte Anführungszeichen gesetzt wurde.

In Seam 3 http://seamframework.org/Seam3/Solder ist diese Funktion das Modul Seam Solder

Jorgwel
quelle
3
Nein, Sie haben die Parameter zur Laufzeit nicht aufgelöst. Die Parameter wurden zur Kompilierungszeit aufgelöst. Dass sie dann zur Laufzeit verwendet wurden, hat buchstäblich nichts damit zu tun, wann ihre Werte festgelegt wurden.
Fund Monica Klage
1

Sie können enum verwenden und diese Aufzählung im Anmerkungsfeld referenzieren

Kaustubh Thawari
quelle
1
Sie sollten ein Beispiel hinzufügen.
m02ph3u5