aboutsummaryrefslogtreecommitdiffstats
path: root/docs/progGuideDB/pitfalls.xml
diff options
context:
space:
mode:
Diffstat (limited to 'docs/progGuideDB/pitfalls.xml')
-rw-r--r--docs/progGuideDB/pitfalls.xml103
1 files changed, 103 insertions, 0 deletions
diff --git a/docs/progGuideDB/pitfalls.xml b/docs/progGuideDB/pitfalls.xml
new file mode 100644
index 000000000..5379d5daa
--- /dev/null
+++ b/docs/progGuideDB/pitfalls.xml
@@ -0,0 +1,103 @@
+<chapter id="pitfalls" xreflabel="Pitfalls">
+ <title>Pitfalls</title>
+
+ <sect1><!-- About this Chapter -->
+ <title>About this Chapter</title>
+
+ <para>This chapter consists of aspectj programs that may lead to surprising
+ behaviour and how to understand them.
+ </para>
+
+ </sect1>
+
+ <sect1>
+ <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
+ will 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>
+
+<!--
+Local variables:
+compile-command: "java sax.SAXCount -v progguide.xml && java com.icl.saxon.StyleSheet -w0 progguide.xml progguide.html.xsl"
+fill-column: 79
+sgml-local-ecat-files: "progguide.ced"
+sgml-parent-document:("progguide.xml" "book" "chapter")
+End:
+-->