假设我们有一个这样的结构:
class A {
@AMethodAnnotation("my-data")
public void myMethod() {
}
}
@MyClassAnnotation
class B extends A {
@Override
public void myMethod() {
}
}
使用注释处理,我试图从位于类AMethodAnnotation
内部的方法myMethod
上的注释A
中提取数据。类B
扩展了该类并覆盖了方法myMethod
。
扭曲之处在于,如果其中的类具有注释AMethodAnnotation
,我希望使用MyClassAnnotation
的方法中的数据。
我正在获取带有注释MyClassAnnotation
的类,并循环遍历enclosedElements
,在那里我可以检查它是否具有Override
注释,但是我不确定如何获取它覆盖的方法,因为这是AMethodAnnotation
和我想要的数据所在的位置。 ExecutableElement
似乎没有提供实现此目的的方法。
for (Element classElement : roundEnv.getElementsAnnotatedWith(MyClassAnnotation.class)) {
// Make sure it's a class
if (classElement.getKind() != ElementKind.CLASS) {
continue;
}
// Loop through methods inside class
for (Element methodElement : classElement.getEnclosedElements()) {
// Make sure the element is a method & has a @Path annotation
if (methodElement.getKind() != ElementKind.METHOD) {
continue;
}
// If method has @Override annotation do stuff
}
}
有没有办法引用被覆盖的方法?
有一种方法,您可以得到B
的{{1}}的超类,然后遍历A
中的enclosedElements
,则必须验证是否方法名称相同,并且参数相同且顺序相同。但是我发现这种方法需要大量检查,因此我想知道是否有更好的方法。
答案 0 :(得分:1)
我根据评论中发布的@rmuller链接编写了以下方法。如Javadoc和下图所示,该方法有大量文档,在此文档中更具可读性。
/**
* Will find the method which the method <strong>methodElement</strong> is overriding, if any.
* It does this by recursively traversing up the superclass tree of the
* <strong>classElement</strong> and checking if there are methods which override the
* <strong>methodElement</strong>. It will return after it finds the first method with the
* annotation <strong>annotation</strong>.
*
* @param originalClassElement The original class inside which the
* <strong>methodElement</strong> is located.
* @param classElement The class which represents the superclass while recursively
* looking up the tree, it should be equal to the
* <strong>originalClassElement</strong> when first calling this
* method.
* @param methodElement The method for which should be checked if it's overriding
* anything.
* @param annotation The annotation which must be matched before returning the result
* @return Will return the following, the list is written in order:
* <ul>
* <li>The method <strong>methodElement</strong> if <strong>methodElement</strong>
* already has an annotation of the type <strong>annotation</strong></li>
* <li>Null if the method <strong>methodElement</strong> does not have an @Override
* annotation</li>
* <li>Null if the class <strong>classElement</strong> does not have a superclass</li>
* <li>The method element which was found to have the annotation
* <strong>annotation</strong></li>
* </ul>
*/
public ExecutableElement getMethodOverride(TypeElement originalClassElement,
TypeElement classElement, ExecutableElement methodElement,
Class<? extends Annotation> annotation) {
if (methodElement.getAnnotation(annotation) != null) {
// The methodElement which was passed has the required annotation already
return methodElement;
}
if (methodElement.getAnnotation(Override.class) == null) {
// The methodElement which was passed does not have an @Override annotation and is
// therefore not overriding anything.
return null;
}
if (classElement.getSuperclass().getKind() == TypeKind.NONE) {
// Class has no superclass
return null;
}
for (Element elem : classElement.getEnclosedElements()) {
if (elem.getKind() != ElementKind.METHOD) {
// Not a method
continue;
}
// Check if the method inside the superclass overrids the method inside the original
// class
if (this.processingEnv.getElementUtils().overrides(methodElement,
(ExecutableElement) elem, classElement)) {
// Recursively go up the tree and check since this method might also override
// another method
return getMethodOverride(originalClassElement,
this.env.getElementUtils()
.getTypeElement(classElement.getSuperclass().toString()),
(ExecutableElement) elem, annotation);
}
}
// Recursively go up the tree and check there
return getMethodOverride(originalClassElement,
this.env.getElementUtils().getTypeElement(classElement.getSuperclass().toString()),
methodElement, annotation);
}