查找被注释处理覆盖的方法
Find method that's being overridden with annotation processing
代码结构
假设我们有这样的结构:
class A {
@AMethodAnnotation("my-data")
public void myMethod() {
}
}
@MyClassAnnotation
class B extends A {
@Override
public void myMethod() {
}
}
我想要达到的目标
使用注解处理我试图从位于 class A
中的方法 myMethod
上的注解 AMethodAnnotation
中提取数据。 class B
扩展此 class 并覆盖它的方法 myMethod
.
不同之处在于,如果其中的 class 具有注释 MyClassAnnotation
.
,我想要来自具有 AMethodAnnotation
的方法的数据
我正在获取带有注释 MyClassAnnotation
的 classes 并循环遍历 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
的superclass,也就是A
,你循环遍历A
中的enclosedElements
,然后您将必须验证方法名称是否相同,以及参数是否相同且顺序是否相同。但是我发现这种方法需要大量检查,因此我想问一下是否有更好的方法。
我根据评论中的link @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);
}
代码结构
假设我们有这样的结构:
class A {
@AMethodAnnotation("my-data")
public void myMethod() {
}
}
@MyClassAnnotation
class B extends A {
@Override
public void myMethod() {
}
}
我想要达到的目标
使用注解处理我试图从位于 class A
中的方法 myMethod
上的注解 AMethodAnnotation
中提取数据。 class B
扩展此 class 并覆盖它的方法 myMethod
.
不同之处在于,如果其中的 class 具有注释 MyClassAnnotation
.
AMethodAnnotation
的方法的数据
我正在获取带有注释 MyClassAnnotation
的 classes 并循环遍历 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
的superclass,也就是A
,你循环遍历A
中的enclosedElements
,然后您将必须验证方法名称是否相同,以及参数是否相同且顺序是否相同。但是我发现这种方法需要大量检查,因此我想问一下是否有更好的方法。
我根据评论中的link @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);
}