diff options
Diffstat (limited to 'docs/progguide/pitfalls.xml')
-rw-r--r-- | docs/progguide/pitfalls.xml | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/docs/progguide/pitfalls.xml b/docs/progguide/pitfalls.xml new file mode 100644 index 000000000..daf08f801 --- /dev/null +++ b/docs/progguide/pitfalls.xml @@ -0,0 +1,112 @@ +<chapter id="pitfalls" xreflabel="Pitfalls"> + <title>Pitfalls</title> + + <sect1 id="pitfalls-intro"> + <title>Introduction</title> + + <para> + This chapter consists of a few AspectJ programs that may lead to + surprising behavior and how to understand them. + </para> + + </sect1> + + <sect1 id="pitfalls-infiniteLoops"> + <title>Infinite loops</title> + + <para> + Here is a Java program with peculiar behavior + </para> + +<programlisting><![CDATA[ +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(); + } + } +} +]]></programlisting> + + <para> + This program will never reach the println call, but when it aborts + may have no stack trace. + </para> + + <para> + This silence is caused by multiple StackOverflowExceptions. 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. + </para> + + <para> + The following short aspect will also generate this behavior: + </para> + +<programlisting><![CDATA[ +aspect A { + before(): call(* *(..)) { System.out.println("before"); } + after(): call(* *(..)) { System.out.println("after"); } +} +]]></programlisting> + + <para> + Why? Because the call to println is also a call matched by the + pointcut <literal>call (* *(..))</literal>. We get no output because + we used simple after() advice. If the aspect were changed to + </para> + +<programlisting><![CDATA[ +aspect A { + before(): call(* *(..)) { System.out.println("before"); } + after() returning: call(* *(..)) { System.out.println("after"); } +} +]]></programlisting> + + <para> + 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. + </para> + + <para> + 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: + </para> + +<programlisting><![CDATA[ +aspect A { + before(): call(* *(..)) && !within(A) { System.out.println("before"); } + after() returning: call(* *(..)) && !within(A) { System.out.println("after"); } +} +]]></programlisting> + + <para> + Other solutions might be to more closely restrict the pointcut in + other ways, for example: + </para> + +<programlisting><![CDATA[ +aspect A { + before(): call(* MyObject.*(..)) { System.out.println("before"); } + after() returning: call(* MyObject.*(..)) { System.out.println("after"); } +} +]]></programlisting> + + <para> + The moral of the story is that unrestricted generic pointcuts can + pick out more join points than intended. + </para> + + </sect1> +</chapter> |