diff options
Diffstat (limited to 'docs/release/README-1.1.adoc')
-rw-r--r-- | docs/release/README-1.1.adoc | 1381 |
1 files changed, 1381 insertions, 0 deletions
diff --git a/docs/release/README-1.1.adoc b/docs/release/README-1.1.adoc new file mode 100644 index 000000000..d846cff81 --- /dev/null +++ b/docs/release/README-1.1.adoc @@ -0,0 +1,1381 @@ +[[readme-1_1]] +== AspectJ 1.1 + +_© Copyright 2002 Palo Alto Research Center, Incorporated, 2003 +Contributors. All rights reserved._ + +This is the initial release of AspectJ 1.1. It includes a small number +of new language features as well as major improvements to the +functionality of the tools. + +This document describes the differences between AspectJ versions 1.1 and +1.0.6. Users new to AspectJ need only read the +link:progguide/index.html[AspectJ Programming Guide] since it describes +the 1.1 language. Users familiar with AspectJ 1.0 may find this document +a quicker way to learn what changed in the language and tools, and +should use it as a guide for porting programs from 1.0 to 1.1. + +This document first summarizes changes from the 1.0 release in + +* xref:#language[the language], +* xref:#compiler[the compiler], +* xref:#tools[the support tools], +* xref:#runtime[the runtime], +* xref:#devenv[the development environment support], +* xref:#sources[the sources], and +* xref:#distribution[the distribution], + +then xref:#details[details] some of the language and compiler changes, +and finally points readers to the bug database for any +xref:#knownLimitations[known limitations]. + +''''' + +[[language]] +=== The Language + +AspectJ 1.1 is a slightly different language than AspectJ 1.0. In all +but a few cases, programs written in AspectJ 1.0 should compile +correctly in AspectJ 1.1. In many cases, there are new or preferred +forms in AspectJ 1.1. However, some AspectJ 1.0 features have changed in +1.1, so some 1.0 programs will not compile or will run differently in +1.1. The corresponding features are marked below as compile-time or +run-time incompatible (_CTI_ or _RTI_, respectively). When the language +change involves a move in the static shadow effective at run-time but +also apparent at compile-time (e.g., in declare error or warning +statements), it is marked _CRTI_. Programs using run-time incompatible +forms should be verified that they are behaving as expected in 1.1. + +Most changes to the language are additions to expressibility requested +by our users: + +* xref:#THROWS_PATTERN[Matching based on throws]: You can now make finer +discriminations between methods based on declared exceptions. +* xref:#NEW_PCDS[New kinded pointcut designators]: Now every kind of +join point has a corresponding kinded pointcut designator. + +Some are have different behavior in edge cases but offer improved power +and clarity: + +* xref:#ASPECT_PRECEDENCE[New aspect precedence form]: AspectJ 1.1 has a +new declare form, `declare precedence`, that replaces the +"dominates" clause on aspects. (_CTI_) +* The order of xref:#SUPER_IFACE_INITS[initialization join points for +super-interfaces] has been clarified. (_RTI_) + +But in order to support weaving into bytecode effectively, several +incompatible changes had to be made to the language: + +* A class's default constructor may +xref:#DEFAULT_CONSTRUCTOR_CONFLICT[conflict] with an inter-type +constructor. (_CTI_) +* xref:#NO_CALLEE_SIDE_CALL[No callee-side call join points]: The +AspectJ 1.1 compiler does not expose call join points unless it is given +the calling code. (_CRTI_) +* xref:#SINGLE_INTERCLASS_TARGET[One target for intertype declarations]. +(_CTI_) +* xref:#UNAVAILABLE_JOIN_POINTS[No initializer execution join points]. +(_RTI_) +* xref:#AFTER_HANDLER[No after or around advice on handler join points]. +(_CTI_) +* xref:#CONSTRUCTOR_EXECUTION_IS_BIGGER[Initializers run inside +constructor execution join points]. (_RTI_) +* xref:#INTER_TYPE_FIELD_INITIALIZERS[inter-type field initializers] run +before class-local field initializers. (_RTI_) +* xref:#WITHIN_MEMBER_TYPES[Small limitations of the within pointcut.] +(_CRTI_) +* xref:#WITHIN_CODE[Small limitations of the withincode pointcut.] +(_CRTI_) +* xref:#INSTANCEOF_ON_WILD[Can't do instanceof matching on type patterns +with wildcards]. (_CTI_) +* xref:#NO_SOURCE_COLUMN[SourceLocation.getColumn() is deprecated and +will always return 0]. (_RTI_) +* The interaction between aspect instantiation and advice has been +xref:#ASPECT_INSTANTIATION_AND_ADVICE[clarified]. (_RTI_) +* xref:#STRINGBUFFER[The String + operator is now correctly advised]. +(_CRTI_) + +[#NEW_LIMITATIONS]#There# are a couple of language limitations for +things that are rarely used that make the implementation simpler, so we +have restricted the language accordingly. + +* xref:#VOID_FIELD_SET[Field set join points now have a `void` return +type.] This will require porting of code that uses the `set` PCD in +conjunction with after-returning or around advice. (_CTI_) +* 'declare soft: TYPE: POINTCUT;' - AspectJ 1.1 only accepts TYPE rather +than a TYPE_PATTERN. This limitation makes declare soft much easier to +implement efficiently. (_CTI_) +* Inter-type field declarations only allow a single field per line, i.e. +this is now illegal 'int C.field1, D.field2;' This must instead be, 'int +C.field1; int D.field2;' (_CTI_) +* We did not implement the handling of more than one `..` wildcard in +args PCD's (rarely encountered in the wild) because we didn't have the +time. This might be available in later releases if there is significant +outcry. (_CTI_) + +We did not implement the long-awaited xref:#PER_TYPE[new pertype aspect +specifier] in this release, but it may well be in a future release. + +''''' + +[[compiler]] +=== The Compiler + +The compiler for AspectJ 1.1 is different than the compiler for AspectJ +1.0. While this document describes the differences in the compiler, it's +worthwhile noting that much effort has been made to make sure that the +interface to ajc 1.1 is, as much as possible, the same as the interface +to ajc 1.0. There are two important changes under the hood, however. + +First, the 1.1 compiler is implemented on top of the open-source Eclipse +compiler. This has two benefits: It allows us to concentrate on the +AspectJ extensions to Java and let the Eclipse team worry about making +sure the Java edge cases work, and it allows us to piggyback on +Eclipse's already mature incremental compilation facilities. + +Second, ajc now cleanly delineates compilation of source code from +assembly (or "weaving") of bytecode. The compiler still accepts source +code, but internally it transforms it into bytecode format before +weaving. + +This new architecture, and other changes to the compiler, allows us to +implement some features that were defined in the AspectJ 1.0 language +but not implementable in the 1.1 compiler. It also makes some new +features available: + +* xref:#SOURCEROOT[The -sourceroots option] takes one or more +directories, and indicates that all the source files in those +directories should be passed to the compiler. +* xref:#BYTECODE_WEAVING[The -injars option] takes one or more jar +files, and indicates that all the classfiles in the jar files should be +woven into. +* xref:#BINARY_ASPECTS[The -aspectpath option] takes one or more jar +files, and weaves any aspects in .class form into the sources. +* xref:#OUTJAR[The -outjar option] indicates that the result classfiles +of compiling and weaving should be placed in the specified jar file. +* xref:#XLINT[The -Xlint option] allows control over warnings. +* xref:#OTHER_X_OPTIONS[Various -X options] changed. +* xref:#INCREMENTAL[The -incremental option] tells the AspectJ 1.1 +compiler to recompile only as necessary. + +Some other features we wanted to support for 1.1, but did not make it +into this release: + +* xref:#ERROR_MESSAGES[Error messages will sometimes be scary] +* xref:#MESSAGE_CONTEXT[Source code context is not shown for errors and +warnings detected during bytecode weaving] + +But some features of the 1.0 compiler are not supported in the 1.1 +compiler: + +* xref:#NO_SOURCE[The source-related options] -preprocess, -usejavac, +-nocomment and -workingdir +* xref:#NO_STRICT_LENIENT[The -strict and -lenient options] +* xref:#NO_PORTING[The -porting option] +* xref:#_13_REQUIRED[J2SE 1.2 is not supported; J2SE 1.3 or later is +required.] + +A short description of the options ajc accepts is available with +"`ajc -help`". Longer descriptions are available in the +link:devguide/ajc-ref.html[Development Environment Guide section on +ajc]. + +Some changes to the implementation are almost entirely internal: + +* The behavior of the compiler in xref:#TARGET_TYPES_MADE_PUBLIC[lifting +the visibility] of the target types of some declares and pointcuts to +public has been clarified. + +Also, it is worth noting that because AspectJ now works on bytecode, it +is somewhat sensitive to how different compilers generate bytecode, +especially when compiling with and without +xref:#ONE_FOUR_METHOD_SIGNATURES[the -1.4 flag]. + +''''' + +[[tools]] +=== Support Tools + +This release includes an Ant task for old-style 1.0 build scripts, a new +task for all the new compiler options, and a CompilerAdapter to support +running `ajc` with the Javac task by setting the `build.compiler` +property. The new task can automatically copy input resources to output +and work in incremental mode using a "tag" file. + +This release does not include `ajdoc`, the documentation tool for +AspectJ sources. Ajdoc is deeply dependent on the abstract syntax tree +classes from the old compiler, so it needs a bottom-up rewrite. We think +it best to use this opportunity to implement more general API's for +publishing and rendering static structure. Because those API's are last +to settle in the new architecture, and because the compiler itself is a +higher priority, we are delaying work on ajdoc until after the 1.1 +release. + +AspectJ 1.1 will not include ajdb, the AspectJ stand-alone debugger. It +is no longer necessary for two reasons. First, the -XnoInline flag will +tell the compiler to generate code without inlining that should work +correctly with any Java debugger. For code generated with inlining +enabled, more third-party debuggers are starting to work according to +JSR 45, "Debugging support for other languages," which is supported by +AspectJ 1.0. We aim to support JSR-45 in AspectJ 1.1, but support will +not be in the initial release. Consider using the -XnoInline flag until +support is available. + +''''' + +[[runtime]] +=== The Runtime Library + +This release has minor additions to the runtime library classes. As with +any release, you should compile and run with the runtime library that +came with your compiler, and you may run with a later version of the +library without recompiling your code. + +In one instance, however, runtime classes behave differently this +release. Because the AspectJ 1.1 compiler does its weaving through +bytecode, column numbers of source locations are not available. +Therefore, `thisJoinPoint.getSourceLocation().getColumn()` is deprecated +and will always return 0. + +''''' + +[[devenv]] +=== The AJDE Tools + +The AspectJ Browser supports incremental compilation and running +programs. AJDE for JBuilder, AJDE for NetBeans, and AJDE for Emacs are +now independent SourceForge projects (to keep their licenses). They use +the batch-build mode of the new compiler. + +''''' + +[[sources]] +=== The Sources and the Licenses + +The AspectJ tools sources are available under the +https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt[Eclipse Public +License v 2.0] in the Git repository at https://eclipse.org/aspectj. For +more information, see the FAQ entry on building sources. + +''''' + +[[distribution]] +=== The AspectJ distribution + +AspectJ 1.0 had many distributions - for the tools, the documentation, +each IDE support package, their respective sources, and the Ant tasks - +because they came under different licenses. All of AspectJ 1.1 is +licensed under the CPL 1.0, so the tools, Ant tasks, and documentation +are all in one distribution available from https://eclipse.org/aspectj. +To retain their MPL 1.1 license, Ajde for +http://aspectj4emacs.sourceforge.net/[Emacs], +http://aspectj4netbean.sourceforge.net/[NetBeans] and +http://aspectj4jbuildr.sourceforge.net/[JBuilder] are now independent +SourceForge projects. + +''''' + +''''' + +[[details]] +=== Details of some language and compiler changes + +[[ASPECT_INSTANTIATION_AND_ADVICE]] +==== Aspect Instantiation and Advice + +In AspectJ 1.0.6, we made an effort to hide some complications with +Aspect instantiation from the user. In particular, the following code +compiled and ran: + +[source, java] +.... +public class Client { + public static void main(String[] args) { + Client c = new Client(); + } +} + +aspect Watchcall { + pointcut myConstructor(): execution(new(..)); + + before(): myConstructor() { + System.err.println("Entering Constructor"); + } +} +.... + +But there's a conceptual problem with this code: The before advice +should run before the execution of all constructors in the system. It +must run in the context of an instance of the Watchcall aspect. The only +way to get such an instance is to have Watchcall's default constructor +execute. But before that executes, we need to run the before advice... + +AspectJ 1.0.6 hid this circularity through the ad-hoc mechanism of +preventing an aspect's advice from matching join points that were within +the aspect's definition, and occurred before the aspect was initialized. +But even in AspectJ 1.0.6, this circularity could be exposed: + +[source, java] +.... +public class Client { + public static int foo() { return 3; } + public static void main(String[] args) { + Client c = new Client(); + } +} + +aspect Watchcall { + int i = Client.foo(); + pointcut myConstructor(): + execution(new(..)) || execution(int foo()); + + before(): myConstructor() { + System.err.println("Entering Constructor"); + } +} +.... + +This program would throw a NullPointerException when run, since +Client.foo() was called before the Watchcall instance could be +instantiated. + +In AspectJ 1.1, we have decided that half-hiding the problem just leads +to trouble, and so we are no longer silently hiding some join points +before aspect initialization. However, we have provided a better +exception than a NullPointerException for this case. In AspectJ 1.1, +both of the above programs will throw +org.aspectj.lang.NoAspectBoundException. + +[[THROWS_PATTERN]] +==== Matching based on throws + +Type patterns may now be used to pick out methods and constructors based +on their throws clauses. This allows the following two kinds of +extremely wildcarded pointcuts: + +[source, java] +.... +pointcut throwsMathlike(): + // each call to a method with a throws clause containing at least + // one exception with "Math" in its name. + call(* *(..) throws *..*Math*); + +pointcut doesNotThrowMathlike(): + // each call to a method with a throws clause containing no + // exceptions with "Math" in its name. + call(* *(..) throws !*..*Math*); +.... + +The longwinded rules are that a method or constructor pattern can have a +"throws clause pattern". Throws clause patterns look like: + +[source, text] +.... +ThrowsClausePattern: + ThrowsClausePatternItem ("," ThrowsClausePatternItem)* + +ThrowsClausePatternItem: + ["!"] TypeNamePattern +.... + +A ThrowsClausePattern matches the ThrowsClause of any code member +signature. To match, each ThrowsClausePatternItem must match the throws +clause of the member in question. If any item doesn't match, then the +whole pattern doesn't match. This rule is unchanged from AspectJ 1.0. + +If a ThrowsClausePatternItem begins with "!", then it matches a +particular throws clause if and only if _none_ of the types named in the +throws clause is matched by the TypeNamePattern. + +If a ThrowsClausePatternItem does not begin with "!", then it matches a +throws clause if and only if _any_ of the types named in the throws +clause is matched by the TypeNamePattern. + +These rules are completely backwards compatible with AspectJ 1.0. The +rule for "!" matching has one potentially surprising property, in that +the two PCD's shown below will have different matching rules. + +[source, java] +.... +/*[1]*/ call(* *(..) throws !IOException) +/*[2]*/ call(* *(..) throws (!IOException)) + +void m() throws RuntimeException, IOException {} +.... + +[1] will NOT match the method m(), because method m's throws clause +declares that it throws IOException. [2] WILL match the method m(), +because method m's throws clause declares the it throws some exception +which does not match IOException, i.e. RuntimeException. + +[[NEW_PCDS]] +==== New kinded pointcut designators + +AspectJ 1.0 does not provide kinded pointcut designators for two (rarely +used) join points: preinitialization (the code that runs before a super +constructor call is made) and advice execution. AspectJ 1.1 does not +change the meaning of the join points, but provides two new pointcut +designators to pick out these join points, thus making join points and +pointcut designators more parallel. + +`adviceexectuion()` will pick out advice execution join points. You will +usually want to use `adviceexecution() && within(Aspect)` to +restrict it to only those pieces of advice defined in a particular +aspect. + +`preinitialization(ConstructorPattern)` will pick out pre-initialization +join points where the initialization process is entered through +`ConstructorPattern`. + +[[PER_TYPE]] +==== New pertype aspect specifier (not in 1.1) + +We strongly considered adding a pertype aspect kind to 1.1. This is +somewhat motivated by the new +xref:#SINGLE_INTERCLASS_TARGET[restrictions on inter-type declarations] + +. This is also motivated by many previous request to support a common +logging idiom. Here's what pertype would look like: + +[source, java] +.... +/** One instance of this aspect will be created for each class, + * interface or aspect in the com.bigboxco packages. + */ +aspect Logger pertype(com.bigboxco..*) { + /* This field holds a logger for the class. */ + Log log; + + /* This advice will run for every public execution defined by + * a type for which a Logger aspect has been created, i.e. + * any type in com.bigboxco..* + */ + before(): execution(public * *(..)) { + log.enterMethod(thisJoinPoint.getSignature().getName()); + } + + /* We can use a special constructor to initialize the log field */ + public Logger(Class myType) { + this.log = new Log(myType); + } +} + +/** External code could use aspectOf to get at the log, i.e. */ +Log l = Logger.aspectOf(com.bigboxco.Foo.class).log; +.... + +The one open question that we see is how this should interact with inner +types. If a pertype aspect is created for an outer type should advice in +that aspect run for join points in inner types? That is the behavior of +the most common uses of this idiom. + +In any case, this feature will not be in AspectJ 1.1. + +[[SINGLE_INTERCLASS_TARGET]] +==== One target for intertype declarations + +Intertype declarations (once called "introductions") in AspectJ 1.1 can +only have one target type. So the following code intended to declare +that there is a void doStuff() method on all subtypes of Target is not +legal AspectJ 1.1 code. + +[source, java] +.... +aspect A { + public void Target+.doStuff() { ... } +} +.... + +The functionality of "multi-intertype declarations" can be recovered by +using a helper interface. + +[source, java] +.... +aspect A { + private interface MyTarget {} + declare parents: Target+ implements MyTarget; + public void MyTarget.doStuff() { ... } +} +.... + +We believe this is better style in AspectJ 1.0 as well, as it makes +clear the static type of "this" inside the method body. + +The one piece of functionality that can not be easily recovered is the +ability to add static fields to many classes. We believe that the +xref:#PER_TYPE[pertype proposal] provides this functionality in a much +more usable form. + +[[UNAVAILABLE_JOIN_POINTS]] +==== No initializer execution join points + +AspectJ 1.1 does not consider initializer execution a principled join +point. The collection of initializer code (the code that sets fields +with initializers and the code in non-static initializer blocks) is +something that makes sense only in Java source code, not in Java +bytecode. + +[[AFTER_HANDLER]] +==== No after or around advice on handler join points + +The end of an exception handler is underdetermined in bytecode, so ajc +will not implement after or around advice on handler join points, +instead signaling a compile-time error. + +[[CONSTRUCTOR_EXECUTION_IS_BIGGER]] +==== Initializers run inside constructor execution join points + +The code generated by the initializers in Java source code now runs +inside of constructor execution join points. This changes how before +advice runs on constructor execution join points. Consider: + +[source, java] +.... +class C { + C() { } + String id = "identifier"; // this assignment + // has to happen sometime +} + +aspect A { + before(C c) this(c) && execution(C.new()) { + System.out.println(c.id.length()); + } +} +.... + +In AspectJ 1.0, this will print "10", since id is assigned its initial +value prior to the before advice's execution. However, in AspectJ 1.1, +this will throw a NullPointerExcception, since "id" does not have a +value prior to the before advice's execution. + +Note that the various flavors of after returning advice are unchanged in +this respect in AspectJ 1.1. Also note that this only matters for the +execution of constructors that call a super-constructor. Execution of +constructors that call a this-constructor are the same in AspectJ 1.1 as +in AspectJ 1.0. + +We believe this difference should be minimal to real programs, since +programmers using before advice on constructor execution must always +assume incomplete object initialization, since the constructor has not +yet run. + +[[INTER_TYPE_FIELD_INITIALIZERS]] +==== Inter-type field initializers + +The initializer, if any, of an inter-type field definition runs before +the class-local initializers of its target class. + +In AspectJ 1.0.6, such an initializer would run after the initializers +of a class but before the execution of any of its constructor bodies. As +already discussed in the sections about +xref:#UNAVAILABLE_JOIN_POINTS[initializer execution join points] and +xref:#CONSTRUCTOR_EXECUTION_IS_BIGGER[constructor execution], the point +in code between the initializers of a class and its constructor body is +not principled in bytecode. So we had a choice of running the +initializer of an inter-type field definition at the beginning of +initialization (i.e., before initializers from the target class) or at +the end (i.e., just before its called constructor exits). We chose the +former, having this pattern in mind: + +[source, java] +.... +int C.methodCount = 0; +before(C c): this(c) && execution(* *(..)) { c.methodCount++; } +.... + +We felt there would be too much surprise if a constructor called a +method (thus incrementing the method count) and then the field was reset +to zero after the constructor was done. + +[[WITHIN_MEMBER_TYPES]] +==== Small limitations of the within pointcut + +Because of the guarantees made (and not made) by the Java classfile +format, there are cases where AspectJ 1.1 cannot guarantee that the +within pointcut designator will pick out all code that was originally +within the source code of a certain type. + +The non-guarantee applies to code inside of anonymous and local types +inside member types. While the within pointcut designator behaves +exactly as it did in AspectJ 1.0 when given a package-level type (like +C, below), if given a member-type (like C.InsideC, below), it is not +guaranteed to capture code in contained local and anonymous types. For +example: + +[source, java] +.... +class C { + Thread t; + class InsideC { + void setupOuterThread() { + t = new Thread( + new Runnable() { + public void run() { + // join points with code here + // might not be captured by + // within(C.InsideC), but are + // captured by within(C) + System.out.println("hi"); + } + }); + } + } +} +.... + +We believe the non-guarantee is small, and we haven't verified that it +is a problem in practice. + +[[WITHIN_CODE]] +==== Small limitations of the withincode pointcut + +The withincode pointcut has similar issues to those described above for +within. + +[[INSTANCEOF_ON_WILD]] +==== Can't do instanceof matching on type patterns with wildcard + +The pointcut designators this, target and args specify a dynamic test on +their argument. These tests can not be performed on type patterns with +wildcards in them. The following code that compiled under 1.0 will be an +error in AspectJ-1.1: + +[source, java] +.... +pointcut oneOfMine(): this(com.bigboxco..*); +.... + +The only way to implement this kind of matching in a modular way would +be to use the reflection API at runtime on the Class of the object. This +would have a very high performance cost and possible security issues. +There are two good work-arounds. If you control the source or bytecode +to the type you want to match then you can use declare parents, i.e.: + +[source, java] +.... +private interface OneOfMine {} +declare parents: com.bigboxco..* implements OneOfMine; +pointcut oneOfMine(): this(OneOfMine); +.... + +If you want the more dynamic matching and are willing to pay for the +performance, then you should use the Java reflection API combined with +if. That would look something like: + +[source, java] +.... +pointcut oneOfMine(): this(Object) && + if(classMatches("com.bigboxco..*", + thisJoinPoint.getTarget().getClass())); + +static boolean classMatches(String pattern, Class _class) { + if (patternMatches(pattern, _class.getName())) return true; + ... +} +.... + +Note: wildcard type matching still works in all other PCD's that match +based on static types. So, you can use 'within(com.bigboxco..*+)' to +match any code lexically within one of your classes or a subtype +thereof. This is often a good choice. + +[[NO_SOURCE_COLUMN]] +==== SourceLocation.getColumn() + +The Java .class file format contains information about the source file +and line numbers of its contents; however, it has no information about +source columns. As a result, we can not effectively support the access +of column information in the reflection API. So, any calls to +thisJoinPoint.getSourceLocation().getColumn() will be marked as +deprecated by the compiler, and will always return 0. + +[[ASPECT_PRECEDENCE]] +==== Aspect precedence + +AspectJ 1.1 has a new declare form: + +[source, java] +.... +declare precedence ":" TypePatternList ";" +.... + +This is used to declare advice ordering constraints on join points. For +example, the constraints that (1) aspects that have Security as part of +their name should dominate all other aspects, and (2) the Logging aspect +(and any aspect that extends it) should dominate all non-security +aspects, can be expressed by: + +[source, java] +.... +declare precedence: *..*Security*, Logging+, *; +.... + +In the TypePatternList, the wildcard * means "any type not matched by +another type in the declare precedence". + +===== Various cycles + +It is an error for any aspect to be matched by more than one TypePattern +in a single declare precedence, so: + +[source, java] +.... +declare precedence: A, B, A ; // error +.... + +However, multiple declare precedence forms may legally have this kind of +circularity. For example, each of these declare precedence is perfectly +legal: + +[source, java] +.... +declare precedence: B, A; +declare precedence: A, B; +.... + +And a system in which both constraints are active may also be legal, so +long as advice from A and B don't share a join point. So this is an +idiom that can be used to enforce that A and B are strongly independent. + +===== Applies to concrete aspects + +Consider the following library aspects: + +[source, java] +.... +abstract aspect Logging { + abstract pointcut logged(); + + before(): logged() { + System.err.println("thisJoinPoint: " + thisJoinPoint); + } +} + +aspect MyProfiling { + abstract pointcut profiled(); + + Object around(): profiled() { + long beforeTime = System.currentTimeMillis(); + try { + return proceed(); + } finally { + long afterTime = System.currentTimeMillis(); + addToProfile(thisJoinPointStaticPart, + afterTime - beforeTime); + } + } + abstract void addToProfile( + org.aspectj.JoinPoint.StaticPart jp, + long elapsed); +} +.... + +In order to use either aspect, they must be extended with concrete +aspects, say, MyLogging and MyProfiling. In AspectJ 1.0, it was not +possible to express that Logging's advice (when concerned with the +concrete aspect MyLogging) dominated Profiling's advice (when concerned +with the concrete aspect MyProfiling) without adding a dominates clause +to Logging itself. In AspectJ 1.1, we can express that constraint with a +simple: + +[source, java] +.... +declare precedence: MyLogging, MyProfiling; +.... + +===== Changing order of advice for sub-aspects + +By default, advice in a sub-aspect has more precedence than advice in a +super-aspect. One use of the AspectJ 1.0 dominates form was to change +this precedence: + +[source, java] +.... +abstract aspect SuperA dominates SubA { + pointcut foo(): ... ; + + before(): foo() { + // in AspectJ 1.0, runs before the advice in SubA + // because of the dominates clause + } +} + +aspect SubA extends SuperA { + before(): foo() { + // in AspectJ 1.0, runs after the advice in SuperA + // because of the dominates clause + } +} +.... + +This no longer works in AspectJ 1.1, since declare precedence only +matters for concrete aspects. Thus, if you want to regain this kind of +precedence change, you will need to refactor your aspects. + +[[SOURCEROOT]] +==== The -sourceroots option + +The AspectJ 1.1 compiler now accepts a -sourceroots option used to pass +all .java files in particular directories to the compiler. It takes +either a single directory name, or a list of directory names separated +with the CLASSPATH separator character (":" for various Unices, ";" for +various Windows). + +So, if you have your project separated into a gui module and a base +module, each of which is stored in a directory tree, you might use one +of + +[source, text] +.... +ajc -sourceroots /myProject/gui:/myProject/base +ajc -sourceroots d:\myProject\gui;d:\myProject\base +.... + +This option may be used in conjunction with lst files, listing .java +files on the command line, and the -injars option. + +[[BYTECODE_WEAVING]] +==== The -injars option + +The AspectJ 1.1 compiler now accepts an -injars option used to pass all +.class files in a particular jar file to the compiler. It takes either a +single directory name, or a list of directory names separated with the +CLASSPATH separator character (":" for various Unices, ";" for various +Windows). + +So, if MyTracing.java defines a trace aspect that you want to apply to +all the classes in myBase.jar and myGui.jar, you would use one of: + +[source, text] +.... +ajc -injars /bin/myBase.jar:/bin/myGui.jar MyTracing.java +ajc -injars d:\bin\myBase.jar;d:\bin\myGui.jar MyTracing.java +.... + +The class files in the input jars must not have had advice woven into +them, since AspectJ enforces the requirement that advice is woven into a +particular classfile only once. So if the classfiles in the jar file are +to be created with the ajc compiler (as opposed to a pure Java +compiler), they should not be compiled with any non-abstract aspects. + +This option may be used in conjunction with lst files, listing .java +files on the command line, and the -sourceroots option. + +[[OUTJAR]] +==== The -outjar option + +The -outjar option takes the name of a jar file into which the results +of the compilation should be put. For example: + +[source, text] +.... +ajc -injars myBase.jar MyTracing.java -outjar myTracedBase.jar +.... + +No meta information is placed in the output jar file. + +[[INCREMENTAL]] +==== Incremental compilation + +The AspectJ 1.1 compiler now supports incremental compilation. When ajc +is called with the -incremental option, it must also be passed a +-sourceroots option specifying a directory to incrementally compile. +Once the initial compile is done, ajc waits for console input. Every +time it reads a new line (i.e., every time the user hits return) ajc +recompiles those input files that need recompiling. + +===== Limitations + +This new functionality is still only lightly tested. + +[[XNOWEAVE]] +==== -XnoWeave, a compiler option to suppress weaving + +The -XnoWeave option suppresses weaving, and generates classfiles and +that can be passed to ajc again (through the -injars option) to generate +final, woven classfiles. + +This option was originally envisioned to be the primary way to generate +binary aspects that could be linked with other code, and so it was +previously (in AspectJ 1.1beta1) named `-noweave`. We feel that using +the `-aspectpath` option is a much better option. There may still be use +cases for unwoven classfiles, but we've moved the flag to experimental +status. + +[[BINARY_ASPECTS]] +==== -aspectpath, working with aspects in .class/.jar form + +When aspects are compiled into classfiles, they include all information +necessary for the ajc compiler to weave their advice and deal with their +inter-type declarations. In order for these aspects to have an effect on +a compilation process, they must be passed to the compiler on the +-aspectpath. Every .jar file on this path will be searched for aspects +and any aspects that are found will be enabled during the compilation. +The binary forms of this aspects will be untouched. + +[[NO_CALLEE_SIDE_CALL]] +==== Callee-side call join points + +The 1.0 implementation of AspectJ, when given: + +[source, java] +.... +class MyRunnable implements Runnable { + public void run() { /*...*/ } +} + +aspect A { + call(): (void run()) && target(MyRunnable) { + // do something here + } +} +.... + +would cause A's advice to execute even when, say, java.lang.Thread +called run() on a MyRunnable instance. + +With the new compiler, two things have happened in regard to callee-side +calls: + +. because the programmer has access to more code (i.e., bytecode, not +just source code), callee-side calls are much less important to have. +. because compilation is more modular, allowing and encouraging separate +compilation, callee-side calls are much more difficult to implement + +With these two points in mind, advice in an aspect will not be applied +to call join points whose call site is completely unavailable to the +aspect. + +. One reason (though not the only reason) we worked so hard in the +_implementation_ of 1.0.6 to expose call join points, even if we only +had access to the callee's code, was that otherwise users couldn't get +access to call join points where the call was made from bytecode. This +is no longer the case. In short, the implementation controls much more +code (or has the capability to) than ever before. +. The implementation model for the AspectJ 1.1 compiler is to separate +the compilation of aspects/advice from their weaving/linking. A property +of the model is that the compilation requires no access to "target" +code, only the weaving/linking does, and weaving/linking is inherently +per-class local: No action at weaving/linking time depends on the +coordinated mangling of multiple classfiles. Rather, all weaving is done +on a per classfile basis. This is an essential property for the current +separate compilation model. + +However, allowing implementation of call advice on either side requires +simultaneous knowledge of both sides. If we first have access to a call, +we can't decide to simply put the advice on the call site, since later +we may decide to implement on the callee. + +This implementation decision is completely in the letter and the spirit +of the AspectJ language. From the semantics guide describing code the +implementation controls: + +____ +But AspectJ implementations are permitted to deviate from this in a +well-defined way -- they are permitted to advise only accesses in _code +the implementation controls_. Each implementation is free within certain +bounds to provide its own definition of what it means to control code. +____ + +And about a particular decision about the 1.0.6 implementation: + +____ +Different join points have different requirements. Method call join +points can be advised only if ajc controls _either_ the code for the +caller or the code for the receiver, and some call pointcut designators +may require caller context (what the static type of the receiver is, for +example) to pick out join points. +____ + +The 1.1 implementation makes a different design decision: Method call +join points can be advised only if ajc (in compiler or linker form) +controls the code for the caller. + +What does 1.1 gain from this? + +* a clear (and implemented) separate compilation model (see point 2, +above) +* a less confusing interaction between call join points and the +thisJoinPoint reflective object: We still get bug reports about source +information sometimes existing and sometimes not existing at call join +points. + +What does 1.1 lose from this? + +* The ability to capture all calls to Runnable.run() from anywhere to +code ajc has access too, even from Thread, even if you don't compile +java.lang with ajc. +* The ability to, without access to the caller, capture entry to a +particular method, but not super calls. +* A code-size-improvement performance optimization. + +What are the possibilities for the future? + +* AspectJ 1.1.1 could expand its capture of call join points, possibly +at the expense of separate compilation clarity, possibly not. +* AspectJ 1.1.1 could re-introduce reception join points from AspectJ +0.7 (what callee-side call join points actually are): though they would +never ever be taught in a tutorial or entry-level description of the +model, they may have specialized uses. + +How will this affect developers? + +* When using the call PCD but only supplying the callee code, supply the +calling code or use the execution PCD instead. + +[[OTHER_X_OPTIONS]] +==== Various -X options + +The AspectJ 1.0 compiler supported a number of options that started with +X, for "experimental". Some of them will not be supported in 1.1, either +because the "experiment" succeeded (in which case it's part of the +normal functionality) or failed. Others will be supported as is (or +nearly so) in 1.1: + +* -XOcodeSize: This is no longer necessary because inlining of around +advice is on by default. We support its inverse, +xref:#XNOINLINE[`-XnoInline`]. +* xref:#XNOWEAVE[-XnoWeave, a compiler option to suppress weaving] +* -XtargetNearSource: Not supported in this release. +* -XserializableAspects: Supported. +* -XaddSafePrefix: This option will not be supported in 1.1 at all +because we're now always using (what we believe to be) safe prefixes. +* -Xlint: Still supported, with xref:#XLINT[various options]. + +[[ERROR_MESSAGES]] +==== Some confusing error messages + +Building on the eclipse compiler has given us access to a very +sophisticated problem reporting system as well as highly optimized error +messages for pure Java code. Often this leads to noticeably better error +messages than from ajc-1.0.6. However, when we don't handle errors +correctly this can sometimes lead to cascading error messages where a +single small syntax error will produce dozens of other messages. Please +report any very confusing error messages as bugs. + +[[MESSAGE_CONTEXT]] +==== Source code context is not shown for errors and warnings detected during bytecode weaving + +For compiler errors and warnings detected during bytecode weaving, +source code context will not be displayed. In particular, for declare +error and declare warning statements, the compiler now only emits the +file and line. We are investigating ways to overcome this in cases where +the source code is available; in cases where source code is not +available, we might specify the signature of the offending code. For +more information, see bug 31724. + +[[XLINT]] +==== The -Xlint option + +`-Xlint:ignore,error,warning` will set the level for all Xlint warnings. +`-Xlint`, alone, is an abbreviation for `-Xlint:warning`. + +The `-Xlintfile:lint.properties` allows fine-grained control. In +tools.jar, see `org/aspectj/weaver/XlintDefault.properties` for the +default behavior and a template to copy. + +More `-Xlint` warnings are supported now, and we may add disabled +warnings in subsequent bug-fix releases of 1.1. Because the +configurability allows users to turn off warnings, we will be able to +warn about more potentially dangerous situations, such as the +potentially unsafe casts used by very polymorphic uses of proceed in +around advice. + +[[NO_SOURCE]] +==== Source-specific options + +Because AspectJ 1.1 does not generate source code after weaving, the +source-code-specific options -preprocess, -usejavac, -nocomment and +-workingdir options are meaningless and so not supported. + +[[NO_STRICT_LENIENT]] +==== The -strict and -lenient options + +Because AspectJ 1.1 uses the Eclipse compiler, which has its own +mechanism for changing strictness, we no longer support the -strict and +-lenient options. + +[[NO_PORTING]] +==== The -porting option + +AspectJ 1.1 does not have a -porting option. + +[[_13_REQUIRED]] +==== J2SE 1.3 required + +Because we build on Eclipse, the compiler will no longer run under J2SE +1.2. You must run the compiler (and all tools based on the compiler) +using J2SE 1.3 or later. The code generated by the compiler can still +run on Java 1.1 or later VM's if compiled against the correct runtime +libraries. + +[[DEFAULT_CONSTRUCTOR_CONFLICT]] +==== Default constructors + +AspectJ 1.1 does not allow the inter-type definition of a zero-argument +constructor on a class with a visible default constructor. So this is no +longer allowed: + +[source, java] +.... +class C {} + +aspect A { + C.new() {} // was allowed in 1.0.6 + // is a "multiple definitions" conflict in 1.1 +} +.... + +In the Java Programming Language, a class defined without a constructor +actually has a "default" constructor that takes no arguments and just +calls `super()`. + +This default constructor is a member of the class like any other member, +and can be referenced by other classes, and has code generated for it in +classfiles. Therefore, it was an oversight that AspectJ 1.0.6 allowed +such an "overriding" inter-type constructor definition. + +[[SUPER_IFACE_INITS]] +==== Initialization join points for super-interfaces + +In AspectJ, interfaces may have non-static members due to inter-type +declarations. Because of this, the semantics of AspectJ defines the +order that initializer code for interfaces is run. + +In the semantics document for AspectJ 1.0.6, the following promises were +made about the order of this initialization: + +. a supertype is initialized before a subtype +. initialized code runs only once +. initializers for supertypes run in left-to-right order + +The first two properties are important and are preserved in AspectJ 1.1, +but the third property is and was ludicrous, and was never properly +implemented (and never could be) in AspectJ 1.0.6. Consider: + +[source, java] +.... +interface Top0 {} +interface Top1 {} +interface I extends Top0, Top1 {} +interface J extends Top1, Top0 {} + +class C implements I, J {} +// I says Top0's inits must run before Top1's +// J says Top1's inits must run before Top0's + +aspect A { + int Top0.i = foo("I'm in Top0"); + int Top1.i = foo("I'm in Top1"); + static int foo(String s) { + System.out.println(s); + return 37; + } +} +.... + +This was simply a bug in the AspectJ specification. The correct third +rule is: + +____ +the initializers for a type's superclass are run before the initializers +for its superinterfaces. +____ + +[[VOID_FIELD_SET]] +==== Field Set Join Points + +In AspectJ 1.0.6, the join point for setting a field F had, as a return +type, F's type. This was "java compatible" because field assignment in +java, such as "Foo.i = 37", is in fact an expression, and does in fact +return a value, the value that the field is assigned to. + +This was never "java programmer compatible", however, largely because +programmers have absorbed the good style of rarely using an assignment +statement in a value context. Programmers typically expect "Foo.i = 37" +not to return a value, but to simply assign a value. + +Thus, programmers typically wanted to write something like: + +[source, java] +.... +void around(): set(int Foo.i) { + if (theSetIsAllowed()) { + proceed(); + } +} +.... + +And were confused by it being a compile-time error. They weren't +confused for long, and soon adapted to writing: + +[source, java] +.... +int around(): set(int Foo.i) { + if (theSetIsAllowed()) { + return proceed(); + } else { + return Foo.i; + } +} +.... + +But there was definitely a short disconnect. + +On top of that, we were never shown a convincing use-case for returning +an interesting value from a set join point. When we revisited this +issue, in fact, we realized we had a long-standing bug in 1.0.6 dealing +with the return value of pre-increment expressions (such as ++Foo.i) +that nobody had found because nobody cares about the return value of +such join points. + +So, because it's easier to implement, and because we believe that this +is the last possibility to make the semantics more useful, we have made +set join points have a void return type in 1.1. + +[[XNOINLINE]] +==== The -XnoInline Option + +The `-XnoInline` option to indicate that no inlining of any kind should +be done. This is purely a compiler pragma: No program semantics (apart +from stack traces) will be changed by the presence or absence of this +option. + +[[TARGET_TYPES_MADE_PUBLIC]] +==== Target types made public + +Even in 1.0.6, the AspectJ compiler has occasionally needed to convert +the visibility of a package-level class to a public one. This was +previously done in an ad-hoc basis that took whole-program analysis into +account. With the incremental compilation model of AspectJ 1.1, we can +now specify the occasions when the compiler makes these visibility +changes. + +In particular, the types used in the `this`, `target`, and `args` +pointcuts are made public, as are the super-types from `declare parents` +and the exception type from `declare soft`. + +We believe the visibility changes could be avoided in the future with +various implementation tricks if they become a serious concern, but did +not encounter them as such a concern when they were done in the 1.0.6 +implementation. + +[[STRINGBUFFER]] +==== String + now advised + +In Java, the + operator sometimes results in StringBuffer objects being +created, appended to, and used to generate a new String. Thus, + +[source, java] +.... +class Foo { + String makeEmphatic(String s) { + return s + "!"; + } +} +.... + +is approximately the same at runtime as + +[source, java] +.... +class Foo { + String makeEmphatic(String s) { + return new StringBuffer(s).append("!").toString(); + } +} +.... + +In the design process of AspectJ 1.0.6 we didn't expose those +StringBuffer methods and constructors as join points (though we did +discuss it), but in 1.1 we do. + +This change is likely to affect highly wildcarded aspects, and can do so +in surprising ways. In particular: + +[source, java] +.... +class A { + before(int i): call(* *(int)) && args(i) { + System.err.println("entering with " + i); + } +} +.... + +may result in a stack overflow error, since the argument to println is +really + +[source, java] +.... +new StringBuffer("entering with ").append(i).toString() +.... + +which has a call to StringBuffer.append(int). In such cases, it's worth +restricting your pointcut, with something like one of: + +[source, java] +.... +call(* *(int)) && args(i) && !within(A) +call(* *(int)) && args(i) && !target(StringBuffer) +.... + +[[ONE_FOUR_METHOD_SIGNATURES]] +==== The -1.4 flag and method signatures + +Consider the following aspect + +[source, java] +.... +public aspect SwingCalls { + + pointcut callingAnySwing(): call(* javax.swing..*+.*(..)); + + before(): callingAnySwing() { + System.out.println("Calling any Swing"); + } +} +.... + +And then consider the two statements + +[source, java] +.... +JFrame frame = new JFrame(); +frame.setTitle("Title"); +.... + +According to the Java Language Specification version 2, the call to +`frame.setTitle("Title")` should always produce the bytecode for a call +to `javax.swing.JFrame.setTitle`. However, older compilers (and eclipse +when run without the `-1.4` flag) will generate the bytecode for a call +to `java.awt.Frame.setTitle` instead since this method is not overriden +by JFrame. The AspectJ weaver depends on the correctly generated +bytecode in order to match patterns like the one you show correctly. + +This is a good example of why the pattern +`call(* *(..)) && target(JFrame)` is the recommended style. In general, +OO programmers don't want to care about the static type of an object at +a call site, but only want to know the dynamic instanceof behavior which +is what the target matching will handle. + +[[knownLimitations]] +=== Known limitations + +The AspectJ 1.1.0 release contains a small number of known limitations +relative to the AspectJ 1.1 language. For the most up-to-date +information about known limitations in an AspectJ 1.1 release, see the +bug database at https://bugs.eclipse.org/bugs, especially the open bugs +for the +https://bugs.eclipse.org/bugs/buglist.cgi?product=AspectJ&component=Compiler&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED[compiler], +https://bugs.eclipse.org/bugs/buglist.cgi?product=AspectJ&component=IDE&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED[IDE +support], +https://bugs.eclipse.org/bugs/buglist.cgi?product=AspectJ&component=Doc&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED[documentation], +and +https://bugs.eclipse.org/bugs/buglist.cgi?product=AspectJ&component=Ant&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED[Ant +tasks]. Developers should know about bugs marked with the "info" keyword +because those bugs reflect failures to implement the 1.1 language +perfectly. These might be fixed during the 1.1 release cycle; find them +using the query +https://bugs.eclipse.org/bugs/buglist.cgi?product=AspectJ&keywords=info +For ajc's 1.1 implementation limitations, see +link:progguide/implementation.html[Programming Guide Appendix: +"Implementation Notes"]. |