You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <chapter id="pitfalls" xreflabel="Pitfalls">
  2. <title>Pitfalls</title>
  3. <sect1 id="pitfalls-intro">
  4. <title>Introduction</title>
  5. <para>
  6. This chapter consists of a few AspectJ programs that may lead to
  7. surprising behavior and how to understand them.
  8. </para>
  9. </sect1>
  10. <sect1 id="pitfalls-infiniteLoops">
  11. <title>Infinite loops</title>
  12. <para>
  13. Here is a Java program with peculiar behavior
  14. </para>
  15. <programlisting><![CDATA[
  16. public class Main {
  17. public static void main(String[] args) {
  18. foo();
  19. System.out.println("done with call to foo");
  20. }
  21. static void foo() {
  22. try {
  23. foo();
  24. } finally {
  25. foo();
  26. }
  27. }
  28. }
  29. ]]></programlisting>
  30. <para>
  31. This program will never reach the println call, but when it aborts
  32. may have no stack trace.
  33. </para>
  34. <para>
  35. This silence is caused by multiple StackOverflowExceptions. First
  36. the infinite loop in the body of the method generates one, which the
  37. finally clause tries to handle. But this finally clause also
  38. generates an infinite loop which the current JVMs can't handle
  39. gracefully leading to the completely silent abort.
  40. </para>
  41. <para>
  42. The following short aspect will also generate this behavior:
  43. </para>
  44. <programlisting><![CDATA[
  45. aspect A {
  46. before(): call(* *(..)) { System.out.println("before"); }
  47. after(): call(* *(..)) { System.out.println("after"); }
  48. }
  49. ]]></programlisting>
  50. <para>
  51. Why? Because the call to println is also a call matched by the
  52. pointcut <literal>call (* *(..))</literal>. We get no output because
  53. we used simple after() advice. If the aspect were changed to
  54. </para>
  55. <programlisting><![CDATA[
  56. aspect A {
  57. before(): call(* *(..)) { System.out.println("before"); }
  58. after() returning: call(* *(..)) { System.out.println("after"); }
  59. }
  60. ]]></programlisting>
  61. <para>
  62. Then at least a StackOverflowException with a stack trace would be
  63. seen. In both cases, though, the overall problem is advice applying
  64. within its own body.
  65. </para>
  66. <para>
  67. There's a simple idiom to use if you ever have a worry that your
  68. advice might apply in this way. Just restrict the advice from occurring in
  69. join points caused within the aspect. So:
  70. </para>
  71. <programlisting><![CDATA[
  72. aspect A {
  73. before(): call(* *(..)) && !within(A) { System.out.println("before"); }
  74. after() returning: call(* *(..)) && !within(A) { System.out.println("after"); }
  75. }
  76. ]]></programlisting>
  77. <para>
  78. Other solutions might be to more closely restrict the pointcut in
  79. other ways, for example:
  80. </para>
  81. <programlisting><![CDATA[
  82. aspect A {
  83. before(): call(* MyObject.*(..)) { System.out.println("before"); }
  84. after() returning: call(* MyObject.*(..)) { System.out.println("after"); }
  85. }
  86. ]]></programlisting>
  87. <para>
  88. The moral of the story is that unrestricted generic pointcuts can
  89. pick out more join points than intended.
  90. </para>
  91. </sect1>
  92. </chapter>