Параметризованные типы AspectJ не поддерживают целевые точки
Я хотел бы создать класс, который указывает на методы в интерфейсе списка. Это работает, пока я не добавлю цель (список) к своему совету. Я хотел бы просмотреть элементы списка до и после добавления (например), чтобы посмотреть, что изменилось, но я не могу передать свой список, как объект. Вот что у меня есть, это не работает с целью (список), но работает без него:
pointcut addPointCut() : call(boolean List.add(..));
before(List<Integer> list) : addPointCut() && target(list) {
System.out.println("testing");
for(Object i : list) {
System.out.println(i);
}
}
2 ответа
Ответ Нандора правильный, поскольку он описывает ошибку компилятора, которую вы видите. Я хочу пойти немного дальше, а также объяснить, почему вы получаете эту ошибку:
Прежде всего, проблема не связана напрямую с AspectJ, а скорее с тем, как Java реализует дженерики. Пожалуйста, ознакомьтесь с феноменом, называемым стиранием типа, прежде чем продолжить чтение.
Ну, потому что стирание типа является реальностью JVM и потому что target()
а также this()
разрешаются во время выполнения, а не во время компиляции - это можно сделать косвенным образом из того факта, что оба getTarget()
а также getThis()
методы JoinPoint
скорее, чем JoinPoint.StaticPart
- то, что вы хотите сделать, не может работать и, как следствие, приводит к ошибке компиляции AspectJ. Единственное, что вы можете сделать, это использовать instanceof
для того, чтобы динамически определить, что добавляется в целевой список. Самый элегантный способ сделать это if()
выражение pointcut.
Вот пример кода:
Приложение для водителя:
Чтобы сделать вещи немного более интересными, мы используем два типа списков, а также два типа add(..)
звонки. Цель должна состоять в том, чтобы перехватывать только целые числа для добавления в соответствующий список, независимо от того, какая подпись add(..)
метод имеет.
package de.scrum_master.app;
import java.util.ArrayList;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<Integer> integers = new ArrayList<>();
integers.add(11);
integers.add(0, 22);
integers.add(33);
List<String> strings = new ArrayList<>();
strings.add("foo");
strings.add(0, "bar");
strings.add("zot");
}
}
аспект:
package de.scrum_master.aspect;
import java.util.List;
@SuppressWarnings({"rawtypes", "unchecked"})
public aspect GenericsAspect {
pointcut addPointCut(List list, Object newElement) :
!within(GenericsAspect) && // avoid stack overflow due to recursion
call(* List.add(..)) && // intercept all calls to List.add
args(.., newElement) && // capture last method parameter
if(newElement instanceof Integer) && // only capture added int/Integer elements
target(list); // target is a List
before(List list, Object newElement) :
addPointCut(list, newElement)
{
System.out.println(thisJoinPoint + " -> new element = " + newElement);
for(Object i : list)
System.out.println(" " + i);
// Type erasure in action:
// During runtime there is no such thing as List<Integer>, only a raw List.
// Thus, we can easily add a String to a list declared as List<Integer>.
list.add("#" + newElement + "#");
}
}
Консольный журнал:
call(boolean java.util.List.add(Object)) -> new element = 11
call(void java.util.List.add(int, Object)) -> new element = 22
#11#
11
call(boolean java.util.List.add(Object)) -> new element = 33
22
#11#
11
#22#
Есть еще вопросы?
Использование дженериков в типе target(...)
или же this(...)
pointcut не поддерживается, и компиляция завершится с этой ошибкой: parameterized types not supported for this and target pointcuts (erasure limitation)
, Удалите параметр типа из списка, и он должен работать как положено.