Параметризованные типы 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), Удалите параметр типа из списка, и он должен работать как положено.

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