@AspectJ pointcut для методов, которые переопределяют метод интерфейса с помощью аннотации.

Как я могу написать аспектную точку, которая применяется к выполнению метода, который переопределяет метод интерфейса с аннотацией? Например:

interface A {
  @MyAnnotation void method();
}
class B implements A {
  void method();
}

Pointcut execution(@MyAnnotation * *.*(..)) соответствует только в том случае, если B.method() содержит саму аннотацию. Есть ли другой способ сделать это?


person Hans-Peter Störr    schedule 24.08.2011    source источник
comment
Я столкнулся с аналогичной проблемой с аннотацией JAX-RS javax.ws.rs.Path. Все пути ресурсов в моем проекте определены в интерфейсе, и я хочу указать его. Я терплю неудачу с треском до сих пор.   -  person dpknegi    schedule 09.05.2021


Ответы (3)


Как указал Николас, в AspectJ это невозможно. Вот еще одно доказательство того, почему это невозможно (взято из http://www.eclipse.org/aspectj/doc/released/adk15notebook/annotations-pointcuts-and-advice.html раздел Наследование аннотаций и сопоставление pointcut):

Согласно спецификации Java 5 аннотации, не относящиеся к типам, не наследуются, а аннотации к типам наследуются только в том случае, если они имеют метааннотацию @Inherited. Вызов c2.aMethod (в вашем примере это будет b.method()) не соответствует, потому что сопоставление точки соединения для модификаторов (модификаторы видимости, аннотации и предложение throws) основано на субъекте точки соединения (предложение фактически вызываемый метод).

Пострадав от этой же проблемы, я написал небольшой метод/библиотеку, которая позволит вам писать точки для таких методов. Вот как это будет работать для вашего примера:

myAnnotationIsExecuted(): execution(public * *.*(..)) && 
             if(implementsAnnotation("@MyAnnotation()", thisJoinPoint));

OR

myAnnotationIsExecuted(): execution(public * A+.*(..)) &&
             if(implementsAnnotation("@MyAnnotation()", thisJoinPoint));

Метод implementsAnnotation(String,JoinPoint) взят из библиотеки; базовый метод, который проверяет, содержат ли реализованные методы указанную аннотацию.

Дополнительную информацию о методе/библиотеке можно найти здесь.

person Guven    schedule 19.09.2011

Обновить

Поскольку кажется, что это невозможно сделать в 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, что заставляет меня думать, что это глобальное правило.

person nicholas.hauschild    schedule 24.08.2011
comment
Спасибо; это объясняет, почему мой pointcut не работает. Тем не менее, я ищу тот, который работает. :-) - person Hans-Peter Störr; 24.08.2011
comment
@hstoerr: После того, как вы отредактировали свой вопрос, я отредактировал свой ответ. Дайте мне знать, если это все еще неприемлемо. - person nicholas.hauschild; 24.08.2011
comment
В документации Spring на самом деле не говорится, что невозможно сопоставить что-то вроде того, что я хочу, - просто тот простой подход, который я пробовал, не работает. В Aspectj можно делать какие-то странные вещи, о которых я не могу думать. Так что я все еще надеюсь. :-) - person Hans-Peter Störr; 24.08.2011
comment
Будет ли приемлемо идти по имени метода? Это потребуется для распространения среди разработчиков, и это то, чего можно достичь с помощью AspectJ. - person nicholas.hauschild; 24.08.2011

//introducing empty marker interface
declare parents : hasmethod(@MyAnnotation * *(..)) implements TrackedParentMarker;

public pointcut p1() : execution(* TrackedParentMarker+.*(..));

Также вы должны включить флаг компилятора –XhasMember.

person alehro    schedule 25.08.2011
comment
К сожалению, это не совсем так. Он применяется к каждому методу всех классов, реализующих интерфейс, у которого есть хотя бы один метод, несущий аннотацию. Но это должно применяться только к одному методу, который реализует метод интерфейса с этим маркером. Или, по крайней мере, к методам, которые имеют то же имя, что и отмеченный метод интерфейса, если это можно сказать в AspectJ. - person Hans-Peter Störr; 25.08.2011
comment
@alehro, как вы настроили свое приложение для использования файлов *.aj? Не могли бы вы взглянуть на этот вопрос .com/questions/50391609/? - person VB_; 17.05.2018