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.

porting.adoc 56KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963
  1. = AspectJ Porting Notes
  2. _© Copyright 1998-2002 Palo Alto Research Center Incorporated,
  3. 2003-2004 Contributors. All rights reserved._
  4. * xref:#pre-1_2[Pre-1.2 code]
  5. * xref:#pre-1_1[Pre-1.1 code]
  6. * xref:#pre-1_0_4[Pre-1.0.4 code]
  7. * xref:#pre-1_0rc1[Pre-1.0rc1 code]
  8. * xref:#pre-1_0beta1[Pre-1.0beta1 code]
  9. * xref:#pre-1_0alpha1[Pre-1.0alpha1 code]
  10. * xref:#pre08b3[Pre-0.8beta3 code]
  11. * xref:#pre08b1[Pre-0.8beta1 code]
  12. * xref:#pre07b11[Pre-0.7beta11 code]
  13. * xref:#pre07b10[Pre-0.7beta10 code]
  14. [[pre-1_2]]
  15. == Porting pre-1.2 code to AspectJ 1.2
  16. README-1.2.html contains a discussion of the changes between 1.1 and 1.2.
  17. The key points are:
  18. *The default AspectJ compiler compliance level is now 1.4* (whereas in
  19. previous releases the default compliance level was 1.3). This has a
  20. number of implications:
  21. * class files generated by the compiler are now JRE v1.2 and upwards
  22. compatible. (At compliance level 1.3, AspectJ generated class files that
  23. were compatible with JRE 1.1 also).
  24. * `call` pointcuts may match more join points than in the same program
  25. compiled at compliance level 1.3.
  26. The AspectJ compiler can be restored to 1.3 compliance settings by
  27. specifying the "-1.3" option on the command-line.
  28. The following example program illustrates the differences in join point
  29. matching with the `call` pointcut designator between 1.4 and 1.3
  30. compliance levels.
  31. [source, java]
  32. ....
  33. /*01*/ class A {
  34. /*02*/ public void doIt() {...};
  35. /*03*/ }
  36. /*04*/
  37. /*05*/ class B extends A {
  38. /*06*/ public void doThisToo() {...};
  39. /*07*/ }
  40. /*08*/
  41. /*09*/
  42. /*10*/ public class CallsAandB {
  43. /*11*/
  44. /*12*/ public static void main(String[] args) {
  45. /*13*/ B b = new B();
  46. /*14*/ A bInDisguise = new B();
  47. /*15*/
  48. /*16*/ b.doIt(); // AspectJ 1.2 matches here
  49. /*17*/ bInDisguise.doIt(); // this is never matched
  50. /*18*/ }
  51. /*19*/
  52. /*20*/ }
  53. /*21*/
  54. /*22*/ aspect CallPCDMatchingExample {
  55. /*23*/
  56. /*24*/ before() : call(* B.doIt(..)) {
  57. /*25*/ System.out.println("About to call B.doIt(...)");
  58. /*26*/ }
  59. /*27*/
  60. /*28*/ }
  61. ....
  62. When this program is compiled with AspectJ 1.2 using the default
  63. compiler options, it will produce one line of output when it is
  64. executed:
  65. `About to call B.doIt(...)`
  66. The same program compiled under AspectJ 1.1 (or using AspectJ 1.2 with
  67. the -1.3 flag specified) does not produce any output when it is run.
  68. The reason for the additional call pcd match is that prior to compliance
  69. level 1.4, Java compilers produced bytecodes that call A.doIt() (the
  70. defining type of the method), rather than B.doIt() (the declared type in
  71. the program text). The generated call to A.doIt() is not matched by the
  72. call pcd used in the before advice. At compliance level 1.4, the
  73. bytecodes retain the declared type of the receiver in the program
  74. source, generating a call to B.doIt(), which _is_ matched by the call
  75. pcd.
  76. This is a good example of why the recommended style is to use
  77. `call(* doIt(..)) && target(B)`, which always matches based on the
  78. actual type of the receiver.
  79. *New warnings emitted by the compiler for unmatched call pcds.* Because
  80. users have found the static type matching used for a type pattern
  81. specified in a `call` pcd confusing (as evidenced by the example above),
  82. AspectJ 1.2 has a new Xlint warning which is enable by default. The
  83. compiler will now produce a warning whenever a call pointcut designator
  84. does not match at a join point, and a user may have expected it to.
  85. Compiling the above program using AspectJ 1.2 produces the following
  86. compiler output:
  87. [source, text]
  88. ....
  89. CallsAandB.java:24 warning does not match because declaring type is A, if match desired use target(B) [Xlint:unmatchedSuperTypeInCall]
  90. before() : call(* B.doIt(..)) {
  91. ^^^^^^^^^^^^^^^
  92. see also: CallsAandB.java:17
  93. 1 warning
  94. ....
  95. The warning is telling us that the call pointcut associated with the
  96. before advice on line 24 of the source file does not match at a join
  97. point where the user may have expected it to. The source location
  98. corresponding to the unmatched join point is indicated by the "see also"
  99. line - in this case line 17 of the source file. At line 17 we find a
  100. call to `bInDisguise.doIt()`. Since the static type of `bInDisguise` is
  101. `A`, this call will never be matched. The warning also tells us a
  102. possible solution if we intended the pointcut to match at this join
  103. point: use `call(* doIt(..) && target(B)`.
  104. If you find warnings of this kind coming out when you use the AspectJ
  105. 1.2 compiler, the recommended fix is to switch to using the `target`
  106. designator in place of a type pattern in the `call` pointcut expression.
  107. Note that there is no loss of runtime efficiency here - runtime tests
  108. are only added in the cases where it cannot be determined at compile
  109. time whether the type of the receiver will match the type specified in
  110. the `target` expression. Note that `target` cannot be used in `declare`
  111. statements.
  112. *Use of non-statically determinable pointcut expressions in declare
  113. statements* has always been forbidden, but prior to 1.2 the AspectJ
  114. compiler did not raise an error if they were used. The AspectJ Language
  115. Semantics appendix states that `cflow, cflowbelow, this, target, args`
  116. and `if` pointcut designators cannot be used directly or indirectly
  117. (through a user-defined pointcut) inside of a `declare` statment. When
  118. moving code from 1.1 to 1.2, additional errors may be raised due to the
  119. stricter policing of this rule. The solution is to recode the declare
  120. statement avoiding pointcut expressions that may require a run-time
  121. test.
  122. *Interface constructors no longer supported*. Declaring a constructor on
  123. an interface is now (correctly) prohibited, and there will no longer be
  124. a constructor-execution join point for the interface. To initialize a
  125. field declared on an interface, use initialization, e.g.,
  126. [source, java]
  127. ....
  128. int I.i;
  129. after(I i) returning: initialization(I) && this(i) { i.i = 2; }
  130. ....
  131. To pick out the constructor-execution for any implementation of I, try
  132. [source, java]
  133. ....
  134. execution(I+.new(..))
  135. ....
  136. For more information, see bug
  137. https://bugs.eclipse.org/bugs/show_bug.cgi?id=49295[49295].
  138. *Declaring a static method on an interface* is now (correctly)
  139. prohibited. One workaround is to define a static method on the aspect
  140. instead. For more information, see bug
  141. https://bugs.eclipse.org/bugs/show_bug.cgi?id=47754[47754].
  142. *Watch for problems due to incompatible BCEL versions.* AspectJ 1.2
  143. includes a different version of BCEL than AspectJ 1.1. If you have the
  144. older version of BCEL available earlier on your classpath than the
  145. version included in the 1.2 aspectjtools.jar then you will see errors
  146. like:
  147. [source, text]
  148. ....
  149. C:\work\test\TestAspect.aj error Internal compiler error
  150. java.lang.NoSuchMethodError: org.apache.bcel.generic.InstructionFactory.
  151. createNewArray(Lorg/apache/bcel/generic/Type;S)Lorg/apache/bcel/generic/Instruction;
  152. ....
  153. This typically happens because the old version of BCEL has been included
  154. as a standard extension in your JVM configuration. Ensure you have
  155. removed it from jre/lib/ext under your JDK installation.
  156. For more information, see bugs including
  157. https://bugs.eclipse.org/bugs/show_bug.cgi?id=60389[60389],
  158. https://bugs.eclipse.org/bugs/show_bug.cgi?id=59921[59921].
  159. [[pre-1_1]]
  160. == Porting pre-1.1 code to AspectJ 1.1
  161. README-1.1.html contains a discussion of the language changes from 1.0 to
  162. 1.1. The high points:
  163. The `call(..)` pointcut designator is now implemented only at the call
  164. site; by contrast, the AspectJ 1.0 compiler could also implement it on
  165. the callee side. So in 1.0 if you compiled a pointcut using `call(..)`
  166. but only passed the compiler the code for the target of the call, the
  167. pointcut could be implemented. This is not true for 1.1. To fix this,
  168. use `execution(..)` in place of `call(..)`, or include all calling
  169. clients in the compile. (xref:README-1.1.adoc#NO_CALLEE_SIDE_CALL[more
  170. info])
  171. Type-patterns are no longer permitted for the defining type of
  172. inter-type declarations. Replace the pattern with a type. In many cases,
  173. you can declare members on an interface type, and then declare that the
  174. types picked out by the type-pattern implement have the interface as
  175. their parent. (xref:README-1.1.adoc#SINGLE_INTERCLASS_TARGET[more info])
  176. Type-patterns are no longer permitted when specifying `declare soft`.
  177. Replace the pattern with a literal type.
  178. Wildcards patterns (`foo..*`) are no longer permitted for `this()`,
  179. `target()`, or `args()`. Replace the pattern with a literal type or with
  180. a subtype wildcard (`Type+`).
  181. (xref:README-1.1.adoc#INSTANCEOF_ON_WILD[more info])
  182. Conflicts will be reported for no-argument constructors generated by
  183. compilers when no constructor is defined for a class. That means the
  184. following code will compile in 1.0 but not in 1.1:
  185. [source, java]
  186. ....
  187. class C {}
  188. aspect A {
  189. C.new() {} // permitted in 1.0; conflict in 1.1
  190. }
  191. ....
  192. One fix is to declare a non-conflicting constructor by adding arguments
  193. (or defining a constructor in the target class); a better fix might be
  194. to do the work of the declared constructor in advice on the
  195. initialization join point for the object.
  196. (xref:README-1.1.adoc#DEFAULT_CONSTRUCTOR_CONFLICT[more info])
  197. The pointcut designators `within()` and `withincode()` will not pick out
  198. code within the lexical extent of method-local and anonymous inner types
  199. (because these are not represented as such in bytecode form). Because
  200. `within` forms specify staticly-determinable pointcuts, they might be
  201. used in declare error or declare warning statements, which might produce
  202. different results. (xref:README-1.1.adoc#WITHIN_MEMBER_TYPES[more info])
  203. The compiler will report an error that the form
  204. `aspect \{name} dominates \{list}...` is no longer supported. It has been
  205. replaced by a new declare statement:
  206. [source, java]
  207. ....
  208. declare precedence : {name} {list}...
  209. ....
  210. (xref:README-1.1.adoc#ASPECT_PRECEDENCE[more info])
  211. The field set join point now has a return type of `void`. Compiling
  212. programs using around advice on these join points might cause errors
  213. unless the return type of the around advice and the result of any
  214. proceed() call is `Object` or `void`.
  215. (xref:README-1.1.adoc#VOID_FIELD_SET[more info])
  216. The compiler cannot implement after or around advice for the handler PCD
  217. because the end of exception handlers is ambiguous in bytecode. Try to
  218. use before advice. (xref:README-1.1.adoc#AFTER_HANDLER[more info])
  219. [[pre-1_0_4]]
  220. == Porting pre-1.0.4 code
  221. In versions of AspectJ prior to 1.0.4, the compiler was not correctly
  222. implementing the AspectJ-1.0 language design for some uses of after
  223. returning advice.
  224. The main change that was made was of after returning advice for
  225. constructor execution join points. Previously, this advice was legal:
  226. [source, java]
  227. ....
  228. after() returning (Foo f): execution(Foo.new(..)) { ... }
  229. ....
  230. However, it has always been a part of the 1.0 language design (and of
  231. Java's language design) that constructors themselves (as opposed to
  232. constructor calls) do not return the value of the new object. Rather,
  233. `this` is bound to the new object, and the constructor behaves like a
  234. void method. With that in mind, any code like the above should be
  235. conveted to the form.
  236. [source, java]
  237. ....
  238. after(Foo f) returning: this(f) && execution(Foo.new(..)) { ... }
  239. ....
  240. In compilers prior to 1.0.4, the following advice could pick out join
  241. points
  242. [source, java]
  243. ....
  244. after() returning (String s): call(void foo()) { ... }
  245. ....
  246. This is no longer picked out. This pattern was most commonly used in
  247. highly polymorphic contexts, such as
  248. [source, java]
  249. ....
  250. after() returning (String s): call(* foo()) { ... }
  251. ....
  252. If you want to capture all calls, binding null objects for those that
  253. would otherwise have no value, you must use the `Object` type.
  254. [source, java]
  255. ....
  256. after() returning (Object o): call(* foo()) { ... }
  257. ....
  258. Uses of both of these forms are highleted with compiler warnings in the
  259. 1.0.4 compiler.
  260. '''''
  261. [[pre-1_0rc1]]
  262. == Porting pre-1.0rc1 code
  263. Aspects can no longer be declared to implement the `Serializable` or
  264. `Cloneable` interfaces. If you previously used serializable or cloneable
  265. aspects, you should refactor your code to keep the state you need to
  266. serialize or clone in objects associated with the aspects.
  267. '''''
  268. [[pre-1_0beta1]]
  269. == Porting pre-1.0beta1 code
  270. The `static` modifier is no longer allowed on pointcut declarations
  271. anywhere. Porting is simple; just remove the static declarations when
  272. you find them.
  273. Also, though the `returns` modifier on pointcuts has not been part of
  274. the language since 1.0alpha1, the compiler still accepted them until
  275. now. If you used this feature, now is the right time to remove the
  276. `returns` modifier when the compiler complains about it.
  277. '''''
  278. [[pre-1_0alpha1]]
  279. == Porting pre-1.0alpha1 code
  280. The release of AspectJ 1.0alpha1 involved sweeping cleanups of the
  281. language to bring it to 1.0 status.
  282. * xref:#_1_0a1-pointcuts[Pointcuts]
  283. * xref:#_1_0a1-type-patterns[Type patterns]
  284. * xref:#_1_0a1-advice[Advice]
  285. * xref:#_1_0a1-introduction-and-static[Introduction and static
  286. crosscutting]
  287. * xref:#_1_0a1-aspects[Aspects]
  288. [[_1_0a1-pointcuts]]
  289. === Pointcuts
  290. [[_1_0a1-plural-to-singular]]
  291. ==== Removing the "s" from pointcuts
  292. One of the most pervasive changes in porting code written before
  293. 1.0alpha1 is the change in some of the pointcut names from plural to
  294. singular, that is, they lose an "s". In one sense, making this change in
  295. your programs is easy: Just go through and whever you see uses of the
  296. pointcuts `calls, executions, gets, sets, handlers, initializations,
  297. staticinitializations`.
  298. Just take off the final "s", to make one of `call, execution, get, set, handler, initialization, staticinitialization`.
  299. Often, there will be other changes you should make for each of these
  300. pointcuts, but as for the name, just take off the "s".
  301. One risk you will have when doing this is creating name conflicts. If,
  302. for example, you named a parameter of a pointcut "set", you should (for
  303. your own sanity -- the compiler doesn't require it) rename it in the
  304. rewritten pointcut.
  305. [source, java]
  306. ....
  307. pointcut sort(Collection set): calls(void addAll(set));
  308. // ==>
  309. pointcut sort(Collection mySet): call(void addAll(mySet));
  310. ....
  311. While converting to use singular nouns for the primitive pointcuts, you
  312. may also want to remove the "s" from your user-defined pointcuts.
  313. [source, java]
  314. ....
  315. pointcut publicCalls(): calls(public * *(..));
  316. // ==>
  317. pointcut publicCall(): call(public * *(..));
  318. ....
  319. Of course, your naming conventions are your own, but throughout these
  320. porting notes we will be making these changes in our example ports.
  321. [[_1_0a1-remove-receptions]]
  322. ==== Removing the receptions pointcut
  323. Perhaps the largest semantic change in the 1.0 language is the removal
  324. of receptions join points. They have been merged with call join points
  325. in AspectJ 1.0, so now a call join point doesn't represent the
  326. "caller-side" of a call, but the call itself, both caller and receiver.
  327. Changing code that used the `receptions` pointcut should be fairly
  328. straightforward, depending on whether the pointcut exposed state or not.
  329. ===== Not exposing state
  330. Receptions pointcuts that did not expose state can simply be replaced by
  331. the new `call` and `target` pointcuts:
  332. [source, java]
  333. ....
  334. receptions(void Foo.m())
  335. // ==>
  336. target(Foo) && call(void m())
  337. ....
  338. ===== Exposing state
  339. Some receptions pointcuts exposed the receiving object by replacing the
  340. receiving type with a pointcut formal. These PCDs should be rewritten to
  341. use the new `target` pointcut to expose the receiving object.
  342. [source, java]
  343. ....
  344. pointcut fooCallees(Foo f): receptions(void f.m());
  345. // ==>
  346. pointcut fooCallee(Foo f): target(f) && call(void m());
  347. ....
  348. Like xref:#_1_0a1-fixing-state-access[other pointcuts], receptions
  349. pointcuts that exposed one or more arguments should be rewritten to use
  350. the `args` pointcut:
  351. [source, java]
  352. ....
  353. pointcut intPassers(int i, int j): receptions(void Foo.m(i, j));
  354. // ==>
  355. pointcut intPasser(int i, int j):
  356. args(i, j) && target(Foo) && call(void m(int, int));
  357. ....
  358. ===== Constructor receptions
  359. There are two issues with constructor receptions in particular.
  360. Like xref:#_1_0a1-constructor-calls[constructor calls], constructor
  361. receptions pointcuts had a dynamic character, in that
  362. `receptions(C.new())` would capture constructions of not only C classes,
  363. but also of classes that extended C.
  364. If you want this behaviour, then you need to use the new subtypes
  365. operator, +, on the type name in question. So,
  366. [source, java]
  367. ....
  368. receptions(C.new())
  369. // ==>
  370. call(C+.new())
  371. ....
  372. Also like xref:#_1_0a1-constructor-calls[constructor calls], constructor
  373. receptions allowed access to the constructed object in the same way as
  374. any other object. Since the only advice possible on constructor
  375. receptions join points was `after returning` advice, the object was
  376. always guaranteed to be there. But since constructor call join points
  377. allow all kinds of advice it may be that the object isn't constructed
  378. yet (say, in before or around advice). This is a benefit, in that it
  379. allows caching constructed objects
  380. [source, java]
  381. ....
  382. aspect Singleton {
  383. private C theC = null;
  384. C around(): call(C.new(..)) {
  385. if (c == null) theC = proceed();
  386. return theC;
  387. }
  388. }
  389. ....
  390. but it does require some rewriting. The new object can be accessed as
  391. the return value in after returning advice. So,
  392. [source, java]
  393. ....
  394. after(Point p) returning (): receptions(p.new(int, int)) { ... }
  395. // ==>
  396. after() returning (Point p): call(Point+.new(int, int)) { ... }
  397. ....
  398. [[_1_0a1-fixing-state-access]]
  399. ==== Fixing state access
  400. In previous versions of AspectJ, state such as the currently executing
  401. object or a particular argument of a method call could be accessed from
  402. the signatures of many pointcuts, leading to difficult-to-read forms. In
  403. AspectJ 1.0, all state accesses now use only three pointcuts `args, this, target`
  404. which pick out argument values, the currently executing object, and the
  405. target object of a method call or field operation, respectively.
  406. ===== Using args
  407. Any time you have a pointcut that has a signature where one of the
  408. arguments was a pointcut or advice formal, just replace that formal with
  409. its type and add an `args` pointcut.
  410. [source, java]
  411. ....
  412. pointcut intPassers(int i, int j): calls(void Foo.m(i, j));
  413. // ==>
  414. pointcut intPasser(int i, int j): args(i, j) && call(void Foo.m(int, int));
  415. ....
  416. [source, java]
  417. ....
  418. pointcut stringPassers(String s): receptions(void Foo.m(s, ..));
  419. // ==>
  420. pointcut stringPasser(String s): args(s, ..) && call(void Foo.m(String, ..));
  421. ....
  422. ===== Rewriting calls
  423. If a calls pointcut exposed the the receiving object, such as
  424. [source, java]
  425. ....
  426. pointcut fooCallees(Foo f): calls(void f.m());
  427. ....
  428. then the new version should use the `target` pointcut to get at that
  429. object
  430. [source, java]
  431. ....
  432. pointcut fooCallee(Foo f): target(f) && call(void Foo.m());
  433. ....
  434. AspectJ's calls pointcut previously allowed the new object to be
  435. exposed, even though it may not have been constructed yet. AspectJ 1.0
  436. no longer allows this; you can access the new instance only in after
  437. returning advice, when it is guaranteed that the object was successfully
  438. constructed. So instead of using the `target` pointcut to expose the
  439. value, you should use the normal `after returning` mechanism:
  440. [source, java]
  441. ....
  442. after(Point p) returning (): calls(p.new(int, int)) { ... }
  443. // ==>
  444. after() returning (Point p): call(Point+.new(int, int)) { ... }
  445. ....
  446. ===== Rewriting gets and sets
  447. Exposing the target object of a `gets` or `sets` pointcut should be done
  448. the same way it was for `calls` pointcuts, with the new `target`
  449. pointcut.
  450. [source, java]
  451. ....
  452. before(Frame f): gets(Color f.color) { ... }
  453. // ==>
  454. before(Frame f): target(f) && get(Color Frame.color) { ... }
  455. ....
  456. [source, java]
  457. ....
  458. before(Frame f): sets(Color f.color) { ... }
  459. // ==>
  460. before(Frame f): target(f) && set(Color Frame.color) { ... }
  461. ....
  462. In addition, the clumsy syntax for getting the old value of the field
  463. has been eliminated. For before advice, the port is simple; just access
  464. the field yourself in the body. Depending on the rest of your system,
  465. you may need to restrict the advice from the aspect body to eliminiate
  466. the circularity.
  467. [source, java]
  468. ....
  469. aspect A {
  470. before(Frame f, Color c): gets(Color f.color)[c] { ... }
  471. }
  472. // ==>
  473. aspect A {
  474. before(Frame f):
  475. target(f) && get(Color Frame.color) && !within(A)
  476. {
  477. Color c = f.color;
  478. // ...
  479. }
  480. }
  481. ....
  482. The same can be done for `around` advice. However, the only way to port
  483. after advice that needs the old value is to convert it to around advice.
  484. [source, java]
  485. ....
  486. aspect A {
  487. after(Frame f, Color c) returning (): gets(Color f.color)[c] { ... }
  488. }
  489. // ==>
  490. aspect A {
  491. void around(Frame f):
  492. target(f) && get(Color Frame.color) && !within(A)
  493. {
  494. Color c = f.color;
  495. proceed(f);
  496. // ...
  497. }
  498. }
  499. ....
  500. When porting `sets` pointcuts, the new value of a field is still
  501. available, but not the way it was previously. Instead of using the
  502. square bracket syntax, we use an `args` pointcut. All set join points
  503. are assumed to have exactly one argument, which holds the new value. So,
  504. [source, java]
  505. ....
  506. after(Color newColor): sets(Color Frame.color)[][newColor] { ... }
  507. // ==>
  508. after(Color newColor): args(newColor) && set(Color Frame.color) { ... }
  509. ....
  510. Also, if the field was declared private, in order to get at its old
  511. value the aspect must be declared `privileged`.
  512. ===== Rewriting handlers
  513. The value of the exception at an exception handler join point is now
  514. accessed through the `args` pointcut; all exception handler join points
  515. are treated as having exactly one argument, the exception value. So,
  516. [source, java]
  517. ....
  518. before(NotFoundException e): handlers(e) { ... }
  519. // ==>
  520. before(NotFoundException e): args(e) && handler(NotFoundException) { ... }
  521. ....
  522. ===== Rewriting within
  523. The `within` pointcut was not typically used to export context. Though
  524. it was accidentally possible to do so in versions of AspectJ before 1.0,
  525. it often didn't do what users expected it to. This loophole has now been
  526. closed, and within can only take type patterns, not pointcut or advice
  527. formals. A use of the `this` pointcut will capture what previous
  528. implementations did:
  529. [source, java]
  530. ....
  531. pointcut usesFoo(Foo f): within(f);
  532. // ==>
  533. pointcut usesFoo(Foo f): this(f) && within(Foo);
  534. ....
  535. [[_1_0a1-no-subs-in-sigs]]
  536. ==== Understanding signatures
  537. Now that we have `this`, `target`, and `args` pointcuts, all of our
  538. signatures are composed of just types, names, and wildcards; there are
  539. no more parameters.
  540. Also, now that we have the `+` wildcard to pick out
  541. xref:#_1_0a1-subtypes-to-plus[subtypes], we can make signature matching
  542. much more uniform.
  543. Previously, some signatures matched based on subtypes, some based on
  544. instanceof, and some exactly. Now, we have made all signatures match
  545. exactly.
  546. What does this mean for your program? Well, it means that you may have
  547. to add `+` to some of your signatures, depending on what you meant them
  548. to match.
  549. For example, the pointcut
  550. [source, java]
  551. ....
  552. calls(void m(Object))
  553. ....
  554. previously picked out all method calls to a method named m that took one
  555. argument, which was a subtype of Object. Now, however, it will only pick
  556. out method calls to methods that are defined to take exactly the type
  557. Object, which may be a lot fewer join points. If you want the old
  558. behaviour, simply convert to
  559. [source, java]
  560. ....
  561. call(void m(Object+))
  562. ....
  563. [[_1_0a1-fixing-instanceof]]
  564. ==== Removing the instanceof pointcut
  565. The intanceof pointcut has been split into two different pointcuts,
  566. `this` and `target`.
  567. Typically, the instanceof pointcut would only exist in a compound
  568. pointcut, composed (with `&&`) with another pointcut. If the other
  569. pointcut was a `receptions` pointcut, then `instanceof` should be
  570. converted to `target` (and `receptions` converted to `call`). So,
  571. [source, java]
  572. ....
  573. pointcut stateChanges(Subject s):
  574. instanceof(s) && receptions(void Button.click());
  575. // ==>
  576. pointcut stateChange(Subject s):
  577. target(s) && call(void Button.click());
  578. ....
  579. In all other cases, `instanceof` referred to the currently executing
  580. object, and so should be converted into `this`
  581. [source, java]
  582. ....
  583. before(Point p): instanceof(p) && executions(* makePolar(..)) { ... }
  584. // ==>
  585. before(Point p): this(p) && execution(* makePolar(..)) { ... }
  586. ....
  587. [source, java]
  588. ....
  589. pointcut setup(Client c): instanceof(c) && calls(Remote Naming.lookup(String));
  590. // ==>
  591. pointcut setup(Client c): this(c) && calls(Remote Naming.lookup(String));
  592. ....
  593. [[_1_0a1-initializations]]
  594. ==== Rewriting the initializations pointcut
  595. Object initialization join points are now more complicated, and more
  596. true to Java's execution model. Now they bracket all of the
  597. initialization that a class can do, after the return of its super
  598. constructor call (before which no initialization can happen). Previous
  599. versions of AspectJ had object initialization join points that only
  600. included initialization that was made in dynamic initializers and
  601. fields.
  602. The old behaviour can be recovered with a simple rewrite.
  603. [source, java]
  604. ....
  605. initializations(A)
  606. // ==>
  607. initialization(A.new(..)) && !execution(A.new(..))
  608. ....
  609. [[_1_0a1-constructor-calls]]
  610. ==== Understanding constructor calls
  611. Previously, constructor call join points were matched by subtypes, so
  612. `calls(Foo.new())` would match both calls to create new `Foo` objects,
  613. and new `SubFoo` objects. The new `call` pointcut designator matches
  614. types exactly, so if you want the old behaviour, you should write
  615. `call(Foo+.new())`.
  616. Similarly, constructor execution join points were matched by subtypes.
  617. So the old `executions(Foo.new())` is now represented by
  618. `execution(Foo+.new())`.
  619. In both of these cases, think before using the + operator; it may be
  620. that you didn't intend subtype matching in the first place.
  621. [[_1_0a1-hasaspect]]
  622. ==== Removing the hasaspect pointcut
  623. The `hasaspect` pointcut is no longer defined, but you can get the same
  624. behaviour using the new `if` pointcut.
  625. If the aspect whose presense you are checking for was defined
  626. `of eachcflow`, `of eachcflowbelow`, or, more unlikely, `of eachJVM()`,
  627. then the conversion is simple:
  628. [source, java]
  629. ....
  630. hasaspect(A)
  631. // ==>
  632. if(A.hasAspect())
  633. ....
  634. If the aspect was defined `of eachobject`, then you will have to expose
  635. the current object in your pointcut or advice parameters:
  636. [source, java]
  637. ....
  638. pointcut cut(): hasaspect(A) ... ;
  639. // ==>
  640. pointcut cut(Object o): this(o) && if(A.hasAspect(o)) ... ;
  641. // or
  642. pointcut cut(Object o): target(o) && if(A.hasAspect(o)) ... ;
  643. ....
  644. If you were using the `hasaspect` pointcut to expose the state of the
  645. aspect, then you can get the same state by using `A.aspectOf()` in the
  646. body of the advice. For example, if the aspect A were defined
  647. `of eachcflow`, then
  648. [source, java]
  649. ....
  650. before(A myA): hasaspect(myA) {
  651. myA.checkStatus();
  652. }
  653. // ==>
  654. before(): if(A.hasAspect()) {
  655. A myA = A.aspectOf();
  656. myA.checkStatus();
  657. }
  658. ....
  659. [[_1_0a1-withinall]]
  660. ==== Removing the withinall pointcut
  661. The withinall poinctut is no longer defined. You can use a combination
  662. of within and the xref:#_1_0a1-subtypes-to-plus[new subtypes operator],
  663. `+`, instead. You'll save two characters and be using a simpler and more
  664. orthogonal language.
  665. [source, java]
  666. ....
  667. withinall(Foo)
  668. // ==>
  669. within(Foo+)
  670. ....
  671. [[_1_0a1-user-defined-returns]]
  672. ==== Removing returns modifier from pointcuts
  673. The returns keyword is no longer necessary for user-defined pointcuts.
  674. Simply remove it when you find it.
  675. [source, java]
  676. ....
  677. pointcut publicIntCalls() returns int: calls(public int *(..));
  678. // ==>
  679. pointcut publicIntCall(): call(public int *(..));
  680. ....
  681. [[_1_0a1-static-pointcuts]]
  682. ==== Making some pointcuts static
  683. In Java, only static members may be accessed by their declaring type
  684. name, like the static method `Math.max()` can be accessed.
  685. Pointcuts now have that property too. Pointcuts may be declared to be
  686. static, in which case they can be accessed like `MyAspect.move()`, or
  687. they can be left non-static, in which case they can be overridden by a
  688. subaspect.
  689. In addition, while pointcuts can still be defined in classes, only
  690. `static` pointcuts can be defined in classes.
  691. Porting should be straightforward; just make all your pointcuts in
  692. classes `static`, and make any pointcut with a qualified reference
  693. static.
  694. [[_1_0a1-type-patterns]]
  695. === Type patterns
  696. [[_1_0a1-new-wildcards]]
  697. ==== Understanding * and .. in type patterns
  698. Previous versions of AspectJ treated * and .. too cleverly in type
  699. patterns, placing restrictions based on what is a package and what is a
  700. type, and basing their meanings on the definition of a package
  701. hierarchy.
  702. In AspectJ 1.0, both of these wildcards are defined simply, and
  703. textually:
  704. * The * wildcard alone matches all types.
  705. * The * wildcard in a pattern matches zero or more characters, but will
  706. not match "."
  707. * The .. wildcard matches any sequence of characters that begins and
  708. ends with "."
  709. That's it.
  710. This change won't affect most programs, but it will make understanding
  711. programs easier. There is one ugly idiom, however, that this change
  712. disposes of. If your program includes the type pattern `*..*`, which
  713. used to match all types, you can replace it with the much simpler *.
  714. [source, java]
  715. ....
  716. pointcut unaryVoidMethods(): call(void *(*..*));
  717. // ==>
  718. pointcut unaryVoidMethod(): call(void *(*));
  719. ....
  720. [[_1_0a1-subtypes-to-plus]]
  721. ==== Fixing subtypes in introduction
  722. The new + operator is used to normalize the many places you want to use
  723. subtypes of some types.
  724. In introduction forms, you will need to replace `subtypes(TypePattern)`
  725. type patterns with the new subtype operator, +. In the case where you
  726. wrote `subtypes(Foo)`, i.e., the subtypes of a single type, simply
  727. replace this with `Foo+`. Otherwise, use the + operator as appropriate
  728. in `TypePattern`.
  729. [source, java]
  730. ....
  731. public void (subtypes(Target0 || Target1)).accept(Visitor v) {
  732. v.visit(this);
  733. }
  734. // ==>
  735. public void (Target0+ || Target1+).accept(Visitor v) {
  736. v.visit(this);
  737. }
  738. ....
  739. [[_1_0a1-advice]]
  740. === Advice
  741. [[_1_0a1-around-returns]]
  742. ==== Moving the return type of around
  743. The returns keyword is no longer used for around advice. Instead, the
  744. return type is declared as it is for methods. So,
  745. [source, java]
  746. ....
  747. around(Point p) returns void: setters(p) { ... }
  748. // ==>
  749. void around(Point p): setter(p) { ... }
  750. ....
  751. [[_1_0a1-around-throws]]
  752. ==== Adding a throws clause to around
  753. Around advice must now declare the checked exceptions it throws with a
  754. `throws` clause, much like a method.
  755. [source, java]
  756. ....
  757. char around(char c) throws java.io.CharConversionException: converter(c) {
  758. char result;
  759. try { result = proceed(); }
  760. catch (Exception e) {
  761. throw new java.io.CharConversionException();
  762. }
  763. if (result == 0) throw new java.io.CharConversionException();
  764. return result;
  765. }
  766. ....
  767. [[_1_0a1-advice-precedence]]
  768. ==== Understanding advice precedence
  769. In previous versions of AspectJ, advice precedence within an aspect was
  770. simple: if a piece of advice appeared before another piece, it was more
  771. precedent. This made perfect sense for `before` and `around` advice, but
  772. was the cause of confusion (even among the AspectJ designers, more than
  773. once) for `after` advice, as it seemed backward.
  774. In addition, advice was ordered by kind, in that around advice always
  775. surrounded before and after advice.
  776. AspectJ 1.0 has changed this; precedence for `after` advice is inverted,
  777. and advice is no longer ordered by kind.
  778. This won't matter to you unless you write pieces of advice in the same
  779. aspect that apply to the same join point.
  780. If you do, here's what to think about: If you're looking at two pieces
  781. of advice and want to know which has precedence, if either is `after`
  782. advice, then the second one has precedence. Otherwise, the first does.
  783. This allows interesting advice interaction. In the following advice, for
  784. example, the `after throwing` advice will catch the exception thrown by
  785. the `before` advice
  786. [source, java]
  787. ....
  788. aspect A {
  789. before(): call(void main(..)) {
  790. throw new RuntimeException();
  791. }
  792. after() throwing(RuntimeException e): call(void main(..)) {
  793. System.err.println("caught you!");
  794. }
  795. }
  796. ....
  797. But reversing the order will give the `before` advice more precedence,
  798. making its exception uncatchable by the `after throwing` advice
  799. [source, java]
  800. ....
  801. aspect A {
  802. after() throwing(RuntimeException e): call(void main(..)) {
  803. System.err.println("missed you!");
  804. }
  805. before(): call(void main(..)) {
  806. throw new RuntimeException();
  807. }
  808. }
  809. ....
  810. Advice in _different_ aspects is ordered by the normal aspect precedence
  811. rules of subtyping and the `dominates` modifier.
  812. [[_1_0a1-after-returning]]
  813. ==== Fixing after returning
  814. If you use after returning advice and do not need to expose the return
  815. value, you no longer need to write an empty set of parentheses to
  816. indicate that fact. So,
  817. [source, java]
  818. ....
  819. after(Formals) returning (): Pointcut { ... }
  820. // ==>
  821. after(Formals) returning: Pointcut { ... }
  822. ....
  823. The same syntax is now available for after throwing advice, in case you
  824. do not care what `Throwable` is thrown.
  825. [source, java]
  826. ....
  827. after(Formals) throwing: Pointcut { ... }
  828. ....
  829. [[_1_0a1-this-static-join-point]]
  830. ==== Renaming thisStaticJoinPoint
  831. `thisStaticJoinPoint` has been renamed `thisJoinPointStaticPart`, to
  832. reflect that it is now exactly the static part of `thisJoinPoint`: It
  833. will return the same object as `thisJoinPoint.getStaticPart()`.
  834. [[_1_0a1-this-join-point]]
  835. ==== Converting access to thisJoinPoint
  836. The `JoinPoint` object hierarchy has been folded into a single class,
  837. `org.aspectj.lang.JoinPoint`. A common pattern in logging, for example,
  838. was
  839. [source, java]
  840. ....
  841. before() executions(* myMethod()) {
  842. ExecutionJoinPoint jp = (ExecutionJoinPoint)thisJoinPoint;
  843. CodeSignature jp = (CodeSignature)jp.getSignature();
  844. System.err.println(jp.getParameters());
  845. System.err.println(jp.getParameterNames());
  846. }
  847. ....
  848. While there is still a rich hierarchy for signatures, there is only one
  849. `JoinPoint` type, so this can be rewritten as:
  850. [source, java]
  851. ....
  852. before() executions(* myMethod()) {
  853. JoinPoint jp = thisJoinPoint;
  854. CodeSignature jp = (CodeSignature)jp.getSignature();
  855. System.err.println(jp.getArgs());
  856. System.err.println(jp.getParameterNames());
  857. }
  858. ....
  859. Some of the method names of `JoinPoint` have been reorganized, as well.
  860. [[_1_0a1-introduction-and-static]]
  861. === Introduction and static crosscutting
  862. [[_1_0a1-plus-implements-extends]]
  863. ==== Removing +implements and +extends
  864. The keywords `+implements` and `+extends` no longer exist. Instead,
  865. AspectJ uses the `declare` form for exactly the same functionality.
  866. [source, java]
  867. ....
  868. Point +implements Serializable;
  869. // ==>
  870. declare parents: Point implements Serializable;
  871. ....
  872. [source, java]
  873. ....
  874. MyButton +extends ButtonAdaptor;
  875. // ==>
  876. declare parents: MyButton extends ButtonAdaptor;
  877. ....
  878. [[_1_0a1-now-use-soft]]
  879. ==== Using declare soft
  880. Around advice advice no longer effects the static exception checking of
  881. Java. This means that the following code previously compiled:
  882. [source, java]
  883. ....
  884. class C {
  885. void noExceptionDeclared() {
  886. exceptionDeclared();
  887. }
  888. void exceptionDeclared() throws IOException {}
  889. }
  890. aspect A {
  891. around(): call(void C.exceptionDeclared()) {
  892. try { proceed(); }
  893. catch (IOException e) {}
  894. }
  895. }
  896. ....
  897. even though the class `C` is not compilable on its own (because
  898. `noExceptionDeclared` actually throws an `Exception`).
  899. AspectJ now firmly places everything that affects the type system of
  900. Java, including the declared-exception checking system, into the space
  901. of introduction and declare. So, in order to state that the call to
  902. `exceptionDeclared()` will not, actually, throw an exception, we now
  903. "soften" that exception, that is, take it out of the space of declared
  904. exceptions.
  905. [source, java]
  906. ....
  907. declare soft: ExceptionType: Pointcut;
  908. ....
  909. The pointcuts allowed here are limited; you cannot use pointcuts that
  910. would require runtime information. But picking out method calls is just
  911. fine. So in order to make the above example work, one new declaration is
  912. needed:
  913. [source, java]
  914. ....
  915. declare soft: IOException:
  916. call(void C.exceptionDeclared()) &&
  917. withincode(void noExceptionDeclared());
  918. ....
  919. [[_1_0a1-aspects]]
  920. === Aspects
  921. The syntax of "of each" modifiers has changed. For `of eachcflow` and
  922. `of eachcflowbelow`, you can simply replace "of each" with "per". So,
  923. [source, java]
  924. ....
  925. aspect A of eachcflow(...) { ... }
  926. // ==>
  927. aspect A percflow(...) { ... }
  928. ....
  929. If you have any aspects defined `of eachJVM()`, then you should either
  930. remove that declaration entirely (because this is the default
  931. behaviour), or replace the `of eachJVM()` declaration with an
  932. `issingleton` declaration.
  933. [source, java]
  934. ....
  935. aspect of eachJVM() { ... }
  936. // ==>
  937. aspect A { ... }
  938. // or
  939. aspect A issingleton { ... }
  940. ....
  941. The `of eachobject(Pointcut)` modifier has been split into two different
  942. forms, `of perthis(Pointcut)` and `of pertarget(Pointcut)`. Which one
  943. you replace with depends on the `Pointcut` you use.
  944. If you use a pointcut that picked out reception join points, then use
  945. `pertarget`, and rewrite the pointcut to pick out call join points. So
  946. [source, java]
  947. ....
  948. aspect Shadow
  949. of eachobject(
  950. receptions(void Point.setX(int)) ||
  951. receptions(void Point.setY(int))
  952. )
  953. {
  954. // ...
  955. }
  956. // ==>
  957. aspect Shadow
  958. pertarget(
  959. call(void Point.setX(int)) ||
  960. call(void Point.setY(int))
  961. )
  962. {
  963. // ...
  964. }
  965. ....
  966. Otherwise, in most cases, use `perthis`. When you convert, remember the
  967. meaning of each of these modifiers. `perthis(Pointcut)` indicates that
  968. an instance of the aspect should be associated with every object that is
  969. `this` at each of the join points picked out by `Pointcut`, while
  970. `pertarget(Pointcut)` associates with every object that is the target
  971. object at such join points.
  972. '''''
  973. [[pre08b3]]
  974. == Porting pre-0.8beta3 code
  975. * xref:#cflowTerminology[Changing cflow terminology]
  976. * xref:#abstractPointcuts[Overriding abstract pointcuts]
  977. * xref:#recursiveAdvice[Limiting recursive advice]
  978. The following changes are only required when porting code written prior
  979. to the 0.8beta3 release of AspectJ.
  980. [[cflowTerminology]]
  981. === Changing cflow terminology
  982. Changing pre-0.8beta3 code that uses AspectJ's control-flow-based
  983. features only requires rewriting occurrences of `eachcflowroot`,
  984. `cflow`, and `cflowtop`. No editing of other aspect code is necessary.
  985. ==== eachcflowroot
  986. The aspect modifier "`of eachcflowroot(Pointcut)`" should now be written
  987. more as "`percflow(Pointcut)`".
  988. ==== cflow
  989. In previous versions of AspectJ, the pointcut `cflow(Pointcut)` picked
  990. out all join points in the cflow below the join points of `Pointcut`.
  991. That is, it did not include the join points of `Pointcut`, only the join
  992. points in their control flow.
  993. As of version 0.8beta3, `cflowbelow(Pointcut)` has that behavior.
  994. `cflow(Pointcut)` includes the join points of `Pointcut`.
  995. In many cases, you may not care whether the points of `Pointcut` are
  996. included or not, and so can safely leave `cflow(Pointcut)` pointcut
  997. designators alone. However, if you use the idiom
  998. [source, java]
  999. ----
  1000. Pointcut && ! cflow(Pointcut)
  1001. ----
  1002. to capture the non-recursive entries to a particular pointcut, you will
  1003. definitely want to rewrite that as
  1004. [source, java]
  1005. ----
  1006. Pointcut && ! cflowbelow(Pointcut)
  1007. ----
  1008. ==== cflowtop
  1009. The primitive pointcut designator `cflowtop(Pointcut)` has been removed
  1010. from the language, as it is expressible with `cflow` or `cflowbelow`.
  1011. All uses of `cflowtop(Pointcut)` can be rewritten as:
  1012. [source, java]
  1013. ----
  1014. cflowbelow(Pointcut && ! cflowbelow(Pointcut))
  1015. ----
  1016. Though in most cases the following is sufficient
  1017. [source, java]
  1018. ----
  1019. cflow(Pointcut && ! cflowbelow(Pointcut))
  1020. ----
  1021. [[abstractPointcuts]]
  1022. === Overriding abstract pointcuts
  1023. In previous versions of AspectJ, a concrete aspect would implicitly
  1024. override all of its abstract pointcuts with an empty pointcut. AspectJ
  1025. 0.8beta3 enforces the restriction that a concrete aspect may not have
  1026. any abstract pointcuts. Thus the following extension:
  1027. [source, java]
  1028. ----
  1029. abstract aspect A {
  1030. abstract pointcut pc();
  1031. }
  1032. aspect B {}
  1033. ----
  1034. will no longer compile.
  1035. Adding the new empty pointcut designator
  1036. [source, java]
  1037. ----
  1038. pointcut Id();
  1039. ----
  1040. in the declaration of the concrete aspect fixes this problem.
  1041. [source, java]
  1042. ----
  1043. abstract aspect A {
  1044. abstract pointcut pc();
  1045. }
  1046. aspect B {
  1047. pointcut pc();
  1048. }
  1049. ----
  1050. [[recursiveAdvice]]
  1051. === Limiting recursive advice
  1052. Previously, the compiler silently refrained from applying a piece of
  1053. advice to join points within its own advice body. So, for example, in
  1054. [source, java]
  1055. ----
  1056. class C {
  1057. static int i;
  1058. }
  1059. aspect A {
  1060. before(): gets(int C.i) {
  1061. System.err.println("C.i was " + C.i)
  1062. }
  1063. }
  1064. ----
  1065. The advice would trace all references of the static field `C.i` except
  1066. those in the body of the before.
  1067. The compiler has now removed this special case, and so running the above
  1068. example will now cause a `StackOverflowException` to be thrown.
  1069. Most cases of this error can be fixed by correctly specifying the
  1070. desired pointcut: In the above example, the intention is clearly not to
  1071. trace _all_ references of `C.i`, just those outside the aspect.
  1072. [source, java]
  1073. ----
  1074. class C {
  1075. static int i;
  1076. }
  1077. aspect A {
  1078. before(): get(int C.i) && ! within(A) {
  1079. System.err.println("C.i was " + C.i)
  1080. }
  1081. }
  1082. ----
  1083. In a very few cases, you may want the advice to be applicable to other
  1084. code in the aspect, but not in the particular piece of advice. In such
  1085. cases, you can pull the body of the advice into a method and restrict
  1086. away from that method (and away from calls to that method):
  1087. [source, java]
  1088. ----
  1089. class C {
  1090. static int i;
  1091. }
  1092. aspect A {
  1093. public static int getCi() {
  1094. return C.i; // will be traced
  1095. }
  1096. before(): get(int C.i) &&
  1097. ! withincode(void A.traceCi()) &&
  1098. ! call(void A.traceCi())
  1099. {
  1100. traceCi();
  1101. }
  1102. private void traceCi() {
  1103. System.err.println("C.i was " + C.i) // will not be traced
  1104. }
  1105. }
  1106. ----
  1107. '''''
  1108. [[pre08b1]]
  1109. == Porting pre-0.8beta1 code
  1110. * xref:#introSyntax[Rewriting introductions]
  1111. * xref:#staticAdvice[Removing static advice]
  1112. * xref:#aspect-aspect[Fixing aspect-aspect inheritance]
  1113. * xref:#usingPrivateIntroduction[Using private introduction]
  1114. The following changes are only required when porting code written prior
  1115. to the 0.8beta1 release of AspectJ.
  1116. [[introSyntax]]
  1117. === Rewriting introductions
  1118. ==== Syntax
  1119. The syntax of introduction has changed. Porting most programs should
  1120. require some simple editing. Anywhere you have an introduction block
  1121. [source, java]
  1122. ----
  1123. introduction GTN {
  1124. // ...
  1125. }
  1126. ----
  1127. simply move the `GTN` down into the introduction declarations and remove
  1128. the block.
  1129. For method introduction, place the `GTN` in front of the method name,
  1130. For field introduction, place the `GTN` in front of the field name, and
  1131. for constructor introduction, place the `GTN` in front of the `new`
  1132. identifier.
  1133. [source, java]
  1134. ----
  1135. introduction Foo {
  1136. public void doStuff() { this.doStuffLater(); }
  1137. public int calorieCount = 3;
  1138. public new(int x) { super(); calorieCount = x; }
  1139. }
  1140. // ==>
  1141. public void Foo.doStuff() { this.doStuffLater(); }
  1142. public int Foo.calorieCount= 3;
  1143. public Foo.new(int x) { super(); calorieCount = x; }
  1144. ----
  1145. For implements and extends introduction, move the `GTN` in front of the
  1146. new identifiers `implements` or `extends`, and place that in a
  1147. `declare parents` form.
  1148. [source, java]
  1149. ----
  1150. introduction Foo {
  1151. implements Comparable;
  1152. extends Goo;
  1153. }
  1154. // ==>
  1155. declare parents: Foo implements Comparable;
  1156. declare parents: Foo extends Goo;
  1157. ----
  1158. In all cases, if the `GTN` is just a type name, it can be moved down on
  1159. its own. However, if the `GTN` uses any of `&&`, `||`, and `!`, it must
  1160. be parenthesized.
  1161. [source, java]
  1162. ----
  1163. introduction subtypes(Foo) && !Goo {
  1164. int x;
  1165. }
  1166. // ==>
  1167. int (Foo+ && !Goo).x;
  1168. ----
  1169. ==== Access
  1170. If you had an introduction that was referring to private or protected
  1171. members of the target class, this will no longer work. You will either
  1172. need to modify your code to avoid this accessibility issue, or you will
  1173. need to use the `privileged` modifier on the aspect that contains the
  1174. introduction.
  1175. [source, java]
  1176. ----
  1177. class Counter {
  1178. private int count = 2;
  1179. }
  1180. aspect ExposeCountersPrivates {
  1181. introduction Counter {
  1182. public int getCount() { return count; }
  1183. }
  1184. }
  1185. // ==>
  1186. // in 0.8, only privileged aspects can expose a class's privates
  1187. privileged aspect ExposeCountersPrivates {
  1188. public int Counter.getCount() { return count; }
  1189. }
  1190. ----
  1191. If you have introduced private or package-protected members, you will
  1192. probably have to re-write some code. Most previous uses of introducing
  1193. privates can be improved by using private introduction instead.
  1194. [source, java]
  1195. ----
  1196. class C {}
  1197. aspect AddCounter {
  1198. introduction C {
  1199. private int count;
  1200. public int getCount() { return count; }
  1201. }
  1202. }
  1203. // ==>
  1204. aspect AddCounter {
  1205. private int Counter.count;
  1206. public int Counter.getCount() { return count; }
  1207. }
  1208. ----
  1209. There is one case that we know of where the inability to perform the
  1210. introduction of private members makes 0.7 code difficult to port to 0.8.
  1211. If you were using the introduction of a `private void writeObject(..)`
  1212. or a `private void readObject(..)` method to interact with Java's
  1213. serialization API, you will need to come up with an alternative design.
  1214. Using some combination of `Externalizable`, `writeReplace(..)` and/or
  1215. `readResolve(..)` methods should allow you to port your code. If you
  1216. find this isn't the case, we'd like to hear about it.
  1217. If you were introducing either a protected member or a package-private
  1218. member onto a class in order to override a protected member that was
  1219. inherited from a superclass, you will have to make this introduction
  1220. public.
  1221. [[staticAdvice]]
  1222. === Removing static advice
  1223. Static advice has been removed from the language. Now, every piece of
  1224. advice is non-static, meaning that it will run in the context of an
  1225. aspect instance.
  1226. If you have an aspect that only contains static advice, has no "of"
  1227. clause or is declared "of eachJVM()", and is not extended by another
  1228. aspect, simply remove the keyword "static" from all pieces of advice,
  1229. and make sure the aspect is not defined with the "abstract" modifier.
  1230. [source, java]
  1231. ----
  1232. aspect Tracing {
  1233. static before(): executions(* *(..)) {
  1234. System.out.println("Got Here! " + thisJoinPoint);
  1235. }
  1236. }
  1237. // ==>
  1238. aspect Tracing {
  1239. before(): execution(* *(..)) {
  1240. System.out.println("Got Here! " + thisJoinPoint);
  1241. }
  1242. }
  1243. ----
  1244. Otherwise, if you have an aspect contains both static and non-static
  1245. advice, is extended, or is "of eachObject(...)" or "of
  1246. eachcflowroot(...)", you should group your static advice together and
  1247. put it in a new aspect, possibly even an inner aspect.
  1248. [source, java]
  1249. ----
  1250. aspect ComplexTracing of eachobject(cflow(executions(void Main.main(..)))) {
  1251. static before(): executions(* *(..)) {
  1252. System.out.println("Got Here! " + thisJoinPoint);
  1253. }
  1254. static after(): executions(* *(..)) {
  1255. System.out.println("Returned! " + thisJoinPoint);
  1256. }
  1257. // some other dynamic advice, fields, etc
  1258. }
  1259. // ==>
  1260. aspect ComplexTracing of eachobject(cflow(executions(void Main.main(..)))) {
  1261. static aspect AlwaysTracing {
  1262. before(): execution(* *(..)) {
  1263. System.out.println("Got Here! " + thisJoinPoint);
  1264. }
  1265. after(): execution(* *(..)) {
  1266. System.out.println("Returned! " + thisJoinPoint);
  1267. }
  1268. }
  1269. // some other dynamic advice, fields, etc
  1270. }
  1271. ----
  1272. [[aspect-aspect]]
  1273. === Fixing aspect-aspect inheritance
  1274. Aspects can now only extend abstract aspects. This restriction may cause
  1275. some redesign of aspect hierarchies. You will probably find that for the
  1276. majority of your code the most serious change this requires is to add an
  1277. explicit `abstract` modifier to a super-aspect that was already
  1278. implicitly abstract.
  1279. [source, java]
  1280. ----
  1281. aspect BaseTracing {
  1282. abstract pointcut traced();
  1283. before(): traced() {
  1284. System.out.println("Got Here! " + thisJoinPoint);
  1285. }
  1286. }
  1287. // ==>
  1288. // make this abstract aspect explicitly abstract
  1289. abstract aspect BaseTracing {
  1290. // ...
  1291. }
  1292. ----
  1293. This change has also affected the `getAspect` static method. Now,
  1294. `getAspect` is only defined on non-abstract aspects. Previously, you
  1295. could call `getAspect` on an abstract superaspect and (sometimes) get an
  1296. instance of a subaspect back.
  1297. This pattern was used in the Spacewar example in the AspectJ
  1298. distribution. We had the class hierarchy
  1299. [source, text]
  1300. ....
  1301. SpaceObject (abstract)
  1302. |- Ship
  1303. |- Bullet
  1304. |- EnergyPellet
  1305. ....
  1306. And the aspect hierarchy
  1307. [source, text]
  1308. ....
  1309. SpaceObjectDA (abstract)
  1310. |- ShipDA of eachobject(instanceof(Ship))
  1311. |- BulletDA of eachobject(instanceof(Ship))
  1312. |- EnergyPacketDA of eachobject(instanceof(Ship))
  1313. ....
  1314. And we would call `SpaceObjectDA.getAspect(SpaceObject)` to access the
  1315. aspect associated with a ship, bullet, or energy pellet. This pattern
  1316. depended on the `SpaceObjectDA` aspect hierarchy exactly mirroring the
  1317. `SpaceObject` hierarchy, and being maintained that way.
  1318. A better way to implement this kind of design aspect is to use private
  1319. introduction, a new feature of AspectJ.
  1320. [[usingPrivateIntroduction]]
  1321. === Using private introduction
  1322. A common pattern for AspectJ programs that need to associate some state
  1323. with every object of a particular type has been to use aspects that are
  1324. defined `of eachobject(instanceof(...))`. A prime example of this was
  1325. the `BoundPoint` aspect of the bean example: which needed to associate
  1326. each point with a `PropertyChangeSupport` object.
  1327. [source, java]
  1328. ----
  1329. aspect BoundPoint of eachobject(instanceof(Point)) {
  1330. java.beans.PropertyChangeSupport support = null;
  1331. after() returning(Point p): receptions(p.new(..)){
  1332. support = new PropertyChangeSupport(myPoint);
  1333. }
  1334. around(Point p) returns void: receptions(void p.set*(*)) {
  1335. // code that uses support
  1336. }
  1337. }
  1338. ----
  1339. In the new version of AspectJ, a better way of accomplishing many of
  1340. these state association is to use privately introduced fields. Instead
  1341. of creating an aspect instance for every `Point` object, store the
  1342. `PropertyChagneSupport` object in the `Point` objects themselves.
  1343. [source, java]
  1344. ----
  1345. aspect BoundPoint {
  1346. private PropertyChangeSupport Point.support = new PropertyChangeSupport(this);
  1347. void around(Point p): setters(p) {
  1348. // code that uses p.support
  1349. }
  1350. }
  1351. ----
  1352. Just as in the past, the PropertyChangeSupport object is not accessable
  1353. to anyone but the aspect, but now less mechanism is needed.
  1354. There are times when changing aspects that are defined
  1355. `of eachobject(instanceof(...))` may not be reasonable. If the aspect
  1356. instance is stored or passed to other methods, then having a real
  1357. `of eachobject(instanceof(...))`, now written `perthis(this(...))`,
  1358. association may capture the crosscutting concern best.
  1359. '''''
  1360. [[pre07b11]]
  1361. == Porting pre-0.7beta11 code
  1362. * xref:#twoArgumentCalls[Removing two-argument calls]
  1363. * xref:#adviceInClasses[Removing advice from Class declarations]
  1364. The following changes are only required when porting code written prior
  1365. to the 0.7beta11 release of AspectJ.
  1366. [[twoArgumentCalls]]
  1367. === Removing two-argument calls
  1368. In AspectJ 0.7beta11, the two-argument `calls` primitive pointcut
  1369. designator was deprecated. Removing these designators will require
  1370. different cases depending on what the original pointcut did.
  1371. ==== Calls to static methods
  1372. For pointcuts denoting calls to particular static methods, such as
  1373. [source, java]
  1374. ....
  1375. calls(String, static String valueOf(int)) // deprecated
  1376. ....
  1377. the transformation is easy. Simply make the desired signature explicit.
  1378. Instead of catching all calls to any static method that happens to have
  1379. the signature `String valueOf(int)`, catch calls to that exact method
  1380. defined in the String class.
  1381. [source, java]
  1382. ....
  1383. call(static String String.valueOf(int))
  1384. ....
  1385. Pointcuts denoting calls to classes of static methods can also be
  1386. rewritten with these rules. For example,
  1387. [source, java]
  1388. ....
  1389. calls(my.package.*, static * get*(..)) // deprecated
  1390. ....
  1391. should now be written
  1392. [source, java]
  1393. ....
  1394. call(static * my.package.*.get*(..))
  1395. ....
  1396. ==== Calls to non-static methods
  1397. Many pointcuts denoting calls to non-static methods can be fixed the
  1398. same way that those pointcuts denoting calls to static methods are
  1399. fixed. So,
  1400. [source, java]
  1401. ....
  1402. calls(Thread, int getPriority()) // deprecated
  1403. ....
  1404. which denotes all calls to nullary int methods named `getPriority` when
  1405. the called object is an instance of the `Thread` type, can almost always
  1406. be rewritten
  1407. [source, java]
  1408. ....
  1409. call(int Thread.getPriority())
  1410. ....
  1411. which denotes all calls to the nullary int `Thread.getPriority()`
  1412. method.
  1413. Expanding the signature picks out slightly different join points than
  1414. the original two-argument form. This won't matter for most programs, but
  1415. in some cases the differences may be noticable. In particular, the
  1416. expanded-signature form only picks out those calls where the called
  1417. object is statically typed to `Thread` when its `int getPriority()`
  1418. method is called. If you want to capture calls to the
  1419. `int Thread.getPriority()` method, regardless of how the called object
  1420. is statically typed, you shoud use the different translation:
  1421. [source, java]
  1422. ....
  1423. call(int getPriority()) && target(Thread)
  1424. ....
  1425. This will capture all call join points of methods with signature
  1426. `int Thread.getPriority()`.
  1427. It will also denote any join points if the Thread type does not define
  1428. (possibly abstractly) some `int getPriority()` method, though.
  1429. [[adviceInClasses]]
  1430. === Removing advice from Class declarations
  1431. The simplest way to remove an advice declaration from a class is to
  1432. simply define the advice declaration in an inner aspect. So, instead of
  1433. [source, java]
  1434. ....
  1435. class C {
  1436. static before(): executions(C.new()) { /*...*/ } // deprecated
  1437. }
  1438. ....
  1439. write
  1440. [source, java]
  1441. ....
  1442. class C {
  1443. static aspect ConstructionProtocol {
  1444. static before(): executions(C.new()) { /*...*/ }
  1445. }
  1446. }
  1447. ....
  1448. If your advice doesn't refer to any inner classes or interfaces of C,
  1449. you can move the inner aspect out of the class entirely.
  1450. [source, java]
  1451. ....
  1452. class C { /*...*/ }
  1453. aspect ConstructionProtocol {
  1454. static before(): execution(C.new()) { /*...*/ }
  1455. }
  1456. ....
  1457. Your code will be clearer if you consider the purpose of each piece of
  1458. advice when you make this change. It may be that some of the advice
  1459. naturally belongs to another aspect, perhaps already existing. Or it may
  1460. be that some pieces of advice in a class are associated to one concern
  1461. and some to another; in which case more than aspect would be
  1462. appropriate.
  1463. '''''
  1464. [[pre07b10]]
  1465. == Porting pre-0.7beta10 code
  1466. * xref:#joinPoints[Changing access to thisJoinPoint]
  1467. The following changes are only required when porting code written prior
  1468. to the 0.7beta10 release of AspectJ.
  1469. [[joinPoints]]
  1470. === Changing access to thisJoinPoint
  1471. In AspectJ 0.7beta10, access to the reflective object `thisJoinPoint`
  1472. substantially changed. The two parts of this change were the elimination
  1473. of the `runNext()` static method, and the use of an interface hierarchy
  1474. represent the join point object.
  1475. [[proceed]]
  1476. ==== `thisJoinPoint.runNext()` to `proceed()`
  1477. The elimination of the `runNext()` static method requires almost no
  1478. porting work. An automatic replacement of the string
  1479. [source, java]
  1480. ....
  1481. thisJoinPoint.runNext
  1482. ....
  1483. with the string
  1484. [source, java]
  1485. ....
  1486. proceed
  1487. ....
  1488. will do the job. However, if any around advice used the identifier
  1489. `proceed` as a formal parameter or local variable, it must be renamed,
  1490. and if any aspect used it as a field, then references to the field in
  1491. around advice should be made explicit (prefixing the reference with the
  1492. aspect name or `this`, depending on whether the field is static or
  1493. not).
  1494. [[thisJoinPoint]]
  1495. ==== Using `thisJoinPoint`
  1496. While access to reflective information through `thisJoinPoint` is more
  1497. powerful and regular through its interface hierarchy, the previous uses
  1498. must be rewritten. Changing your code will likely require manual
  1499. editing, but in doing so your code should get simpler and cleaner.
  1500. Many existing uses of the fields on join points can be re-written to use
  1501. one of:
  1502. * `thisJoinPoint.toString()`
  1503. * `thisJoinPoint.toShortString()`
  1504. * `thisJoinPoint.toLongString()`
  1505. * `thisJoinPoint.getSignature().toString()`
  1506. * `thisJoinPoint.getSignature().toShortString()`
  1507. * `thisJoinPoint.getSignature().toLongString()`
  1508. For example:
  1509. * `System.out.println(thisJoinPoint.className + "." + thisJoinPoint.methodName)`
  1510. can be replaced with
  1511. * `System.out.println(thisJoinPoint)` or
  1512. * `System.out.println(thisJoinPoint.getSignature().toShortString())`
  1513. with comparable behavior.
  1514. Accesses to the parameters field of join points should be changed as
  1515. follows. A field access like:
  1516. * `thisJoinPoint.parameters`
  1517. must be changed to:
  1518. * `thisJoinPoint.getArgs()`
  1519. Accesses to the methodName and className fields of join points that are
  1520. not suitable for replacement with a toString method, should be changed
  1521. as follows. Field accesses like:
  1522. * `thisJoinPoint.className`
  1523. * `thisJoinPoint.methodName`
  1524. must be changed to:
  1525. * `thisJoinPoint.getSignature().getDeclaringType().getName()`
  1526. * `thisJoinPoint.getSignature().getName()`
  1527. Accessses to the parameterNames and parameterTypes fields of join
  1528. points, that are not suitable for conversion to one of the toString()
  1529. methods should be changed as follows. Field access like:
  1530. * `thisJoinPoint.parameterNames`
  1531. * `thisJoinPoint.parameterTypes`
  1532. must be changed to:
  1533. * `((CodeSignature)thisJoinPoint.getSignature()).getParameterNames()`
  1534. * `((CodeSignature)thisJoinPoint.getSignature()).getParameterTypes()`