1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963 |
- = AspectJ Porting Notes
-
- _© Copyright 1998-2002 Palo Alto Research Center Incorporated,
- 2003-2004 Contributors. All rights reserved._
-
- * xref:#pre-1_2[Pre-1.2 code]
- * xref:#pre-1_1[Pre-1.1 code]
- * xref:#pre-1_0_4[Pre-1.0.4 code]
- * xref:#pre-1_0rc1[Pre-1.0rc1 code]
- * xref:#pre-1_0beta1[Pre-1.0beta1 code]
- * xref:#pre-1_0alpha1[Pre-1.0alpha1 code]
- * xref:#pre08b3[Pre-0.8beta3 code]
- * xref:#pre08b1[Pre-0.8beta1 code]
- * xref:#pre07b11[Pre-0.7beta11 code]
- * xref:#pre07b10[Pre-0.7beta10 code]
-
- [[pre-1_2]]
- == Porting pre-1.2 code to AspectJ 1.2
-
- README-1.2.html contains a discussion of the changes between 1.1 and 1.2.
- The key points are:
-
- *The default AspectJ compiler compliance level is now 1.4* (whereas in
- previous releases the default compliance level was 1.3). This has a
- number of implications:
-
- * class files generated by the compiler are now JRE v1.2 and upwards
- compatible. (At compliance level 1.3, AspectJ generated class files that
- were compatible with JRE 1.1 also).
- * `call` pointcuts may match more join points than in the same program
- compiled at compliance level 1.3.
-
- The AspectJ compiler can be restored to 1.3 compliance settings by
- specifying the "-1.3" option on the command-line.
-
- The following example program illustrates the differences in join point
- matching with the `call` pointcut designator between 1.4 and 1.3
- compliance levels.
-
- [source, java]
- ....
- /*01*/ class A {
- /*02*/ public void doIt() {...};
- /*03*/ }
- /*04*/
- /*05*/ class B extends A {
- /*06*/ public void doThisToo() {...};
- /*07*/ }
- /*08*/
- /*09*/
- /*10*/ public class CallsAandB {
- /*11*/
- /*12*/ public static void main(String[] args) {
- /*13*/ B b = new B();
- /*14*/ A bInDisguise = new B();
- /*15*/
- /*16*/ b.doIt(); // AspectJ 1.2 matches here
- /*17*/ bInDisguise.doIt(); // this is never matched
- /*18*/ }
- /*19*/
- /*20*/ }
- /*21*/
- /*22*/ aspect CallPCDMatchingExample {
- /*23*/
- /*24*/ before() : call(* B.doIt(..)) {
- /*25*/ System.out.println("About to call B.doIt(...)");
- /*26*/ }
- /*27*/
- /*28*/ }
- ....
-
- When this program is compiled with AspectJ 1.2 using the default
- compiler options, it will produce one line of output when it is
- executed:
-
- `About to call B.doIt(...)`
-
- The same program compiled under AspectJ 1.1 (or using AspectJ 1.2 with
- the -1.3 flag specified) does not produce any output when it is run.
-
- The reason for the additional call pcd match is that prior to compliance
- level 1.4, Java compilers produced bytecodes that call A.doIt() (the
- defining type of the method), rather than B.doIt() (the declared type in
- the program text). The generated call to A.doIt() is not matched by the
- call pcd used in the before advice. At compliance level 1.4, the
- bytecodes retain the declared type of the receiver in the program
- source, generating a call to B.doIt(), which _is_ matched by the call
- pcd.
-
- This is a good example of why the recommended style is to use
- `call(* doIt(..)) && target(B)`, which always matches based on the
- actual type of the receiver.
-
- *New warnings emitted by the compiler for unmatched call pcds.* Because
- users have found the static type matching used for a type pattern
- specified in a `call` pcd confusing (as evidenced by the example above),
- AspectJ 1.2 has a new Xlint warning which is enable by default. The
- compiler will now produce a warning whenever a call pointcut designator
- does not match at a join point, and a user may have expected it to.
- Compiling the above program using AspectJ 1.2 produces the following
- compiler output:
-
- [source, text]
- ....
- CallsAandB.java:24 warning does not match because declaring type is A, if match desired use target(B) [Xlint:unmatchedSuperTypeInCall]
- before() : call(* B.doIt(..)) {
- ^^^^^^^^^^^^^^^
-
- see also: CallsAandB.java:17
-
-
- 1 warning
- ....
-
- The warning is telling us that the call pointcut associated with the
- before advice on line 24 of the source file does not match at a join
- point where the user may have expected it to. The source location
- corresponding to the unmatched join point is indicated by the "see also"
- line - in this case line 17 of the source file. At line 17 we find a
- call to `bInDisguise.doIt()`. Since the static type of `bInDisguise` is
- `A`, this call will never be matched. The warning also tells us a
- possible solution if we intended the pointcut to match at this join
- point: use `call(* doIt(..) && target(B)`.
-
- If you find warnings of this kind coming out when you use the AspectJ
- 1.2 compiler, the recommended fix is to switch to using the `target`
- designator in place of a type pattern in the `call` pointcut expression.
- Note that there is no loss of runtime efficiency here - runtime tests
- are only added in the cases where it cannot be determined at compile
- time whether the type of the receiver will match the type specified in
- the `target` expression. Note that `target` cannot be used in `declare`
- statements.
-
- *Use of non-statically determinable pointcut expressions in declare
- statements* has always been forbidden, but prior to 1.2 the AspectJ
- compiler did not raise an error if they were used. The AspectJ Language
- Semantics appendix states that `cflow, cflowbelow, this, target, args`
- and `if` pointcut designators cannot be used directly or indirectly
- (through a user-defined pointcut) inside of a `declare` statment. When
- moving code from 1.1 to 1.2, additional errors may be raised due to the
- stricter policing of this rule. The solution is to recode the declare
- statement avoiding pointcut expressions that may require a run-time
- test.
-
- *Interface constructors no longer supported*. Declaring a constructor on
- an interface is now (correctly) prohibited, and there will no longer be
- a constructor-execution join point for the interface. To initialize a
- field declared on an interface, use initialization, e.g.,
-
- [source, java]
- ....
- int I.i;
- after(I i) returning: initialization(I) && this(i) { i.i = 2; }
- ....
-
- To pick out the constructor-execution for any implementation of I, try
-
- [source, java]
- ....
- execution(I+.new(..))
- ....
-
- For more information, see bug
- https://bugs.eclipse.org/bugs/show_bug.cgi?id=49295[49295].
-
- *Declaring a static method on an interface* is now (correctly)
- prohibited. One workaround is to define a static method on the aspect
- instead. For more information, see bug
- https://bugs.eclipse.org/bugs/show_bug.cgi?id=47754[47754].
-
- *Watch for problems due to incompatible BCEL versions.* AspectJ 1.2
- includes a different version of BCEL than AspectJ 1.1. If you have the
- older version of BCEL available earlier on your classpath than the
- version included in the 1.2 aspectjtools.jar then you will see errors
- like:
-
- [source, text]
- ....
- C:\work\test\TestAspect.aj error Internal compiler error
- java.lang.NoSuchMethodError: org.apache.bcel.generic.InstructionFactory.
- createNewArray(Lorg/apache/bcel/generic/Type;S)Lorg/apache/bcel/generic/Instruction;
- ....
-
- This typically happens because the old version of BCEL has been included
- as a standard extension in your JVM configuration. Ensure you have
- removed it from jre/lib/ext under your JDK installation.
-
- For more information, see bugs including
- https://bugs.eclipse.org/bugs/show_bug.cgi?id=60389[60389],
- https://bugs.eclipse.org/bugs/show_bug.cgi?id=59921[59921].
-
- [[pre-1_1]]
- == Porting pre-1.1 code to AspectJ 1.1
-
- README-1.1.html contains a discussion of the language changes from 1.0 to
- 1.1. The high points:
-
- The `call(..)` pointcut designator is now implemented only at the call
- site; by contrast, the AspectJ 1.0 compiler could also implement it on
- the callee side. So in 1.0 if you compiled a pointcut using `call(..)`
- but only passed the compiler the code for the target of the call, the
- pointcut could be implemented. This is not true for 1.1. To fix this,
- use `execution(..)` in place of `call(..)`, or include all calling
- clients in the compile. (xref:README-1.1.adoc#NO_CALLEE_SIDE_CALL[more
- info])
-
- Type-patterns are no longer permitted for the defining type of
- inter-type declarations. Replace the pattern with a type. In many cases,
- you can declare members on an interface type, and then declare that the
- types picked out by the type-pattern implement have the interface as
- their parent. (xref:README-1.1.adoc#SINGLE_INTERCLASS_TARGET[more info])
-
- Type-patterns are no longer permitted when specifying `declare soft`.
- Replace the pattern with a literal type.
-
- Wildcards patterns (`foo..*`) are no longer permitted for `this()`,
- `target()`, or `args()`. Replace the pattern with a literal type or with
- a subtype wildcard (`Type+`).
- (xref:README-1.1.adoc#INSTANCEOF_ON_WILD[more info])
-
- Conflicts will be reported for no-argument constructors generated by
- compilers when no constructor is defined for a class. That means the
- following code will compile in 1.0 but not in 1.1:
-
- [source, java]
- ....
- class C {}
- aspect A {
- C.new() {} // permitted in 1.0; conflict in 1.1
- }
- ....
-
- One fix is to declare a non-conflicting constructor by adding arguments
- (or defining a constructor in the target class); a better fix might be
- to do the work of the declared constructor in advice on the
- initialization join point for the object.
- (xref:README-1.1.adoc#DEFAULT_CONSTRUCTOR_CONFLICT[more info])
-
- The pointcut designators `within()` and `withincode()` will not pick out
- code within the lexical extent of method-local and anonymous inner types
- (because these are not represented as such in bytecode form). Because
- `within` forms specify staticly-determinable pointcuts, they might be
- used in declare error or declare warning statements, which might produce
- different results. (xref:README-1.1.adoc#WITHIN_MEMBER_TYPES[more info])
-
- The compiler will report an error that the form
- `aspect \{name} dominates \{list}...` is no longer supported. It has been
- replaced by a new declare statement:
-
- [source, java]
- ....
- declare precedence : {name} {list}...
- ....
-
- (xref:README-1.1.adoc#ASPECT_PRECEDENCE[more info])
-
- The field set join point now has a return type of `void`. Compiling
- programs using around advice on these join points might cause errors
- unless the return type of the around advice and the result of any
- proceed() call is `Object` or `void`.
- (xref:README-1.1.adoc#VOID_FIELD_SET[more info])
-
- The compiler cannot implement after or around advice for the handler PCD
- because the end of exception handlers is ambiguous in bytecode. Try to
- use before advice. (xref:README-1.1.adoc#AFTER_HANDLER[more info])
-
- [[pre-1_0_4]]
- == Porting pre-1.0.4 code
-
- In versions of AspectJ prior to 1.0.4, the compiler was not correctly
- implementing the AspectJ-1.0 language design for some uses of after
- returning advice.
-
- The main change that was made was of after returning advice for
- constructor execution join points. Previously, this advice was legal:
-
- [source, java]
- ....
- after() returning (Foo f): execution(Foo.new(..)) { ... }
- ....
-
- However, it has always been a part of the 1.0 language design (and of
- Java's language design) that constructors themselves (as opposed to
- constructor calls) do not return the value of the new object. Rather,
- `this` is bound to the new object, and the constructor behaves like a
- void method. With that in mind, any code like the above should be
- conveted to the form.
-
- [source, java]
- ....
- after(Foo f) returning: this(f) && execution(Foo.new(..)) { ... }
- ....
-
- In compilers prior to 1.0.4, the following advice could pick out join
- points
-
- [source, java]
- ....
- after() returning (String s): call(void foo()) { ... }
- ....
-
- This is no longer picked out. This pattern was most commonly used in
- highly polymorphic contexts, such as
-
- [source, java]
- ....
- after() returning (String s): call(* foo()) { ... }
- ....
-
- If you want to capture all calls, binding null objects for those that
- would otherwise have no value, you must use the `Object` type.
-
- [source, java]
- ....
- after() returning (Object o): call(* foo()) { ... }
- ....
-
- Uses of both of these forms are highleted with compiler warnings in the
- 1.0.4 compiler.
-
- '''''
-
- [[pre-1_0rc1]]
- == Porting pre-1.0rc1 code
-
- Aspects can no longer be declared to implement the `Serializable` or
- `Cloneable` interfaces. If you previously used serializable or cloneable
- aspects, you should refactor your code to keep the state you need to
- serialize or clone in objects associated with the aspects.
-
- '''''
-
- [[pre-1_0beta1]]
- == Porting pre-1.0beta1 code
-
- The `static` modifier is no longer allowed on pointcut declarations
- anywhere. Porting is simple; just remove the static declarations when
- you find them.
-
- Also, though the `returns` modifier on pointcuts has not been part of
- the language since 1.0alpha1, the compiler still accepted them until
- now. If you used this feature, now is the right time to remove the
- `returns` modifier when the compiler complains about it.
-
- '''''
-
- [[pre-1_0alpha1]]
- == Porting pre-1.0alpha1 code
-
- The release of AspectJ 1.0alpha1 involved sweeping cleanups of the
- language to bring it to 1.0 status.
-
- * xref:#_1_0a1-pointcuts[Pointcuts]
- * xref:#_1_0a1-type-patterns[Type patterns]
- * xref:#_1_0a1-advice[Advice]
- * xref:#_1_0a1-introduction-and-static[Introduction and static
- crosscutting]
- * xref:#_1_0a1-aspects[Aspects]
-
- [[_1_0a1-pointcuts]]
- === Pointcuts
-
- [[_1_0a1-plural-to-singular]]
- ==== Removing the "s" from pointcuts
-
- One of the most pervasive changes in porting code written before
- 1.0alpha1 is the change in some of the pointcut names from plural to
- singular, that is, they lose an "s". In one sense, making this change in
- your programs is easy: Just go through and whever you see uses of the
- pointcuts `calls, executions, gets, sets, handlers, initializations,
- staticinitializations`.
-
- Just take off the final "s", to make one of `call, execution, get, set, handler, initialization, staticinitialization`.
-
- Often, there will be other changes you should make for each of these
- pointcuts, but as for the name, just take off the "s".
-
- One risk you will have when doing this is creating name conflicts. If,
- for example, you named a parameter of a pointcut "set", you should (for
- your own sanity -- the compiler doesn't require it) rename it in the
- rewritten pointcut.
-
- [source, java]
- ....
- pointcut sort(Collection set): calls(void addAll(set));
- // ==>
- pointcut sort(Collection mySet): call(void addAll(mySet));
- ....
-
- While converting to use singular nouns for the primitive pointcuts, you
- may also want to remove the "s" from your user-defined pointcuts.
-
- [source, java]
- ....
- pointcut publicCalls(): calls(public * *(..));
- // ==>
- pointcut publicCall(): call(public * *(..));
- ....
-
- Of course, your naming conventions are your own, but throughout these
- porting notes we will be making these changes in our example ports.
-
- [[_1_0a1-remove-receptions]]
- ==== Removing the receptions pointcut
-
- Perhaps the largest semantic change in the 1.0 language is the removal
- of receptions join points. They have been merged with call join points
- in AspectJ 1.0, so now a call join point doesn't represent the
- "caller-side" of a call, but the call itself, both caller and receiver.
-
- Changing code that used the `receptions` pointcut should be fairly
- straightforward, depending on whether the pointcut exposed state or not.
-
- ===== Not exposing state
-
- Receptions pointcuts that did not expose state can simply be replaced by
- the new `call` and `target` pointcuts:
-
- [source, java]
- ....
- receptions(void Foo.m())
- // ==>
- target(Foo) && call(void m())
- ....
-
- ===== Exposing state
-
- Some receptions pointcuts exposed the receiving object by replacing the
- receiving type with a pointcut formal. These PCDs should be rewritten to
- use the new `target` pointcut to expose the receiving object.
-
- [source, java]
- ....
- pointcut fooCallees(Foo f): receptions(void f.m());
- // ==>
- pointcut fooCallee(Foo f): target(f) && call(void m());
- ....
-
- Like xref:#_1_0a1-fixing-state-access[other pointcuts], receptions
- pointcuts that exposed one or more arguments should be rewritten to use
- the `args` pointcut:
-
- [source, java]
- ....
- pointcut intPassers(int i, int j): receptions(void Foo.m(i, j));
- // ==>
- pointcut intPasser(int i, int j):
- args(i, j) && target(Foo) && call(void m(int, int));
- ....
-
- ===== Constructor receptions
-
- There are two issues with constructor receptions in particular.
-
- Like xref:#_1_0a1-constructor-calls[constructor calls], constructor
- receptions pointcuts had a dynamic character, in that
- `receptions(C.new())` would capture constructions of not only C classes,
- but also of classes that extended C.
-
- If you want this behaviour, then you need to use the new subtypes
- operator, +, on the type name in question. So,
-
- [source, java]
- ....
- receptions(C.new())
- // ==>
- call(C+.new())
- ....
-
- Also like xref:#_1_0a1-constructor-calls[constructor calls], constructor
- receptions allowed access to the constructed object in the same way as
- any other object. Since the only advice possible on constructor
- receptions join points was `after returning` advice, the object was
- always guaranteed to be there. But since constructor call join points
- allow all kinds of advice it may be that the object isn't constructed
- yet (say, in before or around advice). This is a benefit, in that it
- allows caching constructed objects
-
- [source, java]
- ....
- aspect Singleton {
- private C theC = null;
-
- C around(): call(C.new(..)) {
- if (c == null) theC = proceed();
- return theC;
- }
- }
- ....
-
- but it does require some rewriting. The new object can be accessed as
- the return value in after returning advice. So,
-
- [source, java]
- ....
- after(Point p) returning (): receptions(p.new(int, int)) { ... }
- // ==>
- after() returning (Point p): call(Point+.new(int, int)) { ... }
- ....
-
- [[_1_0a1-fixing-state-access]]
- ==== Fixing state access
-
- In previous versions of AspectJ, state such as the currently executing
- object or a particular argument of a method call could be accessed from
- the signatures of many pointcuts, leading to difficult-to-read forms. In
- AspectJ 1.0, all state accesses now use only three pointcuts `args, this, target`
- which pick out argument values, the currently executing object, and the
- target object of a method call or field operation, respectively.
-
- ===== Using args
-
- Any time you have a pointcut that has a signature where one of the
- arguments was a pointcut or advice formal, just replace that formal with
- its type and add an `args` pointcut.
-
- [source, java]
- ....
- pointcut intPassers(int i, int j): calls(void Foo.m(i, j));
- // ==>
- pointcut intPasser(int i, int j): args(i, j) && call(void Foo.m(int, int));
- ....
-
- [source, java]
- ....
- pointcut stringPassers(String s): receptions(void Foo.m(s, ..));
- // ==>
- pointcut stringPasser(String s): args(s, ..) && call(void Foo.m(String, ..));
- ....
-
- ===== Rewriting calls
-
- If a calls pointcut exposed the the receiving object, such as
-
- [source, java]
- ....
- pointcut fooCallees(Foo f): calls(void f.m());
- ....
-
- then the new version should use the `target` pointcut to get at that
- object
-
- [source, java]
- ....
- pointcut fooCallee(Foo f): target(f) && call(void Foo.m());
- ....
-
- AspectJ's calls pointcut previously allowed the new object to be
- exposed, even though it may not have been constructed yet. AspectJ 1.0
- no longer allows this; you can access the new instance only in after
- returning advice, when it is guaranteed that the object was successfully
- constructed. So instead of using the `target` pointcut to expose the
- value, you should use the normal `after returning` mechanism:
-
- [source, java]
- ....
- after(Point p) returning (): calls(p.new(int, int)) { ... }
- // ==>
- after() returning (Point p): call(Point+.new(int, int)) { ... }
- ....
-
- ===== Rewriting gets and sets
-
- Exposing the target object of a `gets` or `sets` pointcut should be done
- the same way it was for `calls` pointcuts, with the new `target`
- pointcut.
-
- [source, java]
- ....
- before(Frame f): gets(Color f.color) { ... }
- // ==>
- before(Frame f): target(f) && get(Color Frame.color) { ... }
- ....
-
- [source, java]
- ....
- before(Frame f): sets(Color f.color) { ... }
- // ==>
- before(Frame f): target(f) && set(Color Frame.color) { ... }
- ....
-
- In addition, the clumsy syntax for getting the old value of the field
- has been eliminated. For before advice, the port is simple; just access
- the field yourself in the body. Depending on the rest of your system,
- you may need to restrict the advice from the aspect body to eliminiate
- the circularity.
-
- [source, java]
- ....
- aspect A {
- before(Frame f, Color c): gets(Color f.color)[c] { ... }
- }
-
- // ==>
-
- aspect A {
- before(Frame f):
- target(f) && get(Color Frame.color) && !within(A)
- {
- Color c = f.color;
- // ...
- }
- }
- ....
-
- The same can be done for `around` advice. However, the only way to port
- after advice that needs the old value is to convert it to around advice.
-
- [source, java]
- ....
- aspect A {
- after(Frame f, Color c) returning (): gets(Color f.color)[c] { ... }
- }
-
- // ==>
-
- aspect A {
- void around(Frame f):
- target(f) && get(Color Frame.color) && !within(A)
- {
- Color c = f.color;
- proceed(f);
- // ...
- }
- }
- ....
-
- When porting `sets` pointcuts, the new value of a field is still
- available, but not the way it was previously. Instead of using the
- square bracket syntax, we use an `args` pointcut. All set join points
- are assumed to have exactly one argument, which holds the new value. So,
-
- [source, java]
- ....
- after(Color newColor): sets(Color Frame.color)[][newColor] { ... }
- // ==>
- after(Color newColor): args(newColor) && set(Color Frame.color) { ... }
- ....
-
- Also, if the field was declared private, in order to get at its old
- value the aspect must be declared `privileged`.
-
- ===== Rewriting handlers
-
- The value of the exception at an exception handler join point is now
- accessed through the `args` pointcut; all exception handler join points
- are treated as having exactly one argument, the exception value. So,
-
- [source, java]
- ....
- before(NotFoundException e): handlers(e) { ... }
- // ==>
- before(NotFoundException e): args(e) && handler(NotFoundException) { ... }
- ....
-
- ===== Rewriting within
-
- The `within` pointcut was not typically used to export context. Though
- it was accidentally possible to do so in versions of AspectJ before 1.0,
- it often didn't do what users expected it to. This loophole has now been
- closed, and within can only take type patterns, not pointcut or advice
- formals. A use of the `this` pointcut will capture what previous
- implementations did:
-
- [source, java]
- ....
- pointcut usesFoo(Foo f): within(f);
- // ==>
- pointcut usesFoo(Foo f): this(f) && within(Foo);
- ....
-
- [[_1_0a1-no-subs-in-sigs]]
- ==== Understanding signatures
-
- Now that we have `this`, `target`, and `args` pointcuts, all of our
- signatures are composed of just types, names, and wildcards; there are
- no more parameters.
-
- Also, now that we have the `+` wildcard to pick out
- xref:#_1_0a1-subtypes-to-plus[subtypes], we can make signature matching
- much more uniform.
-
- Previously, some signatures matched based on subtypes, some based on
- instanceof, and some exactly. Now, we have made all signatures match
- exactly.
-
- What does this mean for your program? Well, it means that you may have
- to add `+` to some of your signatures, depending on what you meant them
- to match.
-
- For example, the pointcut
-
- [source, java]
- ....
- calls(void m(Object))
- ....
-
- previously picked out all method calls to a method named m that took one
- argument, which was a subtype of Object. Now, however, it will only pick
- out method calls to methods that are defined to take exactly the type
- Object, which may be a lot fewer join points. If you want the old
- behaviour, simply convert to
-
- [source, java]
- ....
- call(void m(Object+))
- ....
-
- [[_1_0a1-fixing-instanceof]]
- ==== Removing the instanceof pointcut
-
- The intanceof pointcut has been split into two different pointcuts,
- `this` and `target`.
-
- Typically, the instanceof pointcut would only exist in a compound
- pointcut, composed (with `&&`) with another pointcut. If the other
- pointcut was a `receptions` pointcut, then `instanceof` should be
- converted to `target` (and `receptions` converted to `call`). So,
-
- [source, java]
- ....
- pointcut stateChanges(Subject s):
- instanceof(s) && receptions(void Button.click());
-
- // ==>
-
- pointcut stateChange(Subject s):
- target(s) && call(void Button.click());
- ....
-
- In all other cases, `instanceof` referred to the currently executing
- object, and so should be converted into `this`
-
- [source, java]
- ....
- before(Point p): instanceof(p) && executions(* makePolar(..)) { ... }
- // ==>
- before(Point p): this(p) && execution(* makePolar(..)) { ... }
- ....
-
- [source, java]
- ....
- pointcut setup(Client c): instanceof(c) && calls(Remote Naming.lookup(String));
- // ==>
- pointcut setup(Client c): this(c) && calls(Remote Naming.lookup(String));
- ....
-
- [[_1_0a1-initializations]]
- ==== Rewriting the initializations pointcut
-
- Object initialization join points are now more complicated, and more
- true to Java's execution model. Now they bracket all of the
- initialization that a class can do, after the return of its super
- constructor call (before which no initialization can happen). Previous
- versions of AspectJ had object initialization join points that only
- included initialization that was made in dynamic initializers and
- fields.
-
- The old behaviour can be recovered with a simple rewrite.
-
- [source, java]
- ....
- initializations(A)
- // ==>
- initialization(A.new(..)) && !execution(A.new(..))
- ....
-
- [[_1_0a1-constructor-calls]]
- ==== Understanding constructor calls
-
- Previously, constructor call join points were matched by subtypes, so
- `calls(Foo.new())` would match both calls to create new `Foo` objects,
- and new `SubFoo` objects. The new `call` pointcut designator matches
- types exactly, so if you want the old behaviour, you should write
- `call(Foo+.new())`.
-
- Similarly, constructor execution join points were matched by subtypes.
- So the old `executions(Foo.new())` is now represented by
- `execution(Foo+.new())`.
-
- In both of these cases, think before using the + operator; it may be
- that you didn't intend subtype matching in the first place.
-
- [[_1_0a1-hasaspect]]
- ==== Removing the hasaspect pointcut
-
- The `hasaspect` pointcut is no longer defined, but you can get the same
- behaviour using the new `if` pointcut.
-
- If the aspect whose presense you are checking for was defined
- `of eachcflow`, `of eachcflowbelow`, or, more unlikely, `of eachJVM()`,
- then the conversion is simple:
-
- [source, java]
- ....
- hasaspect(A)
- // ==>
- if(A.hasAspect())
- ....
-
- If the aspect was defined `of eachobject`, then you will have to expose
- the current object in your pointcut or advice parameters:
-
- [source, java]
- ....
- pointcut cut(): hasaspect(A) ... ;
- // ==>
- pointcut cut(Object o): this(o) && if(A.hasAspect(o)) ... ;
- // or
- pointcut cut(Object o): target(o) && if(A.hasAspect(o)) ... ;
- ....
-
- If you were using the `hasaspect` pointcut to expose the state of the
- aspect, then you can get the same state by using `A.aspectOf()` in the
- body of the advice. For example, if the aspect A were defined
- `of eachcflow`, then
-
- [source, java]
- ....
- before(A myA): hasaspect(myA) {
- myA.checkStatus();
- }
- // ==>
- before(): if(A.hasAspect()) {
- A myA = A.aspectOf();
- myA.checkStatus();
- }
- ....
-
- [[_1_0a1-withinall]]
- ==== Removing the withinall pointcut
-
- The withinall poinctut is no longer defined. You can use a combination
- of within and the xref:#_1_0a1-subtypes-to-plus[new subtypes operator],
- `+`, instead. You'll save two characters and be using a simpler and more
- orthogonal language.
-
- [source, java]
- ....
- withinall(Foo)
- // ==>
- within(Foo+)
- ....
-
- [[_1_0a1-user-defined-returns]]
- ==== Removing returns modifier from pointcuts
-
- The returns keyword is no longer necessary for user-defined pointcuts.
- Simply remove it when you find it.
-
- [source, java]
- ....
- pointcut publicIntCalls() returns int: calls(public int *(..));
- // ==>
- pointcut publicIntCall(): call(public int *(..));
- ....
-
- [[_1_0a1-static-pointcuts]]
- ==== Making some pointcuts static
-
- In Java, only static members may be accessed by their declaring type
- name, like the static method `Math.max()` can be accessed.
-
- Pointcuts now have that property too. Pointcuts may be declared to be
- static, in which case they can be accessed like `MyAspect.move()`, or
- they can be left non-static, in which case they can be overridden by a
- subaspect.
-
- In addition, while pointcuts can still be defined in classes, only
- `static` pointcuts can be defined in classes.
-
- Porting should be straightforward; just make all your pointcuts in
- classes `static`, and make any pointcut with a qualified reference
- static.
-
- [[_1_0a1-type-patterns]]
- === Type patterns
-
- [[_1_0a1-new-wildcards]]
- ==== Understanding * and .. in type patterns
-
- Previous versions of AspectJ treated * and .. too cleverly in type
- patterns, placing restrictions based on what is a package and what is a
- type, and basing their meanings on the definition of a package
- hierarchy.
-
- In AspectJ 1.0, both of these wildcards are defined simply, and
- textually:
-
- * The * wildcard alone matches all types.
- * The * wildcard in a pattern matches zero or more characters, but will
- not match "."
- * The .. wildcard matches any sequence of characters that begins and
- ends with "."
-
- That's it.
-
- This change won't affect most programs, but it will make understanding
- programs easier. There is one ugly idiom, however, that this change
- disposes of. If your program includes the type pattern `*..*`, which
- used to match all types, you can replace it with the much simpler *.
-
- [source, java]
- ....
- pointcut unaryVoidMethods(): call(void *(*..*));
- // ==>
- pointcut unaryVoidMethod(): call(void *(*));
- ....
-
- [[_1_0a1-subtypes-to-plus]]
- ==== Fixing subtypes in introduction
-
- The new + operator is used to normalize the many places you want to use
- subtypes of some types.
-
- In introduction forms, you will need to replace `subtypes(TypePattern)`
- type patterns with the new subtype operator, +. In the case where you
- wrote `subtypes(Foo)`, i.e., the subtypes of a single type, simply
- replace this with `Foo+`. Otherwise, use the + operator as appropriate
- in `TypePattern`.
-
- [source, java]
- ....
- public void (subtypes(Target0 || Target1)).accept(Visitor v) {
- v.visit(this);
- }
- // ==>
- public void (Target0+ || Target1+).accept(Visitor v) {
- v.visit(this);
- }
- ....
-
- [[_1_0a1-advice]]
- === Advice
-
- [[_1_0a1-around-returns]]
- ==== Moving the return type of around
-
- The returns keyword is no longer used for around advice. Instead, the
- return type is declared as it is for methods. So,
-
- [source, java]
- ....
- around(Point p) returns void: setters(p) { ... }
- // ==>
- void around(Point p): setter(p) { ... }
- ....
-
- [[_1_0a1-around-throws]]
- ==== Adding a throws clause to around
-
- Around advice must now declare the checked exceptions it throws with a
- `throws` clause, much like a method.
-
- [source, java]
- ....
- char around(char c) throws java.io.CharConversionException: converter(c) {
- char result;
- try { result = proceed(); }
- catch (Exception e) {
- throw new java.io.CharConversionException();
- }
- if (result == 0) throw new java.io.CharConversionException();
- return result;
- }
- ....
-
- [[_1_0a1-advice-precedence]]
- ==== Understanding advice precedence
-
- In previous versions of AspectJ, advice precedence within an aspect was
- simple: if a piece of advice appeared before another piece, it was more
- precedent. This made perfect sense for `before` and `around` advice, but
- was the cause of confusion (even among the AspectJ designers, more than
- once) for `after` advice, as it seemed backward.
-
- In addition, advice was ordered by kind, in that around advice always
- surrounded before and after advice.
-
- AspectJ 1.0 has changed this; precedence for `after` advice is inverted,
- and advice is no longer ordered by kind.
-
- This won't matter to you unless you write pieces of advice in the same
- aspect that apply to the same join point.
-
- If you do, here's what to think about: If you're looking at two pieces
- of advice and want to know which has precedence, if either is `after`
- advice, then the second one has precedence. Otherwise, the first does.
-
- This allows interesting advice interaction. In the following advice, for
- example, the `after throwing` advice will catch the exception thrown by
- the `before` advice
-
- [source, java]
- ....
- aspect A {
- before(): call(void main(..)) {
- throw new RuntimeException();
- }
- after() throwing(RuntimeException e): call(void main(..)) {
- System.err.println("caught you!");
- }
- }
- ....
-
- But reversing the order will give the `before` advice more precedence,
- making its exception uncatchable by the `after throwing` advice
-
- [source, java]
- ....
- aspect A {
- after() throwing(RuntimeException e): call(void main(..)) {
- System.err.println("missed you!");
- }
- before(): call(void main(..)) {
- throw new RuntimeException();
- }
- }
- ....
-
- Advice in _different_ aspects is ordered by the normal aspect precedence
- rules of subtyping and the `dominates` modifier.
-
- [[_1_0a1-after-returning]]
- ==== Fixing after returning
-
- If you use after returning advice and do not need to expose the return
- value, you no longer need to write an empty set of parentheses to
- indicate that fact. So,
-
- [source, java]
- ....
- after(Formals) returning (): Pointcut { ... }
- // ==>
- after(Formals) returning: Pointcut { ... }
- ....
-
- The same syntax is now available for after throwing advice, in case you
- do not care what `Throwable` is thrown.
-
- [source, java]
- ....
- after(Formals) throwing: Pointcut { ... }
- ....
-
- [[_1_0a1-this-static-join-point]]
- ==== Renaming thisStaticJoinPoint
-
- `thisStaticJoinPoint` has been renamed `thisJoinPointStaticPart`, to
- reflect that it is now exactly the static part of `thisJoinPoint`: It
- will return the same object as `thisJoinPoint.getStaticPart()`.
-
- [[_1_0a1-this-join-point]]
- ==== Converting access to thisJoinPoint
-
- The `JoinPoint` object hierarchy has been folded into a single class,
- `org.aspectj.lang.JoinPoint`. A common pattern in logging, for example,
- was
-
- [source, java]
- ....
- before() executions(* myMethod()) {
- ExecutionJoinPoint jp = (ExecutionJoinPoint)thisJoinPoint;
- CodeSignature jp = (CodeSignature)jp.getSignature();
- System.err.println(jp.getParameters());
- System.err.println(jp.getParameterNames());
- }
- ....
-
- While there is still a rich hierarchy for signatures, there is only one
- `JoinPoint` type, so this can be rewritten as:
-
- [source, java]
- ....
- before() executions(* myMethod()) {
- JoinPoint jp = thisJoinPoint;
- CodeSignature jp = (CodeSignature)jp.getSignature();
- System.err.println(jp.getArgs());
- System.err.println(jp.getParameterNames());
- }
- ....
-
- Some of the method names of `JoinPoint` have been reorganized, as well.
-
- [[_1_0a1-introduction-and-static]]
- === Introduction and static crosscutting
-
- [[_1_0a1-plus-implements-extends]]
- ==== Removing +implements and +extends
-
- The keywords `+implements` and `+extends` no longer exist. Instead,
- AspectJ uses the `declare` form for exactly the same functionality.
-
- [source, java]
- ....
- Point +implements Serializable;
- // ==>
- declare parents: Point implements Serializable;
- ....
-
- [source, java]
- ....
- MyButton +extends ButtonAdaptor;
- // ==>
- declare parents: MyButton extends ButtonAdaptor;
- ....
-
- [[_1_0a1-now-use-soft]]
- ==== Using declare soft
-
- Around advice advice no longer effects the static exception checking of
- Java. This means that the following code previously compiled:
-
- [source, java]
- ....
- class C {
- void noExceptionDeclared() {
- exceptionDeclared();
- }
- void exceptionDeclared() throws IOException {}
- }
-
- aspect A {
- around(): call(void C.exceptionDeclared()) {
- try { proceed(); }
- catch (IOException e) {}
- }
- }
- ....
-
- even though the class `C` is not compilable on its own (because
- `noExceptionDeclared` actually throws an `Exception`).
-
- AspectJ now firmly places everything that affects the type system of
- Java, including the declared-exception checking system, into the space
- of introduction and declare. So, in order to state that the call to
- `exceptionDeclared()` will not, actually, throw an exception, we now
- "soften" that exception, that is, take it out of the space of declared
- exceptions.
-
- [source, java]
- ....
- declare soft: ExceptionType: Pointcut;
- ....
-
- The pointcuts allowed here are limited; you cannot use pointcuts that
- would require runtime information. But picking out method calls is just
- fine. So in order to make the above example work, one new declaration is
- needed:
-
- [source, java]
- ....
- declare soft: IOException:
- call(void C.exceptionDeclared()) &&
- withincode(void noExceptionDeclared());
- ....
-
- [[_1_0a1-aspects]]
- === Aspects
-
- The syntax of "of each" modifiers has changed. For `of eachcflow` and
- `of eachcflowbelow`, you can simply replace "of each" with "per". So,
-
- [source, java]
- ....
- aspect A of eachcflow(...) { ... }
- // ==>
- aspect A percflow(...) { ... }
- ....
-
- If you have any aspects defined `of eachJVM()`, then you should either
- remove that declaration entirely (because this is the default
- behaviour), or replace the `of eachJVM()` declaration with an
- `issingleton` declaration.
-
- [source, java]
- ....
- aspect of eachJVM() { ... }
- // ==>
- aspect A { ... }
- // or
- aspect A issingleton { ... }
- ....
-
- The `of eachobject(Pointcut)` modifier has been split into two different
- forms, `of perthis(Pointcut)` and `of pertarget(Pointcut)`. Which one
- you replace with depends on the `Pointcut` you use.
-
- If you use a pointcut that picked out reception join points, then use
- `pertarget`, and rewrite the pointcut to pick out call join points. So
-
- [source, java]
- ....
- aspect Shadow
- of eachobject(
- receptions(void Point.setX(int)) ||
- receptions(void Point.setY(int))
- )
- {
- // ...
- }
-
- // ==>
-
- aspect Shadow
- pertarget(
- call(void Point.setX(int)) ||
- call(void Point.setY(int))
- )
- {
- // ...
- }
- ....
-
- Otherwise, in most cases, use `perthis`. When you convert, remember the
- meaning of each of these modifiers. `perthis(Pointcut)` indicates that
- an instance of the aspect should be associated with every object that is
- `this` at each of the join points picked out by `Pointcut`, while
- `pertarget(Pointcut)` associates with every object that is the target
- object at such join points.
-
- '''''
-
- [[pre08b3]]
- == Porting pre-0.8beta3 code
-
- * xref:#cflowTerminology[Changing cflow terminology]
- * xref:#abstractPointcuts[Overriding abstract pointcuts]
- * xref:#recursiveAdvice[Limiting recursive advice]
-
- The following changes are only required when porting code written prior
- to the 0.8beta3 release of AspectJ.
-
- [[cflowTerminology]]
- === Changing cflow terminology
-
- Changing pre-0.8beta3 code that uses AspectJ's control-flow-based
- features only requires rewriting occurrences of `eachcflowroot`,
- `cflow`, and `cflowtop`. No editing of other aspect code is necessary.
-
- ==== eachcflowroot
-
- The aspect modifier "`of eachcflowroot(Pointcut)`" should now be written
- more as "`percflow(Pointcut)`".
-
- ==== cflow
-
- In previous versions of AspectJ, the pointcut `cflow(Pointcut)` picked
- out all join points in the cflow below the join points of `Pointcut`.
- That is, it did not include the join points of `Pointcut`, only the join
- points in their control flow.
-
- As of version 0.8beta3, `cflowbelow(Pointcut)` has that behavior.
- `cflow(Pointcut)` includes the join points of `Pointcut`.
-
- In many cases, you may not care whether the points of `Pointcut` are
- included or not, and so can safely leave `cflow(Pointcut)` pointcut
- designators alone. However, if you use the idiom
-
- [source, java]
- ----
- Pointcut && ! cflow(Pointcut)
- ----
-
- to capture the non-recursive entries to a particular pointcut, you will
- definitely want to rewrite that as
-
- [source, java]
- ----
- Pointcut && ! cflowbelow(Pointcut)
- ----
-
- ==== cflowtop
-
- The primitive pointcut designator `cflowtop(Pointcut)` has been removed
- from the language, as it is expressible with `cflow` or `cflowbelow`.
- All uses of `cflowtop(Pointcut)` can be rewritten as:
-
- [source, java]
- ----
- cflowbelow(Pointcut && ! cflowbelow(Pointcut))
- ----
-
- Though in most cases the following is sufficient
-
- [source, java]
- ----
- cflow(Pointcut && ! cflowbelow(Pointcut))
- ----
-
- [[abstractPointcuts]]
- === Overriding abstract pointcuts
-
- In previous versions of AspectJ, a concrete aspect would implicitly
- override all of its abstract pointcuts with an empty pointcut. AspectJ
- 0.8beta3 enforces the restriction that a concrete aspect may not have
- any abstract pointcuts. Thus the following extension:
-
- [source, java]
- ----
- abstract aspect A {
- abstract pointcut pc();
- }
-
- aspect B {}
- ----
-
- will no longer compile.
-
- Adding the new empty pointcut designator
-
- [source, java]
- ----
- pointcut Id();
- ----
-
- in the declaration of the concrete aspect fixes this problem.
-
- [source, java]
- ----
- abstract aspect A {
- abstract pointcut pc();
- }
-
- aspect B {
- pointcut pc();
- }
- ----
-
- [[recursiveAdvice]]
- === Limiting recursive advice
-
- Previously, the compiler silently refrained from applying a piece of
- advice to join points within its own advice body. So, for example, in
-
- [source, java]
- ----
- class C {
- static int i;
- }
-
- aspect A {
- before(): gets(int C.i) {
- System.err.println("C.i was " + C.i)
- }
- }
- ----
-
- The advice would trace all references of the static field `C.i` except
- those in the body of the before.
-
- The compiler has now removed this special case, and so running the above
- example will now cause a `StackOverflowException` to be thrown.
-
- Most cases of this error can be fixed by correctly specifying the
- desired pointcut: In the above example, the intention is clearly not to
- trace _all_ references of `C.i`, just those outside the aspect.
-
- [source, java]
- ----
- class C {
- static int i;
- }
-
- aspect A {
- before(): get(int C.i) && ! within(A) {
- System.err.println("C.i was " + C.i)
- }
- }
- ----
-
- In a very few cases, you may want the advice to be applicable to other
- code in the aspect, but not in the particular piece of advice. In such
- cases, you can pull the body of the advice into a method and restrict
- away from that method (and away from calls to that method):
-
- [source, java]
- ----
- class C {
- static int i;
- }
-
- aspect A {
- public static int getCi() {
- return C.i; // will be traced
- }
-
- before(): get(int C.i) &&
- ! withincode(void A.traceCi()) &&
- ! call(void A.traceCi())
- {
- traceCi();
- }
-
- private void traceCi() {
- System.err.println("C.i was " + C.i) // will not be traced
- }
- }
- ----
-
- '''''
-
- [[pre08b1]]
- == Porting pre-0.8beta1 code
-
- * xref:#introSyntax[Rewriting introductions]
- * xref:#staticAdvice[Removing static advice]
- * xref:#aspect-aspect[Fixing aspect-aspect inheritance]
- * xref:#usingPrivateIntroduction[Using private introduction]
-
- The following changes are only required when porting code written prior
- to the 0.8beta1 release of AspectJ.
-
- [[introSyntax]]
- === Rewriting introductions
-
- ==== Syntax
-
- The syntax of introduction has changed. Porting most programs should
- require some simple editing. Anywhere you have an introduction block
-
- [source, java]
- ----
- introduction GTN {
- // ...
- }
- ----
-
- simply move the `GTN` down into the introduction declarations and remove
- the block.
-
- For method introduction, place the `GTN` in front of the method name,
- For field introduction, place the `GTN` in front of the field name, and
- for constructor introduction, place the `GTN` in front of the `new`
- identifier.
-
- [source, java]
- ----
- introduction Foo {
- public void doStuff() { this.doStuffLater(); }
- public int calorieCount = 3;
- public new(int x) { super(); calorieCount = x; }
- }
-
- // ==>
-
- public void Foo.doStuff() { this.doStuffLater(); }
- public int Foo.calorieCount= 3;
- public Foo.new(int x) { super(); calorieCount = x; }
- ----
-
- For implements and extends introduction, move the `GTN` in front of the
- new identifiers `implements` or `extends`, and place that in a
- `declare parents` form.
-
- [source, java]
- ----
- introduction Foo {
- implements Comparable;
- extends Goo;
- }
-
- // ==>
-
- declare parents: Foo implements Comparable;
- declare parents: Foo extends Goo;
- ----
-
- In all cases, if the `GTN` is just a type name, it can be moved down on
- its own. However, if the `GTN` uses any of `&&`, `||`, and `!`, it must
- be parenthesized.
-
- [source, java]
- ----
- introduction subtypes(Foo) && !Goo {
- int x;
- }
-
- // ==>
-
- int (Foo+ && !Goo).x;
- ----
-
- ==== Access
-
- If you had an introduction that was referring to private or protected
- members of the target class, this will no longer work. You will either
- need to modify your code to avoid this accessibility issue, or you will
- need to use the `privileged` modifier on the aspect that contains the
- introduction.
-
- [source, java]
- ----
- class Counter {
- private int count = 2;
- }
-
- aspect ExposeCountersPrivates {
- introduction Counter {
- public int getCount() { return count; }
- }
- }
-
- // ==>
-
- // in 0.8, only privileged aspects can expose a class's privates
- privileged aspect ExposeCountersPrivates {
- public int Counter.getCount() { return count; }
- }
- ----
-
- If you have introduced private or package-protected members, you will
- probably have to re-write some code. Most previous uses of introducing
- privates can be improved by using private introduction instead.
-
- [source, java]
- ----
- class C {}
-
- aspect AddCounter {
- introduction C {
- private int count;
- public int getCount() { return count; }
- }
- }
-
- // ==>
-
- aspect AddCounter {
- private int Counter.count;
- public int Counter.getCount() { return count; }
- }
- ----
-
- There is one case that we know of where the inability to perform the
- introduction of private members makes 0.7 code difficult to port to 0.8.
- If you were using the introduction of a `private void writeObject(..)`
- or a `private void readObject(..)` method to interact with Java's
- serialization API, you will need to come up with an alternative design.
- Using some combination of `Externalizable`, `writeReplace(..)` and/or
- `readResolve(..)` methods should allow you to port your code. If you
- find this isn't the case, we'd like to hear about it.
-
- If you were introducing either a protected member or a package-private
- member onto a class in order to override a protected member that was
- inherited from a superclass, you will have to make this introduction
- public.
-
- [[staticAdvice]]
- === Removing static advice
-
- Static advice has been removed from the language. Now, every piece of
- advice is non-static, meaning that it will run in the context of an
- aspect instance.
-
- If you have an aspect that only contains static advice, has no "of"
- clause or is declared "of eachJVM()", and is not extended by another
- aspect, simply remove the keyword "static" from all pieces of advice,
- and make sure the aspect is not defined with the "abstract" modifier.
-
- [source, java]
- ----
- aspect Tracing {
- static before(): executions(* *(..)) {
- System.out.println("Got Here! " + thisJoinPoint);
- }
- }
-
- // ==>
-
- aspect Tracing {
- before(): execution(* *(..)) {
- System.out.println("Got Here! " + thisJoinPoint);
- }
- }
- ----
-
- Otherwise, if you have an aspect contains both static and non-static
- advice, is extended, or is "of eachObject(...)" or "of
- eachcflowroot(...)", you should group your static advice together and
- put it in a new aspect, possibly even an inner aspect.
-
- [source, java]
- ----
- aspect ComplexTracing of eachobject(cflow(executions(void Main.main(..)))) {
- static before(): executions(* *(..)) {
- System.out.println("Got Here! " + thisJoinPoint);
- }
- static after(): executions(* *(..)) {
- System.out.println("Returned! " + thisJoinPoint);
- }
-
- // some other dynamic advice, fields, etc
- }
-
- // ==>
-
- aspect ComplexTracing of eachobject(cflow(executions(void Main.main(..)))) {
- static aspect AlwaysTracing {
- before(): execution(* *(..)) {
- System.out.println("Got Here! " + thisJoinPoint);
- }
- after(): execution(* *(..)) {
- System.out.println("Returned! " + thisJoinPoint);
- }
- }
-
- // some other dynamic advice, fields, etc
- }
- ----
-
- [[aspect-aspect]]
- === Fixing aspect-aspect inheritance
-
- Aspects can now only extend abstract aspects. This restriction may cause
- some redesign of aspect hierarchies. You will probably find that for the
- majority of your code the most serious change this requires is to add an
- explicit `abstract` modifier to a super-aspect that was already
- implicitly abstract.
-
- [source, java]
- ----
- aspect BaseTracing {
- abstract pointcut traced();
- before(): traced() {
- System.out.println("Got Here! " + thisJoinPoint);
- }
- }
-
- // ==>
-
- // make this abstract aspect explicitly abstract
- abstract aspect BaseTracing {
- // ...
- }
- ----
-
- This change has also affected the `getAspect` static method. Now,
- `getAspect` is only defined on non-abstract aspects. Previously, you
- could call `getAspect` on an abstract superaspect and (sometimes) get an
- instance of a subaspect back.
-
- This pattern was used in the Spacewar example in the AspectJ
- distribution. We had the class hierarchy
-
- [source, text]
- ....
- SpaceObject (abstract)
- |- Ship
- |- Bullet
- |- EnergyPellet
- ....
-
- And the aspect hierarchy
-
- [source, text]
- ....
- SpaceObjectDA (abstract)
- |- ShipDA of eachobject(instanceof(Ship))
- |- BulletDA of eachobject(instanceof(Ship))
- |- EnergyPacketDA of eachobject(instanceof(Ship))
- ....
-
- And we would call `SpaceObjectDA.getAspect(SpaceObject)` to access the
- aspect associated with a ship, bullet, or energy pellet. This pattern
- depended on the `SpaceObjectDA` aspect hierarchy exactly mirroring the
- `SpaceObject` hierarchy, and being maintained that way.
-
- A better way to implement this kind of design aspect is to use private
- introduction, a new feature of AspectJ.
-
- [[usingPrivateIntroduction]]
- === Using private introduction
-
- A common pattern for AspectJ programs that need to associate some state
- with every object of a particular type has been to use aspects that are
- defined `of eachobject(instanceof(...))`. A prime example of this was
- the `BoundPoint` aspect of the bean example: which needed to associate
- each point with a `PropertyChangeSupport` object.
-
- [source, java]
- ----
- aspect BoundPoint of eachobject(instanceof(Point)) {
-
- java.beans.PropertyChangeSupport support = null;
-
- after() returning(Point p): receptions(p.new(..)){
- support = new PropertyChangeSupport(myPoint);
- }
-
- around(Point p) returns void: receptions(void p.set*(*)) {
- // code that uses support
- }
- }
- ----
-
- In the new version of AspectJ, a better way of accomplishing many of
- these state association is to use privately introduced fields. Instead
- of creating an aspect instance for every `Point` object, store the
- `PropertyChagneSupport` object in the `Point` objects themselves.
-
- [source, java]
- ----
- aspect BoundPoint {
- private PropertyChangeSupport Point.support = new PropertyChangeSupport(this);
-
- void around(Point p): setters(p) {
- // code that uses p.support
- }
- }
- ----
-
- Just as in the past, the PropertyChangeSupport object is not accessable
- to anyone but the aspect, but now less mechanism is needed.
-
- There are times when changing aspects that are defined
- `of eachobject(instanceof(...))` may not be reasonable. If the aspect
- instance is stored or passed to other methods, then having a real
- `of eachobject(instanceof(...))`, now written `perthis(this(...))`,
- association may capture the crosscutting concern best.
-
- '''''
-
- [[pre07b11]]
- == Porting pre-0.7beta11 code
-
- * xref:#twoArgumentCalls[Removing two-argument calls]
- * xref:#adviceInClasses[Removing advice from Class declarations]
-
- The following changes are only required when porting code written prior
- to the 0.7beta11 release of AspectJ.
-
- [[twoArgumentCalls]]
- === Removing two-argument calls
-
- In AspectJ 0.7beta11, the two-argument `calls` primitive pointcut
- designator was deprecated. Removing these designators will require
- different cases depending on what the original pointcut did.
-
- ==== Calls to static methods
-
- For pointcuts denoting calls to particular static methods, such as
-
- [source, java]
- ....
- calls(String, static String valueOf(int)) // deprecated
- ....
-
- the transformation is easy. Simply make the desired signature explicit.
- Instead of catching all calls to any static method that happens to have
- the signature `String valueOf(int)`, catch calls to that exact method
- defined in the String class.
-
- [source, java]
- ....
- call(static String String.valueOf(int))
- ....
-
- Pointcuts denoting calls to classes of static methods can also be
- rewritten with these rules. For example,
-
- [source, java]
- ....
- calls(my.package.*, static * get*(..)) // deprecated
- ....
-
- should now be written
-
- [source, java]
- ....
- call(static * my.package.*.get*(..))
- ....
-
- ==== Calls to non-static methods
-
- Many pointcuts denoting calls to non-static methods can be fixed the
- same way that those pointcuts denoting calls to static methods are
- fixed. So,
-
- [source, java]
- ....
- calls(Thread, int getPriority()) // deprecated
- ....
-
- which denotes all calls to nullary int methods named `getPriority` when
- the called object is an instance of the `Thread` type, can almost always
- be rewritten
-
- [source, java]
- ....
- call(int Thread.getPriority())
- ....
-
- which denotes all calls to the nullary int `Thread.getPriority()`
- method.
-
- Expanding the signature picks out slightly different join points than
- the original two-argument form. This won't matter for most programs, but
- in some cases the differences may be noticable. In particular, the
- expanded-signature form only picks out those calls where the called
- object is statically typed to `Thread` when its `int getPriority()`
- method is called. If you want to capture calls to the
- `int Thread.getPriority()` method, regardless of how the called object
- is statically typed, you shoud use the different translation:
-
- [source, java]
- ....
- call(int getPriority()) && target(Thread)
- ....
-
- This will capture all call join points of methods with signature
- `int Thread.getPriority()`.
-
- It will also denote any join points if the Thread type does not define
- (possibly abstractly) some `int getPriority()` method, though.
-
- [[adviceInClasses]]
- === Removing advice from Class declarations
-
- The simplest way to remove an advice declaration from a class is to
- simply define the advice declaration in an inner aspect. So, instead of
-
- [source, java]
- ....
- class C {
- static before(): executions(C.new()) { /*...*/ } // deprecated
- }
- ....
-
- write
-
- [source, java]
- ....
- class C {
- static aspect ConstructionProtocol {
- static before(): executions(C.new()) { /*...*/ }
- }
- }
- ....
-
- If your advice doesn't refer to any inner classes or interfaces of C,
- you can move the inner aspect out of the class entirely.
-
- [source, java]
- ....
- class C { /*...*/ }
-
- aspect ConstructionProtocol {
- static before(): execution(C.new()) { /*...*/ }
- }
- ....
-
- Your code will be clearer if you consider the purpose of each piece of
- advice when you make this change. It may be that some of the advice
- naturally belongs to another aspect, perhaps already existing. Or it may
- be that some pieces of advice in a class are associated to one concern
- and some to another; in which case more than aspect would be
- appropriate.
-
- '''''
-
- [[pre07b10]]
- == Porting pre-0.7beta10 code
-
- * xref:#joinPoints[Changing access to thisJoinPoint]
-
- The following changes are only required when porting code written prior
- to the 0.7beta10 release of AspectJ.
-
- [[joinPoints]]
- === Changing access to thisJoinPoint
-
- In AspectJ 0.7beta10, access to the reflective object `thisJoinPoint`
- substantially changed. The two parts of this change were the elimination
- of the `runNext()` static method, and the use of an interface hierarchy
- represent the join point object.
-
- [[proceed]]
- ==== `thisJoinPoint.runNext()` to `proceed()`
-
- The elimination of the `runNext()` static method requires almost no
- porting work. An automatic replacement of the string
-
- [source, java]
- ....
- thisJoinPoint.runNext
- ....
-
- with the string
-
- [source, java]
- ....
- proceed
- ....
-
- will do the job. However, if any around advice used the identifier
- `proceed` as a formal parameter or local variable, it must be renamed,
- and if any aspect used it as a field, then references to the field in
- around advice should be made explicit (prefixing the reference with the
- aspect name or `this`, depending on whether the field is static or
- not).
-
- [[thisJoinPoint]]
- ==== Using `thisJoinPoint`
-
- While access to reflective information through `thisJoinPoint` is more
- powerful and regular through its interface hierarchy, the previous uses
- must be rewritten. Changing your code will likely require manual
- editing, but in doing so your code should get simpler and cleaner.
-
- Many existing uses of the fields on join points can be re-written to use
- one of:
-
- * `thisJoinPoint.toString()`
- * `thisJoinPoint.toShortString()`
- * `thisJoinPoint.toLongString()`
- * `thisJoinPoint.getSignature().toString()`
- * `thisJoinPoint.getSignature().toShortString()`
- * `thisJoinPoint.getSignature().toLongString()`
-
- For example:
-
- * `System.out.println(thisJoinPoint.className + "." + thisJoinPoint.methodName)`
-
- can be replaced with
-
- * `System.out.println(thisJoinPoint)` or
- * `System.out.println(thisJoinPoint.getSignature().toShortString())`
-
- with comparable behavior.
-
- Accesses to the parameters field of join points should be changed as
- follows. A field access like:
-
- * `thisJoinPoint.parameters`
-
- must be changed to:
-
- * `thisJoinPoint.getArgs()`
-
- Accesses to the methodName and className fields of join points that are
- not suitable for replacement with a toString method, should be changed
- as follows. Field accesses like:
-
- * `thisJoinPoint.className`
- * `thisJoinPoint.methodName`
-
- must be changed to:
-
- * `thisJoinPoint.getSignature().getDeclaringType().getName()`
- * `thisJoinPoint.getSignature().getName()`
-
- Accessses to the parameterNames and parameterTypes fields of join
- points, that are not suitable for conversion to one of the toString()
- methods should be changed as follows. Field access like:
-
- * `thisJoinPoint.parameterNames`
- * `thisJoinPoint.parameterTypes`
-
- must be changed to:
-
- * `((CodeSignature)thisJoinPoint.getSignature()).getParameterNames()`
- * `((CodeSignature)thisJoinPoint.getSignature()).getParameterTypes()`
|