12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- = Pitfalls
-
- [[pitfalls-intro]]
- == Introduction
-
- This chapter consists of a few AspectJ programs that may lead to
- surprising behavior and how to understand them.
-
- [[pitfalls-infiniteLoops]]
- == Infinite loops
-
- Here is a Java program with peculiar behavior
-
- [source, java]
- ....
- public class Main {
- public static void main(String[] args) {
- foo();
- System.out.println("done with call to foo");
- }
-
- static void foo() {
- try {
- foo();
- } finally {
- foo();
- }
- }
- }
- ....
-
- This program will never reach the `println` call, but when it aborts may
- have no stack trace.
-
- This silence is caused by multiple ``StackOverflowException``s. First the
- infinite loop in the body of the method generates one, which the finally
- clause tries to handle. But this finally clause also generates an
- infinite loop which the current JVMs can't handle gracefully leading to
- the completely silent abort.
-
- The following short aspect will also generate this behavior:
-
- [source, java]
- ....
- aspect A {
- before(): call(* *(..)) { System.out.println("before"); }
- after(): call(* *(..)) { System.out.println("after"); }
- }
- ....
-
- Why? Because the call to println is also a call matched by the pointcut
- `call (* *(..))`. We get no output because we used simple `after()`
- advice. If the aspect were changed to
-
- [source, java]
- ....
- aspect A {
- before(): call(* *(..)) { System.out.println("before"); }
- after() returning: call(* *(..)) { System.out.println("after"); }
- }
- ....
-
- then at least a `StackOverflowException` with a stack trace would be seen.
- In both cases, though, the overall problem is advice applying within its
- own body.
-
- There's a simple idiom to use if you ever have a worry that your advice
- might apply in this way. Just restrict the advice from occurring in join
- points caused within the aspect. So:
-
- [source, java]
- ....
- aspect A {
- before(): call(* *(..)) && !within(A) { System.out.println("before"); }
- after() returning: call(* *(..)) && !within(A) { System.out.println("after"); }
- }
- ....
-
- Other solutions might be to more closely restrict the pointcut in other
- ways, for example:
-
- [source, java]
- ....
- aspect A {
- before(): call(* MyObject.*(..)) { System.out.println("before"); }
- after() returning: call(* MyObject.*(..)) { System.out.println("after"); }
- }
- ....
-
- The moral of the story is that unrestricted generic pointcuts can pick
- out more join points than intended.
|