Подтвердить что ты не робот

Точки по унаследованным методам (в контексте дизайна-агностики класса)

Я возился с 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

Так что же я сделал не так?

4b9b3361

Ответ 1

Вы можете попытаться аннотировать аннотацию @Marker с помощью @Inherited аннотации. Подклассы должны наследовать аннотацию @Marker.

java.lang.annotation.Inherited

@Inherited
public @interface Marked{

}

Ответ 2

Я могу думать только о написании нескольких строк кода в совете, чтобы выполнить ваши 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());
        }

    }
}

Это просто рекурсивно рассматривает открытые классы и их подклассы, чтобы найти, есть ли у них аннотация, которая является маркером или нет. Конечно, вы можете улучшить код, как хотите.