@AspectJ pointcut для методов, которые переопределяют интерфейсный метод с аннотацией
Как я могу написать pointj aspectj, который применяется к выполнению методов, которые переопределяют метод интерфейса с аннотацией? Например:
interface A {
@MyAnnotation void method();
}
class B implements A {
void method();
}
Pointcut execution(@MyAnnotation * *.*(..))
соответствует только если B.method()
несет саму аннотацию. Есть ли другой способ сделать это?
3 ответа
Как отметил Николас, в Аспекте это невозможно. Вот еще одно доказательство того, почему это невозможно (взято с http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations-pointcuts-and-advice.html раздел "Наследование аннотаций и сопоставление точек"):
Согласно спецификации Java 5 аннотации не-типов не наследуются, а аннотации типов наследуются только в том случае, если они содержат метааннотацию @Inherited. Вызов c2.aMethod (в вашем примере это b.method()) не сопоставляется, поскольку сопоставление точек соединения для модификаторов (модификаторов видимости, аннотаций и предложения throws) основано на предмете точки соединения (метод на самом деле вызывается).
Пострадав от этой же проблемы, я написал небольшой метод / библиотеку, которая позволила бы вам создавать контрольные точки для таких методов. Вот как это будет работать для вашего примера:
myAnnotationIsExecuted(): execution(public * *.*(..)) &&
if(implementsAnnotation("@MyAnnotation()", thisJoinPoint));
ИЛИ ЖЕ
myAnnotationIsExecuted(): execution(public * A+.*(..)) &&
if(implementsAnnotation("@MyAnnotation()", thisJoinPoint));
Метод implementsAnnotation(String,JoinPoint)
идет из библиотеки; основной метод, который проверяет, содержат ли реализованные методы указанную аннотацию.
Более подробную информацию о методе / библиотеке можно найти здесь.
Обновить
Поскольку кажется, что это не может быть сделано в Spring (см. Оригинальный ответ), я бы сказал, что вам нужно добавить аннотацию к каждому методу в реализующих классах. Существует очевидный способ сделать это, но я полагаю, что если вы ищете более автоматический способ, вам нужно будет написать его самостоятельно.
Я могу представить себе своего рода постпроцессор, который будет искать конкретную аннотацию, скажем так @ApplyThisAnnotationToAllWhoInheritMe
, Как только он находит эту аннотацию, он сканирует исходный код на предмет наследования элементов и добавляет запрошенную аннотацию, где это необходимо, до того, как происходит компиляция.
Независимо от того, если вы используете Spring AOP для этого, похоже, что он должен быть в методе реализаторов. Если классы, которые, как вы надеетесь, вам помогут, находятся вне вашего контроля, вам, возможно, придется написать свой собственный инструмент Spring AOP.
Оригинальный ответ
AspectJ следует правилу Java, согласно которому аннотации на интерфейсах не наследуются.
Я нашел этот бит в разделе 7.8.2 Other Spring aspects for AspectJ
, которая является частью 7.8 Using AspectJ with Spring applications
, что заставляет меня думать, что это глобальное правило.
//introducing empty marker interface
declare parents : hasmethod(@MyAnnotation * *(..)) implements TrackedParentMarker;
public pointcut p1() : execution(* TrackedParentMarker+.*(..));
Также вы должны включить флаг компилятора –XhasMember.