You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pointcuts.adoc 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. [[pointcuts]]
  2. = Debugging Pointcuts
  3. [[pointcuts-introduction]]
  4. == Introduction
  5. This section describes how to write and debug pointcuts using the usual
  6. approach of iteration and decomposition. New users are often stumped
  7. when their advice does not match. That means the pointcut doesn't match;
  8. they rewrite the pointcut and it still doesn't match, with no new
  9. information. This can be frustrating if each iteration involves
  10. building, deploying, and testing a complex application. Learning to
  11. break it down, particularly into parts that can be checked at
  12. compile-time, can save a lot of time.
  13. [[pointcuts-debugging]]
  14. == Debugging pointcuts
  15. Go at it top-down and then bottom-up.
  16. === Top-down
  17. Top-down, draft significant
  18. aspects by first writing the comments to specify responsibilities.
  19. Advice responsibility usually takes the form, _"When X, do Y"_. Pointcut
  20. responsibility for _"When X"_ often takes the form, _"When [join points]
  21. [in locations] [are ...]"_. These __[]__'s often translate to named pointcuts
  22. like `libraryCalls() && within(Client) && args(Context)`, which form a
  23. semantic bridge to the plain-text meaning in a comment, e.g. `// when
  24. the client passes only context into the library`. This gets you to a
  25. point where you can debug the parts of the pointcut independently.
  26. === Bottom-up
  27. Bottom-up (to build each part), consider each primitive pointcut
  28. designator (PCD), then the composition, and then any implicit
  29. constraints:
  30. [arabic]
  31. . What kinds of join points should it match? (constructor-call?
  32. field-get?)? This translates to using the kinded pointcuts (`call(..)`,
  33. `get(..)`, etc.).
  34. . Are these restricted to being lexically within something? This
  35. translates to using `within\{code}(..)`. If this is true, it should
  36. always be used, to speed up weaving.
  37. . What runtime constraints and context should be true and available at
  38. each join point? This translates to `this()`, `target()`, `args()`,
  39. `cflow\{below}()` and `if(..)`.
  40. . Are there any advice or implementation limitations at issue? This
  41. involves knowing the few constraints on AspectJ imposed by Java bytecode
  42. as listed in the AspectJ Programming Guide section on
  43. xref:../progguide/implementation.adoc#implementation[Implementation Notes].
  44. It's much faster to iterate a pointcut at compile-time using declare
  45. warning (even better, some errors are identified at parse-time in the
  46. latest versions of AJDT). Start with the parts of the pointcut that are
  47. staticly-determinable (i.e., they do not involve the runtime PCD's
  48. listed above). If compiles themselves take too long because of all the
  49. AspectJ weaving, then try to only include the debugging aspect with the
  50. prototype pointcut, and limit the scope using `within(..)`.
  51. == Common pointcut mistakes
  52. There are some typical types of mistakes developers make when designing pointcuts.
  53. Here are a few examples:
  54. === Mistakes in primitive pointcuts
  55. * `this(Foo) && execution(static * *(..))`: There is no `this` in a
  56. static context, so `this()` or `target()` should not be used in a static
  57. context or when targetting a static context (respectively). This happens
  58. most often when you want to say things like "all calls to `Foo` from ``Bar``"
  59. and you only pick out calls to instance methods of `Foo` or you try to
  60. pick out calls from static methods of `Bar`.
  61. * `target(Foo) && call(new(..)`: This will never match. In
  62. constructor-call join points, there is no target because the object has
  63. not been created yet.
  64. * `call(* Foo.*(..))`: `Foo` refers to the compile-time type of the
  65. invoking reference, not the implementing class. In Java before 1.4, the
  66. compile-time type was rendered as the defining type, not the reference
  67. type; this was corrected in 1.4 (as shown when using ajc with the -1.4
  68. flag) Most people should use `target(Foo) && call(...)`.
  69. * `execution(* Foo.bar(..))`: An execution join point for `Foo` is always
  70. within `Foo`, so this won't pick out any overrides of `bar(..)`. Use
  71. `target(Foo) && execution(* bar(..))` for instance methods.
  72. * `within(Foo)`: anonymous types are not known at weave-time to be
  73. within the lexically-enclosing type (a limitation of Java bytecode).
  74. === Mistakes in composition
  75. * `call(* foo(Bar, Foo)) && args(Foo)`: This will never match. The
  76. parameters in `args(..)` are position-dependent, so `args(Foo)` only
  77. picks out join points where there is only one argument possible, of type
  78. Foo. Use the indeterminate-arguments operator `..` as needed, e.g.,
  79. `args(Foo, ..)`.
  80. * `call(* foo()) && execution(* foo())`: This will never match. Each
  81. pointcut must be true at each join point matched. For a union of
  82. different kinds of join points (here, call or execution), use `||`.
  83. E.g., to match both method-call and field-get join points, use
  84. `call(* ...) || get(...)`.
  85. === Mistakes in implicit advice constraints
  86. * `after () returning (Foo foo) : ...`: after advice can bind the
  87. returned object or exception thrown. That effectively acts like
  88. `target()`, `this()`, or `args()` in restricting when the advice runs
  89. based on the runtime type of the bound object, even though it is not
  90. explicitly part of the pointcut.
  91. === Mistakes in implementation requirements
  92. * _ajc_ has to control the code for a join point in order to implement
  93. the join point. This translates to an implicit `within({code under the
  94. control of the compiler})` for all join points, with additional caveat
  95. for some join points. Take exception handlers, for example: there is no
  96. way to be sure from the bytecode where the original handler ends, so
  97. _ajc_ can't implement after advice on handler join points. (Since these
  98. are on a per-join-point basis, they should be considered for each
  99. corresponding primitive pointcut designator.) Unlike the mistakes with
  100. the primitive PCDs above, the compiler will emit an error for these
  101. caveats.
  102. * `call(@SuperAnnotation Subclass.meth()`: Annotations are not inherited
  103. by default, so e.g., if the pointcut specifies an annotation, then
  104. subclass implementations of that method will not be matched.