123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112 |
- <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>
|