eine Ressourcenmethode zu kommentieren, damit der Anmerkungsprozessor automatisch eine Wiki-Seite generieren kann, die die erwartete Ressource und den erwarteten Typ beschreibt.
Ich muss den Wert von lesen value Feld in einem Anmerkungsprozessor, aber ich erhalte einen Laufzeitfehler.
Im Quellcode für meinen Prozessor habe ich folgende Zeilen:
final Pojo pojo = element.getAnnotation(Pojo.class);
// ...
final Class<?> pojoJavaClass = pojo.value();
aber die eigentliche Klasse steht dem Prozessor nicht zur Verfügung. Ich glaube, ich brauche eine javax.lang.model.type.TypeMirror stattdessen als Ersatz für die echte Klasse. Ich bin mir nicht sicher, wie man einen bekommt.
Der Fehler, den ich bekomme, ist:
javax.lang.model.type.MirroredTypeException: Attempt to access Class object for TypeMirror com.example.restserver.model.appointment.Appointment
Der Appointment ist eine Klasse, die in einem meiner erwähnt wird @Pojo Anmerkung.
Leider scheinen Dokumente und/oder Tutorials zur Verarbeitung von Java-Annotationen rar zu sein. Habe versucht zu googeln.
Nicht viele Leute stellen diese Art von Fragen, aber für diejenigen von uns, die im (Java-)Tartarus leben, erweist sich die Unterstützung anderer als sehr nützlich
– Ordel
25. Januar 2015 um 6:59 Uhr
David Dopson
Ich bin hierher gekommen, um genau die gleiche Frage zu stellen. … und das gleiche gefunden Blog-Link gepostet von Ralf.
Es ist ein langer Artikel, aber sehr reichhaltig. Zusammenfassung der Geschichte – es gibt zwei Möglichkeiten, es zu tun, den einfachen Weg und den „richtigeren“ Weg.
Dies ist der einfache Weg:
private static TypeMirror getMyValue1(MyAnnotation annotation) {
try
{
annotation.myValue(); // this should throw
}
catch( MirroredTypeException mte )
{
return mte.getTypeMirror();
}
return null; // can this ever happen ??
}
… dieser letzte kleine, nicht offensichtliche Teil hat mich eine Stunde lang an den Haaren gezogen, bevor ich ihn das erste Mal aussortiert habe. Diese Anmerkungsprozessoren sind eigentlich gar nicht so schwer zu schreiben, die APIs sind anfangs nur super verwirrend und unglaublich ausführlich. Ich bin versucht, eine Hilfsklasse herauszubringen, die alle grundlegenden Operationen offensichtlich macht … aber das ist eine Geschichte für einen anderen Tag (sg mir, wenn Sie es wollen).
Ich stecke auch hier fest. Könnten Sie bitte einen Kern mit Ihrem Helfer veröffentlichen, wenn Sie einen gemacht haben?
Ich denke, dass +1 für diese Antwort nicht ausreicht. Es sollte +10 sein.
– Mohamed El-Beltagy
30. Juli 2018 um 2:42 Uhr
@MohamedEl-Beltagy – vielen Dank für deine freundlichen Worte!
– David Dopson
31. Juli 2018 um 16:36 Uhr
Das ist tolles Zeug. Ich kann @MohamedEl-Beltagy nur zustimmen. Hier ist ein weiterer großartiger Artikel zum gleichen Thema für alle Interessierten. hauchee.blogspot.com/2015/12/…
Dort besteht der Trick darin, tatsächlich getAnnotation() zu verwenden und die MirroredTypeException abzufangen. Überraschenderweise liefert die Ausnahme dann den TypeMirror der benötigten Klasse.
Ich weiß nicht, ob das eine gute Lösung ist, aber es ist eine. Meiner persönlichen Meinung nach würde ich versuchen, den Typ hinter den MirroredType zu bekommen, aber ich weiß nicht, ob das möglich ist.
Das mag ausreichen, obwohl mir “Klebeband und Kaugummi” in den Sinn kommen. Übrigens, cooler Benutzername :-).
– Ralf
7. Oktober 2011 um 13:48 Uhr
Meine Antwort ist im Grunde die gleiche wie die von Dave Dopson, nur der Code wurde etwas geändert:
public default Optional<? extends AnnotationMirror> getAnnotationMirror( final Element element, final Class<? extends Annotation> annotationClass )
{
final var annotationClassName = annotationClass.getName();
final Optional<? extends AnnotationMirror> retValue = element.getAnnotationMirrors().stream()
.filter( m -> m.getAnnotationType().toString().equals( annotationClassName ) )
.findFirst();
return retValue;
}
Sein Code verwendet TypeElement als Typ für das erste Argument von getAnnotationMirror(), wodurch die Verwendung der Methode nur auf Klassen beschränkt wird. Ändern Sie das zu Element macht es für jedes annotierte Element verwendbar. Verwendung einer auf Streams basierenden Implementierung anstelle des Originals for Schleife ist reine Geschmackssache.
public default Optional<? extends AnnotationValue> getAnnotationValue( final AnnotationMirror annotationMirror, final String name )
{
final Elements elementUtils = this.processingEnv.getElementUtils();
final Map<? extends ExecutableElement, ? extends AnnotationValue> elementValues = elementUtils.getElementValuesWithDefaults( annotationMirror );
final Optional<? extends AnnotationValue> retValue = elementValues.keySet().stream()
.filter( k -> k.getSimpleName().toString().equals( name ) )
.map( k -> elementValues.get( k ) )
.findAny();
return retValue;
}
David verwendet Element.getElementValues() um die Annotationswerte zu erhalten, aber dies gibt nur die Werte zurück, die explizit auf die konkrete Annotation angewendet wurden. Die Voreinstellungen werden weggelassen. Die Methode Elements.getElementValuesWithDefaults() gibt auch die Standardwerte zurück (wie Sie vielleicht schon aus dem Namen erraten haben).
Das ist mein Trick:
public class APUtils {
@FunctionalInterface
public interface GetClassValue {
void execute() throws MirroredTypeException, MirroredTypesException;
}
public static List<? extends TypeMirror> getTypeMirrorFromAnnotationValue(GetClassValue c) {
try {
c.execute();
}
catch(MirroredTypesException ex) {
return ex.getTypeMirrors();
}
return null;
}
}
Dann kann ich mit jedem Anmerkungswert verwenden:
public @interface MyAnnotationType {
public Class<?>[] value() default {};
}
Beispiel
@MyAnnotationType(String.class)
public class Test { ... }
Nicht viele Leute stellen diese Art von Fragen, aber für diejenigen von uns, die im (Java-)Tartarus leben, erweist sich die Unterstützung anderer als sehr nützlich
– Ordel
25. Januar 2015 um 6:59 Uhr