From cce24d74634779801e999fb09f9031687eaa3d31 Mon Sep 17 00:00:00 2001 From: acolyer Date: Fri, 19 Mar 2004 20:49:58 +0000 Subject: [PATCH] placeholder readme for 1.2 --- docs/dist/doc/README-12.html | 1542 ++++++++++++++++++++++++++++++++++ 1 file changed, 1542 insertions(+) create mode 100644 docs/dist/doc/README-12.html diff --git a/docs/dist/doc/README-12.html b/docs/dist/doc/README-12.html new file mode 100644 index 000000000..7ca9e558c --- /dev/null +++ b/docs/dist/doc/README-12.html @@ -0,0 +1,1542 @@ + + +AspectJ 1.1 Readme + + + + +
+© Copyright 2002 Palo Alto Research Center, Incorporated, +2003 Contributors. +All rights reserved. +
+ + +

AspectJ 1.2 Readme

+ + content to be replaced + + +

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

+ + + +

then details some of the language + and compiler changes, + and finally points readers to the bug database for any + known limitations. +

+ + +
+

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: +

+ + + +

Some are have different behavior in edge cases but offer + improved power and clarity:

+ + + +

But in order to support weaving into bytecode effectively, + several incompatible changes had to be made to the language:

+ + + +

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. +

+ + + +

We did not implement the long-awaited new + pertype aspect specifier in this release, but it may well + be in a future release.

+ + + +
+

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:

+ + + +

Some other features we wanted to support for 1.1, but did not make + it into this release:

+ + + +

But some features of the 1.0 compiler are not supported in the + 1.1 compiler:

+ + + +

A short description of the options ajc accepts is available with + "ajc -help". + Longer descriptions are available in the + Development Environment Guide + section on ajc.

+

+ + +

Some changes to the implementation are almost entirely + internal: +

+ + + +

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 the -1.4 flag.

+ + + + +
+

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.

+ + +
+

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.

+ + +
+

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. +

+ + +
+

The Sources and the Licenses

+ +

The AspectJ tools sources are available under the + Common Public + License in the CVS repository + at http://eclipse.org/aspectj. + For more information, see the FAQ entry on + building sources. +

+ + + +
+

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 + + http://eclipse.org/aspectj. +To retain their MPL 1.1 license, +Ajde for +Emacs, +NetBeans and +JBuilder +are now independent SourceForge projects.

+ +

+ + + +
+
+

Details of some language and compiler changes

+ +

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: +

+ +
+      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: +

+ +
+      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. +

+ +

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:

+ +
    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:

+ +
    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.

+ +
    [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 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.

+ +

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 + 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:

+ +
    /** 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. +

+ +

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. +

+ +
    aspect A {
+        public void Target+.doStuff() { ... }
+    }
+    
+ +

The functionality of "multi-intertype declarations" can be + recovered by using a helper interface. +

+ +
    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 pertype proposal provides + this functionality in a much more usable form.

+ +

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.

+ +

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.

+ +

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:

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

+ +

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 + initializer execution join + points and 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: +

+ +
+    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. +

+ +

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:

+ +
    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.

+ +

Small limitations of the withincode + pointcut

+ +

The withincode pointcut has similar issues to those described + above for within. +

+ +

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:

+ +
    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.:

+ +
    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:

+ +
    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.

+

+ + +

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

+ +

AspectJ 1.1 has a new declare form: +

+ +
    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:

+ +
    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:

+ +
      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: +

+ +
      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: +

+ +
      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:

+ +
      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: +

+ +
      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. +

+ +

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 +

+ +
    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. +

+ +

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:

+ +
    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. +

+ +

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: + +

    ajc -injars myBase.jar MyTracing.java -outjar myTracedBase.jar
+    
+ +

No meta information is placed in the output jar file.

+ +

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, 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. +

+ +

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

+ +

Callee-side call join + points

+ +

The 1.0 implementation of AspectJ, when given: +

+ +
    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: +

+ +
    +
  1. because the programmer has access to more code (i.e., + bytecode, not just source code), callee-side calls are much + less important to have.
  2. + +
  3. because compilation is more modular, allowing and + encouraging separate compilation, callee-side calls are much + more difficult to implement
  4. +
+ +

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.

+ +
    +
  1. 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.
  2. + +
  3. 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.
  4. +
+ +

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?

+ + + +

What does 1.1 lose from this?

+ + + +

What are the possibilities for the future?

+ + + +

How will this affect developers?

+ + +

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: +

+ + + +

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.

+ + +

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.

+ + +

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.

+ +

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.

+ +

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.

+ +

The -porting option

+ +

AspectJ 1.1 does not have a -porting option.

+ +

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 + 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:

+ +
+    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. +

+ +

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: +

+ +
    +
  1. a supertype is initialized before a subtype
  2. +
  3. initialized code runs only once
  4. +
  5. initializers for supertypes run in left-to-right order
  6. +
+ +

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:

+ +
+    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. +
+ + +

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: +

+ +
+    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: +

+ +
+    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.

+ +

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

+ +

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.

+ +

String + now advised

+ +

In Java, the + operator sometimes results in StringBuffer objects +being created, appended to, and used to generate a new String. Thus, +

+ +
+class Foo {
+    String makeEmphatic(String s) {
+        return s + "!";
+    }
+}
+
+ +

is approximately the same at runtime as +

+ +
+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: +

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

+ +
+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: +

+ +
+call(* *(int)) && args(i) && !within(A)
+call(* *(int)) && args(i) && !target(StringBuffer)
+
+ +

The -1.4 flag and method signatures

+ +

Consider the following aspect +

+ +
+public aspect SwingCalls {
+    
+    pointcut callingAnySwing(): call(* javax.swing..*+.*(..));
+
+    before(): callingAnySwing() {
+        System.out.println("Calling any Swing");
+    }
+}
+
+ +

And then consider the two statements +

+ +
+  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.

+ + +

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 + http://bugs.eclipse.org/bugs, +especially the open bugs for the + + compiler, + + IDE support, + + documentation, and + + 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 + + http://bugs.eclipse.org/bugs/buglist.cgi?product=AspectJ&keywords=info + +For ajc's 1.1 implementation limitations, see + + Programming Guide Appendix: "Implementation Notes". + +

+ -- 2.39.5