Используя вызов точек соединения (* *. * (..)), могу ли я представить аргументы совету, если он доступен? - PullRequest
0 голосов
/ 08 января 2009

С моим аспектом я отслеживаю изменения в определенных коллекциях, посоветовав определенные вызовы методов для экземпляров java.util.Set, в частности add(Object) и remove(Object). Поскольку изменения не отражаются в самой коллекции, вызовы Set.contains(Object) или Set.size() возвращают неверные результаты.

Поэтому я хочу перехватить все вызовы методов для экземпляров Set (кроме add и remove) и перенаправить вызовы в мою современную коллекцию.

Конечно, я мог бы определить два совета, используя разные точки, что-то вроде этого:

// matches Collection.size(), Collection.isEmpty(), ...
* around(Collection c) : call(* Collection.*()) && target(c)
            && !remove(/*...*/) && !add(/*...*/) {
    if (notApplicable())
        return proceed(c);

    return proceed(getUpToDateCollection());
}

// matches Collection.contains(Object), ...
* around(Collection c, Object arg) : call(* Collection.*(*)) && target(c) && args(arg) 
            && !remove(/*...*/) && !add(/*...*/) {
    if (notApplicable())
        return proceed(c, arg);

    return proceed(getUpToDateCollection(), arg);
}

Это работает, но довольно уродливо, поскольку тела моих советов весьма аналогичны. Поэтому я хотел бы «объединить» их; эффективно иметь единый совет, который можно сплетать для обеих точек, очень похожий на этот:

* around(Object[] args): call(* Collection.*(..)) && args(arr) {...}`

Возможно ли это вообще? У меня такое ощущение, что это не так, потому что в одном из баллов я выставляю аргумент (и впоследствии использую его в совете), а в другом нет аргумента, поэтому кажется невозможным связать «потенциальный идентификатор» в прилагаемом совете ... Но я надеюсь, что что-то упустил, и вы могли бы указать мне правильное направление. Спасибо!

Ответы [ 2 ]

0 голосов
/ 29 мая 2017

Понятия не имею, почему этот вопрос появился в моей ленте как "новый" после стольких лет, но до сих пор остается без ответа, поэтому я отвечу:

  • Ваше предположение верно, вы не можете использовать args() для привязки несуществующего аргумента.
  • Вы можете, если вы абсолютно хотите иметь одно тело совета, использовать JoinPoint.getArgs(..), но это будет уродливо (как при использовании циклов и приведений) и потенциально медленнее, чем наличие двух точек. Слишком широкая точка разреза также потенциально может соответствовать слишком многим точкам соединения, если сделано неправильно.
  • Мой совет - без каламбура - на самом деле выделять дублирующийся код в вспомогательные методы и вызывать их из обоих советов AspectJ. Возможно, эти вспомогательные методы также нуждаются в параметре ProceedingJoinPoint для вызова proceed(), если вы также хотите выделить эту часть. Но подумайте и о удобочитаемости. Это всегда зависит от вашего конкретного случая.

Я мог бы ответить более конкретно (с кодом аспекта), если бы ваш код был буквально SSCCE .

0 голосов
/ 12 сентября 2010

только для записи.
можно написать сценарий, который выставляет аргумент, а затем использовать этот совет в совете, который не имеет доступа к параметру аргумента. Вместо того, чтобы записывать выражение pointcut сразу в определение совета, я всегда предпочел бы определить pointcut явно, ссылаясь на него из рекомендации просто по имени pointcut (и аргументам)

...