Zugriff auf Annotation

Guten Morgen Community,

meine Frage zielt zwar prinzipiell auf Annotationen ab, aber da ich als DI Container Spring verwende poste ich es mal hier, vielleicht gibt es noch einen alternativen Tipp in Bezug auf Spring.

Ich habe eine Klasse, welche 2 Member vom selben Typ enthalten, welche ich per @Autowired injizieren möchte:

public class Test {

	@Autowired
	@Prefix("prefix1")
	A	a1;

	@Autowired
	@Prefix("prefix2")
	A	a2;
}```

nun soll jede Instanz ein Merkmal mitbekommen (**@Prefix("")**), welche sie dann zur internen Verwendung weiterverarbeitet wird. In dem Fall sollen eindeutige aussagekräftige ID's fürs JSF Binding vergeben werden.

Nun möchte ich gern in **A** wissen, welches Prefix für die Instanz vergeben wurde:
```@Component
@Scope("prototype")
public class A {

	@PostConstruct
	public void init() {
		/** Zugriff auf Prefix.value??? */
	}
}```

Zur Vollständigkeit: Prefix ist eine eigene Annotation:
```public @interface Prefix {
	String value();
}```

Meinst Du sowas?

final String prefStr = (pref == null) ?  null  : pref.value();```

Mal aus’m Kopp:

Prefix prefix = A.class.getField("a1").getAnnotation("Prefix");
String value = prefix.value();

Voraussetzung ist natürlich, das bei der Definition von Prefix als Retention RUNTIME gesetzt ist.

Ich probiere es mal aus. Ganz spontan würde ich sagen, dass eure beiden Vorschläge nicht gehen, da es in A kein Member a1 gibt, sondern in Test. Aber vielleicht irre ich mich und habe ein falsches Verständnis von getField()

Wie bereits beschrieben: Annotationen die du über du in deinem Programm auswerten willst, müssen auch entsprechend “gekennzeichnet” werden. Das geht mit @Retention(RetentionPolicy.RUNTIME):

@interface MyAnnotation {
	String value();
}

Um damit jetzt arbeiten zu können, benötigst du Reflection. Da ich mit solchen Dingen gerne arbeite, hier mal ein KSKB wie man das Feld mit dem Wert der Annotaion füllen kann:

import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;

public class AnnotationExample
{
	@MyAnnotation("Example")
	private String alpha;
	
	public static void main(final String[] args) throws Exception 
	{
		AnnotationExample example = new AnnotationExample();
		Field field = AnnotationExample.class.getDeclaredField("alpha");
		field.setAccessible(true);

		if(field.isAnnotationPresent(MyAnnotation.class)) {
			MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
			field.set(example, annotation.value());
		}
		
		System.out.println(example.alpha);
	}
}

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
	String value();
}

OK, ich habe die ersten beiden Einträge ausprobiert und es endet natürlich mit einer java.lang.NoSuchFieldException: a1. Das ist auch der Grund, warum @Tomate_Salat 's Beispiel auch nicht geht. A weiß nun mal nicht, in welcher Klasse und mit welcher Memberbezeichnung es instanziiert wurde.

Das Problem ist, dass ich natürlich gern mit @PostConstruct in A arbeiten möchte (wo ich das Prefix bereits benötige) und zu dem Zeitpunkt sehe ich keine Möglichkeit von Test aus mitzugeben, welches Prefix genutzt werden soll.

PS: @Retention(RetentionPolicy.RUNTIME) habe ich ergänzt. Danke.

*** Edit ***

Mit Spring kann man ja auch Properties setzen. Leider habe ich zu meinem Beispiel nix sinnvolles gefunden. Bis jetzt nur, wo man in Beans allgemein ein Property vorbelegt. Kennt jemand in der Richtung etwas mit Spring … vielleicht sogar Annotation basiert?

Stimmt, ich hatte überlesen, dass die Member in einer anderen Klasse stecken.
Ich fürchte, dass das, was Du erreichen willst, mit Reflection nicht gehen wird. Eine beliebige Instanz der Klasse A weiß ja nichts von den Variablen, von denen sie referenziert wird. Irgendein A-Objekt könnte also Test.a1, Test.a2, keines von beiden oder auch alle beide gleichzeitig „sein“.

Oder gibt es eine Möglichkeit mit Spring? So dass ich vor dem @PostConstruct an die Member a1 und a2 komme und dann prüfen kann, ob ein Member mit @Prefix annotiert ist? Dann könnte ich diesem Member ein bestimmtes Property setzen mit dem Value vom @Prefix.

Klar, es muss Test.class.getField("a1").getAnnotation("Prefix"); heißen, hatte mich verlesen.

Ja, prinzipiell richtig, wenn die Instanz wüsste, dass sie „a1“ heist.

*** Edit ***

Zur Info: Ich habe es auch schon mit dem Spring BeanPostProzessor versucht: (Chapter 3. The IoC container)

Leider ist das auch kein Weg, den ich gehen kann, da A komplett vorher abgearbeitet wird (incl. @PostConstruct), bevor ich auch nur Test bearbeiten kann.

OK. Da das Thema schon beim Erstellen aussichtslos erschien und nur ein Fünkchen Hoffnung da war, welches aber jetzt erloschen ist, schließe ich das Thema.

Natürlich gibt es eine nicht so schöne Lösung dafür: Man erstellt zwei weitere Klassen, die von A erben: z.B. AA extends A und AB extends A. Hier kann man dann natürlich alles anpassen, was man möchte.
Nachteil dieser Lösung: Brauche ich a1 … a10 dann brauche ich auch 10 Klassen :frowning: