@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.

Оригинальный ответ

Из документации Spring 3.0:

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.

Другие вопросы по тегам