aboutsummaryrefslogtreecommitdiffstats
path: root/docs/progguide/pitfalls.xml
diff options
context:
space:
mode:
Diffstat (limited to 'docs/progguide/pitfalls.xml')
-rw-r--r--docs/progguide/pitfalls.xml112
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>