Ответ 1
Вы можете попытаться аннотировать аннотацию @Marker с помощью @Inherited аннотации. Подклассы должны наследовать аннотацию @Marker.
java.lang.annotation.Inherited
@Inherited
public @interface Marked{
}
Я возился с AspectJ и придумал идею, что я, похоже, не умею правильно реализовывать (рассказ о моей жизни).
Я определил аспект:
package my.package;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.ProceedingJoinPoint;
@Aspect
public class MyAspect {
@Pointcut("execution(* *(..)) && this(o)")
public void instanceMethod(Object o) {}
@Pointcut("within(@Marker *)")
public void methodsFromMarkedClasses() {}
@Around("methodsFromMarkedClasses() && instanceMethod(o)")
public Object markedMethodsAdvice(ProceedingJoinPoint joinPoint, Object o) throws Throwable {
// do awesome stuff
return null; //<- not the actual return, just added this so that my head wouldn't hurt
}
}
Я определил аннотацию @Marker
, которая просто пуста.
Идея состоит в том, чтобы дать совет markedMethodsAdvice
выполнить ЛЮБОЕ время, когда вызывается метод для объекта класса, помеченного @Marker
. Даже (и здесь сложные штуки):
Случай 1
Если указанный метод наследуется от класса, который не отмечен, см. пример:
Учитывая
package my.package;
public class Alpha {
public void methodA() {}
}
Когда
package my.package;
@Marked
public class Beta extends Alpha {}
Тогда
/* Should trigger the advice */
new Beta().methodA();
Случай 2
Если указанный метод вызывается в объекте подкласса (Liskov)
Учитывая
@Marked
public class Beta extends Alpha { //still extends A just to be coherent with previous example
public void methodB() {}
}
Когда
package my.package;
public class Gamma extends Beta {
}
Тогда
/* Should trigger the advice */
new Gamma().methodB();
(И так как я жадный, я прошу этот бонус один)
Случай 3
Если указанный метод объявлен в подклассе
Учитывая
@Marked
public class Beta extends Alpha {} //still extends A just to be coherent with previous example
Когда
package my.package;
public class Gamma extends Beta {
public void methodC() {}
}
Тогда
/* Should trigger the advice */
new Gamma().methodC();
Документация aspectj указывает, что это возможно
execution(public void Middle.*())
выбирает все методы исполнения для общедоступных методов, возвращающих void и не имеющих аргументов, которые либо объявлены, либо унаследованы, Middle, даже если эти методы переопределены в подклассе Middle
Так что же я сделал не так?
Вы можете попытаться аннотировать аннотацию @Marker с помощью @Inherited аннотации. Подклассы должны наследовать аннотацию @Marker.
java.lang.annotation.Inherited
@Inherited
public @interface Marked{
}
Я могу думать только о написании нескольких строк кода в совете, чтобы выполнить ваши 3 случая.
public aspect MyAspect {
pointcut instanceMethod(Alpha o) : execution(* Alpha+.*(..)) && this(o);
Object around(Alpha o): instanceMethod(o){
Class clazz = o.getClass();
this.findSpecificAnnotation(clazz);
return null; //<- not the actual return, just added this so that my head wouldn't hurt
}
private void findSpecificAnnotation (Class c){
boolean exists = Arrays.asList(c.getAnnotations()).stream().anyMatch(an -> {
if (an.annotationType().getSimpleName().equals("Marked")){
// do awesome stuff
System.out.println("Around" );
return true;
}
else
return false;
});
if (!exists && !c.getSimpleName().equals("Object")) {
this.findSpecificAnnotation(c.getSuperclass());
}
}
}
Это просто рекурсивно рассматривает открытые классы и их подклассы, чтобы найти, есть ли у них аннотация, которая является маркером или нет. Конечно, вы можете улучшить код, как хотите.