diff options
author | Alexander Kriegisch <Alexander@Kriegisch.name> | 2021-07-16 10:48:06 +0700 |
---|---|---|
committer | Alexander Kriegisch <Alexander@Kriegisch.name> | 2024-01-06 10:09:11 +0100 |
commit | a6a1dbea46fd4829189b23fb900da6a586a8151a (patch) | |
tree | b6d8a3b4e38e320813566535c6ea4f036fb4ba91 | |
parent | fa63feda31a6a9656173a63dc057993d98469305 (diff) | |
download | aspectj-a6a1dbea46fd4829189b23fb900da6a586a8151a.tar.gz aspectj-a6a1dbea46fd4829189b23fb900da6a586a8151a.zip |
Fix more AsciiDoc links and code blocks (WIP)
- Add Java syntax highlighting to AspectJ and Java files
- Add XML syntax highlighting to XML files (Ant, LTW etc.)
- Dedent and remove empty lines, where necessary
- Enclose in-line line numbers for Java code in /*23*/ comments in order
to enable Java formatting
Signed-off-by: Alexander Kriegisch <Alexander@Kriegisch.name>
64 files changed, 1479 insertions, 1260 deletions
diff --git a/docs/adk15ProgGuideDB/annotations.adoc b/docs/adk15ProgGuideDB/annotations.adoc index 795860a42..e0e56fc71 100644 --- a/docs/adk15ProgGuideDB/annotations.adoc +++ b/docs/adk15ProgGuideDB/annotations.adoc @@ -19,10 +19,10 @@ program source by using the `@` symbol. For example, the following piece of code uses the `@Deprecated` annotation to indicate that the `obsoleteMethod()` has been deprecated: +[source, java] .... @Deprecated public void obsoleteMethod() { ... } - .... Annotations may be _marker annotations_, _single-valued annotations_, or @@ -32,27 +32,27 @@ annotations, as in the deprecation example above. Single-value annotation types have a single member, and the annotation may be written in one of two equivalent forms: +[source, java] .... @SuppressWarnings({"unchecked"}) public void someMethod() {...} - .... or +[source, java] .... @SuppressWarnings(value={"unchecked"}) public void someMethod() {...} - .... Multi-value annotations must use the `member-name=value ` syntax to specify annotation values. For example: +[source, java] .... @Authenticated(role="supervisor",clearanceLevel=5) public void someMethod() {...} - .... ==== Retention Policies @@ -96,6 +96,7 @@ presence or absence of annotations. By default annotations are _not_ inherited. Given the following program +[source, java] .... @MyAnnotation class Super { @@ -105,7 +106,6 @@ class Super { class Sub extends Super { public void foo() {} } - .... Then `Sub` _does not_ have the `MyAnnotation` annotation, and @@ -133,6 +133,7 @@ permitted on pointcut declarations or on `declare` statements. The following example illustrates the use of annotations in aspects: +[source, java] .... @AspectAnnotation public abstract aspect ObserverProtocol { @@ -192,6 +193,7 @@ advice statement by using the the same way as the Java 5 SuppressWarnings annotation (See JLS 9.6.1.5), but has class file retention. +[source, java] .... import org.aspectj.lang.annotation.SuppressAjWarnings; @@ -262,6 +264,7 @@ Some examples of annotation patterns follow: AspectJ 1.5 extends type patterns to allow an optional `AnnotationPattern` prefix. +[source, text] .... TypePattern := SimpleTypePattern | '!' TypePattern | @@ -288,9 +291,9 @@ pattern, the parenthesis are required (as in `(@Foo Hello+)`). In some cases (such as a type pattern used within a `within` or `handler` pointcut expression), the parenthesis are optional: +[source, text] .... OptionalParensTypePattern := AnnotationPattern? TypePattern - .... The following examples illustrate the use of annotations in type @@ -330,6 +333,7 @@ patterns: A `FieldPattern` can optionally specify an annotation-matching pattern as the first element: +[source, text] .... FieldPattern := AnnotationPattern? FieldModifiersPattern? @@ -371,6 +375,7 @@ annotations that match the pattern. For example: A `MethodPattern` can optionally specify an annotation-matching pattern as the first element. +[source, text] .... MethodPattern := AnnotationPattern? MethodModifiersPattern? TypePattern @@ -397,6 +402,7 @@ TypePatternList := TypePattern (',' TypePattern)* A `ConstructorPattern` has the form +[source, text] .... ConstructorPattern := AnnotationPattern? ConstructorModifiersPattern? @@ -470,6 +476,7 @@ Like their counterparts, these pointcut designators can be used both for join point matching, and to expose context. The format of these new designators is: +[source, text] .... AtThis := '@this' '(' AnnotationOrIdentifer ')' @@ -505,6 +512,7 @@ Annotations can be exposed as context in the body of advice by using the forms of `@this(), @target()` and `@args()` that use bound variables in the place of annotation names. For example: +[source, java] .... pointcut callToClassifiedObject(Classified classificationInfo) : call(* *(..)) && @target(classificationInfo); @@ -521,6 +529,7 @@ at a given position in an `@args` expression indicates that the runtime type of the argument in that position at a join point must have an annotation of the indicated type. For example: +[source, java] .... /** * matches any join point with at least one argument, and where the @@ -544,6 +553,7 @@ available reflectively with the body of advice through the the arguments, or object bound to this or target at a join point you can use the following code fragments: +[source, java] .... Annotation[] thisAnnotations = thisJoinPoint.getThis().getClass().getAnnotations(); Annotation[] targetAnnotations = thisJoinPoint.getTarget().getClass().getAnnotations(); @@ -555,6 +565,7 @@ point where the executing code is defined within a type (`@within`), or a method/constructor (`@withincode`) that has an annotation of the specified type. The form of these designators is: +[source, text] .... AtWithin := '@within' '(' AnnotationOrIdentifier ')' AtWithinCode := '@withincode' '(' AnnotationOrIdentifier ')' @@ -574,6 +585,7 @@ The `@annotation` pointcut designator matches any join point where the _subject_ of the join point has an annotation of the given type. Like the other @pcds, it can also be used for context exposure. +[source, text] .... AtAnnotation := '@annotation' '(' AnnotationOrIdentifier ')' .... @@ -589,6 +601,7 @@ extended with additional operations that provide access to the annnotations can be queried. The following fragment illustrates an example use of this interface to access annotation information. +[source, java] .... Signature sig = thisJoinPointStaticPart.getSignature(); AnnotatedElement declaringTypeAnnotationInfo = sig.getDeclaringType(); @@ -621,6 +634,7 @@ considered to be an annotation on the parameter type or an annotation on the parameter itself is determined through the use of parentheses around the parameter type. Consider the following: +[source, java] .... @SomeAnnotation class AnnotatedType {} @@ -634,6 +648,7 @@ class C { The method foo has a parameter of an annotated type, and can be matched by this pointcut: +[source, java] .... pointcut p(): execution(* *(@SomeAnnotation *)); .... @@ -645,6 +660,7 @@ parameter of any type that has the annotation @SomeAnnotation'. To match the parameter annotation case, the method goo, this is the pointcut: +[source, java] .... pointcut p(): execution(* *(@SomeAnnotation (*))); .... @@ -657,6 +673,7 @@ annotation of @SomeAnnotation'. To match when there is a parameter annotation and an annotation on the type as well: +[source, java] .... pointcut p(): execution(* *(@SomeAnnotation (@SomeOtherAnnotation *))); .... @@ -671,6 +688,7 @@ According to the Java 5 specification, non-type annotations are not inherited, and annotations on types are only inherited if they have the `@Inherited` meta-annotation. Given the following program: +[source, java] .... class C1 { @SomeAnnotation @@ -714,6 +732,7 @@ actually being called). The `if` pointcut designator can be used to write pointcuts that match based on the values annotation members. For example: +[source, java] .... pointcut txRequiredMethod(Tx transactionAnnotation) : execution(* *(..)) && @this(transactionAnnotation) @@ -729,12 +748,14 @@ Since pointcut expressions in AspectJ 5 support join point matching based on annotations, this facility can be exploited when writing `declare warning` and `declare error` statements. For example: +[source, java] .... declare warning : withincode(@PerformanceCritical * *(..)) && call(@ExpensiveOperation * *(..)) : "Expensive operation called from within performance critical section"; .... +[source, java] .... declare error : call(* org.xyz.model.*.*(..)) && !@within(Trusted) @@ -745,6 +766,7 @@ declare error : call(* org.xyz.model.*.*(..)) && The general form of a `declare parents` statement is: +[source, text] .... declare parents : TypePattern extends Type; declare parents : TypePattern implements TypeList; @@ -774,6 +796,7 @@ issued). The general form of a declare precedence statement is: +[source, java] .... declare precedence : TypePatList; .... @@ -798,6 +821,7 @@ a future release. The general form is: +[source, text] .... declare @<kind> : ElementPattern : Annotation ; .... @@ -809,6 +833,7 @@ specified by the `@Target` annotation. `ElementPattern` is defined as follows: +[source, text] .... ElementPattern := TypePattern | MethodPattern | diff --git a/docs/adk15ProgGuideDB/ataspectj.adoc b/docs/adk15ProgGuideDB/ataspectj.adoc index e69fb205a..7f480f667 100644 --- a/docs/adk15ProgGuideDB/ataspectj.adoc +++ b/docs/adk15ProgGuideDB/ataspectj.adoc @@ -30,6 +30,7 @@ used to declare aspects and aspect members. Aspect declarations are supported by the `org.aspectj.lang.annotation.Aspect` annotation. The declaration: +[source, java] .... @Aspect public class Foo {} @@ -37,6 +38,7 @@ public class Foo {} Is equivalent to: +[source, java] .... public aspect Foo {} .... @@ -44,6 +46,7 @@ public aspect Foo {} To specify an aspect an aspect instantiation model (the default is singleton), provide the perclause as the `@Aspect` value. For example: +[source, java] .... @Aspect("perthis(execution(* abc..*(..)))") public class Foo {} @@ -51,6 +54,7 @@ public class Foo {} is equivalent to... +[source, java] .... public aspect Foo perthis(execution(* abc..*(..))) {} .... @@ -86,6 +90,7 @@ section. Here is a simple example of a pointcut declaration in both code and @AspectJ styles: +[source, java] .... @Pointcut("call(* *.*(..))") void anyCall() {} @@ -93,6 +98,7 @@ void anyCall() {} is equivalent to... +[source, java] .... pointcut anyCall() : call(* *.*(..)); .... @@ -100,6 +106,7 @@ pointcut anyCall() : call(* *.*(..)); When binding arguments, simply declare the arguments as normal in the annotated method: +[source, java] .... @Pointcut("call(* *.*(int)) && args(i) && target(callee)") void anyCall(int i, Foo callee) {} @@ -107,6 +114,7 @@ void anyCall(int i, Foo callee) {} is equivalent to... +[source, java] .... pointcut anyCall(int i, Foo callee) : call(* *.*(int)) && args(i) && target(callee); .... @@ -115,6 +123,7 @@ An example with modifiers (Remember that Java 5 annotations are not inherited, so the `@Pointcut` annotation must be present on the extending aspect's pointcut declaration too): +[source, java] .... @Pointcut("") protected abstract void anyCall(); @@ -122,6 +131,7 @@ protected abstract void anyCall(); is equivalent to... +[source, java] .... protected abstract pointcut anyCall(); .... @@ -139,6 +149,7 @@ scope. Consider the following compilation unit: +[source, java] .... package org.aspectprogrammer.examples; @@ -152,6 +163,7 @@ public aspect Foo { Using the annotation style this would be written as: +[source, java] .... package org.aspectprogrammer.examples; @@ -186,6 +198,7 @@ have either an empty body (`if()`, or be one of the expression forms and return a boolean. The body of the method contains the condition to be evaluated. For example: +[source, java] .... @Pointcut("call(* *.*(int)) && args(i) && if()") public static boolean someCallWithIfTest(int i) { @@ -195,12 +208,14 @@ public static boolean someCallWithIfTest(int i) { is equivalent to... +[source, java] .... pointcut someCallWithIfTest(int i) : call(* *.*(int)) && args(i) && if(i > 0); .... and the following is also a valid form: +[source, java] .... static int COUNT = 0; @@ -260,6 +275,7 @@ method execution join point). The following example shows a simple before advice declaration in both styles: +[source, java] .... @Before("call(* org.aspectprogrammer..*(..)) && this(Foo)") public void callFromFoo() { @@ -269,6 +285,7 @@ public void callFromFoo() { is equivalent to... +[source, java] .... before() : call(* org.aspectprogrammer..*(..)) && this(Foo) { System.out.println("Call from Foo"); @@ -278,6 +295,7 @@ before() : call(* org.aspectprogrammer..*(..)) && this(Foo) { If the advice body needs to know which particular `Foo` instance is making the call, just add a parameter to the advice declaration. +[source, java] .... before(Foo foo) : call(* org.aspectprogrammer..*(..)) && this(foo) { System.out.println("Call from Foo: " + foo); @@ -286,6 +304,7 @@ before(Foo foo) : call(* org.aspectprogrammer..*(..)) && this(foo) { can be written as: +[source, java] .... @Before("call(* org.aspectprogrammer..*(..)) && this(foo)") public void callFromFoo(Foo foo) { @@ -298,6 +317,7 @@ If the advice body needs access to `thisJoinPoint` , these need to be declared as additional method parameters when using the annotation style. +[source, java] .... @Before("call(* org.aspectprogrammer..*(..)) && this(foo)") public void callFromFoo(JoinPoint thisJoinPoint, Foo foo) { @@ -308,6 +328,7 @@ public void callFromFoo(JoinPoint thisJoinPoint, Foo foo) { is equivalent to... +[source, java] .... before(Foo foo) : call(* org.aspectprogrammer..*(..)) && this(foo) { System.out.println("Call from Foo: " + foo + " at " @@ -317,6 +338,7 @@ before(Foo foo) : call(* org.aspectprogrammer..*(..)) && this(foo) { Advice that needs all three variables would be declared: +[source, java] .... @Before("call(* org.aspectprogrammer..*(..)) && this(Foo)") public void callFromFoo(JoinPoint thisJoinPoint, @@ -340,6 +362,7 @@ To expose a return value with after returning advice simply declare the returning parameter as a parameter in the method body and bind it with the "returning" attribute: +[source, java] .... @AfterReturning("criticalOperation()") public void phew() { @@ -354,6 +377,7 @@ public void itsAFoo(Foo f) { is equivalent to... +[source, java] .... after() returning : criticalOperation() { System.out.println("phew"); @@ -375,6 +399,7 @@ the design goals for the annotation style is that a large class of AspectJ applications should be compilable with a standard Java 5 compiler. A straight call to `proceed` inside a method body: +[source, java] .... @Around("call(* org.aspectprogrammer..*(..))") public Object doNothing() { @@ -386,6 +411,7 @@ will result in a "No such method" compilation error. For this reason AspectJ 5 defines a new sub-interface of `JoinPoint` , `ProceedingJoinPoint` . +[source, java] .... public interface ProceedingJoinPoint extends JoinPoint { public Object proceed(Object[] args); @@ -394,6 +420,7 @@ public interface ProceedingJoinPoint extends JoinPoint { The around advice given above can now be written as: +[source, java] .... @Around("call(* org.aspectprogrammer..*(..))") public Object doNothing(ProceedingJoinPoint thisJoinPoint) { @@ -403,6 +430,7 @@ public Object doNothing(ProceedingJoinPoint thisJoinPoint) { Here's an example that uses parameters for the proceed call: +[source, java] .... @Aspect public class ProceedAspect { @@ -420,6 +448,7 @@ public class ProceedAspect { is equivalent to: +[source, java] .... public aspect ProceedAspect { pointcut setAge(int i): call(* setAge(..)) && args(i); @@ -505,6 +534,7 @@ introduce a marker interface. Consider the following aspect: +[source, java] .... public aspect MoodIndicator { @@ -532,6 +562,7 @@ type of the inter-type declaration). Using the annotation style this aspect can be written: +[source, java] .... @Aspect public class MoodIndicator { @@ -575,6 +606,7 @@ aspect' field of a non-interface type. The interface type is the inter-type declaration contract that dictates which methods are declared on the target type. +[source, java] .... // this type will be affected by the inter-type declaration as the type pattern matches package org.xyz; @@ -596,6 +628,7 @@ interface methods. Consider the following aspect: +[source, java] .... public aspect SerializableMarker { declare parents : org.xyz..* implements Serializable; @@ -604,6 +637,7 @@ public aspect SerializableMarker { Using the annotation style this aspect can be written: +[source, java] .... @Aspect public class SerializableMarker { @@ -620,6 +654,7 @@ implemented by the target type, an error will be issued during weaving. Consider the following aspect: +[source, java] .... public aspect MoodIndicator { @@ -647,6 +682,7 @@ type of the inter-type declaration). Using the annotation style this aspect can be written: +[source, java] .... @Aspect public class MoodIndicator { @@ -690,6 +726,7 @@ Exploiting this syntax requires the user to obey the rules of pure Java. So references to any targeted type as if it were affected by the Mixin must be made through a cast, like this: +[source, java] .... // this type will be affected by the inter-type declaration as the type pattern matches package org.xyz; @@ -710,6 +747,7 @@ parameter. If it does, then when the factory method is called the parameter will be the object instance for which a delegate should be created: +[source, java] .... @Aspect public class Foo { @@ -725,6 +763,7 @@ It is also possible to make the factory method non-static - and in this case it can then exploit the local state in the surrounding aspect instance, but this is only supported for singleton aspects: +[source, java] .... @Aspect public class Foo { @@ -743,6 +782,7 @@ necessary. In this example the return type of the method extends multiple other interfaces and only a couple of them (I and J) should be mixed into any matching targets: +[source, java] .... // interfaces is an array of interface classes that should be mixed in @DeclareMixin(value="org.xyz..*",interfaces={I.class,J.class}) @@ -777,6 +817,7 @@ Declare annotation is also not supported in the 1.5.0 release of AspectJ Declare precedence _is_ supported. For declare precedence, use the `@DeclarePrecedence` annotation as in the following example: +[source, java] .... public aspect SystemArchitecture { declare precedence : Security*, TransactionSupport, Persistence; @@ -787,6 +828,7 @@ public aspect SystemArchitecture { can be written as: +[source, java] .... @Aspect @DeclarePrecedence("Security*,org.xyz.TransactionSupport,org.xyz.Persistence") @@ -806,6 +848,7 @@ issued. Note that the String must be a literal and not the result of the invocation of a static method for example. +[source, java] .... declare warning : call(* javax.sql..*(..)) && !within(org.xyz.daos..*) : "Only DAOs should be calling JDBC."; @@ -816,6 +859,7 @@ declare error : execution(* IFoo+.*(..)) && !within(org.foo..*) can be written as... +[source, java] .... @DeclareWarning("call(* javax.sql..*(..)) && !within(org.xyz.daos..*)") static final String aMessage = "Only DAOs should be calling JDBC."; @@ -844,6 +888,7 @@ compilation error if another part of the program tries to call them. To provide equivalent support for AspectJ applications compiled with a standard Java 5 compiler, AspectJ 5 defines the `Aspects` utility class: +[source, java] .... public class Aspects { diff --git a/docs/adk15ProgGuideDB/autoboxing.adoc b/docs/adk15ProgGuideDB/autoboxing.adoc index ced4f49fe..8426ea45f 100644 --- a/docs/adk15ProgGuideDB/autoboxing.adoc +++ b/docs/adk15ProgGuideDB/autoboxing.adoc @@ -15,6 +15,7 @@ assignments or method or constructor invocations. For example: +[source, java] .... int i = 0; i = new Integer(5); // auto-unboxing @@ -28,6 +29,7 @@ Integer i2 = 5; // autoboxing Most of the pointcut designators match based on signatures, and hence are unaffected by autoboxing. For example, a call to a method +[source, java] .... public void foo(Integer i); .... @@ -52,6 +54,7 @@ single argument of type `Integer` or of type `int`. Autoboxing and unboxing are also applied when binding pointcut or advice parameters, for example: +[source, java] .... pointcut foo(int i) : args(i); diff --git a/docs/adk15ProgGuideDB/covariance.adoc b/docs/adk15ProgGuideDB/covariance.adoc index fa1a2ddcc..49dda35ee 100644 --- a/docs/adk15ProgGuideDB/covariance.adoc +++ b/docs/adk15ProgGuideDB/covariance.adoc @@ -6,6 +6,7 @@ Java 5 (and hence AspectJ 5) allows you to narrow the return type in an overriding method. For example: +[source, java] .... class A { public A whoAreYou() {...} @@ -26,6 +27,7 @@ designators are extended to match against covariant methods. Given the classes `A` and `B` as defined in the previous section, and the program fragment +[source, java] .... A a = new A(); B b = new B(); @@ -35,12 +37,14 @@ b.whoAreYou(); The signatures for the call join point `a.whoAreYou()` are simply: +[source, java] .... A A.whoAreYou() .... The signatures for the call join point `b.whoAreYou()` are: +[source, java] .... A A.whoAreYou() B B.whoAreYou() diff --git a/docs/adk15ProgGuideDB/enumeratedtypes.adoc b/docs/adk15ProgGuideDB/enumeratedtypes.adoc index 6124a5e55..1149d06f3 100644 --- a/docs/adk15ProgGuideDB/enumeratedtypes.adoc +++ b/docs/adk15ProgGuideDB/enumeratedtypes.adoc @@ -8,6 +8,7 @@ Java 5 (and hence AspectJ 5) provides explicit support for enumerated types. In the simplest case, you can declare an enumerated type as follows: +[source, java] .... public enum ProgrammingLanguages { COBOL, C, JAVA, ASPECTJ diff --git a/docs/adk15ProgGuideDB/generics.adoc b/docs/adk15ProgGuideDB/generics.adoc index 3a00cfc52..cd9c101b1 100644 --- a/docs/adk15ProgGuideDB/generics.adoc +++ b/docs/adk15ProgGuideDB/generics.adoc @@ -15,6 +15,7 @@ the type name. By convention formal type parameters are named using a single letter, though this is not required. A simple generic list type (that can contain elements of any type `E`) could be declared: +[source, java] .... interface List<E> { Iterator<E> iterator(); @@ -63,6 +64,7 @@ parameterized type by specifying a concrete type specfication for each type parameter in the generic type. The following example declares a list of strings and a list of numbers: +[source, java] .... List<String> strings; List<Number> numbers; @@ -78,6 +80,7 @@ written in the Java 5 language would not be expected to use raw types. Parameterized types are instantiated by specifying type parameter values in the constructor call expression as in the following examples: +[source, java] .... List<String> strings = new MyListImpl<String>(); List<Number> numbers = new MyListImpl<Number>(); @@ -135,6 +138,7 @@ The supertype of a generic type `C` is the type given in the extends clause of `C`, or `Object` if no extends clause is present. Given the type declaration +[source, java] .... public interface List<E> extends Collection<E> {... } .... @@ -164,6 +168,7 @@ type `List<? extends Number>`. A static method may be declared with one or more type parameters as in the following declaration: +[source, java] .... static <T> T first(List<T> ts) { ... } .... @@ -174,6 +179,7 @@ not need to be declared as a type parameter of the enclosing type. Non-static methods may also be declared with one or more type parameters in a similar fashion: +[source, java] .... <T extends Number> T max(T t1, T t2) { ... } .... @@ -215,6 +221,7 @@ generic type. Generic methods and constructors, and members defined in generic types, may use type variables as part of their signature. For example: +[source, java] .... public class Utils { @@ -334,6 +341,7 @@ types (methods) and field types (fields). This is achieved by specifying a parameterized type pattern at the appropriate point in the signature pattern. For example, given the class `Foo`: +[source, java] .... public class Foo { @@ -376,6 +384,7 @@ expression `call(* addStrings(List))` and by the expression Remember that any type variable reference in a generic member is _always_ matched by its erasure. Thus given the following example: +[source, java] .... class G<T> { List<T> foo(List<String> ls) { return null; } @@ -396,6 +405,7 @@ different type to `List<String>`, even though a variable of type `List<String>` can be assigned to a variable of type `List<?>`. Given the methods: +[source, java] .... class C { public void foo(List<? extends Number> listOfSomeNumberType) {} @@ -423,6 +433,7 @@ Under certain circumstances a Java 5 compiler is required to create _bridge methods_ that support the compilation of programs using raw types. Consider the types +[source, java] .... class Generic<T> { public T foo(T someObject) { @@ -445,6 +456,7 @@ in `Generic`. This is an example of a case where a Java 5 compiler will create a _bridge method_ in `SubGeneric`. Although you never see it, the bridge method will look something like this: +[source, java] .... public Object foo(Object arg) { Number n = (Number) arg; // "bridge" to the signature defined in this type @@ -464,6 +476,7 @@ It _is_ possible to _call_ a bridge method as the following short code snippet demonstrates. Such a call _does_ result in a call join point for the call to the method. +[source, java] .... SubGeneric rawType = new SubGeneric(); rawType.foo("hi"); // call to bridge method (will result in a runtime failure in this case) @@ -483,6 +496,7 @@ types with the `this()` and `target()` pointcuts. Parameterized types may however be used in conjunction with `args()`. Consider the following class +[source, java] .... public class C { public void foo(List<String> listOfStrings) {} @@ -513,6 +527,7 @@ args(List<Double>):: instance of List at join point method-execution(void C.goo(List<? extends Number>)) [Xlint:uncheckedArgument]"; +[source, java] .... public aspect A { before(List<Double> listOfDoubles) : execution(* C.*(..)) && args(listOfDoubles) { @@ -533,6 +548,7 @@ pointcut associated with the advice will be suppressed. To suppress just an `uncheckedArgument` warning, use the annotation `@SuppressWarnings("uncheckedArgument")` as in the following examples: +[source, java] .... import org.aspectj.lang.annotation.SuppressAjWarnings public aspect A { @@ -560,6 +576,7 @@ following example the advice will match the execution of `bar` but not of `goo` since the signature of `goo` is not matched by the execution pointcut expression. +[source, java] .... public aspect A { before(List<Double> listOfDoubles) : execution(* C.*(List<Double>)) && args(listOfDoubles) { @@ -580,6 +597,7 @@ an `uncheckedArgument` warning. Consider the following program: +[source, java] .... public class C { public static void main(String[] args) { @@ -622,6 +640,7 @@ to a method declared to take a `List<? extends Number>`, matching to only those join points at which the argument is guaranteed to be an instance of `List<? extends Number>`. +[source, java] .... aspect A { before(List<? extends Number> aListOfSomeNumberType) @@ -641,6 +660,7 @@ described for args. For example, the following aspect matches the execution of any method returning a `List`, and makes the returned list available to the body of the advice. +[source, java] .... public aspect A { pointcut executionOfAnyMethodReturningAList() : execution(List *(..)); @@ -661,6 +681,7 @@ we only perform safe operations on the list. Given the class +[source, java] .... public class C { public List<String> foo(List<String> listOfStrings) {...} @@ -676,6 +697,7 @@ bind the return value. It will also run after the execution of `goo` and bind the return value, but gives an `uncheckedArgument` warning during compilation. It does _not_ run after the execution of `foo`. +[source, java] .... public aspect Returning { after() returning(List<Double> listOfDoubles) : execution(* C.*(..)) { @@ -701,6 +723,7 @@ reference, and not a raw type reference. Consider the generic type `Generic` with a pointcut `foo`: +[source, java] .... public class Generic<T> { /** @@ -713,6 +736,7 @@ public class Generic<T> { Such a pointcut must be refered to using a parameterized reference as shown below. +[source, java] .... public aspect A { // runs before the execution of any implementation of a method defined for MyClass @@ -813,6 +837,7 @@ permitted in this parameterization. Given the aspect declaration: +[source, java] .... public abstract aspect ParentChildRelationship<P,C> { ... @@ -843,6 +868,7 @@ within inter-type declarations_. For example, we can declare a `ParentChildRelationship` aspect to manage the bi-directional relationship between parent and child nodes as follows: +[source, java] .... /** * a generic aspect, we've used descriptive role names for the type variables @@ -939,6 +965,7 @@ parent and child. In a compiler implementation managing an abstract syntax tree (AST) in which AST nodes may contain other AST nodes we could declare the concrete aspect: +[source, java] .... public aspect ASTNodeContainment extends ParentChildRelationship<ASTNode,ASTNode> { before(ASTNode parent, ASTNode child) : addingChild(parent, child) { @@ -965,6 +992,7 @@ void setParent(ASTNode parent) In a system managing orders, we could declare the concrete aspect: +[source, java] .... public aspect OrderItemsInOrders extends ParentChildRelationship<Order, OrderItem> { } @@ -991,6 +1019,7 @@ void setParent(Order parent) A second example of an abstract aspect, this time for handling exceptions in a uniform manner, is shown below: +[source, java] .... abstract aspect ExceptionHandling<T extends Throwable> { @@ -1024,6 +1053,7 @@ of the aspect to be designed to work together in a type-safe manner. The following concrete sub-aspect shows how the abstract aspect might be extended to handle `IOExceptions`. +[source, java] .... public aspect IOExceptionHandling extends ExceptionHandling<IOException>{ diff --git a/docs/adk15ProgGuideDB/grammar.adoc b/docs/adk15ProgGuideDB/grammar.adoc index df4b33af8..3e1f345e5 100644 --- a/docs/adk15ProgGuideDB/grammar.adoc +++ b/docs/adk15ProgGuideDB/grammar.adoc @@ -1,6 +1,7 @@ [[grammar]] == A Grammar for the AspectJ 5 Language +[source, text] .... === type patterns === diff --git a/docs/adk15ProgGuideDB/joinpointsignatures.adoc b/docs/adk15ProgGuideDB/joinpointsignatures.adoc index d8bf63c4d..07df75f92 100644 --- a/docs/adk15ProgGuideDB/joinpointsignatures.adoc +++ b/docs/adk15ProgGuideDB/joinpointsignatures.adoc @@ -25,6 +25,7 @@ A kinded pointcut is written using patterns, some of which match based on _signature_, and some of which match based on _modifiers_. For example, in the `call` pointcut designator: +[source, text] .... call(ModifierPattern TypePattern TypePattern.IdPattern(TypePatternList) ThrowsPattern) .... @@ -96,6 +97,7 @@ For a call join point where a call is made to a method `m(parameter_types)` on a target type `T` (where `T` is the static type of the target): +[source, java] .... T t = new T(); t.m("hello"); <= call join point occurs when this line is executed @@ -108,6 +110,7 @@ declare a definition of `m(parameter_types)`, then `R(T)` is the return type in the definition of `m` that `T` inherits. Given the call above, and the definition of `T.m`: +[source, java] .... interface Q { R m(String s); @@ -135,6 +138,7 @@ signature of the call join point, where `R(A)` is the return type of ` Continuing the example from above,we can deduce that +[source, java] .... R' S.m(String) R P.m(String) @@ -151,6 +155,7 @@ different declaring type. Join point signatures for execution join points are defined in a similar manner to signatures for call join points. Given the hierarchy: +[source, java] .... interface Q { R m(String s); @@ -174,6 +179,7 @@ class U extends T { Then the execution join point signatures arising as a result of the call to `u.m("hello")` are: +[source, java] .... R' U.m(String) R' S.m(String) @@ -198,6 +204,7 @@ If `T` does not directly declare a member `f`, then for each super type does declare the member `f`, `F S.f` is a signature of the join point. For example, given the hierarchy: +[source, java] .... class P { F f; @@ -213,6 +220,7 @@ class T extends S { } Then the join point signatures for a field get join point of the field `f` on an object with declared type `T` are: +[source, java] .... F S.f F T.f @@ -263,6 +271,7 @@ chain. For example, given the following types +[source, java] .... public class X { @Foo @@ -293,6 +302,7 @@ point Given the hierarchy +[source, java] .... interface Q { R m(String s); @@ -313,6 +323,7 @@ class T extends S {} and the program fragment: +[source, java] .... P p = new P(); S s = new S(); diff --git a/docs/adk15ProgGuideDB/miscellaneous.adoc b/docs/adk15ProgGuideDB/miscellaneous.adoc index 68c99d2ad..0043c965b 100644 --- a/docs/adk15ProgGuideDB/miscellaneous.adoc +++ b/docs/adk15ProgGuideDB/miscellaneous.adoc @@ -8,6 +8,7 @@ AspectJ 5 is more liberal than AspectJ 1.2.1 in accepting pointcut expressions that bind context variables in more than one location. For example, AspectJ 1.2.1 does not allow: +[source, java] .... pointcut foo(Foo foo) : (execution(* *(..)) && this(foo) ) || (set(* *) && target(foo)); @@ -28,6 +29,7 @@ exceptions. If the exception type specified in a declare soft statement is `RuntimeException` or a subtype of `RuntimeException` then a new XLint warning will be issued: +[source, java] .... declare soft : SomeRuntimeException : execution(* *(..)); @@ -43,6 +45,7 @@ _checked_ exception thrown at a matched join point, where the exception is an instance of the softened exception, will be softened to an `org.aspectj.lang.SoftException`. +[source, java] .... public aspect SoftenExample { declare soft : Exception : execution(* Foo.*(..)); diff --git a/docs/adk15ProgGuideDB/pertypewithin.adoc b/docs/adk15ProgGuideDB/pertypewithin.adoc index db2df9252..6d7b12a0e 100644 --- a/docs/adk15ProgGuideDB/pertypewithin.adoc +++ b/docs/adk15ProgGuideDB/pertypewithin.adoc @@ -5,6 +5,7 @@ AspectJ 5 defines a new per-clause type for aspect instantiation: `pertypewithin`. Unlike the other per-clauses, `pertypewithin` takes a type pattern: +[source, text] .... PerTypeWithin := 'pertypewithin' '(' OptionalParensTypePattern ')' .... @@ -16,6 +17,7 @@ the associated type pattern. Pertypewithin aspects have `aspectOf` and `hasAspect` methods with the following signatures: +[source, java] .... /** * return true if this aspect has an instance associated with @@ -37,6 +39,7 @@ In addition, `pertypewithin` aspects have a `getWithinTypeName` method that can be called to return the package qualified name of the type for which the aspect instance has been created. +[source, java] .... /** * return the package qualified name (eg. com.foo.MyClass) of the type @@ -51,6 +54,7 @@ upon an implicit pointcut condition. In this case, that any join point be `within` the type that the executing aspect is an `aspectOf`. For example, given the aspect definition +[source, java] .... import java.util.*; diff --git a/docs/adk15ProgGuideDB/varargs.adoc b/docs/adk15ProgGuideDB/varargs.adoc index fe1500c1f..bf644ace3 100644 --- a/docs/adk15ProgGuideDB/varargs.adoc +++ b/docs/adk15ProgGuideDB/varargs.adoc @@ -7,6 +7,7 @@ Java 5 (and hence AspectJ 5) allows you to specify methods that take a variable number of arguments of a specified type. This is achieved using an ellipsis (...) in the method signature as shown: +[source, java] .... public void foo(int i, String... strings) { } @@ -21,6 +22,7 @@ A _varargs_ method may be called with zero or more arguments in the variable argument position. For example, given the definition of `foo` above, the following calls are all legal: +[source, java] .... foo(5); foo(5,"One String"); @@ -31,6 +33,7 @@ foo(3,"One String","Two Strings","Three Strings"); A _varargs_ parameter is treated as an array within the defining member. So in the body of `foo` we could write for example: +[source, java] .... public void foo(int i, String... strings) { String[] someStrings = strings; @@ -41,6 +44,7 @@ public void foo(int i, String... strings) { One consequence of this treatment of a varargs parameter as an array is that you can also call a varargs method with an array: +[source, java] .... foo(7,new String[] {"One String","Two Strings"}); .... @@ -63,6 +67,7 @@ annotations (xref:annotations.adoc#signaturePatterns[Signature Patterns]), that `ConstructorPattern` are extended to allow a `varargs` pattern in the last argument position of a method or constructor signature. +[source, text] .... FormalsPattern := '..' (',' FormalsPatternAfterDotDot)? | OptionalParensTypePattern (',' FormalsPattern)* | @@ -93,6 +98,7 @@ initialization(org.xyz.*.new((Foo || Goo)...)):: A variable argument parameter and an array parameter are treated as distinct signature elements, so given the method definitions: +[source, java] .... void foo(String...); void bar(String[]); @@ -110,6 +116,7 @@ array type, as discussed in the introduction to this section. We follow the same convention when binding a varargs parameter via the `args` pointcut designator. Given a method +[source, java] .... public void foo(int i, String... strings) { } @@ -123,6 +130,7 @@ syntax within an args pointcut designator - so you _cannot_ write Binding of a varargs parameter in an advice statement is straightforward: +[source, java] .... before(int i, String[] ss) : call(* foo(int,String...)) && args(i,ss) { // varargs String... argument is accessible in advice body through ss diff --git a/docs/devGuideDB/aj.adoc b/docs/devGuideDB/aj.adoc index 28b50e976..0a7b53108 100644 --- a/docs/devGuideDB/aj.adoc +++ b/docs/devGuideDB/aj.adoc @@ -27,6 +27,7 @@ xref:ltw.adoc#ltw[Load-Time Weaving]. Use ajc to build a library, then weave at load time +[source, text] .... REM compile library ${ASPECTJ_HOME}\bin\ajc.bat -outjar lib\aspects.jar @aspects.lst diff --git a/docs/devGuideDB/ajbrowser.adoc b/docs/devGuideDB/ajbrowser.adoc index 26c762e57..b092ebad5 100644 --- a/docs/devGuideDB/ajbrowser.adoc +++ b/docs/devGuideDB/ajbrowser.adoc @@ -17,9 +17,9 @@ invoke the script in `{aspectj}/bin` (if AspectJ is installed correctly) or by using the `aspectjtools.jar` directly, and specifying no arguments or some number of build configuration files (suffix `.lst`): +[source, text] .... java -jar aspectj1.1/lib/aspectjtools.jar aspectj1.1/doc/examples/spacewar/debug.lst - .... [[ajbrowser-building]] diff --git a/docs/devGuideDB/ajc.adoc b/docs/devGuideDB/ajc.adoc index 02d49b788..fcbc8f492 100644 --- a/docs/devGuideDB/ajc.adoc +++ b/docs/devGuideDB/ajc.adoc @@ -146,6 +146,7 @@ destination directory on the inpath and rebuild.) Emit warnings for any instances of the comma-delimited list of questionable code (eg '-warn:unusedLocals,deprecation'): + +[source, text] .... constructorName method with constructor name packageDefaultMethod attempt to override package-default method @@ -168,6 +169,7 @@ none suppress all compiler warnings -g<:[lines,vars,source]>:: debug attributes level, that may take three forms: + +[source, text] .... -g all debug info ('-g:lines,vars,source') -g:none no debug info @@ -261,6 +263,7 @@ previous releases of AspectJ, see xref:compatibility.adoc#versionCompatibility[V Compile two files: +[source, text] .... ajc HelloWorld.java Trace.java .... @@ -271,6 +274,7 @@ relative to the argfile, and may include other argfiles by @-reference. The following file `sources.lst` contains absolute and relative files and @-references: +[source, text] .... Gui.java /home/user/src/Library.java @@ -283,6 +287,7 @@ view/body/ArrayView.java Compile the files using either the -argfile or @ form: +[source, text] .... ajc -argfile sources.lst ajc @sources.lst @@ -317,6 +322,7 @@ sources with the aspect library. The tracing example is in the AspectJ distribution (\{aspectj}/doc/examples/tracing). This uses the following files: +[source, text] .... aspectj1.1/ bin/ @@ -346,6 +352,7 @@ environment as needed. Setup the path, classpath, and current directory: +[source, text] .... cd examples export ajrt=../lib/aspectjrt.jar @@ -355,18 +362,21 @@ export PATH="../bin:$PATH" Build a read-only tracing library: +[source, text] .... ajc -argfile tracing/tracelib.lst -outjar tracelib.jar .... Build the application with tracing in one step: +[source, text] .... ajc -aspectpath tracelib.jar -argfile tracing/notrace.lst -outjar tracedapp.jar .... Run the application with tracing: +[source, text] .... java -classpath "$ajrt;tracedapp.jar;tracelib.jar" tracing.ExampleMain .... @@ -376,6 +386,7 @@ Build the application with tracing from binaries in two steps: * (a) Build the application classes (using javac for demonstration's sake): + +[source, text] .... mkdir classes javac -d classes tracing/*.java @@ -383,18 +394,21 @@ jar cfM app.jar -C classes . .... * (b) Build the application with tracing: + +[source, text] .... ajc -inpath app.jar -aspectpath tracelib.jar -outjar tracedapp.jar .... Run the application with tracing (same as above): +[source, text] .... java -classpath "$ajrt;tracedapp.jar;tracelib.jar" tracing.ExampleMain .... Run the application without tracing: +[source, text] .... java -classpath "app.jar" tracing.ExampleMain .... @@ -418,6 +432,7 @@ to collect the messages, use `MessageHandler` as your `IMessageHolder`. For example, compile and run the following with `aspectjtools.jar` on the classpath: +[source, java] .... import org.aspectj.bridge.*; import org.aspectj.tools.ajc.Main; @@ -454,6 +469,7 @@ the -XnoInline option.) Probably the only time you may see this format is when you view stack traces, where you may encounter traces of the format +[source, text] .... java.lang.NullPointerException at Main.new$constructor_call37(Main.java;SynchAspect.java[1k]:1030) @@ -461,12 +477,14 @@ java.lang.NullPointerException where instead of the usual +[source, text] .... File:LineNumber .... format, you see +[source, text] .... File0;File1[Number1];File2[Number2] ... :LineNumber .... diff --git a/docs/devGuideDB/ajdb.adoc b/docs/devGuideDB/ajdb.adoc index f1b02d910..4e45cbc80 100644 --- a/docs/devGuideDB/ajdb.adoc +++ b/docs/devGuideDB/ajdb.adoc @@ -133,7 +133,7 @@ Pass a non-standard option to the VM === Capabilities -The AspectJ debugger implements all of `jdb`'s commands. In addition, +The AspectJ debugger implements all of ``jdb``'s commands. In addition, the command `workingdir` allow you to set the AspectJ working directory, and the breakpoint command, `stop on`, has been extended to allow the setting of breakpoint on a source file line. @@ -158,25 +158,25 @@ For this example, we need to set the source path by: ` To view the file to debug, type `list spacewar/Ship.java` which generates the following output: +[source, java] .... -209 void fire() { -210 // firing a shot takes energy -211 if (!expendEnergy(BULLET_ENERGY)) -212 return; -213 -214 //create a bullet object so it doesn't hit the ship that's firing it -215 double xV = getXVel() + BULLET_SPEED * (Math.cos(orientation)); -216 double yV = getYVel() + BULLET_SPEED * (Math.sin(orientation)); -217 -218 // create the actual bullet -219 new Bullet( -220 getGame(), -221 (getXPos() + ((getSize()/2 + 2) * (Math.cos(orientation))) + xV), -222 (getYPos() + ((getSize()/2 + 2) * (Math.sin(orientation))) + yV), -223 xV, -224 yV); -225 } - +/*209*/ void fire() { +/*210*/ // firing a shot takes energy +/*211*/ if (!expendEnergy(BULLET_ENERGY)) +/*212*/ return; +/*213*/ +/*214*/ //create a bullet object so it doesn't hit the ship that's firing it +/*215*/ double xV = getXVel() + BULLET_SPEED * (Math.cos(orientation)); +/*216*/ double yV = getYVel() + BULLET_SPEED * (Math.sin(orientation)); +/*217*/ +/*218*/ // create the actual bullet +/*219*/ new Bullet( +/*220*/ getGame(), +/*221*/ (getXPos() + ((getSize()/2 + 2) * (Math.cos(orientation))) + xV), +/*222*/ (getYPos() + ((getSize()/2 + 2) * (Math.sin(orientation))) + yV), +/*223*/ xV, +/*224*/ yV); +/*225*/ } .... This is different from `jdb` because it allows one to view files before @@ -222,88 +222,88 @@ The following message appears notifying the user that the breakpoint has been noted but will not be set until the class has been loaded by the VM: +[source, text] .... Deferring breakpoint spacewar.Ship.fire() It will be set after the class is loaded. - .... To start Spacewar we type `run spacewar.Game`. When the breakpoint is set, the following message appears: +[source, text] .... Set deferred breakpoint spacewar.Ship.fire() - .... We are notified that we've hit the breakpoint: +[source, text] .... Breakpoint hit: thread="Thread-2", spacewar.Ship.fire(), line=174, bci=0 209 void fire() { - .... The prompt changes to present the thread that has broken, and we can view the current stack with the `where` command, as follows: +[source, text] .... Thread-2[1] where [1] fire (spacewar\Ship.java:209) [2] run (spacewar\Robot.java:100) [3] run [class java.lang.Thread] - .... Next, to stop on line 216 we type `stop on spacewar/Ship.java:216` The following message tells us the breakpoint was set: +[source, text] .... Set breakpoint Ship.java:216 - .... To continue execution, we type `cont` and the breakpoint at line 216 is hit +[source, text] .... Breakpoint hit: thread="Thread-2", spacewar.Ship.fire(), line=216, bci=28 216 double yV = getYVel() + BULLET_SPEED * (Math.sin(orientation)); - .... To view the visible local variables, we type `locals` and ajdb responds with: +[source, text] .... Local variables xV = 12.242462584304468 - .... To change the value of the local variable i to 15, we type `set xV = 16.1` +[source, text] .... Changed 'xV' from '12.242462584304468' to '16.1' - .... To see our changes we can print the value of `i` by the following: +[source, text] .... print xV Value for printing 'xV' = 12.242462584304468 - .... We can now type exit or quit to leave the debugger, and we receive the following message: +[source, text] .... The application has exited. - .... === The AspectJ debugger API @@ -314,13 +314,10 @@ the method `org.aspectj.tools.debugger.Main.main(String[] args)` where `args` are the standard `ajc` command line arguments. This means that an alternative way to run the compiler is -java org.aspectj.tools.debugger.Main - -option - -class - -arguments +[source, text] +.... +java org.aspectj.tools.debugger.Main options class arguments +.... You must additionally include `tools.jar` from your Java developer's kit in your classpath. diff --git a/docs/devGuideDB/ajdee.adoc b/docs/devGuideDB/ajdee.adoc index 9d8963179..ca6df3d66 100644 --- a/docs/devGuideDB/ajdee.adoc +++ b/docs/devGuideDB/ajdee.adoc @@ -123,6 +123,7 @@ enable AspectJ mode on a per-project basis. your `load-path` and are ``required''. This is an example for the 1.0 release: + +[source, text] .... ;; I keep my emacs packages in C:/Emacs (setq load-path @@ -140,7 +141,6 @@ load-path)) (require 'jde) (require 'ajdee) ; can also appear in prj.el - .... . _[Optional]_ add `-emacssym` switch to the `ajc` and `ajc.bat` files in your AspectJ tools installations (in the `/bin` directory). If you @@ -152,6 +152,7 @@ following in your `.emacs` file or in a JDE project file `prj.el` in your project's hierarchy (see the `JDE Project File Name` option for the latter). Here is a simple example: + +[source, text] .... ;; A default version for simple projects, maybe good for ;;; .emacs file. @@ -161,11 +162,11 @@ latter). Here is a simple example: ;; ajc requires all files to be named for a compile '(aspectj-compile-file-specification "*.java")) - .... + Here is an example for spacewar, in `examples/spacewar`. + +[source, text] .... ;;; These options are for the spacewar, in examples/spacewar. (custom-set-variables @@ -180,7 +181,6 @@ Here is an example for spacewar, in `examples/spacewar`. '(jde-compile-option-directory "..") '(jde-run-working-directory "..")) '(jde-run-application-class "spacewar.Game") - .... . _[XEmacs only]_ If you're installing JDE yourself, be sure to closely follow the JDE installation directions for XEmacs, otherwise you may get @@ -207,6 +207,7 @@ for problems not specific to AJDEE's features. * _Symptom_: Get standard speedbar menus in JDE; no annotations display. Message: + +[source, text] .... AspectJ Mode Warning: Can't find declarations file for... .... @@ -235,6 +236,7 @@ AspectJ project's directory (see sample.prj in the distribution). * _Symptom_: Reported bug fixes and new features to AJDEE are not seen, or ajdee.el cannot be found or loaded, with message: + +[source, text] .... Error in init file: File error: "Cannot open load file", "ajdee" .... diff --git a/docs/devGuideDB/ajdoc.adoc b/docs/devGuideDB/ajdoc.adoc index 2a929e3db..6bea2ff16 100644 --- a/docs/devGuideDB/ajdoc.adoc +++ b/docs/devGuideDB/ajdoc.adoc @@ -34,6 +34,7 @@ argfile (`@filename`) conventions as with `ajc`. For example, the following documents all the source files listed in `argfile.lst`, sending the output to the `docDir` output directory. +[source, text] .... ajdoc -d docDir @argfile.lst .... diff --git a/docs/devGuideDB/antsupport.adoc b/docs/devGuideDB/antsupport.adoc index 12de6f296..1bc9b6f70 100644 --- a/docs/devGuideDB/antsupport.adoc +++ b/docs/devGuideDB/antsupport.adoc @@ -38,6 +38,7 @@ in `${ANT_HOME}/lib` where it will be added to the system class path by the ant script. You may specify the task script names directly, or use the "resource" attribute to specify the default names: +[source, xml] .... <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties"/> .... @@ -50,6 +51,7 @@ In Ant 1.6, third-party tasks are declared in their own namespace using spacewar example, if you put the script in the examples directory and `aspectjtools.jar` in the `${ANT_HOME}/lib` directory. +[source, xml] .... <project name="aspectj-ant1.6" default="spacewar" xmlns:aspectj="antlib:org.aspectj" basedir="."> @@ -340,6 +342,7 @@ elements; these are `sourceroots`, `argfiles`, `injars`, `inpath`, `classpath`, `bootclasspath`, `forkclasspath`, and `aspectpath`. In all cases, these may be specified as nested elements, something like this: +[source, xml] .... <iajc {attributes..} /> <{name}> @@ -354,6 +357,7 @@ cases, these may be specified as nested elements, something like this: As with other Path-like structures, they may be defined elsewhere and specified using the refid attribute: +[source, xml] .... <path id="aspect.path"> <pathelement path="${home}/lib/persist.jar"/> @@ -369,6 +373,7 @@ specified using the refid attribute: The task also supports an attribute `{name}ref` for each such parameter. E.g., for `aspectpath`: +[source, xml] .... <iajc {attributes..} aspectpathref="aspect.path"/> .... @@ -379,6 +384,7 @@ E.g., for `aspectpath`: A minimal build script defines the task and runs it, specifying the sources: +[source, xml] .... <project name="simple-example" default="compile" > <taskdef @@ -410,6 +416,7 @@ When this target is built, the compiler will build once and then wait for input from the user. Messages are printed as usual. When the user has quit, then this runs the application. +[source, xml] .... <target name="build-test" > <iajc outjar="${home.dir}/output/application.jar" @@ -453,6 +460,7 @@ case where no files have been updated, there is no reason to recompile sources. One way to implement that is with an explicit dependency check using the uptodate task: +[source, xml] .... <target name="check.aspects.jar"> <uptodate property="build.unnecessary" @@ -512,6 +520,7 @@ example, the call below passes all out-of-date source files in the `src/org/aspectj` subdirectories to the `ajc` command along with the destination directory: +[source, text] .... -- command: @@ -525,6 +534,7 @@ destination directory: To pass ajc-specific arguments, use a compilerarg entry. +[source, text] .... -- command @@ -598,6 +608,7 @@ This tells the compiler adapter to delete all .class files in the destination directory and re-execute the javac task so javac can recalculate the list of source files. e.g., + +[source, text] .... Ant -Dbuild.compiler=org.aspectj.tools.ant.taskdefs.Ajc11CompilerAdapter -Dbuild.compiler.clean=anything ... @@ -746,7 +757,7 @@ This task forms an implicit FileSet and supports all attributes of `<exclude>`, and `<patternset>` elements. These can be used to specify source files. -`ajc`'s `srcdir`, `classpath`, `bootclasspath`, `extdirs`, and `jvmarg` +``ajc``'s `srcdir`, `classpath`, `bootclasspath`, `extdirs`, and `jvmarg` attributes are path-like structures and can also be set via nested `<src>`, `<classpath>`, `<bootclasspath>`, `<extdirs>`, and `<jvmargs>` elements, respectively. @@ -758,6 +769,7 @@ Following is a declaration for the ajc task and a sample invocation that uses the ajc compiler to compile the files listed in `default.lst` into the dest dir: +[source, xml] .... <project name="example" default="compile" > <taskdef name="ajc" @@ -782,6 +794,7 @@ the dest dir: This build script snippet +[source, xml] .... <ajc srcdir="${src}" destdir="${build}" @@ -796,6 +809,7 @@ are included. This next example +[source, xml] .... <ajc srcdir="${src}" destdir="${build}" diff --git a/docs/devGuideDB/aspectj-mode.adoc b/docs/devGuideDB/aspectj-mode.adoc index e4d09acdd..4c585ed2c 100644 --- a/docs/devGuideDB/aspectj-mode.adoc +++ b/docs/devGuideDB/aspectj-mode.adoc @@ -103,11 +103,11 @@ initialization file `sample.emacs` in the distribution. . The files in this package need to be in the load-path and ``required''. For example, for the 1.0 release: + +[source, text] .... ;; I keep my emacs packages in C:/Emacs (setq load-path (cons "C:/Emacs/aspectj-emacsMode-1.0" load-path)) (require 'aspectj-mode) - .... . _[Optional]_ add `-emacssym` switch to the `ajc` and `ajc.bat` files in your AspectJ tools installations (in the `/bin` directory). If you @@ -130,6 +130,7 @@ given in the file `sample.emacs` in the distribution. * _Symptom_: No annotations show. Message: + +[source, text] .... AspectJ Mode Warning: Can't find declarations file for... .... @@ -160,6 +161,7 @@ menu. * _Symptom_: Reported bug fixes and new features to aspectj-mode are not seen, or aspectj-mode.el cannot be found or loaded, with message: + +[source, text] .... Error in init file: File error: "Cannot open load file", "aspectj-mode" .... diff --git a/docs/devGuideDB/ltw.adoc b/docs/devGuideDB/ltw.adoc index ac58dfca7..7b216ba76 100644 --- a/docs/devGuideDB/ltw.adoc +++ b/docs/devGuideDB/ltw.adoc @@ -125,6 +125,7 @@ Aspects defined in this way must extend an abstract aspect visible to the weaver. The abstract aspect may define abstract pointcuts (but not abstract methods). The following example shows a simple aop.xml file: +[source, xml] .... <aspectj> @@ -260,6 +261,7 @@ pointcuts at deployment time, and also gives control over precedence through the `precedence` attribute of the `concrete-aspect` XML element. Consider the following: +[source, java] .... package mypack; @@ -272,13 +274,14 @@ public abstract class AbstractAspect { @Before("scope() && execution(* *..doSome(..))") public void before(JoinPoint jp) { - .... + // ... } } .... This aspect is equivalent to the following in code style: +[source, java] .... package mypack; @@ -288,7 +291,7 @@ public abstract aspect AbstractAspect { abstract pointcut scope(); before() : scope() && execution(* *..doSome(..)) { - .... + // ... } } .... @@ -318,6 +321,7 @@ If more complex aspect inheritance is required use regular aspect inheritance instead of XML. The following XML definition shows a valid concrete sub-aspect for the abstract aspects above: +[source, xml] .... <aspectj> <aspects> @@ -339,6 +343,7 @@ aspect instance(s) (depending on the perclause of the aspect it extends) you have to use the helper API `org.aspectj.lang.Aspects.aspectOf(..)` as in: +[source, java] .... // exception handling omitted Class myConcreteAspectClass = Class.forName("mypack.__My__AbstractAspect"); @@ -359,6 +364,7 @@ abstract aspect. It is therefore possible to use the `concrete-aspect` element without the `extends` attribute and without any `pointcut` nested elements, just a `precedence` attribute. Consider the following: +[source, xml] .... <aspectj> <aspects> @@ -459,6 +465,7 @@ weaving configuration files. When using Java 5 the JVMTI agent can be used by starting the JVM with the following option (adapt according to the path to aspectjweaver.jar): +[source, text] .... -javaagent:pathto/aspectjweaver.jar .... diff --git a/docs/developer/amcDesignNotes.adoc b/docs/developer/amcDesignNotes.adoc index 47cf6960b..77b0dd2d9 100644 --- a/docs/developer/amcDesignNotes.adoc +++ b/docs/developer/amcDesignNotes.adoc @@ -4,6 +4,7 @@ _Last updated: 2004-03-15 by acolyer_ == How Compilation Progresses in the JDT +[source, text] .... Compiler.compile(ICompilationUnit[] sourceUnits) { @@ -35,6 +36,7 @@ passed to the compiler, and the code generation phase is optional == How (batch) Compilation Progresses in AspectJ 1.1.x +[source, text] .... AjBuildManager.doBuild() { @@ -90,6 +92,7 @@ that do different things). This simple model ignores aspectpath, inpath, injars, outjar, sourceDirs for now. +[source, text] .... Compiler.compile(ICompilationUnit[] sourceUnits) { diff --git a/docs/developer/compiler-weaver/index.adoc b/docs/developer/compiler-weaver/index.adoc index 1443370f1..817656e35 100644 --- a/docs/developer/compiler-weaver/index.adoc +++ b/docs/developer/compiler-weaver/index.adoc @@ -65,6 +65,7 @@ code generation Let's trace the following example program through the compiler. +[source, java] .... package example.parse.tree; @@ -99,6 +100,7 @@ image:top-tree.gif[image] Let's look more closely at the pointcut declaration: +[source, java] .... pointcut entries(Main o): execution(void doit()) && this(o); .... @@ -114,6 +116,7 @@ information might be needed to implement a declare soft. Next we look at the processing for an advice declaration: +[source, java] .... before(Main o): entries(o) { o.counter++; @@ -262,6 +265,7 @@ failures, resolve them with the AspectJ developers before moving on. {empty}a. Create a new file in tests/design/pcds/Throw.java +[source, java] .... import org.aspectj.testing.Tester; @@ -290,6 +294,7 @@ aspect A { {empty}b. Create a temporary test harness file to run just this test in myTests.xml +[source, xml] .... <!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd"> <suite> @@ -303,6 +308,7 @@ myTests.xml {empty}c. Run this test using the harness. You should see: +[source, text] .... about to execute: execution(void Throws.willThrow()) about to execute: call(java.lang.RuntimeException(String)) @@ -314,6 +320,7 @@ PASS Suite.Spec(c:\aspectj\eclipse\tests) 1 tests (1 passed) 2 seconds Modify runtime/org.aspectj.lang/JoinPoint.java to add a name for the Throw shadow kind. +[source, java] .... static String THROW = "throw"; .... @@ -328,6 +335,7 @@ This is because the throw bytecode in Java operates on a single argument that is a Throwable which must be the top element on the stack. This argument is removed from the stack by the bytecode. +[source, java] .... public static final Kind Throw = new Kind(JoinPoint.THROW, 12, true); .... @@ -335,6 +343,7 @@ public static final Kind Throw = new Kind(JoinPoint.THROW, 12, true); We also modify the neverHasTarget method to include the Throw kind because in Java there is no target for the throwing of an exception. +[source, java] .... public boolean neverHasTarget() { return this == ConstructorCall @@ -348,6 +357,7 @@ public boolean neverHasTarget() { In the read method on Shadow.Kind, add another case to read in our new Shadow.Kind. +[source, java] .... case 12: return Throw; .... @@ -357,6 +367,7 @@ case 12: return Throw; Modify weaver/org.aspectj.weaver.bcel/BcelClassWeaver.java to recognize this new joinpoint kind. In the method +[source, java] .... private void match( LazyMethodGen mg, @@ -368,6 +379,7 @@ private void match( Add a test for this instruction, i.e. +[source, java] .... } else if (i == InstructionConstants.ATHROW) { match(BcelShadow.makeThrow(world, mg, ih, enclosingShadow), @@ -378,6 +390,7 @@ Add a test for this instruction, i.e. Then, modify BcelShadow.java to create this new kind of join point shadow: +[source, java] .... public static BcelShadow makeThrow( BcelWorld world, @@ -408,6 +421,7 @@ public static BcelShadow makeThrow( Finally modify weaver/org.aspectj.weaver/Member.java to generate the needed signature +[source, java] .... public static Member makeThrowSignature(TypeX inType, TypeX throwType) { return new Member( @@ -421,6 +435,7 @@ public static Member makeThrowSignature(TypeX inType, TypeX throwType) { Run the proto test again and you should see: +[source, text] .... about to execute: execution(void Throws.willThrow()) about to execute: call(java.lang.RuntimeException(String)) @@ -439,6 +454,7 @@ part of the clean-up. For now, let's go on with the interesting parts. Add a second piece of before advice to the test aspect A: +[source, java] .... before(): throw(Throwable) { System.out.println("about to throw: " + thisJoinPoint); @@ -448,6 +464,7 @@ before(): throw(Throwable) { When we run the test again we'll get a long error message from the harness. The interesting part of the message is the following: +[source, text] .... [ 0] [error 0]: error can't find referenced pointcut at C:\aspectj\eclipse\tests\design\pcds\Throws.java:23:0 .... @@ -470,6 +487,7 @@ Modify the parseSinglePointcut method in weaver/org.aspectj.weaver.patterns/PatternParser.java to add one more else if clause for the throw pcd: +[source, java] .... } else if (kind.equals("throw")) { parseIdentifier(); eat("("); @@ -485,6 +503,7 @@ else if clause for the throw pcd: Modify the matches method in weaver/org.aspectj.weaver.patterns/SignaturePattern.java to add: +[source, java] .... if (kind == Member.HANDLER) { return parameterTypes.matches(world.resolve(sig.getParameterTypes()), @@ -494,6 +513,7 @@ if (kind == Member.HANDLER) { Run the proto test again and you should see: +[source, text] .... about to execute: execution(void Throws.willThrow()) about to execute: call(java.lang.RuntimeException(String)) @@ -513,6 +533,7 @@ case. Modify our test aspect A to be the following. In addition to removing the overly generic withincode pcd, this change also prints the actual object that is about to be thrown: +[source, java] .... aspect A { before(Throwable t): throw(*) && args(t) { @@ -523,6 +544,7 @@ aspect A { When we run the test again we should see the output below: +[source, text] .... about to throw: 'java.lang.RuntimeException: expected exception' at throw(catch(Throwable)) PASS Suite.Spec(c:\aspectj\eclipse\tests) 1 tests (1 passed) 1 seconds @@ -546,6 +568,7 @@ exception thrown to be 'Throwable'. Can we set this to be more accurate? Looking at the source code, it seems easy to identify the static type of the exception that is thrown: +[source, java] .... throw new RuntimeException("expected exception"); .... @@ -585,6 +608,7 @@ thrown, we need to fix the parser for the throw pcd to remove this information. We'll fix the PatternParser code that we added in step 1.6 to read as follows: +[source, java] .... } else if (kind.equals("throw")) { parseIdentifier(); eat("("); @@ -602,6 +626,7 @@ before. To make this work we have a set of things to do. First, let's create this new kind in org.aspectj.weaver.Member. Find where the HANDLER kind is defined there, and add a corresponding throw kind: +[source, java] .... public static final Kind THROW = new Kind("THROW", 8); .... @@ -610,6 +635,7 @@ We also need to fix the serialization kind in Member.Kind.read(DataInputStream) just above this constant list to add a case for this new kind: +[source, java] .... case 8: return THROW; .... @@ -617,6 +643,7 @@ case 8: return THROW; Still in this file, we also need to fix Member.makeThrowSignature to use this new kind: +[source, java] .... public static Member makeThrowSignature(TypeX inType, TypeX throwType) { return new ResolvedMember( @@ -631,6 +658,7 @@ public static Member makeThrowSignature(TypeX inType, TypeX throwType) { If you run the test now you'll get an error from the parser reminding us that the throw pcd now doesn't accept a type pattern: +[source, text] .... ------------ FAIL: simple throw join point() ... @@ -642,6 +670,7 @@ FAIL Suite.Spec(c:\aspectj\eclipse\tests) 1 tests (1 failed) 1 seconds This is an easy fix to the test case as we modify our pcd for the new syntax in the aspect A in our Throws.java test code: +[source, java] .... before(Throwable t): throw() && args(t) { .... @@ -649,6 +678,7 @@ before(Throwable t): throw() && args(t) { Now when we run the test case it looks like everything's fixed and we're passing: +[source, text] .... PASS Suite.Spec(c:\aspectj\eclipse\tests) 1 tests (1 passed) 2 seconds .... @@ -664,6 +694,7 @@ that by adding code that notes when the advice runs and then checks for this event. This code uses the Tester.event and Tester.checkEvent methods: +[source, java] .... import org.aspectj.testing.Tester; @@ -694,6 +725,7 @@ aspect A { Now when we run our test case it will fail. This failure is good because we're not matching the throw join point anymore. +[source, text] .... ------------ FAIL: simple throw join point() ... @@ -711,6 +743,7 @@ use combinations with other pcds to narrow their matches. So, find the line for kind == Member.ADVICE and add the same line below it for Member.THROW. +[source, java] .... if (kind == Member.ADVICE) return true; if (kind == Member.THROW) return true; @@ -727,6 +760,7 @@ kind of printing back on the see what's happening. If you uncomment to System.out.println in the test aspect A and rerun the test, you won't be very happy with the results: +[source, text] .... ------------ FAIL: simple throw join point() ... @@ -752,6 +786,7 @@ signature, these classes are extremely simple. Nevertheless, we have to build them. Notice that when we add new source files to the system we need to include the standard eclipse EPL license header. +[source, java] .... /* ******************************************************************* * Copyright (c) 2006 Contributors. @@ -771,6 +806,7 @@ import org.aspectj.lang.Signature; public interface ThrowSignature extends Signature { } .... +[source, java] .... /* ******************************************************************* * Copyright (c) 2006 Contributors. @@ -807,6 +843,7 @@ To finish up our work in the runtime module, we need to extend org.aspectj.runtime.reflect.Factory to add a factory method for this new signature kind: +[source, java] .... public ThrowSignature makeThrowSig(String stringRep) { ThrowSignatureImpl ret = new ThrowSignatureImpl(stringRep); @@ -822,6 +859,7 @@ first place. First let's add a method to create a string for the throw signature. This is a very simple method copied from the other create*SignatureString methods. +[source, java] .... private String getThrowSignatureString(World world) { StringBuffer buf = new StringBuffer(); @@ -836,6 +874,7 @@ private String getThrowSignatureString(World world) { Now we need to modify three methods to add cases for the new Member.THROW kind. First, Member.getSignatureMakerName add: +[source, java] .... } else if (kind == THROW) { return "makeThrowSig"; @@ -843,6 +882,7 @@ Member.THROW kind. First, Member.getSignatureMakerName add: Next, to Member.getSignatureType add: +[source, java] .... } else if (kind == THROW) { return "org.aspectj.lang.reflect.ThrowSignature"; @@ -850,6 +890,7 @@ Next, to Member.getSignatureType add: Finally, to Member.getSignatureString add: +[source, java] .... } else if (kind == THROW) { return getThrowSignatureString(world); @@ -859,6 +900,7 @@ With all of these changes in place we should have working code for thisJoinPoint reflection using our new join point and signature kinds. Rerun the test to confirm: +[source, text] .... about to throw: 'java.lang.RuntimeException: expected exception' at throw(throw) PASS Suite.Spec(c:\aspectj\eclipse\tests) 1 tests (1 passed) 1 seconds @@ -869,6 +911,7 @@ PASS Suite.Spec(c:\aspectj\eclipse\tests) 1 tests (1 passed) 1 seconds Modify the before advice to include at least minimal checks of the new reflective information: +[source, java] .... before(Throwable t): throw() && args(t) { Tester.event("before throw"); @@ -908,6 +951,7 @@ tests. You should expect to see at least one other test case fail when you run ajcTests.xml. Here's the failure message: +[source, text] .... ------------ FAIL: validate (enclosing) join point and source locations() ... @@ -948,6 +992,7 @@ that the only occurence of throw is just before the handler for catch(Error) and right after the call to new Error. We should add our new expected event between these two: +[source, text] .... , "before AllTargetJoinPoints call(java.lang.Error(String))" , "before AllTargetJoinPoints throw(throw)" // added for new throw join point @@ -964,6 +1009,7 @@ to make sure that the new join point kind is compatible with all 5 kinds of advice. Let's extend our current simple Throws test to check for before and the three kinds of after advice: +[source, java] .... import org.aspectj.testing.Tester; @@ -1019,6 +1065,7 @@ point kind work for before and all three kinds of after advice. Let's create a new test case to see how this new join point interacts with around advice. +[source, java] .... import org.aspectj.testing.Tester; @@ -1050,6 +1097,7 @@ aspect A { When we run this test case we get a very unpleasant result: +[source, text] .... ------------ FAIL: simple throw join point with around() ... @@ -1080,6 +1128,7 @@ implemented in the org.aspectj.weaver.Shadow.match(Shadow, World) method. We can add our new rule at the beginning of the if(kind == AdviceKind.Around) block: +[source, java] .... } else if (kind == AdviceKind.Around) { if (shadow.getKind() == Shadow.Throw) { @@ -1093,6 +1142,7 @@ AdviceKind.Around) block: Now if we rerun our test we'll see errors telling us that around is prohibited on throw join points: +[source, text] .... ------------ FAIL: simple throw join point with around() ... @@ -1106,6 +1156,7 @@ To finish this test case up we need to modify the specification to be looking for these errors as the correct behavior. This will produce the following specification: +[source, xml] .... <ajc-test dir="design/pcds" title="simple throw join point with around"> diff --git a/docs/dist/LICENSE-AspectJ.adoc b/docs/dist/LICENSE-AspectJ.adoc index 9a2a163d6..9b874e58f 100644 --- a/docs/dist/LICENSE-AspectJ.adoc +++ b/docs/dist/LICENSE-AspectJ.adoc @@ -50,6 +50,7 @@ http://asm.objectweb.org/download/. The ASM license is available at http://asm.objectweb.org/license.html. The license is also reproduced here: +[source, text] .... Copyright (c) 2000-2005 INRIA, France Telecom All rights reserved. diff --git a/docs/dist/doc/README-11.adoc b/docs/dist/doc/README-11.adoc index 377d18588..1843f38be 100644 --- a/docs/dist/doc/README-11.adoc +++ b/docs/dist/doc/README-11.adoc @@ -288,22 +288,21 @@ 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(..)); +public class Client { + public static void main(String[] args) { + Client c = new Client(); + } +} - before(): myConstructor() { - System.err.println("Entering Constructor"); - } - } +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 @@ -317,25 +316,24 @@ 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()); +public class Client { + public static int foo() { return 3; } + public static void main(String[] args) { + Client c = new Client(); + } +} - before(): myConstructor() { - System.err.println("Entering Constructor"); - } - } +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 @@ -356,29 +354,29 @@ 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*); +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 +ThrowsClausePattern: + ThrowsClausePatternItem ("," ThrowsClausePatternItem)* +ThrowsClausePatternItem: + ["!"] TypeNamePattern .... A ThrowsClausePattern matches the ThrowsClause of any code member @@ -398,12 +396,12 @@ 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]*/ 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 @@ -439,31 +437,31 @@ 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()); - } +/** 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; - /* We can use a special constructor to initialize the log field */ - public Logger(Class myType) { - this.log = new Log(myType); - } + /* 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()); } - /** External code could use aspectOf to get at the log, i.e. */ - Log l = Logger.aspectOf(com.bigboxco.Foo.class).log; + /* 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 @@ -481,23 +479,23 @@ 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() { ... } - } - +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() { ... } - } - +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 @@ -531,18 +529,19 @@ 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()); - } - } +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 @@ -579,10 +578,10 @@ 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++; } - +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 @@ -604,25 +603,25 @@ 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"); - } - }); - } +[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 @@ -642,9 +641,9 @@ 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..*); - +pointcut oneOfMine(): this(com.bigboxco..*); .... The only way to implement this kind of matching in a modular way would @@ -653,27 +652,27 @@ 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); - +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; - ... - } +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 @@ -696,9 +695,9 @@ deprecated by the compiler, and will always return 0. AspectJ 1.1 has a new declare form: +[source, java] .... - declare precedence ":" TypePatternList ";" - +declare precedence ":" TypePatternList ";" .... This is used to declare advice ordering constraints on join points. For @@ -707,9 +706,9 @@ 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+, *; - +declare precedence: *..*Security*, Logging+, *; .... In the TypePatternList, the wildcard * means "any type not matched by @@ -720,19 +719,19 @@ another type in the declare precedence". 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 - +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; - +declare precedence: B, A; +declare precedence: A, B; .... And a system in which both constraints are active may also be legal, so @@ -743,33 +742,33 @@ idiom that can be used to enforce that A and B are strongly independent. Consider the following library aspects: +[source, java] .... - abstract aspect Logging { - abstract pointcut logged(); +abstract aspect Logging { + abstract pointcut logged(); - before(): logged() { - System.err.println("thisJoinPoint: " + thisJoinPoint); - } - } - - aspect MyProfiling { - abstract pointcut profiled(); + before(): logged() { + System.err.println("thisJoinPoint: " + thisJoinPoint); + } +} - 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); - } +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 @@ -780,9 +779,9 @@ 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; - +declare precedence: MyLogging, MyProfiling; .... ===== Changing order of advice for sub-aspects @@ -791,23 +790,23 @@ 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(): ... ; +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 - } - } + 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 @@ -827,10 +826,10 @@ 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 - +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 @@ -848,10 +847,10 @@ 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 - +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 @@ -869,9 +868,9 @@ files on the command line, and the -sourceroots 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 - +ajc -injars myBase.jar MyTracing.java -outjar myTracedBase.jar .... No meta information is placed in the output jar file. @@ -920,17 +919,17 @@ The binary forms of this aspects will be untouched. The 1.0 implementation of AspectJ, when given: +[source, java] .... - class MyRunnable implements Runnable { - public void run() { ... } - } +class MyRunnable implements Runnable { + public void run() { /*...*/ } +} - aspect A { - call(): (void run()) && target(MyRunnable) { - // do something here - } +aspect A { + call(): (void run()) && target(MyRunnable) { + // do something here } - +} .... would cause A's advice to execute even when, say, java.lang.Thread @@ -1117,14 +1116,14 @@ 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 - } +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 @@ -1154,25 +1153,25 @@ 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 {} +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 +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; - } +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 @@ -1198,27 +1197,27 @@ 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(); - } +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; - } +int around(): set(int Foo.i) { + if (theSetIsAllowed()) { + return proceed(); + } else { + return Foo.i; } - +} .... But there was definitely a short disconnect. @@ -1267,6 +1266,7 @@ implementation. 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) { @@ -1277,6 +1277,7 @@ class Foo { is approximately the same at runtime as +[source, java] .... class Foo { String makeEmphatic(String s) { @@ -1292,6 +1293,7 @@ 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) { @@ -1303,6 +1305,7 @@ class A { may result in a stack overflow error, since the argument to println is really +[source, java] .... new StringBuffer("entering with ").append(i).toString() .... @@ -1310,6 +1313,7 @@ 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) @@ -1320,6 +1324,7 @@ call(* *(int)) && args(i) && !target(StringBuffer) Consider the following aspect +[source, java] .... public aspect SwingCalls { @@ -1333,9 +1338,10 @@ public aspect SwingCalls { And then consider the two statements +[source, java] .... - JFrame frame = new JFrame(); - frame.setTitle("Title"); +JFrame frame = new JFrame(); +frame.setTitle("Title"); .... According to the Java Language Specification version 2, the call to diff --git a/docs/dist/doc/README-12.adoc b/docs/dist/doc/README-12.adoc index 95775b45a..0b66b6556 100644 --- a/docs/dist/doc/README-12.adoc +++ b/docs/dist/doc/README-12.adoc @@ -139,21 +139,19 @@ returns false. Consider a simple tracing aspect as follows: +[source, java] .... +public aspect Tracing { - public aspect Tracing { + public static boolean enabled = false; - public static boolean enabled = false; + pointcut toBeTraced() : execution(* *(..)) || execution(new(..)); - pointcut toBeTraced() : execution(* *(..)) || execution(new(..)); - - before() : toBeTraced() && if(enabled) { - Object[] args = thisJoinPoint.getArgs(); - // format args and print out entry trace record etc.... - } + before() : toBeTraced() && if(enabled) { + Object[] args = thisJoinPoint.getArgs(); + // format args and print out entry trace record etc.... } - - +} .... The most important consideration is the system overhead when tracing is @@ -189,20 +187,20 @@ were passed to the compiler. For example, an error message arising as a result of a `declare error` statement might look as follows under AspectJ 1.1.1: +[source, text] .... - BadClass.java:6 should not be calling bad methods - +BadClass.java:6 should not be calling bad methods .... whereas in AspectJ 1.2 you will see: +[source, text] .... - BadClass.java:6 error should not be calling bad methods - new C().bad(); - ^^^^^^^^^^^^^^ - method-call(void C.bad()) - see also: DeclareError.java:5 - +BadClass.java:6 error should not be calling bad methods +new C().bad(); +^^^^^^^^^^^^^^ + method-call(void C.bad()) + see also: DeclareError.java:5 .... There are four new things to note about this error message. Firstly, @@ -220,13 +218,13 @@ When source code is not available, the messages show the binary input source (class file or jar file) in which the error or warning was detected: +[source, text] .... - BadClass.java:6 error should not be calling bad methods - (no source information available) - method-call(void C.bad()) - see also: C:\...\DeclareError.java:5 - see also: C:\...\bin-input.jar - +BadClass.java:6 error should not be calling bad methods +(no source information available) + method-call(void C.bad()) + see also: C:\...\DeclareError.java:5 + see also: C:\...\bin-input.jar .... This error message tells us that `BadClass.class` contained in a jar on @@ -240,38 +238,36 @@ line 5 of the file `DeclareError.java`. Consider the program: +[source, java] .... - - 01 class A { - 02 public void doIt() {...}; - 03 } - 04 - 05 class B extends A { - 06 public void doThisToo() {...}; - 07 } - 08 - 09 - 10 public class CallsAandB { - 11 - 12 public static void main(String[] args) { - 13 B b = new B(); - 14 A bInDisguise = new B(); - 15 - 16 b.doIt(); // AspectJ 1.2 matches here - 17 bInDisguise.doIt(); // this is never matched - 18 } - 19 - 20 } - 21 - 22 aspect CallPCDMatchingExample { - 23 - 24 before() : call(* B.doIt(..)) { - 25 System.out.println("About to call B.doIt(...)"); - 26 } - 27 - 28 } - - +/*01*/ class A { +/*02*/ public void doIt() {...}; +/*03*/ } +/*04*/ +/*05*/ class B extends A { +/*06*/ public void doThisToo() {...}; +/*07*/ } +/*08*/ +/*09*/ +/*10*/ public class CallsAandB { +/*11*/ +/*12*/ public static void main(String[] args) { +/*13*/ B b = new B(); +/*14*/ A bInDisguise = new B(); +/*15*/ +/*16*/ b.doIt(); // AspectJ 1.2 matches here +/*17*/ bInDisguise.doIt(); // this is never matched +/*18*/ } +/*19*/ +/*20*/ } +/*21*/ +/*22*/ aspect CallPCDMatchingExample { +/*23*/ +/*24*/ before() : call(* B.doIt(..)) { +/*25*/ System.out.println("About to call B.doIt(...)"); +/*26*/ } +/*27*/ +/*28*/ } .... Because the static type of `bInDisguise` is `A` (line 14), the call on @@ -287,19 +283,14 @@ designator does not match at a join point, and a user may have expected it to. Compiling the above program using AspectJ 1.2 produces the following compiler output: +[source, text] .... +CallsAandB.java:24 warning does not match because declaring type is A, if match desired use target(B) [Xlint:unmatchedSuperTypeInCall] +before() : call(* B.doIt(..)) { + ^^^^^^^^^^^^^^^ + see also: CallsAandB.java:17 - - CallsAandB.java:24 warning does not match because declaring type is A, if match desired use target(B) [Xlint:unmatchedSuperTypeInCall] - before() : call(* B.doIt(..)) { - ^^^^^^^^^^^^^^^ - see also: CallsAandB.java:17 - - - 1 warning - - - +1 warning .... The warning is telling us that the call pointcut associated with the @@ -385,38 +376,36 @@ Consider again the following example program which illustrates the differences in join point matching with the `call` pointcut designator between 1.4 and 1.3 compliance levels. +[source, java] .... - - 01 class A { - 02 public void doIt() {...}; - 03 } - 04 - 05 class B extends A { - 06 public void doThisToo() {...}; - 07 } - 08 - 09 - 10 public class CallsAandB { - 11 - 12 public static void main(String[] args) { - 13 B b = new B(); - 14 A bInDisguise = new B(); - 15 - 16 b.doIt(); // AspectJ 1.2 matches here - 17 bInDisguise.doIt(); // this is never matched - 18 } - 19 - 20 } - 21 - 22 aspect CallPCDMatchingExample { - 23 - 24 before() : call(* B.doIt(..)) { - 25 System.out.println("About to call B.doIt(...)"); - 26 } - 27 - 28 } - - +/*01*/ class A { +/*02*/ public void doIt() {...}; +/*03*/ } +/*04*/ +/*05*/ class B extends A { +/*06*/ public void doThisToo() {...}; +/*07*/ } +/*08*/ +/*09*/ +/*10*/ public class CallsAandB { +/*11*/ +/*12*/ public static void main(String[] args) { +/*13*/ B b = new B(); +/*14*/ A bInDisguise = new B(); +/*15*/ +/*16*/ b.doIt(); // AspectJ 1.2 matches here +/*17*/ bInDisguise.doIt(); // this is never matched +/*18*/ } +/*19*/ +/*20*/ } +/*21*/ +/*22*/ aspect CallPCDMatchingExample { +/*23*/ +/*24*/ before() : call(* B.doIt(..)) { +/*25*/ System.out.println("About to call B.doIt(...)"); +/*26*/ } +/*27*/ +/*28*/ } .... When this program is compiled with AspectJ 1.2 using the default @@ -492,20 +481,21 @@ sample application that demonstrates these capabilities. Following the instructions in the `README` file in that directory, running "`aj tracing.ExampleMain`" with `ASPECTPATH` unset produces the output: +[source, text] .... - c1.perimeter() = 12.566370614359172 - c1.area() = 12.566370614359172 - s1.perimeter() = 4.0 - s1.area() = 1.0 - c2.distance(c1) = 4.242640687119285 - s1.distance(c1) = 2.23606797749979 - s1.toString(): Square side = 1.0 @ (1.0, 2.0) - +c1.perimeter() = 12.566370614359172 +c1.area() = 12.566370614359172 +s1.perimeter() = 4.0 +s1.area() = 1.0 +c2.distance(c1) = 4.242640687119285 +s1.distance(c1) = 2.23606797749979 +s1.toString(): Square side = 1.0 @ (1.0, 2.0) .... If you set `ASPECTPATH` to include `../jars/tracingLib.jar`, and run "`aj tracing.ExampleMain`" again, the output will be: +[source, text] .... --> tracing.TwoDShape(double, double) <-- tracing.TwoDShape(double, double) @@ -542,7 +532,6 @@ s1.area() = 1.0 <-- double tracing.TwoDShape.getY() <-- double tracing.TwoDShape.distance(TwoDShape) etc... - .... The scripts only support JDK 1.4 and above - attempting to use them with diff --git a/docs/dist/doc/README-121.adoc b/docs/dist/doc/README-121.adoc index 74d4b3030..fd082ebcb 100644 --- a/docs/dist/doc/README-121.adoc +++ b/docs/dist/doc/README-121.adoc @@ -34,17 +34,18 @@ option, or set showweaveinfo=true in the iajc ant task. The following is an example of the messages produced when this option is enabled: +[source, text] .... - C:\aspectj1.2.1\doc\examples\tjp>ajc -showWeaveInfo *.java +C:\aspectj1.2.1\doc\examples\tjp>ajc -showWeaveInfo *.java - Type 'tjp.Demo' (Demo.java:20) advised by around advice from 'tjp.GetInfo' - (GetInfo.java:26) [RuntimeTest=true] +Type 'tjp.Demo' (Demo.java:20) advised by around advice from 'tjp.GetInfo' +(GetInfo.java:26) [RuntimeTest=true] - Type 'tjp.Demo' (Demo.java:30) advised by around advice from 'tjp.GetInfo' - (GetInfo.java:26) [RuntimeTest=true] +Type 'tjp.Demo' (Demo.java:30) advised by around advice from 'tjp.GetInfo' +(GetInfo.java:26) [RuntimeTest=true] - Type 'tjp.Demo' (Demo.java:34) advised by around advice from 'tjp.GetInfo' - (GetInfo.java:26) [RuntimeTest=true] +Type 'tjp.Demo' (Demo.java:34) advised by around advice from 'tjp.GetInfo' +(GetInfo.java:26) [RuntimeTest=true] .... === Dump Support @@ -91,11 +92,11 @@ detecting this performance related bug and for piloting the fix. String concatentation in declare error and warning statements is now supported. For example, you can write: +[source, java] .... - declare warning : jdbcCall() && !inDataLayer() - : "Please don't make calls to JDBC " + - "outside of the data layer."; - +declare warning : jdbcCall() && !inDataLayer() + : "Please don't make calls to JDBC " + + "outside of the data layer."; .... === Load-time Weaving Support diff --git a/docs/dist/doc/README-153.adoc b/docs/dist/doc/README-153.adoc index 8b1c065f1..422b34447 100644 --- a/docs/dist/doc/README-153.adoc +++ b/docs/dist/doc/README-153.adoc @@ -14,8 +14,7 @@ Notable changes since the 1.5.2 release include: + Until this release, the memory profile for AspectJ looked like this (time is along the X axis, memory usage is the Y axis) -`` - +[source, text] .... /\_ / \_ @@ -31,8 +30,7 @@ discarding them once woven and dumped to disk. In 1.5.3 we don't compile everything up front - we compile and weave files one at a time. Giving us this profile: -`` - +[source, text] .... /\ /\ /\ / \/ \/ \ @@ -46,6 +44,7 @@ to compile a project. For example, I have a 1000file project, affected by aspects at >750 join points. For given values of Xmx, here are the times taken to compile it (on the command line) with AspectJ1.5.2: +[source, text] .... Xmx Time 512M 33seconds @@ -58,6 +57,7 @@ The times gradually increase as the memory is reduced because the VM starts to thrash in garbage collection. Here are the results for AspectJ1.5.3: +[source, text] .... Xmx Time 512M 33s @@ -106,8 +106,7 @@ Concrete aspects defined using aop.xml are now exposed for weaving. It is now possible to ask an instance of a ptw aspect which type it is 'attached' to. The method: -`` - +[source, java] .... String getWithinTypeName() .... diff --git a/docs/dist/doc/README-160.adoc b/docs/dist/doc/README-160.adoc index cba5ce076..d62985634 100644 --- a/docs/dist/doc/README-160.adoc +++ b/docs/dist/doc/README-160.adoc @@ -35,6 +35,7 @@ parentheses around the parameter types in a method signature determine whether the annotations relate to the type of the parameter or the parameter itself. +[source, java] .... execution(* *(@A *)); .... @@ -42,12 +43,14 @@ execution(* *(@A *)); - Execution of a method/ctor whose first parameter is of a type annotated with @A. +[source, java] .... execution(* *(@A (*))); .... - Execution of a method/ctor whose first parameter is annotated with @A +[source, java] .... execution(* *(@A (@B *))) .... @@ -55,8 +58,9 @@ execution(* *(@A (@B *))) - Execution of a method/ctor whose first parameter is annotated with @A and is of a type annotated with @B. Example: +[source, java] .... ------- Start of Test.java ----- +// ------ Start of Test.java ----- @interface A {} @interface B {} @@ -69,7 +73,11 @@ aspect X { before(): execution(* *(@A (*))) {} before(): execution(* *(@B (*))) {} } ------- End of Test.java ----- +// ------ End of Test.java ----- +.... + +[source, text] +.... $ ajc -showWeaveInfo -1.6 Test.java Join point 'method-execution(void C.foo(java.lang.String))' in Type 'C' (A.java:5) advised by before advice from 'X' (A.java:10) @@ -78,9 +86,7 @@ Join point 'method-execution(void C.goo(java.lang.String))' in Type 'C' (A.java: Join point 'method-execution(void C.goo(java.lang.String))' in Type 'C' (A.java:6) advised by before advice from 'X' (A.java:10) .... -The first piece of advice matched both methods. The second only matched -goo(). + - + +The first piece of advice matched both methods. The second only matched `goo()`. ==== Annotation Value Matching @@ -93,13 +99,14 @@ has a particular value. Perhaps tracing has been turned on at the type level and a few critical methods should not get traced. Here is some code showing the use case: +[source, java] .... enum TraceLevel { NONE, LEVEL1, LEVEL2, LEVEL3 } @interface Trace { TraceLevel value() default TraceLevel.LEVEL1; } - + aspect X { // Advise all methods marked @Trace except those with a tracelevel of none before(): execution(@Trace !@Trace(TraceLevel.NONE) * *(..)) { diff --git a/docs/dist/doc/README-161.adoc b/docs/dist/doc/README-161.adoc index 2cea859bb..d4ef20cf4 100644 --- a/docs/dist/doc/README-161.adoc +++ b/docs/dist/doc/README-161.adoc @@ -146,8 +146,7 @@ If only binding an annotation at a method-execution join point in order to access an *enum value* within it, there is a more optimal syntax that can be used to produce faster code. Given this setup: -`` - +[source, java] .... enum Colour { RED,GREEN,BLUE;} @@ -159,6 +158,7 @@ public void colouredMethod() { } Current syntax: +[source, java] .... before(ColouredAnnotation anno): execution(* *(..)) && @annotation(anno) { printTheColour(anno.value()); @@ -167,12 +167,9 @@ before(ColouredAnnotation anno): execution(* *(..)) && @annotation(anno) { New optional syntax: -`` - +[source, java] .... before(Colour col): execution(* *(..)) && @annotation(ColouredAnnotation(col)) { printTheColour(col); } .... - -''''' diff --git a/docs/dist/doc/README-1610.adoc b/docs/dist/doc/README-1610.adoc index faf6b85d6..73d3dab90 100644 --- a/docs/dist/doc/README-1610.adoc +++ b/docs/dist/doc/README-1610.adoc @@ -23,6 +23,7 @@ project properties in eclipse and in the AspectJ Compiler section, scroll down to 'Other' and in the non-standard compiler options setting, specify: +[source, text] .... -Xset:minimalModel=true,typeDemotion=true .... diff --git a/docs/dist/doc/README-1611.adoc b/docs/dist/doc/README-1611.adoc index e240e36f4..d88609580 100644 --- a/docs/dist/doc/README-1611.adoc +++ b/docs/dist/doc/README-1611.adoc @@ -74,6 +74,7 @@ annotations, or modify existing annotations by changing their values. 1.6.11 includes a new piece of syntax that we are thinking might be appropriate for one of these scenarios. 1.6.11 supports this: +[source, java] .... declare @field: int Foo.i: -@Anno; .... @@ -89,6 +90,7 @@ but the inability to use it with binary weaving greatly reduced the usefulness. Fixes have gone into 1.6.11 to support binary weaving. What do we mean by intertype innertypes? Here is an example: +[source, java] .... class Foo { public void m() { diff --git a/docs/dist/doc/README-1612.adoc b/docs/dist/doc/README-1612.adoc index d69061257..78a90829a 100644 --- a/docs/dist/doc/README-1612.adoc +++ b/docs/dist/doc/README-1612.adoc @@ -43,13 +43,14 @@ added and for some cases there can be no need for that abstract aspect. This is a work in progress but now you can write this in the aop.xml: +[source, xml] .... <concrete-aspect name="MyAspect"> <before pointcut="execution(* Hello.say2(..)) AND args(message)" - invokeClass="SomeRegularJavaClass" + invokeClass="SomeRegularJavaClass" invokeMethod="someMethod(JoinPoint tjp, java.lang.String message)"/> <after pointcut="execution(* Hello.say2(..)) AND args(message)" - invokeClass="SomeRegularJavaClass" + invokeClass="SomeRegularJavaClass" invokeMethod="someOtherMethod(JoinPoint tjp, java.lang.String message)"/> </concrete-aspect> @@ -58,7 +59,7 @@ public class SomeRegularJavaClass { public static void someMethod(org.aspectj.lang.JoinPoint tjp, String s) { System.out.println("in advice4: s="+s+" at "+tjp); } - + public static void someOtherMethod(org.aspectj.lang.JoinPoint tjp, String s) { System.out.println("in advice5: s="+s+" at "+tjp); } @@ -101,8 +102,9 @@ get started! There is now a new well known name that you can use in the if clauses in your aspects. thisAspectInstance provides access to the aspect instance. -Here is an example: `` +Here is an example: +[source, java] .... aspect X { boolean doit() { @@ -116,10 +118,11 @@ aspect X { } .... -Now why not just use X.aspectOf() instead of thisAspectInstance? Well -thisAspectInstance is quite useful when working with abstract/concrete -aspects: `` +Now why not just use `X.aspectOf()` instead of `thisAspectInstance`? Well, +`thisAspectInstance` is quite useful when working with abstract/concrete +aspects: +[source, java] .... abstract aspect X { abstract pointcut p(); @@ -185,6 +188,7 @@ supports Java7 language constructs - that will happen after Eclipse It is now possible to specify synthetic in pointcuts: +[source, java] .... pointcut p(): execution(!synthetic * *(..)); .... @@ -210,6 +214,7 @@ use when you want to match upon the existence of an annotation but you don't need the annotation, you just need a value from it. This code snippet shows an example: +[source, java] .... @interface SomeAnnotation { int i(); @@ -227,6 +232,7 @@ binding too. Suppose the annotation had multiple int values, how would we select which int to bind? AspectJ will now use the name (if it can) to select the right value: +[source, java] .... @interface SomeAnnotation { int mods(); diff --git a/docs/dist/doc/README-164.adoc b/docs/dist/doc/README-164.adoc index b1de0e9b0..548cb086e 100644 --- a/docs/dist/doc/README-164.adoc +++ b/docs/dist/doc/README-164.adoc @@ -27,8 +27,7 @@ the full build times in AJDT: AJDT 1.6.3 (uses AspectJ 1.6.3) -`` - +[source, text] .... 21352ms 21597ms @@ -37,8 +36,7 @@ AJDT 1.6.3 (uses AspectJ 1.6.3) AJDT 1.6.5dev builds (use AspectJ 1.6.4) -`` - +[source, text] .... 19811ms 19802ms @@ -70,8 +68,7 @@ building code, weaving code. Initially this is using AJDT 1.6.2 (which embeds AspectJ 1.6.3): -`` - +[source, text] .... Type of change: adding a new method to a type Project build times (first one is the compile of our change, the rest are for downstream projects): @@ -88,8 +85,7 @@ Summary: Total time spent in the compiler for that change: 1597ms Now with AspectJ 1.6.5 dev builds (which embed AspectJ 1.6.4): -`` - +[source, text] .... Type of change: adding a new method to a type Project build times (first one is the compile of our change, the rest are for downstream projects): @@ -127,8 +123,9 @@ http://andrewclement.blogspot.com/2009/02/aspectj-fixing-reverse-cascade-errors. *Optimizing support for maintaining per join point state* The traditional way to maintain state on a per join point basis involves -using the JoinPoint.StaticPart as a key into a map: `` +using the JoinPoint.StaticPart as a key into a map: +[source, java] .... aspect X pertypewithin(*) { Map<JoinPoint.StaticPart,Timer> timerMap = ... @@ -149,8 +146,7 @@ points within a target type are unique (and start from 0) - they are ideal for array lookups. So using this the above aspect can be rewritten: -`` - +[source, java] .... aspect X pertypewithin(*) { Timer[] timerArray = ... @@ -189,17 +185,16 @@ target instance. The @DeclareMixin annotation is attached to a factory method which returns instances of the delegate. Here is a basic example: -`` - +[source, java] .... - // The factory method that can build the delegate instance is annotated with @DeclareMixin. - // The annotation value defines the type pattern for targets of the mixin. - // The parameter is the object for which a delegate is being constructed. - // The interface that will be mixed in is the return value of the factory method. - @DeclareMixin("org.xyz..*") - public static SomeInterface createDelegate(Object instance) { - return new SomeImplementation(instance); - } +// The factory method that can build the delegate instance is annotated with @DeclareMixin. +// The annotation value defines the type pattern for targets of the mixin. +// The parameter is the object for which a delegate is being constructed. +// The interface that will be mixed in is the return value of the factory method. +@DeclareMixin("org.xyz..*") +public static SomeInterface createDelegate(Object instance) { + return new SomeImplementation(instance); +} .... More examples are @@ -248,5 +243,3 @@ weaver. Although the type map uses Weak/Soft references to try and better control how it uses memory, the JVM policies for managing these references vary wildly and so some work needs to be done to allow for these differences. - -''''' diff --git a/docs/dist/doc/README-167.adoc b/docs/dist/doc/README-167.adoc index 66476f8cc..5a2a9ffcf 100644 --- a/docs/dist/doc/README-167.adoc +++ b/docs/dist/doc/README-167.adoc @@ -18,6 +18,7 @@ pointcut matching]. Basically by turning on the options '-timers -verbose' on the command line (or via Ant), output will be produced that looks a little like this: +[source, text] .... Pointcut matching cost (total=6532ms for 675000 joinpoint match calls): Time:482ms (jps:#168585) matching against @@ -102,8 +103,7 @@ that actually runs? One user, Oliver Hoff, raised a query on the performance of annotation binding. His case uncovered an old TODO left in the code a few years ago: -`` - +[source, text] .... // OPTIMIZE cache result of getDeclaredMethod and getAnnotation? .... @@ -121,29 +121,28 @@ value at an execution join point in different ways. The three scenarios look like this (where the annotation type is 'Marker' and it has a String value field called 'message'): -`` - +[source, java] .... - // CaseOne: annotation value fetching is done in the advice: - pointcut adviceRetrievesAnnotation(): execution(@Marker * runOne(..)); - before(): adviceRetrievesAnnotation() { - Marker marker = (Marker) ((MethodSignature) - thisJoinPointStaticPart.getSignature()).getMethod().getAnnotation(Marker.class); - String s = marker.message(); - } - - // CaseTwo: annotation binding is done in the pointcut, advice retrieves message - pointcut pointcutBindsAnnotation(Marker l): execution(@Marker * runTwo(..)) && @annotation(l); - before(Marker l): pointcutBindsAnnotation(l) { - String s = l.message(); - } - - // CaseThree: annotation binding directly targets the message value in the annotation - pointcut pointcutBindsAnnotationValue(String msg): - execution(@Marker * runThree(..)) && @annotation(Marker(msg)); - before(String s): pointcutBindsAnnotationValue(s) { - // already got the string - } +// CaseOne: annotation value fetching is done in the advice: +pointcut adviceRetrievesAnnotation(): execution(@Marker * runOne(..)); +before(): adviceRetrievesAnnotation() { + Marker marker = (Marker) ((MethodSignature) + thisJoinPointStaticPart.getSignature()).getMethod().getAnnotation(Marker.class); + String s = marker.message(); +} + +// CaseTwo: annotation binding is done in the pointcut, advice retrieves message +pointcut pointcutBindsAnnotation(Marker l): execution(@Marker * runTwo(..)) && @annotation(l); +before(Marker l): pointcutBindsAnnotation(l) { + String s = l.message(); +} + +// CaseThree: annotation binding directly targets the message value in the annotation +pointcut pointcutBindsAnnotationValue(String msg): + execution(@Marker * runThree(..)) && @annotation(Marker(msg)); +before(String s): pointcutBindsAnnotationValue(s) { + // already got the string +} .... Before 1.6.7, case 2 was slower than case 1 and case 3 wasn't supported @@ -157,8 +156,7 @@ stress the AspectJ binding code. For the benchmark numbers the join points advised by those advice were invoked 1,000,000 times. AspectJ 1.6.7: -`` - +[source, text] .... Manually fetching annotation with getAnnotation(): 645ms Binding annotation with @annotation(Marker): 445ms (was >20 *seconds* for 1.6.6, due to an extra reflection call) diff --git a/docs/dist/doc/README-168.adoc b/docs/dist/doc/README-168.adoc index eee958509..0a8e3cbb8 100644 --- a/docs/dist/doc/README-168.adoc +++ b/docs/dist/doc/README-168.adoc @@ -25,12 +25,11 @@ that is not These three meet that spec: -`` - +[source, xml] .... - <include within="*"/> - <include within="@Foo *"/> - <exclude within="*Funk*y*"/> +<include within="*"/> +<include within="@Foo *"/> +<exclude within="*Funk*y*"/> .... The include="*" can be optimized. The include="@Foo *" is not optimized. @@ -51,22 +50,21 @@ more frequently. The stack trace when this is hit looks like: -`` - +[source, text] .... - ... - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) - at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) - ... +... +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:427) +at org.aspectj.weaver.ReferenceType.isAssignableFrom(ReferenceType.java:393) +... .... The weaver has changed over the 1.5 and 1.6 releases and is now reaching diff --git a/docs/dist/doc/README-169.adoc b/docs/dist/doc/README-169.adoc index 1df44489f..4921f23d4 100644 --- a/docs/dist/doc/README-169.adoc +++ b/docs/dist/doc/README-169.adoc @@ -14,6 +14,7 @@ declare annotation constructs that take a member signature. For example, if you wanted to attach an annotation to all your getter like methods, you needed two constructs +[source, java] .... declare @method: * is*(): @FooBar; declare @method: * get*(): @FooBar; @@ -22,6 +23,7 @@ declare @method: * get*(): @FooBar; Now AspectJ allows compound patterns for declare @method/@constructor/@field. +[source, java] .... declare @method: (* is*()) || (* get*()): @FooBar; .... @@ -32,6 +34,7 @@ It is now possible to ITD member types. The syntax is as would be expected. This example introduces a new member type called Inner into type Foo: +[source, java] .... public class Foo { public static void main(String[] args) { @@ -71,10 +74,9 @@ within it to switch-off if there is nothing for them to do. Here is an example, 'AspectA' will switch itself off if the type 'a.b.c.Anno' cannot be found: -`` - +[source, xml] .... - <aspect name="AspectA" requires="a.b.c.Anno"/> +<aspect name="AspectA" requires="a.b.c.Anno"/> .... ==== Reduction in class file sizes: https://bugs.eclipse.org/bugs/show_bug.cgi?id=312839[312839] @@ -130,8 +132,7 @@ the pointcuts defined in the original aspect. Here is an example: -`` - +[source, xml] .... <aspectj> <aspects> @@ -154,8 +155,7 @@ specifies that Y should in fact only be applied to com.foo..* types. It is now possible to use joinpoint context in the messages attached to declare warning and declare error constructs. Some examples: -`` - +[source, java] .... declare warning: execution(* A.m(..)): "joinpoint is {joinpoint}"; declare warning: execution(* A.m(..)): "joinpoint kind is '{joinpoint.kind}'"; @@ -178,8 +178,7 @@ the message. Please raise an enhancement request if you need other keys It is now possible to use a type pattern with declare warning and declare error. For example: -`` - +[source, java] .... declare warning: I+ && !hasfield(int i): "Implementations of I are expected to have a int field called i"; .... @@ -190,8 +189,7 @@ This is the ability to narrow the types of interest so that interfaces can be ignored, or inner types, or classes or aspects. There is now a new is() construct that enables this: -`` - +[source, java] .... execution(* (!is(InnerType)).m(..)) {} !within(* && is(InnerType)) {} @@ -202,8 +200,9 @@ InnerType, AnonymousType, EnumType, AnonymousType. Note: It is important to understand that "!within(is(InnerType))" and "within(!is(InnerType))" are not the same. The latter one is unlikely to -be what you want to use. For example here: `` +be what you want to use. For example here: +[source, java] .... class Boo { void foo() {} @@ -223,8 +222,7 @@ result of that match will be negated. Some users always expect this: -`` - +[source, java] .... class C { } @@ -248,8 +246,7 @@ produce slightly different output. Here is the output of javap when that is built with 1.6.8: -`` - +[source, java] .... class C extends java.lang.Object{ public int ajc$interField$X$someField; @@ -259,8 +256,7 @@ class C extends java.lang.Object{ Here is the output of javap when that is built with 1.6.9: -`` - +[source, java] .... class C extends java.lang.Object{ private int someField; @@ -284,8 +280,7 @@ and if you browse to it you will see it currently contains 1.6.9 dev builds under the name 1.6.9.BUILD-SNAPSHOT. The repo is added with this magic: -`` - +[source, xml] .... <repository> <id>maven.springframework.org</id> diff --git a/docs/dist/doc/README-170.adoc b/docs/dist/doc/README-170.adoc index de0248de7..b76f56139 100644 --- a/docs/dist/doc/README-170.adoc +++ b/docs/dist/doc/README-170.adoc @@ -36,6 +36,7 @@ start of a system using LTW and then reuses that woven bytecode on subsequent starts - this saves weaving time and also memory consumption. To activate it, use the following system properties: +[source, text] .... -Daj.weaving.cache.enabled=true -Daj.weaving.cache.dir=/tmp/aspectj-cache/ @@ -51,8 +52,9 @@ Eclipse compiler. It means that you can now use the new Java 7 language constructs in your programs: -- Diamond operator in advice: `` +- Diamond operator in advice: +[source, java] .... aspect Foo { before(): execution(* *(..)) { @@ -61,58 +63,63 @@ aspect Foo { } .... -- Diamond operator in ITD: `` +- Diamond operator in ITD: +[source, java] .... public List DiamondITD.ls = new ArrayList<>(); .... -- Underscore literals and binary literals in advice: `` +- Underscore literals and binary literals in advice: +[source, java] .... - before(): execution(* *(..)) { - int onemill = 1_000_000; - int four =0b100; - } +before(): execution(* *(..)) { + int onemill = 1_000_000; + int four =0b100; +} .... - Multi-catch:`` +[source, java] .... before(): execution(* main(..)) { - try { - foo("abc"); - } catch (ExceptionA | ExceptionB ex) { - bar(ex); - } + try { + foo("abc"); + } catch (ExceptionA | ExceptionB ex) { + bar(ex); + } } .... - String switch:`` +[source, java] .... - before(String s): execution(* *(..)) && args(s) { - switch(s) { - case "quux": - foo(); - break; - case "bar": - foo(); - break; - default: - foo(); - break; - } - } +before(String s): execution(* *(..)) && args(s) { + switch(s) { + case "quux": + foo(); + break; + case "bar": + foo(); + break; + default: + foo(); + break; + } +} .... - Try with resources:`` +[source, java] .... - try ( - InputStream in = new FileInputStream(src); - OutputStream out = new FileOutputStream(dest)) - { - // code - } +try ( + InputStream in = new FileInputStream(src); + OutputStream out = new FileOutputStream(dest)) +{ + // code +} .... diff --git a/docs/dist/doc/README-174.adoc b/docs/dist/doc/README-174.adoc index 7b4cbb54c..3b55b4a43 100644 --- a/docs/dist/doc/README-174.adoc +++ b/docs/dist/doc/README-174.adoc @@ -18,6 +18,7 @@ JVM where JMX is turned on (https://bugs.eclipse.org/bugs/show_bug.cgi?id=420210[420210]) The new keys are: + +[source, java] .... joinpoint.enclosingclass // Bar joinpoint.enclosingmember // void Bar.foo(String) @@ -29,6 +30,7 @@ All keys are case insensitive. needing to supply a file (https://bugs.eclipse.org/bugs/show_bug.cgi?id=419279[419279]) + +[source, text] .... ajc -Xlint:adviceDidNotMatch=error,noGuardForLazyTjp=ignore Foo.java .... diff --git a/docs/dist/doc/README-180.adoc b/docs/dist/doc/README-180.adoc index fe988aa5a..115de3d6d 100644 --- a/docs/dist/doc/README-180.adoc +++ b/docs/dist/doc/README-180.adoc @@ -21,8 +21,9 @@ patch on top of Eclipse 4.3.2). Here is a sample AspectJ8 program: +[source, java] .... -=== 8< ==== C.java ==== 8< === +// === 8< ==== C.java ==== 8< === import java.util.Arrays; interface I { @@ -67,5 +68,5 @@ class MyClass { return args; } } -=== 8< ==== C.java ==== 8< === +// === 8< ==== C.java ==== 8< === .... diff --git a/docs/dist/doc/README-182.adoc b/docs/dist/doc/README-182.adoc index 45215367d..28fa7b2da 100644 --- a/docs/dist/doc/README-182.adoc +++ b/docs/dist/doc/README-182.adoc @@ -35,8 +35,7 @@ Here is a short example, a very basic annotation and application: ===== Marker.java -`` - +[source, java] .... import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -47,8 +46,7 @@ public @interface Marker { } ===== Code.java -`` - +[source, java] .... public class Code { @@ -60,13 +58,13 @@ public class Code { } public void moo() {} - + @Marker public void boo() {} - + @Marker public void too() {} - + public void woo() {} } .... @@ -78,8 +76,7 @@ contrived demo!) ===== DemoProcessor.java -`` - +[source, java] .... import java.io.*; import javax.tools.*; @@ -90,7 +87,7 @@ import javax.lang.model.element.*; @SupportedAnnotationTypes(value= {"*"}) @SupportedSourceVersion(SourceVersion.RELEASE_6) -public class DemoProcessor extends AbstractProcessor { +public class DemoProcessor extends AbstractProcessor { private Filer filer; @@ -106,7 +103,7 @@ public class DemoProcessor extends AbstractProcessor { if (element.getKind() == ElementKind.METHOD) { // For any methods we find, create an aspect: String methodName = element.getSimpleName().toString(); - String aspectText = + String aspectText = "public aspect Advise_"+methodName+" {\n"+ " before(): execution(* "+methodName+"(..)) {\n"+ " System.out.println(\""+methodName+" running\");\n"+ @@ -131,22 +128,19 @@ public class DemoProcessor extends AbstractProcessor { With those sources, we compile the processor: -`` - +[source, text] .... ajc -1.6 DemoProcessor.java Marker.java .... Now compile the code with the processor specified: -`` - +[source, text] .... ajc -1.6 -processor DemoProcessor -showWeaveInfo Code.java Marker.java .... -`` - +[source, text] .... Generated aspect to advise too Generated aspect to advise boo @@ -159,8 +153,7 @@ the code being compiled immediately. Finally we can run it: -`` - +[source, text] .... java Code boo running diff --git a/docs/dist/doc/README-183.adoc b/docs/dist/doc/README-183.adoc index 95425e392..8c615ef84 100644 --- a/docs/dist/doc/README-183.adoc +++ b/docs/dist/doc/README-183.adoc @@ -35,6 +35,7 @@ extraneous dependencies to an applications build classpath. Example: +[source, java] .... import org.aspectj.lang.annotation.*; @@ -63,6 +64,7 @@ appears to come up when the aspect is non-optimal anyway and hitting preinitialization was never really intended by the pointcut writer. For example: +[source, java] .... execution(* foo(..)) && cflow(within(Bar)) .... @@ -72,12 +74,14 @@ joinpoints, many of which the user probably didn't mean to. It feels like we actually need a warning to indicate the pointcut is probably suboptimal. What the user probably meant was something more like this: +[source, java] .... execution(* foo(..)) && cflow(execution(* Bar.*(..)) .... or +[source, java] .... execution(* foo(..)) && cflow(within(Bar) && execution(* *(..))) .... diff --git a/docs/dist/doc/README-187.adoc b/docs/dist/doc/README-187.adoc index de61a362b..bcc5f75cc 100644 --- a/docs/dist/doc/README-187.adoc +++ b/docs/dist/doc/README-187.adoc @@ -25,8 +25,7 @@ will not be woven. Here is a simple aspect: -`` - +[source, java] .... public aspect Azpect { before(): execution(* *(..)) { @@ -37,8 +36,7 @@ public aspect Azpect { Compiled via: -`` - +[source, text] .... ajc -1.8 Azpect.java -outxml .... @@ -48,8 +46,7 @@ META-INF/aop-ajc.xml. I then have this sample application (same directory): -`` - +[source, java] .... import java.lang.management.ManagementFactory; import org.aspectj.weaver.loadtime.Agent; @@ -96,8 +93,7 @@ public class Application { And this Sample class: -`` - +[source, java] .... public class Sample { public void doSomething() { @@ -116,8 +112,7 @@ JDK tools.jar on your classpath*. Once compiled we can run it: -`` - +[source, text] .... java -DAGENT_PATH=<path-to>/aspectjweaver.jar Application .... diff --git a/docs/dist/doc/README-190.adoc b/docs/dist/doc/README-190.adoc index 3b1f27784..323573146 100644 --- a/docs/dist/doc/README-190.adoc +++ b/docs/dist/doc/README-190.adoc @@ -41,6 +41,7 @@ In anticipation of not all build plugins supporting that -Xajruntimetarget option, you can now specify these kinds of option in the ASPECTJ_OPTS environment variable. Set that in your environment: +[source, text] .... export ASPECTJ_OPTS="-Xajruntimetarget:1.9" .... @@ -58,17 +59,18 @@ useful with Java9 which includes a number of module related commands. For example, here is an iajc usage with compilerArg that is passing --add-modules java.xml.bind: +[source, xml] .... - <iajc destdir="bin" failonerror="true" - showWeaveInfo="true" source="1.9" target="1.9" - debug="true" fork="true" maxmem="256m"> - <compilerArg value="--add-modules"/> - <compilerArg value="java.xml.bind"/> - <src path="src" /> - <classpath> - <pathelement location="${aspectj.home}/lib/aspectjrt.jar"/> - </classpath> - </iajc> +<iajc destdir="bin" failonerror="true" + showWeaveInfo="true" source="1.9" target="1.9" + debug="true" fork="true" maxmem="256m"> + <compilerArg value="--add-modules"/> + <compilerArg value="java.xml.bind"/> + <src path="src" /> + <classpath> + <pathelement location="${aspectj.home}/lib/aspectjrt.jar"/> + </classpath> +</iajc> .... 1.9.0.RC4 available 21-Feb-2018 @@ -103,6 +105,7 @@ AspectJ can now be used with the new module system available in Java9. The key jars in AspectJ have been given automatic module names. The automatic module name is org.aspectj.runtime for the aspectjrt module: +[source, text] .... $ java --module-path <pathto>/lib/aspectjrt.jar --list-modules | grep aspectj @@ -112,6 +115,7 @@ org.aspectj.runtime file:///<pathto>/lib/aspectjrt.jar automatic And similarly org.aspectj.weaver and org.aspectj.tools for aspectjweaver and aspectjtools respectively: +[source, text] .... $ java --module-path <pathto>/lib/aspectjweaver.jar --describe-module org.aspectj.weaver @@ -137,6 +141,7 @@ contains org.aspectj.asm.internal AspectJ understands module-info.java source files and building modules that include aspects. Here is an example: +[source, java] .... module-info.java @@ -170,6 +175,7 @@ public aspect Azpect { We can now build those into a module: +[source, text] .... $ ajc -1.9 module-info.java otherpkg/Azpect.java pkg/Demo.java -outjar demo.jar @@ -182,12 +188,14 @@ Wait, that failed! Yes, aspectjrt.jar (which includes the required org.aspectj.weaver module) wasn't supplied. We need to pass it on the module-path: +[source, text] .... $ ajc -1.9 --module-path <pathto>/aspectjrt.jar module-info.java otherpkg/Azpect.java pkg/Demo.java -outjar demo.jar .... Now we have a demo module we can run: +[source, text] .... $ java --module-path <pathto>/aspectjrt.jar:demo.jar --module demo/pkg.Demo @@ -206,8 +214,9 @@ A module is really just a jar with a module-info descriptor. As such you can simply pass a module on the inpath and binary weave it with other aspects. Take the module we built above, let's weave into it again: +[source, java] .... -extra/AnotherAzpect.java +// extra/AnotherAzpect.java package extra; @@ -218,6 +227,7 @@ public aspect AnotherAzpect { } .... +[source, text] .... $ ajc -inpath demo.jar AnotherAzpect.java -outjar newdemo.jar .... @@ -231,6 +241,7 @@ Because the new jar produced includes the compiled aspect, the module-info specification inside is still correct, so we can run it exactly as before: +[source, text] .... $ java --module-path ~/installs/aspectj190rc1/lib/aspectjrt.jar:newdemo.jar --module demo/pkg.Demo @@ -239,9 +250,6 @@ AnotherAzpect running Demo running .... - + - + - === Faster Spring AOP Dave Syer recently created a series of benchmarks for checking the speed @@ -250,6 +258,7 @@ of Spring-AspectJ: https://github.com/dsyer/spring-boot-aspectj Here we can see the numbers for AspectJ 1.8.11 (on an older Macbook Pro): +[source, text] .... Benchmark (scale) Mode Cnt Score Error Units StartupBenchmark.ltw N/A avgt 10 2.553 ~ 0.030 s/op @@ -295,6 +304,7 @@ primary change is factoring in the annotation type. What difference does that make? AspectJ 1.9.0.RC1: +[source, text] .... Benchmark (scale) Mode Cnt Score Error Units StartupBenchmark.ltw N/A avgt 10 2.568 ~ 0.035 s/op diff --git a/docs/dist/doc/README-191.adoc b/docs/dist/doc/README-191.adoc index acab550c3..bba435893 100644 --- a/docs/dist/doc/README-191.adoc +++ b/docs/dist/doc/README-191.adoc @@ -14,6 +14,7 @@ AspectJ has updated to a recent JDT compiler version (commit This means you can use the 'var' support. A simple example of combining var with an aspect: +[source, java] .... public class Code3 { public static void main(String []argv) { diff --git a/docs/dist/doc/README-193.adoc b/docs/dist/doc/README-193.adoc index a75724c2c..22824b66b 100644 --- a/docs/dist/doc/README-193.adoc +++ b/docs/dist/doc/README-193.adoc @@ -10,8 +10,9 @@ expression syntax, but you must activate support for that via an --enable-preview flag when using the compiler and attempting to run the resultant classes: Here is Switch3.java: +[source, java] .... -=========8<========= +// =========8<========= public class Switch3 { public static void main(String[] argv) { System.out.println(one(Color.R)); @@ -29,7 +30,7 @@ public class Switch3 { }; return result; } - + public static final int foo(int i) { return i+1; } @@ -44,11 +45,12 @@ aspect X { return proceed()*3; } } -=========8<========= +// =========8<========= .... Compile it with: +[source, text] .... $ ajc --enable-preview -showWeaveInfo -12 Switch3.java @@ -63,6 +65,7 @@ Join point 'method-call(int Switch3.foo(int))' in Type 'Switch3' (Switch3.java:1 Now run it: +[source, text] .... $ java --enable-preview Switch3 3 diff --git a/docs/dist/doc/README-195.adoc b/docs/dist/doc/README-195.adoc index 2af7e42a7..36a157c53 100644 --- a/docs/dist/doc/README-195.adoc +++ b/docs/dist/doc/README-195.adoc @@ -12,8 +12,9 @@ must activate support for that via an --enable-preview flag when using the compiler and attempting to run the resultant classes: Here is Code.java: +[source, java] .... -=======8<========= +// =======8<========= public class Code { public static void main(String[] argv) { } @@ -33,17 +34,19 @@ lines } } -=========8<========= +// =========8<========= .... Compile it with: +[source, text] .... $ ajc --enable-preview -13 Code.java .... Now run it: +[source, text] .... $ java --enable-preview Code This diff --git a/docs/dist/doc/README-196.adoc b/docs/dist/doc/README-196.adoc index 536cd4ec9..35e7ab2d3 100644 --- a/docs/dist/doc/README-196.adoc +++ b/docs/dist/doc/README-196.adoc @@ -11,12 +11,13 @@ AspectJ 1.9.6 supports Java14. Java14 introduces records, but you must activate support for that via an --enable-preview flag when using the compiler and attempting to run the resultant classes: Here is Code.java: +[source, java] .... -=======8<========= +// =======8<========= public record Person(String firstName, String lastName, int age) {} -=======8<========= +// =======8<========= -=======8<========= +// =======8<========= public class UsingPersonRecord { public static void main(String[] argv) { Person p = new Person("A","B",99); @@ -24,25 +25,27 @@ public class UsingPersonRecord { System.out.println(p.firstName()); } } -=======8<========= +// =======8<========= -=======8<========= +// =======8<========= public aspect TraceRecordComponents { before(): execution(public * *()) { System.out.println(thisJoinPointStaticPart); } } -=======8<========= +// =======8<========= .... Compile it with: +[source, text] .... $ ajc --enable-preview -14 Person.java UsingPersonRecord.java TraceRecordComponents.java .... Now run it: +[source, text] .... $ java --enable-preview UsingPersonRecord execution(String Person.toString()) diff --git a/docs/dist/doc/changes.adoc b/docs/dist/doc/changes.adoc index c7b2d6975..25ef37f09 100644 --- a/docs/dist/doc/changes.adoc +++ b/docs/dist/doc/changes.adoc @@ -178,10 +178,10 @@ compiler supports an additional option, -showWeaveInfo, which will produce informational messages concerning the activity of the weaver. For example: + +[source, text] .... - Type 'tjp.Demo' (Demo.java:30) advised by around advice from 'tjp.GetInfo' - (GetInfo.java:26) [RuntimeTest=true] - +Type 'tjp.Demo' (Demo.java:30) advised by around advice from 'tjp.GetInfo' +(GetInfo.java:26) [RuntimeTest=true] .... * https://bugs.eclipse.org/bugs/show_bug.cgi?id=44191[44191] AspectJ 1.2.1 improves the error messages issued in many of the infamous "can't diff --git a/docs/dist/doc/porting.adoc b/docs/dist/doc/porting.adoc index bc95dc5c7..cbf8ede6d 100644 --- a/docs/dist/doc/porting.adoc +++ b/docs/dist/doc/porting.adoc @@ -37,35 +37,36 @@ The following example program illustrates the differences in join point matching with the `call` pointcut designator between 1.4 and 1.3 compliance levels. -.... -01 class A { -02 public void doIt() {...}; -03 } -04 -05 class B extends A { -06 public void doThisToo() {...}; -07 } -08 -09 -10 public class CallsAandB { -11 -12 public static void main(String[] args) { -13 B b = new B(); -14 A bInDisguise = new B(); -15 -16 b.doIt(); // AspectJ 1.2 matches here -17 bInDisguise.doIt(); // this is never matched -18 } -19 -20 } -21 -22 aspect CallPCDMatchingExample { -23 -24 before() : call(* B.doIt(..)) { -25 System.out.println("About to call B.doIt(...)"); -26 } -27 -28 } +[source, java] +.... +/*01*/ class A { +/*02*/ public void doIt() {...}; +/*03*/ } +/*04*/ +/*05*/ class B extends A { +/*06*/ public void doThisToo() {...}; +/*07*/ } +/*08*/ +/*09*/ +/*10*/ public class CallsAandB { +/*11*/ +/*12*/ public static void main(String[] args) { +/*13*/ B b = new B(); +/*14*/ A bInDisguise = new B(); +/*15*/ +/*16*/ b.doIt(); // AspectJ 1.2 matches here +/*17*/ bInDisguise.doIt(); // this is never matched +/*18*/ } +/*19*/ +/*20*/ } +/*21*/ +/*22*/ aspect CallPCDMatchingExample { +/*23*/ +/*24*/ before() : call(* B.doIt(..)) { +/*25*/ System.out.println("About to call B.doIt(...)"); +/*26*/ } +/*27*/ +/*28*/ } .... When this program is compiled with AspectJ 1.2 using the default @@ -99,8 +100,8 @@ does not match at a join point, and a user may have expected it to. Compiling the above program using AspectJ 1.2 produces the following compiler output: +[source, text] .... - CallsAandB.java:24 warning does not match because declaring type is A, if match desired use target(B) [Xlint:unmatchedSuperTypeInCall] before() : call(* B.doIt(..)) { ^^^^^^^^^^^^^^^ @@ -109,7 +110,6 @@ before() : call(* B.doIt(..)) { 1 warning - .... The warning is telling us that the call pointcut associated with the @@ -147,6 +147,7 @@ an interface is now (correctly) prohibited, and there will no longer be a constructor-execution join point for the interface. To initialize a field declared on an interface, use initialization, e.g., +[source, java] .... int I.i; after(I i) returning: initialization(I) && this(i) { i.i = 2; } @@ -154,6 +155,7 @@ after(I i) returning: initialization(I) && this(i) { i.i = 2; } To pick out the constructor-execution for any implementation of I, try +[source, java] .... execution(I+.new(..)) .... @@ -172,6 +174,7 @@ older version of BCEL available earlier on your classpath than the version included in the 1.2 aspectjtools.jar then you will see errors like: +[source, text] .... C:\work\test\TestAspect.aj error Internal compiler error java.lang.NoSuchMethodError: org.apache.bcel.generic.InstructionFactory. @@ -219,6 +222,7 @@ Conflicts will be reported for no-argument constructors generated by compilers when no constructor is defined for a class. That means the following code will compile in 1.0 but not in 1.1: +[source, java] .... class C {} aspect A { @@ -243,6 +247,7 @@ The compiler will report an error that the form `aspect {name} dominates {list}...` is no longer supported. It has been replaced by a new declare statement: +[source, java] .... declare precedence : {name} {list}... .... @@ -269,6 +274,7 @@ returning advice. The main change that was made was of after returning advice for constructor execution join points. Previously, this advice was legal: +[source, java] .... after() returning (Foo f): execution(Foo.new(..)) { ... } .... @@ -280,6 +286,7 @@ constructor calls) do not return the value of the new object. Rather, void method. With that in mind, any code like the above should be conveted to the form. +[source, java] .... after(Foo f) returning: this(f) && execution(Foo.new(..)) { ... } .... @@ -287,6 +294,7 @@ after(Foo f) returning: this(f) && execution(Foo.new(..)) { ... } In compilers prior to 1.0.4, the following advice could pick out join points +[source, java] .... after() returning (String s): call(void foo()) { ... } .... @@ -294,6 +302,7 @@ after() returning (String s): call(void foo()) { ... } This is no longer picked out. This pattern was most commonly used in highly polymorphic contexts, such as +[source, java] .... after() returning (String s): call(* foo()) { ... } .... @@ -301,6 +310,7 @@ after() returning (String s): call(* foo()) { ... } If you want to capture all calls, binding null objects for those that would otherwise have no value, you must use the `Object` type. +[source, java] .... after() returning (Object o): call(* foo()) { ... } .... @@ -378,18 +388,20 @@ for example, you named a parameter of a pointcut "set", you should (for your own sanity -- the compiler doesn't require it) rename it in the rewritten pointcut. +[source, java] .... pointcut sort(Collection set): calls(void addAll(set)); -==> +// ==> pointcut sort(Collection mySet): call(void addAll(mySet)); .... While converting to use singular nouns for the primitive pointcuts, you may also want to remove the "s" from your user-defined pointcuts. +[source, java] .... pointcut publicCalls(): calls(public * *(..)); -==> +// ==> pointcut publicCall(): call(public * *(..)); .... @@ -412,9 +424,10 @@ straightforward, depending on whether the pointcut exposed state or not. Receptions pointcuts that did not expose state can simply be replaced by the new `call` and `target` pointcuts: +[source, java] .... receptions(void Foo.m()) -==> +// ==> target(Foo) && call(void m()) .... @@ -424,9 +437,10 @@ Some receptions pointcuts exposed the receiving object by replacing the receiving type with a pointcut formal. These PCDs should be rewritten to use the new `target` pointcut to expose the receiving object. +[source, java] .... pointcut fooCallees(Foo f): receptions(void f.m()); -==> +// ==> pointcut fooCallee(Foo f): target(f) && call(void m()); .... @@ -434,9 +448,10 @@ Like xref:#_1_0a1-fixing-state-access[other pointcuts], receptions pointcuts that exposed one or more arguments should be rewritten to use the `args` pointcut: +[source, java] .... pointcut intPassers(int i, int j): receptions(void Foo.m(i, j)); -==> +// ==> pointcut intPasser(int i, int j): args(i, j) && target(Foo) && call(void m(int, int)); .... @@ -453,9 +468,10 @@ but also of classes that extended C. If you want this behaviour, then you need to use the new subtypes operator, +, on the type name in question. So, +[source, java] .... receptions(C.new()) -==> +// ==> call(C+.new()) .... @@ -468,6 +484,7 @@ allow all kinds of advice it may be that the object isn't constructed yet (say, in before or around advice). This is a benefit, in that it allows caching constructed objects +[source, java] .... aspect Singleton { private C theC = null; @@ -482,9 +499,10 @@ aspect Singleton { but it does require some rewriting. The new object can be accessed as the return value in after returning advice. So, +[source, java] .... after(Point p) returning (): receptions(p.new(int, int)) { ... } -==> +// ==> after() returning (Point p): call(Point+.new(int, int)) { ... } .... @@ -509,15 +527,17 @@ Any time you have a pointcut that has a signature where one of the arguments was a pointcut or advice formal, just replace that formal with its type and add an `args` pointcut. +[source, java] .... pointcut intPassers(int i, int j): calls(void Foo.m(i, j)); -==> +// ==> pointcut intPasser(int i, int j): args(i, j) && call(void Foo.m(int, int)); .... +[source, java] .... pointcut stringPassers(String s): receptions(void Foo.m(s, ..)); -==> +// ==> pointcut stringPasser(String s): args(s, ..) && call(void Foo.m(String, ..)); .... @@ -525,6 +545,7 @@ pointcut stringPasser(String s): args(s, ..) && call(void Foo.m(String, ..)); If a calls pointcut exposed the the receiving object, such as +[source, java] .... pointcut fooCallees(Foo f): calls(void f.m()); .... @@ -532,6 +553,7 @@ pointcut fooCallees(Foo f): calls(void f.m()); then the new version should use the `target` pointcut to get at that object +[source, java] .... pointcut fooCallee(Foo f): target(f) && call(void Foo.m()); .... @@ -543,9 +565,10 @@ returning advice, when it is guaranteed that the object was successfully constructed. So instead of using the `target` pointcut to expose the value, you should use the normal `after returning` mechanism: +[source, java] .... after(Point p) returning (): calls(p.new(int, int)) { ... } -==> +// ==> after() returning (Point p): call(Point+.new(int, int)) { ... } .... @@ -555,15 +578,17 @@ Exposing the target object of a `gets` or `sets` pointcut should be done the same way it was for `calls` pointcuts, with the new `target` pointcut. +[source, java] .... before(Frame f): gets(Color f.color) { ... } -==> +// ==> before(Frame f): target(f) && get(Color Frame.color) { ... } .... +[source, java] .... before(Frame f): sets(Color f.color) { ... } -==> +// ==> before(Frame f): target(f) && set(Color Frame.color) { ... } .... @@ -573,11 +598,14 @@ the field yourself in the body. Depending on the rest of your system, you may need to restrict the advice from the aspect body to eliminiate the circularity. +[source, java] .... aspect A { before(Frame f, Color c): gets(Color f.color)[c] { ... } } -==> + +// ==> + aspect A { before(Frame f): target(f) && get(Color Frame.color) && !within(A) { @@ -590,11 +618,14 @@ aspect A { The same can be done for `around` advice. However, the only way to port after advice that needs the old value is to convert it to around advice. +[source, java] .... aspect A { after(Frame f, Color c) returning (): gets(Color f.color)[c] { ... } } -==> + +// ==> + aspect A { void around(Frame f): target(f) && get(Color Frame.color) && !within(A) { @@ -610,9 +641,10 @@ available, but not the way it was previously. Instead of using the square bracket syntax, we use an `args` pointcut. All set join points are assumed to have exactly one argument, which holds the new value. So, +[source, java] .... after(Color newColor): sets(Color Frame.color)[][newColor] { ... } -==> +// ==> after(Color newColor): args(newColor) && set(Color Frame.color) { ... } .... @@ -625,9 +657,10 @@ The value of the exception at an exception handler join point is now accessed through the `args` pointcut; all exception handler join points are treated as having exactly one argument, the exception value. So, +[source, java] .... before(NotFoundException e): handlers(e) { ... } -==> +// ==> before(NotFoundException e): args(e) && handler(NotFoundException) { ... } .... @@ -640,9 +673,10 @@ closed, and within can only take type patterns, not pointcut or advice formals. A use of the `this` pointcut will capture what previous implementations did: +[source, java] .... pointcut usesFoo(Foo f): within(f); -==> +// ==> pointcut usesFoo(Foo f): this(f) && within(Foo); .... @@ -667,6 +701,7 @@ to match. For example, the pointcut +[source, java] .... calls(void m(Object)) .... @@ -677,6 +712,7 @@ out method calls to methods that are defined to take exactly the type Object, which may be a lot fewer join points. If you want the old behaviour, simply convert to +[source, java] .... call(void m(Object+)) .... @@ -692,10 +728,11 @@ pointcut, composed (with `&&`) with another pointcut. If the other pointcut was a `receptions` pointcut, then `instanceof` should be converted to `target` (and `receptions` converted to `call`). So, +[source, java] .... pointcut stateChanges(Subject s): instanceof(s) && receptions(void Button.click()); -==> +// ==> pointcut stateChange(Subject s): target(s) && call(void Button.click()); .... @@ -703,15 +740,17 @@ pointcut stateChange(Subject s): In all other cases, `instanceof` referred to the currently executing object, and so should be converted into `this` +[source, java] .... before(Point p): instanceof(p) && executions(* makePolar(..)) { ... } -==> +// ==> before(Point p): this(p) && execution(* makePolar(..)) { ... } .... +[source, java] .... pointcut setup(Client c): instanceof(c) && calls(Remote Naming.lookup(String)); -==> +// ==> pointcut setup(Client c): this(c) && calls(Remote Naming.lookup(String)); .... @@ -728,9 +767,10 @@ fields. The old behaviour can be recovered with a simple rewrite. +[source, java] .... initializations(A) -==> +// ==> initialization(A.new(..)) && !execution(A.new(..)) .... @@ -760,20 +800,22 @@ If the aspect whose presense you are checking for was defined `of eachcflow`, `of eachcflowbelow`, or, more unlikely, `of eachJVM()`, then the conversion is simple: +[source, java] .... hasaspect(A) -==> +// ==> if(A.hasAspect()) .... If the aspect was defined `of eachobject`, then you will have to expose the current object in your pointcut or advice parameters: +[source, java] .... pointcut cut(): hasaspect(A) ... ; -==> +// ==> pointcut cut(Object o): this(o) && if(A.hasAspect(o)) ... ; -or +// or pointcut cut(Object o): target(o) && if(A.hasAspect(o)) ... ; .... @@ -782,11 +824,12 @@ aspect, then you can get the same state by using `A.aspectOf()` in the body of the advice. For example, if the aspect A were defined `of eachcflow`, then +[source, java] .... before(A myA): hasaspect(myA) { myA.checkStatus(); } -==> +// ==> before(): if(A.hasAspect()) { A myA = A.aspectOf(); myA.checkStatus(); @@ -801,9 +844,10 @@ of within and the xref:#_1_0a1-subtypes-to-plus[new subtypes operator], +, instead. You'll save two characters and be using a simpler and more orthogonal language. +[source, java] .... withinall(Foo) -==> +// ==> within(Foo+) .... @@ -813,9 +857,10 @@ within(Foo+) The returns keyword is no longer necessary for user-defined pointcuts. Simply remove it when you find it. +[source, java] .... pointcut publicIntCalls() returns int: calls(public int *(..)); -==> +// ==> pointcut publicIntCall(): call(public int *(..)); .... @@ -864,9 +909,10 @@ programs easier. There is one ugly idiom, however, that this change disposes of. If your program includes the type pattern `*..*`, which used to match all types, you can replace it with the much simpler *. +[source, java] .... pointcut unaryVoidMethods(): call(void *(*..*)); -==> +// ==> pointcut unaryVoidMethod(): call(void *(*)); .... @@ -882,11 +928,12 @@ wrote `subtypes(Foo)`, i.e., the subtypes of a single type, simply replace this with `Foo+`. Otherwise, use the + operator as appropriate in `TypePattern`. +[source, java] .... public void (subtypes(Target0 || Target1)).accept(Visitor v) { v.visit(this); } -==> +// ==> public void (Target0+ || Target1+).accept(Visitor v) { v.visit(this); } @@ -901,9 +948,10 @@ public void (Target0+ || Target1+).accept(Visitor v) { The returns keyword is no longer used for around advice. Instead, the return type is declared as it is for methods. So, +[source, java] .... around(Point p) returns void: setters(p) { ... } -==> +// ==> void around(Point p): setter(p) { ... } .... @@ -913,6 +961,7 @@ void around(Point p): setter(p) { ... } Around advice must now declare the checked exceptions it throws with a `throws` clause, much like a method. +[source, java] .... char around(char c) throws java.io.CharConversionException: converter(c) { char result; @@ -951,6 +1000,7 @@ This allows interesting advice interaction. In the following advice, for example, the `after throwing` advice will catch the exception thrown by the `before` advice +[source, java] .... aspect A { before(): call(void main(..)) { @@ -965,6 +1015,7 @@ aspect A { But reversing the order will give the `before` advice more precedence, making its exception uncatchable by the `after throwing` advice +[source, java] .... aspect A { after() throwing(RuntimeException e): call(void main(..)) { @@ -986,15 +1037,17 @@ If you use after returning advice and do not need to expose the return value, you no longer need to write an empty set of parentheses to indicate that fact. So, +[source, java] .... after(Formals) returning (): Pointcut { ... } -==> +// ==> after(Formals) returning: Pointcut { ... } .... The same syntax is now available for after throwing advice, in case you do not care what `Throwable` is thrown. +[source, java] .... after(Formals) throwing: Pointcut { ... } .... @@ -1013,6 +1066,7 @@ The `JoinPoint` object hierarchy has been folded into a single class, `org.aspectj.lang.JoinPoint`. A common pattern in logging, for example, was +[source, java] .... before() executions(* myMethod()) { ExecutionJoinPoint jp = (ExecutionJoinPoint)thisJoinPoint; @@ -1025,6 +1079,7 @@ before() executions(* myMethod()) { While there is still a rich hierarchy for signatures, there is only one `JoinPoint` type, so this can be rewritten as: +[source, java] .... before() executions(* myMethod()) { JoinPoint jp = thisJoinPoint; @@ -1045,12 +1100,14 @@ Some of the method names of `JoinPoint` have been reorganized, as well. The keywords `+implements` and `+extends` no longer exist. Instead, AspectJ uses the `declare` form for exactly the same functionality. +[source, java] .... Point +implements Serializable; => declare parents: Point implements Serializable; .... +[source, java] .... MyButton +extends ButtonAdaptor; => @@ -1063,6 +1120,7 @@ declare parents: MyButton extends ButtonAdaptor; Around advice advice no longer effects the static exception checking of Java. This means that the following code previously compiled: +[source, java] .... class C { void noExceptionDeclared() { @@ -1088,6 +1146,7 @@ exceptionDeclared() will not, actually, throw an exception, we now "soften" that exception, that is, take it out of the space of declared exceptions. +[source, java] .... declare soft: ExceptionType: Pointcut; .... @@ -1097,6 +1156,7 @@ would require runtime information. But picking out method calls is just fine. So in order to make the above example work, one new declaration is needed: +[source, java] .... declare soft: IOException: call(void C.exceptionDeclared()) && @@ -1109,9 +1169,10 @@ declare soft: IOException: The syntax of "of each" modifiers has changed. For `of eachcflow` and `of eachcflowbelow`, you can simply replace "of each" with "per". So, +[source, java] .... aspect A of eachcflow(...) { ... } -==> +// ==> aspect A percflow(...) { ... } .... @@ -1120,11 +1181,12 @@ remove that declaration entirely (because this is the default behaviour), or replace the `of eachJVM()` declaration with an `issingleton` declaration. +[source, java] .... aspect of eachJVM() { ... } -==> +// ==> aspect A { ... } -or +// or aspect A issingleton { ... } .... @@ -1135,13 +1197,16 @@ you replace with depends on the `Pointcut` you use. If you use a pointcut that picked out reception join points, then use `pertarget`, and rewrite the pointcut to pick out call join points. So +[source, java] .... aspect Shadow of eachobject(receptions(void Point.setX(int)) || receptions(void Point.setY(int))) { ... } -==> + +// ==> + aspect Shadow pertarget(call(void Point.setX(int)) || call(void Point.setY(int))) { ... @@ -1193,7 +1258,7 @@ In many cases, you may not care whether the points of `Pointcut` are included or not, and so can safely leave `cflow(Pointcut)` pointcut designators alone. However, if you use the idiom -[source,codeindent] +[source, java] ---- Pointcut && ! cflow(Pointcut) ---- @@ -1201,7 +1266,7 @@ Pointcut && ! cflow(Pointcut) to capture the non-recursive entries to a particular pointcut, you will definitely want to rewrite that as -[source,codeindent] +[source, java] ---- Pointcut && ! cflowbelow(Pointcut) ---- @@ -1212,14 +1277,14 @@ The primitive pointcut designator `cflowtop(Pointcut)` has been removed from the language, as it is expressible with `cflow` or `cflowbelow`. All uses of `cflowtop(Pointcut)` can be rewritten as: -[source,codeindent] +[source, java] ---- cflowbelow(Pointcut && ! cflowbelow(Pointcut)) ---- Though in most cases the following is sufficient -[source,codeindent] +[source, java] ---- cflow(Pointcut && ! cflowbelow(Pointcut)) ---- @@ -1232,7 +1297,7 @@ override all of its abstract pointcuts with an empty pointcut. AspectJ 0.8beta3 enforces the restriction that a concrete aspect may not have any abstract pointcuts. Thus the following extension: -[source,codeindent] +[source, java] ---- abstract aspect A { abstract pointcut pc(); @@ -1245,14 +1310,14 @@ will no longer compile. Adding the new empty pointcut designator -[source,codeindent] +[source, java] ---- pointcut Id(); ---- in the declaration of the concrete aspect fixes this problem. -[source,codeindent] +[source, java] ---- abstract aspect A { abstract pointcut pc(); @@ -1269,7 +1334,7 @@ aspect B { Previously, the compiler silently refrained from applying a piece of advice to join points within its own advice body. So, for example, in -[source,codeindent] +[source, java] ---- class C { static int i; @@ -1292,7 +1357,7 @@ Most cases of this error can be fixed by correctly specifying the desired pointcut: In the above example, the intention is clearly not to trace _all_ references of `C.i`, just those outside the aspect. -[source,codeindent] +[source, java] ---- class C { static int i; @@ -1310,7 +1375,7 @@ code in the aspect, but not in the particular piece of advice. In such cases, you can pull the body of the advice into a method and restrict away from that method (and away from calls to that method): -[source,codeindent] +[source, java] ---- class C { static int i; @@ -1353,10 +1418,10 @@ to the 0.8beta1 release of AspectJ. The syntax of introduction has changed. Porting most programs should require some simple editing. Anywhere you have an introduction block -[source,codeindent] +[source, java] ---- introduction GTN { - ... + // ... } ---- @@ -1368,7 +1433,7 @@ For field introduction, place the `GTN` in front of the field name, and for constructor introduction, place the `GTN` in front of the `new` identifier. -[source,codeindent] +[source, java] ---- introduction Foo { public void doStuff() { this.doStuffLater(); } @@ -1376,7 +1441,7 @@ introduction Foo { public new(int x) { super(); calorieCount = x; } } -==> +// ==> public void Foo.doStuff() { this.doStuffLater(); } public int Foo.calorieCount= 3; @@ -1387,14 +1452,14 @@ For implements and extends introduction, move the `GTN` in front of the new identifiers `implements` or `extends`, and place that in a `declare parents` form. -[source,codeindent] +[source, java] ---- introduction Foo { implements Comparable; extends Goo; } -==> +// ==> declare parents: Foo implements Comparable; declare parents: Foo extends Goo; @@ -1404,13 +1469,13 @@ In all cases, if the `GTN` is just a type name, it can be moved down on its own. However, if the `GTN` uses any of `&&`, `||`, and `!`, it must be parenthesized. -[source,codeindent] +[source, java] ---- introduction subtypes(Foo) && !Goo { int x; } -==> +// ==> int (Foo+ && !Goo).x; ---- @@ -1423,7 +1488,7 @@ need to modify your code to avoid this accessibility issue, or you will need to use the `privileged` modifier on the aspect that contains the introduction. -[source,codeindent] +[source, java] ---- class Counter { private int count = 2; @@ -1435,7 +1500,8 @@ aspect ExposeCountersPrivates { } } -==> +// ==> + // in 0.8, only privileged aspects can expose a class's privates privileged aspect ExposeCountersPrivates { public int Counter.getCount() { return count; } @@ -1446,7 +1512,7 @@ If you have introduced private or package-protected members, you will probably have to re-write some code. Most previous uses of introducing privates can be improved by using private introduction instead. -[source,codeindent] +[source, java] ---- class C { } @@ -1458,7 +1524,8 @@ aspect AddCounter { } } -==> +// ==> + aspect AddCounter { private int Counter.count; public int Counter.getCount() { return count; } @@ -1491,7 +1558,7 @@ clause or is declared "of eachJVM()", and is not extended by another aspect, simply remove the keyword "static" from all pieces of advice, and make sure the aspect is not defined with the "abstract" modifier. -[source,codeindent] +[source, java] ---- aspect Tracing { static before(): executions(* *(..)) { @@ -1499,7 +1566,7 @@ aspect Tracing { } } -==> +// ==> aspect Tracing { before(): execution(* *(..)) { @@ -1513,7 +1580,7 @@ advice, is extended, or is "of eachObject(...)" or "of eachcflowroot(...)", you should group your static advice together and put it in a new aspect, possibly even an inner aspect. -[source,codeindent] +[source, java] ---- aspect ComplexTracing of eachobject(cflow(executions(void Main.main(..)))) { static before(): executions(* *(..)) { @@ -1526,7 +1593,7 @@ aspect ComplexTracing of eachobject(cflow(executions(void Main.main(..)))) { // some other dynamic advice, fields, etc } -==> +// ==> aspect ComplexTracing of eachobject(cflow(executions(void Main.main(..)))) { static aspect AlwaysTracing { @@ -1551,7 +1618,7 @@ majority of your code the most serious change this requires is to add an explicit `abstract` modifier to a super-aspect that was already implicitly abstract. -[source,codeindent] +[source, java] ---- aspect BaseTracing { abstract pointcut traced(); @@ -1560,11 +1627,11 @@ aspect BaseTracing { } } -==> +// ==> // make this abstract aspect explicitly abstract abstract aspect BaseTracing { - ... + // ... } ---- @@ -1576,20 +1643,22 @@ instance of a subaspect back. This pattern was used in the Spacewar example in the AspectJ distribution. We had the class hierarchy +[source, text] .... - SpaceObject (abstract) - |- Ship - |- Bullet - |- EnergyPellet +SpaceObject (abstract) + |- Ship + |- Bullet + |- EnergyPellet .... And the aspect hierarchy +[source, text] .... - SpaceObjectDA (abstract) - |- ShipDA of eachobject(instanceof(Ship)) - |- BulletDA of eachobject(instanceof(Ship)) - |- EnergyPacketDA of eachobject(instanceof(Ship)) +SpaceObjectDA (abstract) + |- ShipDA of eachobject(instanceof(Ship)) + |- BulletDA of eachobject(instanceof(Ship)) + |- EnergyPacketDA of eachobject(instanceof(Ship)) .... And we would call `SpaceObjectDA.getAspect(SpaceObject)` to access the @@ -1609,7 +1678,7 @@ defined `of eachobject(instanceof(...))`. A prime example of this was the `BoundPoint` aspect of the bean example: which needed to associate each point with a `PropertyChangeSupport` object. -[source,codeindent] +[source, java] ---- aspect BoundPoint of eachobject(instanceof(Point)) { @@ -1630,7 +1699,7 @@ these state association is to use privately introduced fields. Instead of creating an aspect instance for every `Point` object, store the `PropertyChagneSupport` object in the `Point` objects themselves. -[source,codeindent] +[source, java] ---- aspect BoundPoint { private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); diff --git a/docs/faq/faq.adoc b/docs/faq/faq.adoc index 903406d48..0c6333668 100644 --- a/docs/faq/faq.adoc +++ b/docs/faq/faq.adoc @@ -140,9 +140,9 @@ must be able to reach classes in the small (< 100K) runtime library *A:* From AspectJ's http://eclipse.org/aspectj[web page] , download the AspectJ distribution. The `jar` file is installed by executing +[source, text] .... java -jar jar file name - .... Do *not* try to extract the `jar` file contents and then attempt to @@ -503,6 +503,7 @@ AKA agile methods)? *A:* From a question on the user list: +[source, text] .... > Anyone know the connections between AOP and Extreme Programming? > I am really confused. It seems AOP is a programming paradigm, which @@ -510,7 +511,6 @@ AKA agile methods)? > this is a lightweight software development process. One of the common > motivations of AOP and XP is designed to adopt to the requirement > changes, so that it can save the cost of software development. - .... This is Raymond Lee's answer: @@ -649,6 +649,7 @@ in a modular way, something that would otherwise be spread throughout the code. Consider the following code, adapted from the AspectJ tutorial: +[source, java] .... aspect PublicErrorLogging { Log log = new Log(); @@ -660,7 +661,6 @@ aspect PublicErrorLogging { log.write(o, e); } } - .... The effect of this code is to ensure that whenever any public method of @@ -838,6 +838,7 @@ below shows how the different profiles build on top of the two configurations CDC (Connected Device Configuration) and CLDC (Connected Limited Device Configuration): +[source, text] .... -------------- | Personal | @@ -848,7 +849,6 @@ Limited Device Configuration): ------------------------------------------ | Java | ------------------------------------------ - .... Which configuration you have dictates the restrictions when running @@ -1007,18 +1007,18 @@ Environment Guide] link:devguide/ajc-ref.html[Reference for ajc]. line-delimited text file and direct ajc to that file using `-argfile` or `@`: +[source, text] .... ajc @sources.lst ajc -argfile sources.lst - .... Another way in AspectJ 1.1 is to use the `-sourceroots` options, which reads all source files in a given set of directories: +[source, text] .... ajc -sourceroots "src;testsrc" - .... For more information, see the link:devguide/index.html[Development @@ -1063,23 +1063,23 @@ Here's an example of using `ajc` in this sort of cross-compilation mode (assuming a Windows platform with all the default installation directories): +[source, text] .... ajc -target 1.1 -bootclasspath c:\jdk1.1.7\lib\classes.zip \ -classpath c:\aspectj1.0\lib\aspectjrt.jar -extdirs "" \ -argfile jdk11system.lst - .... This same technique can be used if you want to run `ajc` on a JDK 1.3 JVM (highly recommended) but need to generate code for JDK 1.2. That would look something like: +[source, text] .... ajc -bootclasspath c:\jdk1.2\jre\lib\rt.jar \ -classpath c:\aspectj1.0\lib\aspectjrt.jar \ -extdirs c:\jdk1.2\jre\lib\ext -argfile jdk12system.lst - .... *Q:* Does the `ajc` compiler support the `assert` keyword in Java 1.4? @@ -1226,10 +1226,10 @@ which will be affected by any advice specifying the same pointcut. For example, the following will print a warning whereever some code in class Bar gets a field value from Foo: +[source, java] .... declare warning: get(* Foo.*) && within(Bar) : "reading Foo state from Bar"; - .... When you are running your program, you can trace advice as it executes. @@ -1282,6 +1282,7 @@ use implement a hybrid build process by listing the production source files into a javac-compliant argfile, and the development source files in another ajc argfiles: +[source, text] .... -- file "production.lst": One.java @@ -1295,21 +1296,20 @@ Trace.java -- file "development.lst": @production.lst @tracing.lst - .... Then your development build can use `ajc`: +[source, text] .... ajc @development.lst - .... And your development build can use `ajc` or `javac` or `jikes`: +[source, text] .... jikes @production.lst - .... *Q:* We compile module jars and then assemble them. Can we continue this @@ -1331,6 +1331,7 @@ are visible to other clients, which themselves are otherwise unaffected by the aspects. In this case, the common library can be built using ajc, and used on the classpath for the module builds: +[source, text] .... ajc -outjar common.jar -sourceroots "aspectj-src:src" ... cd ../otherProject @@ -1342,6 +1343,7 @@ should affect two or more modules that are in a dependency relationship to one another. It should work to reuse the aspects in binary form for each compile, in dependency order: +[source, text] .... ajc -outjar common-aspects.jar -sourceroots "aspectj-src" ... @@ -1380,6 +1382,7 @@ libraries). In Eclipse's AJDT, you can create a top-level project with symbolic links out to the sources: +[source, text] .... app-assembly/ {link common/aspects} @@ -1425,6 +1428,7 @@ Here's some code Jim Hugunin wrote to trace join points and posted to the users list. To reuse the aspect, define a subaspect and implement the pointcuts, for example: +[source, java] .... aspect JoinPointSampleAspect extends aj.TraceJoinPoints { protected pointcut entry() : @@ -1442,11 +1446,11 @@ aspect JoinPointSampleAspect extends aj.TraceJoinPoints { class JoinPointSample { public static void main(String[] args) {} } - .... Here's the aspect: +[source, java] .... /* TraceJoinPoints.java */ @@ -1639,6 +1643,7 @@ call? How about the most-recent prior entrypoint? most-recent recursive call or (b) the current and original recursive call: +[source, java] .... aspect LogFactorial { pointcut f(int i) : call(int factorial(int)) && args(i); @@ -1654,7 +1659,6 @@ aspect LogFactorial { System.err.println(i + "@" + j); } } - .... *Q:* What is the difference between constructor call, constructor @@ -1672,6 +1676,7 @@ constructor call obtained using `TraceJointPoints.java` from #q:seeingjoinpoints[Q:I don't understand what join points exist. How can I see them?]. +[source, java] .... public class Init { public static void main (String[] args) { @@ -1689,6 +1694,7 @@ class Test extends Super implements I { For a program compiled with AspectJ 1.0, the result is this: +[source, xml] .... <constructor-call sig="Test()" > <staticinitialization sig="Super._init_" /> @@ -1723,9 +1729,9 @@ of thumb: * If you want the join point on the "outside" of object creation, use after returning from call to the constructor: + +[source, java] .... after() returning (Foo newlyCreatedObject): call(Foo.new(..)) { ... } - .... + You might be tempted to use "this" or "target" to expose the new object, @@ -1734,9 +1740,9 @@ object itself might not be created yet... it only exists "on the way out", when you return the object. * If you want the join point inside a particular constructor, use: + +[source, java] .... after(Foo newlyCreatedObject) returning: this(newlyCreatedObject) && execution(Foo.new(..)) { ... } - .... + Remember, though, that if you use "before" advice here, the body of the @@ -1747,9 +1753,9 @@ object that call each other with `this(...)` and you want exactly one join point for each initialization of `Foo`, regardless of the path of constructors it takes, then use: + +[source, java] .... after(Foo f) returning: this(f) && initialization(Foo.new(..)) { ... } - .... *Q:* I want advice to run at two join points, but it doesn't run at all. @@ -1759,9 +1765,9 @@ What gives? mistake. Most likely you want to do something like "run the advice for all public and private calls," and the code looks something like this: +[source, java] .... within(com.xerox.printing..*) && call(public * *(..)) && call(private * *(..)) - .... But a pointcut is evaluated at *each* join point. The expression above @@ -1770,9 +1776,9 @@ has both public and private access. In a pointcut, `pc1() && pc2()` means both must be true at a given join point for advice to run at that join point. The correct pointcut would use `||` as follows: +[source, java] .... within(com.xerox.printing..*) && (call(public * *(..)) || call(private * *(..))) - .... Then the advice will run at the join point. @@ -1796,6 +1802,7 @@ limited to a certain set of classes. Do I have to retype it each time? *A:* No. You can declare that all the types implement an interface you define, and then use the interface type in your program. For example: +[source, java] .... /** * Example of using an interface to represent a type pattern. @@ -1821,7 +1828,6 @@ abstract aspect MarkerExample { aspect MyMarker extends MarkerExample { declare parents: com.mycompany.whatever..* implements Marked; } - .... *Q:* Where do I find example programs and how-to's? @@ -1886,6 +1892,7 @@ Specification] . here is the HTML code for an HTML editor applet that contains some debugging aspects: +[source, xml] .... <APPLET CODE='com.company.swing.applets.EditorApplet' @@ -1914,6 +1921,7 @@ types to Object, so that highly polymorphic advice may be written. This works if an advice parameter or the return type for around is typed to Object. So: +[source, java] .... class Test { static int i; @@ -1928,15 +1936,14 @@ aspect TraceSet { System.err.println(val.class); } } - .... will print out +[source, text] .... 37 java.lang.Integer - .... For more information, see the Programming Guide @@ -1951,10 +1958,10 @@ flag as an argument. To programmatically detect the version of the AspectJ runtime while running under Java 1.4 or later, get the version from the package: +[source, java] .... Package lang = org.aspectj.lang.JoinPoint.class.getPackage(); String version = lang.getImplementationVersion(); - .... When running under Java 1.3 or earlier, read the manifest directly. For @@ -1973,13 +1980,13 @@ in `org.aspectj.bridge.Version`. *A:* The only modifier advice can take is `strictfp`. However, you can enclose the body of the advice in a synchronized clause: +[source, java] .... before() : pc() { synchronized (this) { // advice code here } } - .... It should not be necessary to synchronize a percflow aspect, but you @@ -1999,6 +2006,7 @@ VM exhausts itself in the recursion. Of course, infinite recursion is possible in Java: +[source, java] .... public class Main { public static void main(String[] args) { @@ -2009,7 +2017,6 @@ public class Main { } } } - .... If you compile and run this program, and it will fail silently, trying @@ -2018,11 +2025,11 @@ StackOverflowError. Here's a similar AspectJ program where the recursion is not so obvious: +[source, java] .... aspect A { after(): call(* *(..)) { System.out.println("after " + thisJoinPoint); } } - .... This re-invokes itself because it advises any call. It invokes itself @@ -2042,19 +2049,20 @@ finally clause, understanding that it may run after some failure. {empty}(2) Avoid writing advice that advises itself. One simple way to do so is to exclude the code within the current aspect: +[source, java] .... aspect A { after() returning: !within(A) && call(* *(..)) { System.out.println("after " + thisJoinPoint); } } - .... A better way is often to re-write the pointcut. If the advice is advising itself accidentally, that's a sign that the pointcut is not saying what you mean. +[source, java] .... aspect A { pointcut withinTargetClasses() : within(A+) || within(B+); @@ -2062,12 +2070,12 @@ aspect A { System.out.println("after " + thisJoinPoint); } } - .... *Q:* I've declared a field on every class in my package; how do I use it in advice? +[source, java] .... aspect A { boolean com.xerox..*.dirtyFlag; @@ -2076,7 +2084,6 @@ aspect A { target.dirtyFlag = true; // compile fails here } } - .... *A:* You need a type to refer to any member, field or method. It's @@ -2084,6 +2091,7 @@ generally better to introduce onto an interface and declare classes to implement the interface, which permits you to use the interface type in advice formals. +[source, java] .... aspect A { interface TrackingSets {} @@ -2095,7 +2103,6 @@ aspect A { target.dirtyFlag = true; } } - .... *Q:* The AspectJ compiler aborts with an OutOfMemoryError when compiling @@ -2182,6 +2189,7 @@ How can I fix this?]. For your IDE, do something similar or follow the provider's instructions. For example, to increase memory in JBuilder, edit the `jbuilderX/bin/jbuilder.config` file to have an entry like: +[source, text] .... vmparam -Xmx384m .... @@ -2430,6 +2438,7 @@ not control the code for the method execution), test the context for `invoke(..)`. Here's a pointcut that tests only if the method name is correct: +[source, java] .... aspect A { pointcut runReflectiveCall(Method run) : target(run) && @@ -2438,7 +2447,6 @@ aspect A { System.out.println("before reflective call " + thisJoinPoint); } } - .... *Q:* What are the bugs now most affecting users? @@ -2502,11 +2510,11 @@ CGLIB generate code from the weaving process by appropriate use of the exclude element in the aop.xml. A typical clause in the aop.xml might look as follows: +[source, xml] .... <weaver> <exclude within="*CGLIB*" /> </weaver> - .... [[aj11]] @@ -2653,6 +2661,7 @@ only XML. This means aspect developers can write abstract aspects, and deployers need only configure `aop.xml` and run using the AspectJ weaver in Java 5. For example, to run Java 5 VM with load-time weaving, +[source, text] .... java -javaagent:aspectjweaver.jar -classpath "aspects.jar:${CLASSPATH}" .. .... @@ -2661,6 +2670,7 @@ To declare a concrete aspect, add a a concrete-aspect XML entity to `META-INF/aop.xml`. This example extends a tracing aspect to apply to every type in the application: +[source, xml] .... <concrete-aspect name="com.company.tracing.ConcreteTracing" @@ -2987,10 +2997,10 @@ AJDT development environment and running the correctness tests. Then: * Create a file `aspectjlib.properties` within the `org.aspectj.ajde` project and add the following two lines + +[source, text] .... aspectj.lib.dir=C:/eclipse/aspectj-workspace/aj-build/dist/tools/lib aspectj.doc.dir=C:/eclipse/aspectj-workspace/aj-build/dist/ide/eclipse/org.aspectj.ajde.doc/doc - .... + making sure to change the path to correspond to your set up. @@ -3043,6 +3053,7 @@ is a sample file with some example definitions, preceded by comments showing the directory layout of the files referred to in the test definitions. +[source, xml] .... <!DOCTYPE suite SYSTEM "../tests/ajcTestSuite.dtd"> <suite> @@ -3137,10 +3148,10 @@ tree as described in #q:buildingsource[Q:How do I get and compile the source code for AspectJ?] and then build the `build-testing-drivers` target: +[source, text] .... cd build ../lib/ant/bin/ant -f build.xml build-testing-drivers - .... This produces `../aj-build/jars/testing-drivers-all.jar` which you can @@ -3237,8 +3248,7 @@ http://bugs.eclipse.org/bugs/enter_bug.cgi?product=AJDT ). Bug reports on ajbrowser should have version information for both Java and AspectJ, and (most importantly) clear steps for reproducing the bug. You may submit ajbrowser bugs against the IDE component of AspectJ via -the web form http://bugs.eclipse.org/bugs/enter_bug.cgi?product=AspectJ -. +the web form http://bugs.eclipse.org/bugs/enter_bug.cgi?product=AspectJ. One of the benefits of open-source is that you can find and fix the bug for yourself; when you submit the fix back to us, we can validate the @@ -3422,7 +3432,7 @@ More details for 1.0 and earlier releases are available in changes.html. *Q:* What is the AspectJ development schedule? *A:* Below is a table describing the goals for the major releases. For -information about specific features, search the bug database for `RFE`'s +information about specific features, search the bug database for ``RFE``'s ("requests for enhancement") by http://bugs.eclipse.org/bugs/buglist.cgi?product=AspectJ&bug_severity=enhancement[selecting severity of "enhancement"]. Like many open-source projects, we don't diff --git a/docs/pdGuideDB/ajcore.adoc b/docs/pdGuideDB/ajcore.adoc index a130309f9..5928d372d 100644 --- a/docs/pdGuideDB/ajcore.adoc +++ b/docs/pdGuideDB/ajcore.adoc @@ -44,6 +44,7 @@ dump configuration as well as the exception (with stack trace) that is the source of the problem and any messages issued by the compiler. Most importantly the exact version of AspectJ is included. +[source, text] .... ---- AspectJ Properties --- AspectJ Compiler DEVELOPMENT built on Tuesday Jul 25, 2006 at 13:00:09 GMT @@ -157,5 +158,4 @@ java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory at org.aspectj.tools.ajc.Main.run(Main.java:367) at org.aspectj.tools.ajc.Main.runMain(Main.java:246) at org.aspectj.tools.ajc.Main.main(Main.java:86) - .... diff --git a/docs/pdGuideDB/ltwdump.adoc b/docs/pdGuideDB/ltwdump.adoc index 3f97fb2c1..627be6635 100644 --- a/docs/pdGuideDB/ltwdump.adoc +++ b/docs/pdGuideDB/ltwdump.adoc @@ -31,6 +31,7 @@ package (and subpackages) but not CGLIB generated classes in the `com.foo.bar` package (and subpackages). It will also ensure all woven byte-code is dumped both before and after weaving. +[source, xml] .... <aspectj> <aspects> @@ -46,6 +47,7 @@ byte-code is dumped both before and after weaving. You should see messages similar to this: +[source, text] .... [WeavingURLClassLoader] info AspectJ Weaver Version 1.5.3 built on Thursday Oct 26, 2006 at 17:22:31 GMT [WeavingURLClassLoader] info register classloader org.aspectj.weaver.loadtime.WeavingURLClassLoader @@ -57,6 +59,7 @@ You should see messages similar to this: On disk you would find the following files: +[source, text] .... _ajdump/_before/com/foo/bar/Test.class _ajdump/com/foo/bar/Test.class diff --git a/docs/pdGuideDB/messages.adoc b/docs/pdGuideDB/messages.adoc index ba0ca116a..277a4f472 100644 --- a/docs/pdGuideDB/messages.adoc +++ b/docs/pdGuideDB/messages.adoc @@ -103,6 +103,7 @@ during LTW. The following example will produce basic informational messages about the lifecyle of the weaver in addition to any warning or error messages. +[source, xml] .... <aspectj> <weaver options="-verbose"> @@ -116,6 +117,7 @@ defining class loader associated with weaver. You can use this information in a large system to distinguish between different applications each of which will typically have its own class loader. +[source, text] .... [AppClassLoader@92e78c] info AspectJ Weaver Version 1.5.3 built on Thursday Oct 26, 2006 at 17:22:31 GMT [AppClassLoader@92e78c] info register classloader sun.misc.Launcher$AppClassLoader@92e78c @@ -133,6 +135,7 @@ weaving (LTW), why advice has not been woven. Here is a quick guide to the messages to look for. Firstly if you use the `-verbose` option you should see the following message when your aspect is registered: +[source, text] .... info register aspect MyAspect .... @@ -140,6 +143,7 @@ info register aspect MyAspect Secondly if you use the `-debug` option you should see a message indicating that you class is being woven: +[source, text] .... debug weaving 'HelloWorld' .... @@ -150,6 +154,7 @@ determine whether your pointcuts match you can use the `-showWeaveInfo` option which will cause a message to be issued each time a join point is woven: +[source, text] .... weaveinfo Join point 'method-execution(void HelloWorld.main(java.lang.String[]))' ... .... diff --git a/docs/pdGuideDB/trace.adoc b/docs/pdGuideDB/trace.adoc index bfe20557e..a752e0262 100644 --- a/docs/pdGuideDB/trace.adoc +++ b/docs/pdGuideDB/trace.adoc @@ -82,6 +82,7 @@ Below is an extract from that trace with method arguments removed. You will notice the millisecond time stamp, thread id and indication of entry/exit/event or message type for each line of trace. +[source, text] .... 15:44:18.630 main > org.aspectj.weaver.loadtime.Aj.<init> 15:44:18.660 main < org.aspectj.weaver.loadtime.Aj.<init> @@ -133,6 +134,7 @@ below could be used to configure Java Logging. The resulting file, just containing trace for the `org.aspectj.weaver.loadtime` package, will be written to `java0.log` in your `user.home` directory. +[source, text] .... handlers= java.util.logging.FileHandler @@ -150,6 +152,7 @@ By setting the System property `-Dorg.aspectj.tracing.debug=true` you should see a message confirming which trace infrastructure is being used. +[source, text] .... TraceFactory.instance=org.aspectj.weaver.tools.Jdk14TraceFactory@12dacd1 .... diff --git a/docs/progGuideDB/examples.adoc b/docs/progGuideDB/examples.adoc index fccd57eff..5b20a1b4e 100644 --- a/docs/progGuideDB/examples.adoc +++ b/docs/progGuideDB/examples.adoc @@ -7,35 +7,27 @@ This chapter consists entirely of examples of AspectJ use. The examples can be grouped into four categories: -technique - -Examples which illustrate how to use one or more features of the -language. - -development - -Examples of using AspectJ during the development phase of a project. - -production - -Examples of using AspectJ to provide functionality in an application. - -reusable - -Examples of reuse of aspects and pointcuts. +technique:: + Examples which illustrate how to use one or more features of the language +development:: + Examples of using AspectJ during the development phase of a project +production:: + Examples of using AspectJ to provide functionality in an application +reusable:: + Examples of reuse of aspects and pointcuts [[examples-howto]] === Obtaining, Compiling and Running the Examples The examples source code is part of the AspectJ distribution which may -be downloaded from the AspectJ project page ( -http://eclipse.org/aspectj[] ). +be downloaded from the https://eclipse.org/aspectj[AspectJ project page]. Compiling most examples is straightforward. Go the `InstallDir/examples` directory, and look for a `.lst` file in one of the example subdirectories. Use the `-arglist` option to `ajc` to compile the example. For instance, to compile the telecom example with billing, type +[source, text] .... ajc -argfile telecom/billing.lst .... @@ -45,11 +37,13 @@ Java archive (`aspectjrt.jar`). You may either set the `CLASSPATH` environment variable or use the `-classpath` command line option to the Java interpreter: +[source, text] .... (In Unix use a : in the CLASSPATH) java -classpath ".:InstallDir/lib/aspectjrt.jar" telecom.billingSimulation .... +[source, text] .... (In Windows use a ; in the CLASSPATH) java -classpath ".;InstallDir/lib/aspectjrt.jar" telecom.billingSimulation @@ -64,7 +58,7 @@ dynamic join points and advice, and with static introduction. Advice changes an application's behavior. Introduction changes both an application's behavior and its structure. -The first example, xref:#examples-joinPoints[Join Points and ], is about +The first example, xref:#examples-joinPoints[Join Points and `thisJoinPoint`], is about gathering and using information about the join point that has triggered some advice. The second example, xref:#examples-roles[Roles and Views], concerns a crosscutting view of an existing class hierarchy. @@ -87,6 +81,7 @@ join point. Here, for example, since the only join points picked out by the pointcut are calls of a certain method, we can get the target value and one of the argument values of the method calls directly. +[source, java] .... before(Point p, int x): target(p) && args(x) @@ -101,6 +96,7 @@ But sometimes the shape of the join point is not so clear. For instance, suppose a complex application is being debugged, and we want to trace when any method of some class is executed. The pointcut +[source, java] .... pointcut execsInProblemClass(): within(ProblemClass) && execution(* *(..)); @@ -124,19 +120,16 @@ point * the currently executing object * the target object * an object encapsulating the static information about the join point. -This is also available through the special variable -+ -thisJoinPointStaticPart -+ -. +This is also available through the special variable `thisJoinPointStaticPart`. ===== The `Demo` class The class `tjp.Demo` in `tjp/Demo.java` defines two methods `foo` and `bar` with different parameter lists and return types. Both are called, -with suitable arguments, by `Demo`'s `go` method which was invoked from +with suitable arguments, by ``Demo``'s `go` method which was invoked from within its `main` method. +[source, java] .... public class Demo { static Demo d; @@ -168,6 +161,7 @@ This aspect uses around advice to intercept the execution of methods `foo` and `bar` in `Demo`, and prints out information garnered from `thisJoinPoint` to the console. +[source, java] .... aspect GetInfo { @@ -207,6 +201,7 @@ aspect GetInfo { The pointcut `goCut` is defined as +[source, java] .... cflow(this(Demo)) && execution(void go()) .... @@ -221,7 +216,7 @@ advised. The name of the method and that method's defining class are available as parts of the -xref:../api/org/aspectj/lang/Signature.html[org.aspectj.lang.Signature] +xref:../api/org/aspectj/lang/Signature.html[`org.aspectj.lang.Signature`] object returned by calling `getSignature()` on either `thisJoinPoint` or `thisJoinPointStaticPart`. @@ -274,7 +269,7 @@ are provided by AspectJ without having to modify the code for the class The `Point` class defines geometric points whose interface includes polar and rectangular coordinates, plus some simple operations to -relocate points. `Point`'s implementation has attributes for both its +relocate points. ``Point``'s implementation has attributes for both its polar and rectangular coordinates, plus flags to indicate which currently reflect the position of the point. Some operations cause the polar coordinates to be updated from the rectangular, and some have the @@ -292,20 +287,21 @@ image:aspects.gif[image] ===== The `CloneablePoint` aspect -This first aspect is responsible for `Point`'s implementation of the +This first aspect is responsible for ``Point``'s implementation of the `Cloneable` interface. It declares that `Point implements Cloneable` with a `declare parents` form, and also publically declares a -specialized `Point`'s `clone()` method. In Java, all objects inherit the +specialized ``Point``'s `clone()` method. In Java, all objects inherit the method `clone` from the class `Object`, but an object is not cloneable unless its class also implements the interface `Cloneable`. In addition, classes frequently have requirements over and above the simple bit-for-bit copying that `Object.clone` does. In our case, we want to -update a `Point`'s coordinate systems before we actually clone the +update a ``Point``'s coordinate systems before we actually clone the `Point`. So our aspect makes sure that `Point` overrides `Object.clone` with a new method that does what we want. We also define a test `main` method in the aspect for convenience. +[source, java] .... public aspect CloneablePoint { @@ -338,7 +334,7 @@ public aspect CloneablePoint { ===== The `ComparablePoint` aspect -`ComparablePoint` is responsible for `Point`'s implementation of the +`ComparablePoint` is responsible for ``Point``'s implementation of the `Comparable` interface. The interface `Comparable` defines the single method `compareTo` which @@ -349,11 +345,11 @@ class that implement it. parents` to declare that `Point implements Comparable`, and also publically declares the appropriate `compareTo(Object)` method: A `Point` `p1` is said to be less than -another `Point`` - p2` if `p1` is closer to the origin. +another `Point p2` if `p1` is closer to the origin. We also define a test `main` method in the aspect for convenience. +[source, java] .... public aspect ComparablePoint { @@ -391,8 +387,8 @@ public aspect ComparablePoint { ===== The `HashablePoint` aspect -Our third aspect is responsible for `Point`'s overriding of `Object`'s -`equals` and `hashCode` methods in order to make `Point`s hashable. +Our third aspect is responsible for ``Point``'s overriding of ``Object``'s +`equals` and `hashCode` methods in order to make ``Point``s hashable. The method `Object.hashCode` returns an integer, suitable for use as a hash table key. It is not required that two objects which are not equal @@ -408,14 +404,15 @@ values, or the same `rho` and `theta` values, not just when they refer to the same object. We do this by overriding the methods `equals` and `hashCode` in the class `Point`. -So `HashablePoint` declares `Point`'s `hashCode` and `equals` methods, -using `Point`'s rectangular coordinates to generate a hash code and to +So `HashablePoint` declares ``Point``'s `hashCode` and `equals` methods, +using ``Point``'s rectangular coordinates to generate a hash code and to test for equality. The `x` and `y` coordinates are obtained using the appropriate get methods, which ensure the rectangular coordinates are up-to-date before returning their values. And again, we supply a `main` method in the aspect for testing. +[source, java] .... public aspect HashablePoint { @@ -489,6 +486,7 @@ Throughout this example we will use a simple application that contains only four classes. The application is about shapes. The `TwoDShape` class is the root of the shape hierarchy: +[source, java] .... public abstract class TwoDShape { protected double x, y; @@ -512,6 +510,7 @@ public abstract class TwoDShape { `TwoDShape` has two subclasses, `Circle` and `Square`: +[source, java] .... public class Circle extends TwoDShape { protected double r; @@ -533,6 +532,7 @@ public class Circle extends TwoDShape { } .... +[source, java] .... public class Square extends TwoDShape { protected double s; // side @@ -558,12 +558,14 @@ To run this application, compile the classes. You can do it with or without ajc, the AspectJ compiler. If you've installed AspectJ, go to the directory `InstallDir/examples` and type: +[source, text] .... ajc -argfile tracing/notrace.lst .... To run the program, type +[source, text] .... java tracing.ExampleMain .... @@ -571,6 +573,7 @@ java tracing.ExampleMain (we don't need anything special on the classpath since this is pure Java code). You should see the following output: +[source, text] .... c1.perimeter() = 12.566370614359172 c1.area() = 12.566370614359172 @@ -588,6 +591,7 @@ by writing a `Trace` class that is exactly what we would write if we didn't have aspects. The implementation is in `version1/Trace.java`. Its public interface is: +[source, java] .... public class Trace { public static int TRACELEVEL = 0; @@ -605,8 +609,9 @@ calls, and we would hope we had not forgotten any method. But we can do that more consistently and reliably with the following aspect (found in `version1/TraceMyClasses.java`): +[source, java] .... -aspect TraceMyClasses { +public aspect TraceMyClasses { pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); pointcut myConstructor(): myClass() && execution(new(..)); pointcut myMethod(): myClass() && execution(* *(..)); @@ -638,6 +643,7 @@ information, we can get it through `thisJoinPointStaticPart`. To run this version of tracing, go to the directory `InstallDir/examples` and type: +[source, text] .... ajc -argfile tracing/tracev1.lst .... @@ -645,6 +651,7 @@ ajc -argfile tracing/tracev1.lst Running the main method of `tracing.version1.TraceMyClasses` should produce the output: +[source, text] .... --> tracing.TwoDShape(double, double) <-- tracing.TwoDShape(double, double) @@ -707,6 +714,7 @@ functionality of `Trace - version1` with the crosscutting support of `TraceMyClasses - version1`. We end up with a `Trace` aspect (found in `version2/Trace.java`) with the following public interface +[source, java] .... abstract aspect Trace { @@ -721,6 +729,7 @@ abstract aspect Trace { In order to use it, we need to define our own subclass that knows about our application classes, in `version2/TraceMyClasses.java`: +[source, java] .... public aspect TraceMyClasses extends Trace { pointcut myClass(): within(TwoDShape) || within(Circle) || within(Square); @@ -737,6 +746,7 @@ Notice that we've simply made the pointcut `classes`, that was an abstract pointcut in the super-aspect, concrete. To run this version of tracing, go to the directory `examples` and type: +[source, text] .... ajc -argfile tracing/tracev2.lst .... @@ -748,6 +758,7 @@ the same trace information as that from version 1. The entire implementation of the new `Trace` class is: +[source, java] .... abstract aspect Trace { @@ -869,6 +880,7 @@ bound property protocol. The `Point` class is a very simple class with trivial getters and setters, and a simple vector offset method. +[source, java] .... class Point { @@ -908,11 +920,12 @@ class Point { ===== The `BoundPoint` aspect -The `BoundPoint` aspect is responsible for `Point`'s "beanness". The +The `BoundPoint` aspect is responsible for ``Point``'s "beanness". The first thing it does is privately declare that each `Point` has a `support` field that holds reference to an instance of `PropertyChangeSupport`. +[source, java] .... private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); .... @@ -923,10 +936,11 @@ passing it `this`, an instance of `Point`. Since the `support` field is private declared in the aspect, only the code in the aspect can refer to it. -The aspect also declares `Point`'s methods for registering and managing +The aspect also declares ``Point``'s methods for registering and managing listeners for property change events, which delegate the work to the property change support object: +[source, java] .... public void Point.addPropertyChangeListener(PropertyChangeListener listener){ support.addPropertyChangeListener(listener); @@ -951,6 +965,7 @@ public void Point.hasListeners(String propertyName) { The aspect is also responsible for making sure `Point` implements the `Serializable` interface: +[source, java] .... declare parents: Point implements Serializable; .... @@ -959,13 +974,14 @@ Implementing this interface in Java does not require any methods to be implemented. Serialization for `Point` objects is provided by the default serialization method. -The `setters` pointcut picks out calls to the `Point`'s `set` methods: +The `setters` pointcut picks out calls to the ``Point``'s `set` methods: any method whose name begins with "`set`" and takes one parameter. The around advice on `setters()` stores the values of the `X` and `Y` properties, calls the original `set` method and then fires the appropriate property change event according to which set method was called. +[source, java] .... aspect BoundPoint { private PropertyChangeSupport Point.support = new PropertyChangeSupport(this); @@ -1025,6 +1041,7 @@ that point: calling its set methods and the offset method. Then it serializes the point and writes it to a file and then reads it back. The result of saving and restoring the point is that a new point is created. +[source, java] .... class Demo implements PropertyChangeListener { @@ -1059,6 +1076,7 @@ class Demo implements PropertyChangeListener { To compile and run this example, go to the examples directory and type: +[source, text] .... ajc -argfile bean/files.lst java bean.Demo @@ -1093,6 +1111,7 @@ The generic parts of the protocol are the interfaces `Subject` and view `Observer` objects, and a method for getting data about state changes: +[source, java] .... interface Subject { void addObserver(Observer obs); @@ -1105,6 +1124,7 @@ interface Subject { The `Observer` interface is just as simple, with methods to set and get `Subject` objects, and a method to call when the subject gets updated. +[source, java] .... interface Observer { void setSubject(Subject s); @@ -1117,6 +1137,7 @@ The `SubjectObserverProtocol` aspect contains within it all of the generic parts of the protocol, namely, how to fire the `Observer` objects' update methods when some state changes in a subject. +[source, java] .... abstract aspect SubjectObserverProtocol { @@ -1157,6 +1178,7 @@ its `Subject`. `Button` objects extend `java.awt.Button`, and all they do is make sure the `void click()` method is called whenever a button is clicked. +[source, java] .... class Button extends java.awt.Button { @@ -1187,6 +1209,7 @@ Note that this class knows nothing about being a Subject. ColorLabel objects are labels that support the void colorCycle() method. Again, they know nothing about being an observer. +[source, java] .... class ColorLabel extends Label { @@ -1212,6 +1235,7 @@ Finally, the `SubjectObserverProtocolImpl` implements the subject/observer protocol, with `Button` objects as subjects and `ColorLabel` objects as observers: +[source, java] .... package observer; @@ -1246,6 +1270,7 @@ all `ColorLabel` objects observing that button will `colorCycle`. buttons and three observers and links them together as subjects and observers. So to run the demo, go to the `examples` directory and type: +[source, text] .... ajc -argfile observer/files.lst java observer.Demo @@ -1303,6 +1328,7 @@ involved in many calls at one time. image:telecom.gif[image] `Customer` has methods `call`, `pickup`, `hangup` and `merge` for managing calls. +[source, java] .... public class Customer { @@ -1377,6 +1403,7 @@ connection between customers. It does this with a simple state machine connections can be observed. Connection is an abstract class with two concrete subclasses: `Local` and `LongDistance`. +[source, java] .... abstract class Connection { @@ -1422,6 +1449,7 @@ abstract class Connection { The two kinds of connections supported by our simulation are `Local` and `LongDistance` connections. +[source, java] .... class Local extends Connection { Local(Customer a, Customer b) { @@ -1432,6 +1460,7 @@ class Local extends Connection { } .... +[source, java] .... class LongDistance extends Connection { LongDistance(Customer a, Customer b) { @@ -1448,6 +1477,7 @@ The source files for the basic system are listed in the file `basic.lst`. To build and run the basic system, in a shell window, type these commands: +[source, text] .... ajc -argfile telecom/basic.lst java telecom.BasicSimulation @@ -1466,6 +1496,7 @@ stopped, and returns their difference when asked for the elapsed time. The aspect `TimerLog` (below) can be used to cause the start and stop times to be printed to standard output. +[source, java] .... class Timer { long startTime, stopTime; @@ -1490,6 +1521,7 @@ class Timer { The `TimerLog` aspect can be included in a build to get the timer to announce when it is started and stopped. +[source, java] .... public aspect TimerLog { @@ -1509,6 +1541,7 @@ The `Timing` aspect is declares an inter-type field `totalConnectTime` for `Customer` to store the accumulated connection time per `Customer`. It also declares that each `Connection` object has a timer. +[source, java] .... public long Customer.totalConnectTime = 0; private Timer Connection.timer = new Timer(); @@ -1518,6 +1551,7 @@ Two pieces of after advice ensure that the timer is started when a connection is completed and and stopped when it is dropped. The pointcut `endTiming` is defined so that it can be used by the `Billing` aspect. +[source, java] .... public aspect Timing { @@ -1556,10 +1590,11 @@ responsible to pay for it. It also declares the inter-type method charged differently. The call charge must be calculated after the timer is stopped; the after advice on pointcut `Timing.endTiming` does this, and `Billing` is declared to be more precedent than `Timing` to make -sure that this advice runs after `Timing`'s advice on the same join +sure that this advice runs after ``Timing``'s advice on the same join point. Finally, it declares inter-type methods and fields for `Customer` to handle the `totalCharge`. +[source, java] .... public aspect Billing { // precedence required to get advice on endtiming in the right order @@ -1613,6 +1648,7 @@ the method run of the superclass `AbstractSimulation`. This method is intended to print out the status of the customer, with respect to the `Timing` feature. +[source, java] .... protected void report(Customer c){ Timing t = Timing.aspectOf(); @@ -1626,6 +1662,7 @@ The files timing.lst and billing.lst contain file lists for the timing and billing configurations. To build and run the application with only the timing feature, go to the directory examples and type: +[source, text] .... ajc -argfile telecom/timing.lst java telecom.TimingSimulation @@ -1634,6 +1671,7 @@ java telecom.TimingSimulation To build and run the application with the timing and billing features, go to the directory examples and type: +[source, text] .... ajc -argfile telecom/billing.lst java telecom.BillingSimulation @@ -1669,6 +1707,7 @@ the object whose methods are being traced. This can be achieved in at least two ways. One way is keep the interface of the methods `traceEntry` and `traceExit` as it was before, +[source, java] .... public static void traceEntry(String str); public static void traceExit(String str); @@ -1678,6 +1717,7 @@ In this case, the caller is responsible for ensuring that the string representation of the object is part of the string given as argument. So, calls must look like: +[source, java] .... Trace.traceEntry("Square.distance in " + toString()); .... @@ -1685,6 +1725,7 @@ Trace.traceEntry("Square.distance in " + toString()); Another way is to enforce the requirement with a second argument in the trace operations, e.g. +[source, java] .... public static void traceEntry(String str, Object obj); public static void traceExit(String str, Object obj); @@ -1694,6 +1735,7 @@ In this case, the caller is still responsible for sending the right object, but at least there is some guarantees that some object will be passed. The calls will look like: +[source, java] .... Trace.traceEntry("Square.distance", this); .... @@ -1709,6 +1751,7 @@ only a small effect inside the `Trace` class. Here's a partial view at the implementation of `Trace`, version 3. The differences with respect to version 2 are stressed in the comments: +[source, java] .... abstract aspect Trace { @@ -1794,6 +1837,7 @@ In fact, esimply excluding the execution join point may not be enough, if there are calls to other traced methods within it -- in which case, the restriction should be +[source, java] .... && !cflow(execution(String toString())) .... @@ -1811,6 +1855,7 @@ every application class. Finally, to run this version of tracing, go to the directory `examples` and type: +[source, text] .... ajc -argfile tracing/tracev3.lst .... @@ -1819,12 +1864,14 @@ The file tracev3.lst lists the application classes as well as this version of the files `Trace.java` and `TraceMyClasses.java`. To run the program, type +[source, text] .... java tracing.version3.TraceMyClasses .... The output should be: +[source, text] .... --> tracing.TwoDShape(double, double) <-- tracing.TwoDShape(double, double) diff --git a/docs/progGuideDB/gettingstarted.adoc b/docs/progGuideDB/gettingstarted.adoc index 0dbb85056..f22c9cefd 100644 --- a/docs/progGuideDB/gettingstarted.adoc +++ b/docs/progGuideDB/gettingstarted.adoc @@ -39,7 +39,7 @@ testing and performance tuning of applications. And, in the section following, xref:#starting-production[Production Aspects], we present aspects that implement crosscutting functionality common in Java applications. We will defer discussing a third category of aspects, -reusable aspects, until xref:language.adoc[The AspectJ Language]. +reusable aspects, until xref:language.adoc#language[The AspectJ Language]. These categories are informal, and this ordering is not the only way to adopt AspectJ. Some developers may want to use a production aspect right @@ -56,7 +56,7 @@ language, but this is by no means a complete overview of AspectJ. The features are presented using a simple figure editor system. A `Figure` consists of a number of `FigureElements`, which can be either -`Point`s or `Line`s. The `Figure` class provides factory services. There +``Point``s or ``Line``s. The `Figure` class provides factory services. There is also a `Display`. Most example programs later in this chapter are based on this system as well. @@ -143,17 +143,19 @@ context_ of the original call join point. In AspectJ, _pointcuts_ pick out certain join points in the program flow. For example, the pointcut +[source, java] .... call(void Point.setX(int)) .... picks out each join point that is a call to a method that has the -signature `void Point.setX(int)` - that is, `Point`'s void `setX` method +signature `void Point.setX(int)` - that is, ``Point``'s void `setX` method with a single `int` parameter. A pointcut can be built out of other pointcuts with and, or, and not (spelled `&&`, `||`, and `!`). For example: +[source, java] .... call(void Point.setX(int)) || call(void Point.setY(int)) @@ -165,6 +167,7 @@ picks out each join point that is either a call to `setX` or a call to Pointcuts can identify join points from many different types - in other words, they can crosscut types. For example, +[source, java] .... call(void FigureElement.setXY(int,int)) || call(void Point.setX(int)) || @@ -182,6 +185,7 @@ crosscutting concern, it is a bit of a mouthful. So AspectJ allows programmers to define their own named pointcuts with the `pointcut` form. So the following declares a new, named pointcut: +[source, java] .... pointcut move(): call(void FigureElement.setXY(int,int)) || @@ -202,6 +206,7 @@ _property-based_ crosscutting. The simplest of these involve using wildcards in certain fields of the method signature. For example, the pointcut +[source, java] .... call(void Figure.make*(..)) .... @@ -211,16 +216,18 @@ picks out each join point that's a call to a void method defined on parameters. In our system, this picks out calls to the factory methods `makePoint` and `makeLine`. The pointcut +[source, java] .... call(public * Figure.* (..)) .... -picks out each call to `Figure`'s public methods. +picks out each call to ``Figure``'s public methods. But wildcards aren't the only properties AspectJ supports. Another pointcut, `cflow`, identifies join points based on whether they occur in the dynamic context of other join points. So +[source, java] .... cflow(move()) .... @@ -245,6 +252,7 @@ For example, before advice on a method call join point runs before the actual method starts running, just after the arguments to the method call are evaluated. +[source, java] .... before(): move() { System.out.println("about to move"); @@ -260,6 +268,7 @@ of after advice: `after returning`, `after throwing`, and plain `after` (which runs after returning _or_ throwing, like Java's `finally`). +[source, java] .... after() returning: move() { System.out.println("just successfully moved"); @@ -280,6 +289,7 @@ An advice declaration has a parameter list (like a method) that gives names to all the pieces of context that it uses. For example, the after advice +[source, java] .... after(FigureElement fe, int x, int y) returning: ...SomePointcut... { @@ -288,10 +298,11 @@ after(FigureElement fe, int x, int y) returning: .... uses three pieces of exposed context, a `FigureElement` named fe, and -two `int`s named x and y. +two ``int``s named x and y. The body of the advice uses the names just like method parameters, so +[source, java] .... after(FigureElement fe, int x, int y) returning: ...SomePointcut... { @@ -303,6 +314,7 @@ The advice's pointcut publishes the values for the advice's arguments. The three primitive pointcuts `this`, `target` and `args` are used to publish these values. So now we can write the complete piece of advice: +[source, java] .... after(FigureElement fe, int x, int y) returning: call(void FigureElement.setXY(int, int)) @@ -326,6 +338,7 @@ named pointcut is used (by advice, or in another named pointcut), it publishes its context by name just like the `this`, `target` and `args` pointcut. So another way to write the above advice is +[source, java] .... pointcut setXY(FigureElement fe, int x, int y): call(void FigureElement.setXY(int, int)) @@ -360,8 +373,9 @@ Suppose we want to have `Screen` objects observe changes to `Point` objects, where `Point` is an existing class. We can implement this by writing an aspect declaring that the class Point `Point` has an instance field, `observers`, that keeps track of the `Screen` objects that are -observing `Point`s. +observing ``Point``s. +[source, java] .... aspect PointObserving { private Vector Point.observers = new Vector(); @@ -373,6 +387,7 @@ The `observers` field is private, so only `PointObserving` can see it. So observers are added or removed with the static methods `addObserver` and `removeObserver` on the aspect. +[source, java] .... aspect PointObserving { private Vector Point.observers = new Vector(); @@ -391,6 +406,7 @@ Along with this, we can define a pointcut `changes` that defines what we want to observe, and the after advice defines what we want to do when we observe a change. +[source, java] .... aspect PointObserving { private Vector Point.observers = new Vector(); @@ -417,7 +433,7 @@ aspect PointObserving { } .... -Note that neither `Screen`'s nor `Point`'s code has to be modified, and +Note that neither ``Screen``'s nor ``Point``'s code has to be modified, and that all the changes needed to support this new capability are local to this aspect. @@ -435,6 +451,7 @@ aspect instances. By default, each aspect is a singleton, so one aspect instance is created. This means that advice may use non-static fields of the aspect, if it needs to keep state around: +[source, java] .... aspect Logging { OutputStream logStream = System.err; @@ -471,6 +488,7 @@ workings of a program. It is a simple tracing aspect that prints a message at specified method calls. In our figure editor example, one such aspect might simply trace whenever points are drawn. +[source, java] .... aspect SimpleTracing { pointcut tracedCall(): @@ -487,6 +505,7 @@ advice bodies this variable is bound to an object that describes the current join point. The effect of this code is to print a line like the following every time a figure element receives a `draw` method call: +[source, text] .... Entering: call(void FigureElement.draw(GraphicsContext)) .... @@ -529,6 +548,7 @@ For example, the following aspect counts the number of calls to the methods of a `Point` that happen within the control flow of those calls to `rotate`: +[source, java] .... aspect SetsInRotateCounting { int rotateCount = 0; @@ -589,6 +609,7 @@ properly do the work they are supposed to. AspectJ makes it possible to implement pre- and post-condition testing in modular form. For example, this code +[source, java] .... aspect PointBoundsChecking { @@ -636,6 +657,7 @@ the constraint that only the well-known factory methods can add an element to the registry of figure elements. Enforcing this constraint ensures that no figure element is added to the registry more than once. +[source, java] .... aspect RegistrationProtection { @@ -662,6 +684,7 @@ This advice throws a runtime exception at certain join points, but AspectJ can do better. Using the `declare error` form, we can have the _compiler_ signal the error. +[source, java] .... aspect RegistrationProtection { @@ -722,6 +745,7 @@ state of the dirty flag and resets it to false. The pointcut `move` captures all the method calls that can move a figure element. The after advice on `move` sets the dirty flag whenever an object moves. +[source, java] .... aspect MoveTracking { private static boolean dirty = false; @@ -807,6 +831,7 @@ modular way. The following code adds after advice that runs only when the factory methods of `Figure` are called in the control flow of a method on a `ColorControllingClient`. +[source, java] .... aspect ColorControl { pointcut CCClientCflow(ColorControllingClient client): @@ -841,6 +866,7 @@ captures the public method calls of the package, and the after advice runs whenever one of those calls throws an Error. The advice logs that Error and then the throw resumes. +[source, java] .... aspect PublicErrorLogging { Log log = new Log(); @@ -861,6 +887,7 @@ outermost call into the `com.bigboxco` package and the re-entrant call. The `cflow` primitive pointcut can be used in a nice way to exclude these re-entrant calls: +[source, java] .... after() throwing (Error e): publicMethodCall() && !cflow(publicMethodCall()) { @@ -874,6 +901,7 @@ individual methods handle each of the different kinds of elements that must be parsed. They have names like `parseMethodDec`, `parseThrows`, and `parseExpr`. +[source, java] .... aspect ContextFilling { pointcut parse(JavaParser jp): diff --git a/docs/progGuideDB/idioms.adoc b/docs/progGuideDB/idioms.adoc index 9bc16c081..8e5f6e43e 100644 --- a/docs/progGuideDB/idioms.adoc +++ b/docs/progGuideDB/idioms.adoc @@ -11,6 +11,7 @@ Here's an example of how to enfore a rule that code in the java.sql package can only be used from one particular package in your system. This doesn't require any access to code in the java.sql package. +[source, java] .... /* Any call to methods or constructors in java.sql */ pointcut restrictedCall(): @@ -27,6 +28,7 @@ declare error: restrictedCall() && illegalSource(): Any call to an instance of a subtype of AbstractFacade whose class is not exactly equal to AbstractFacade: +[source, java] .... pointcut nonAbstract(AbstractFacade af): call(* *(..)) @@ -37,6 +39,7 @@ pointcut nonAbstract(AbstractFacade af): If AbstractFacade is an abstract class or an interface, then every instance must be of a subtype and you can replace this with: +[source, java] .... pointcut nonAbstract(AbstractFacade af): call(* *(..)) @@ -46,6 +49,7 @@ pointcut nonAbstract(AbstractFacade af): Any call to a method which is defined by a subtype of AbstractFacade, but which isn't defined by the type AbstractFacade itself: +[source, java] .... pointcut callToUndefinedMethod(): call(* AbstractFacade+.*(..)) @@ -55,6 +59,7 @@ pointcut callToUndefinedMethod(): The execution of a method that is defined in the source code for a type that is a subtype of AbstractFacade but not in AbstractFacade itself: +[source, java] .... pointcut executionOfUndefinedMethod(): execution(* *(..)) diff --git a/docs/progGuideDB/implementation.adoc b/docs/progGuideDB/implementation.adoc index a34324d5f..f7a8f7c7b 100644 --- a/docs/progGuideDB/implementation.adoc +++ b/docs/progGuideDB/implementation.adoc @@ -17,6 +17,7 @@ implementations should do tomorrow. According to the AspectJ language semantics, the declaration +[source, java] .... before(): get(int Point.x) { System.out.println("got x"); } .... @@ -128,6 +129,7 @@ source code. This means that there may be call join points to `Class.forName` or `StringBuffer.append` from programs that do not, at first glance, appear to contain such calls: +[source, java] .... class Test { void main(String[] args) { @@ -158,6 +160,7 @@ be the case. Before advice is allowed. The second is that the control flow of a handler join point is not picked out. For example, the following pointcut +[source, java] .... cflow(call(void foo()) || handler(java.io.IOException)) .... @@ -173,6 +176,7 @@ This does not restrict programs from placing before advice on handlers inside _other_ control flows. This advice, for example, is perfectly fine: +[source, java] .... before(): handler(java.io.IOException) && cflow(void parse()) { System.out.println("about to handle an exception while parsing"); @@ -187,6 +191,7 @@ have fewer such restrictions. The code for Java initializers, such as the assignment to the field d in +[source, java] .... class C { double d = Math.sqrt(2); @@ -203,6 +208,7 @@ a super-constructor (as opposed to a `this` constructor), the target type's initialization code will _not_ be run when that inter-type constructor is called. +[source, java] .... aspect A { C.new(Object o) {} // implicitly calls super() diff --git a/docs/progGuideDB/language.adoc b/docs/progGuideDB/language.adoc index f48cc4290..3aeb5eebd 100644 --- a/docs/progGuideDB/language.adoc +++ b/docs/progGuideDB/language.adoc @@ -24,30 +24,31 @@ exposed to the new terminology introduced by AspectJ. Here's an example of an aspect definition in AspectJ: -.... - 1 aspect FaultHandler { - 2 - 3 private boolean Server.disabled = false; - 4 - 5 private void reportFault() { - 6 System.out.println("Failure! Please fix it."); - 7 } - 8 - 9 public static void fixServer(Server s) { -10 s.disabled = false; -11 } -12 -13 pointcut services(Server s): target(s) && call(public * *(..)); -14 -15 before(Server s): services(s) { -16 if (s.disabled) throw new DisabledException(); -17 } -18 -19 after(Server s) throwing (FaultException e): services(s) { -20 s.disabled = true; -21 reportFault(); -22 } -23 } +[source, java] +.... +/*01*/ aspect FaultHandler { +/*02*/ +/*03*/ private boolean Server.disabled = false; +/*04*/ +/*05*/ private void reportFault() { +/*06*/ System.out.println("Failure! Please fix it."); +/*07*/ } +/*08*/ +/*09*/ public static void fixServer(Server s) { +/*10*/ s.disabled = false; +/*11*/ } +/*12*/ +/*13*/ pointcut services(Server s): target(s) && call(public * *(..)); +/*14*/ +/*15*/ before(Server s): services(s) { +/*16*/ if (s.disabled) throw new DisabledException(); +/*17*/ } +/*18*/ +/*19*/ after(Server s) throwing (FaultException e): services(s) { +/*20*/ s.disabled = true; +/*21*/ reportFault(); +/*22*/ } +/*23*/ } .... The `FaultHandler` consists of one inter-type field on `Server` (line @@ -69,6 +70,7 @@ invocations and executions, the handling of exceptions, field assignments and accesses, etc. Take, for example, the pointcut definition in line 13: +[source, java] .... pointcut services(Server s): target(s) && call(public * *(..)) .... @@ -114,6 +116,7 @@ define aspect implementation that runs at join points picked out by the pointcut. For example, the advice in lines 15-17 specifies that the following piece of code +[source, java] .... { if (s.disabled) throw new DisabledException(); @@ -128,6 +131,7 @@ corresponding methods are executed. The advice in lines 19-22 defines another piece of implementation that is executed on the same pointcut: +[source, java] .... { s.disabled = true; @@ -148,6 +152,7 @@ this guide. Consider the following Java class: +[source, java] .... class Point { private int x, y; @@ -166,6 +171,7 @@ In order to get an intuitive understanding of AspectJ's join points and pointcuts, let's go back to some of the basic principles of Java. Consider the following a method declaration in class Point: +[source, java] .... void setX(int x) { this.x = x; } .... @@ -192,6 +198,7 @@ complete listing.) Pointcuts pick out these join points. For example, the pointcut +[source, java] .... pointcut setter(): target(Point) && (call(void setX(int)) || @@ -201,6 +208,7 @@ pointcut setter(): target(Point) && picks out each call to `setX(int)` or `setY(int)` when called on an instance of `Point`. Here's another example: +[source, java] .... pointcut ioHandler(): within(MyClass) && handler(IOException); .... @@ -230,7 +238,7 @@ when the target object is of type `SomeType`:: `target(SomeType)` when the executing code belongs to class `MyClass`:: `within(MyClass)` -when the join point is in the control flow of a call to a `Test`'s +when the join point is in the control flow of a call to a ``Test``'s no-argument `main` method:: `cflow(call(void Test.main()))` @@ -256,9 +264,9 @@ such `set` method; this pointcut picks out calls to all of them. means (1) the execution of any method with no parameters that returns an `int`, (2) the call to any `setY` method that takes a `long` as an argument, regardless of return type or declaring type, (3) the call to -any of `Point`'s `setY` methods that take an `int` as an argument, +any of ``Point``'s `setY` methods that take an `int` as an argument, regardless of return type, and (4) the call to any classes' constructor, -so long as it takes exactly two `int`s as arguments. +so long as it takes exactly two ``int``s as arguments. * You can compose pointcuts. For example, [arabic] . `target(Point) && call(int *())` @@ -270,7 +278,7 @@ so long as it takes exactly two `int`s as arguments. + means (1) any call to an `int` method with no arguments on an instance of `Point`, regardless of its name, (2) any call to any method where the -call is made from the code in `Point`'s or `Line`'s type declaration, +call is made from the code in ``Point``'s or ``Line``'s type declaration, (3) the execution of any constructor taking exactly one `int` argument, regardless of where the call is made from, and (4) any method call to an `int` method when the executing object is any type except `Point`. @@ -286,12 +294,13 @@ non-static method, and (3) any execution of a public, non-static method. * Pointcuts can also deal with interfaces. For example, given the interface + +[source, java] .... interface MyInterface { ... } .... + the pointcut `call(* MyInterface.*(..))` picks out any call to a method -in `MyInterface`'s signature -- that is, any method defined by +in ``MyInterface``'s signature -- that is, any method defined by `MyInterface` or inherited by one of its a supertypes. [[call-vs-execution]] @@ -339,6 +348,7 @@ primitive pointcuts like `cflow` and `cflowbelow`. Here's an example: `cflow(P)` picks out each join point in the control flow of the join points picked out by <P>. So, pictorially: +[source, text] .... P --------------------- \ @@ -350,6 +360,7 @@ What does `cflow(P) && cflow(Q)` pick out? Well, it picks out each join point that is in both the control flow of <P> and in the control flow of <Q>. So... +[source, text] .... P --------------------- \ @@ -370,6 +381,7 @@ But what does `cflow(P && Q)` mean? Well, it means the control flow of those join points that are both picked out by <P> and picked out by <Q>. +[source, text] .... P && Q ------------------- \ @@ -384,6 +396,7 @@ control flow of `(P && Here's some code that expresses this. +[source, java] .... public class Test { public static void main(String[] args) { @@ -422,6 +435,7 @@ for more details.) Consider again the first pointcut definition in this chapter: +[source, java] .... pointcut setter(): target(Point) && (call(void setX(int)) || @@ -435,6 +449,7 @@ side. An empty parameter list means that none of the context from the join points is published from this pointcut. But consider another version of version of this pointcut definition: +[source, java] .... pointcut setter(Point p): target(p) && (call(void setX(int)) || @@ -452,6 +467,7 @@ matched join point. Here's another example that illustrates the flexible mechanism for defining pointcut parameters: +[source, java] .... pointcut testEquality(Point p): target(Point) && args(p) && @@ -464,10 +480,11 @@ access to a `Point` from each join point. But in this case, looking at the right-hand side we find that the object named in the parameters is not the target `Point` object that receives the call; it's the argument (also of type `Point`) passed to the `equals` method when some other -`Point` is the target. If we wanted access to both `Point`s, then the +`Point` is the target. If we wanted access to both ``Point``s, then the pointcut definition that would expose target `Point p1` and argument `Point p2` would be +[source, java] .... pointcut testEquality(Point p1, Point p2): target(p1) && args(p2) && @@ -476,6 +493,7 @@ pointcut testEquality(Point p1, Point p2): target(p1) && Let's look at another variation of the `setters` pointcut: +[source, java] .... pointcut setter(Point p, int newval): target(p) && args(newval) && @@ -493,6 +511,7 @@ important rule is that all the pointcut parameters must be bound at every join point picked out by the pointcut. So, for example, the following pointcut definition will result in a compilation error: +[source, java] .... pointcut badPointcut(Point p1, Point p2): (target(p1) && call(void setX(int))) || @@ -512,6 +531,7 @@ operations to their `Partner` objects. The aspect `HandleLiveness` ensures that, before the delegations, the partner exists and is alive, or else it throws an exception. +[source, java] .... class Handle { Partner partner = new Partner(); @@ -594,6 +614,7 @@ given either by named pointcuts (like the ones you've seen above) or by anonymous pointcuts. Here is an example of an advice on a named pointcut: +[source, java] .... pointcut setter(Point p1, int newval): target(p1) && args(newval) (call(void setX(int) || @@ -607,6 +628,7 @@ before(Point p1, int newval): setter(p1, newval) { And here is exactly the same example, but using an anonymous pointcut: +[source, java] .... before(Point p1, int newval): target(p1) && args(newval) (call(void setX(int)) || @@ -621,6 +643,7 @@ Here are examples of the different advice: This before advice runs just before the join points picked out by the (anonymous) pointcut: +[source, java] .... before(Point p, int x): target(p) && args(x) && call(void setX(int)) { if (!p.assertX(x)) return; @@ -631,6 +654,7 @@ This after advice runs just after each join point picked out by the (anonymous) pointcut, regardless of whether it returns normally or throws an exception: +[source, java] .... after(Point p, int x): target(p) && args(x) && call(void setX(int)) { if (!p.assertX(x)) throw new PostConditionViolation(); @@ -642,6 +666,7 @@ by the (anonymous) pointcut, but only if it returns normally. The return value can be accessed, and is named `x` here. After the advice runs, the return value is returned: +[source, java] .... after(Point p) returning(int x): target(p) && call(int getX()) { System.out.println("Returning int value " + x + " for p = " + p); @@ -653,6 +678,7 @@ the (anonymous) pointcut, but only when it throws an exception of type `Exception`. Here the exception value can be accessed with the name `e`. The advice re-raises the exception after it's done: +[source, java] .... after() throwing(Exception e): target(Point) && call(void setX(int)) { System.out.println(e); @@ -663,6 +689,7 @@ This around advice traps the execution of the join point; it runs _instead_ of the join point. The original action associated with the join point can be invoked through the special `proceed` call: +[source, java] .... void around(Point p, int x): target(p) && args(x) @@ -683,6 +710,7 @@ class. Here are examples of some such inter-type declarations: This declares that each `Server` has a `boolean` field named `disabled`, initialized to `false`: +[source, java] .... private boolean Server.disabled = false; .... @@ -696,6 +724,7 @@ another aspect) there won't be a name collision, since no reference to This declares that each `Point` has an `int` method named `getX` with no arguments that returns whatever `this.x` is: +[source, java] .... public int Point.getX() { return this.x; } .... @@ -707,6 +736,7 @@ conflict. This publically declares a two-argument constructor for `Point`: +[source, java] .... public Point.new(int x, int y) { this.x = x; this.y = y; } .... @@ -714,6 +744,7 @@ public Point.new(int x, int y) { this.x = x; this.y = y; } This publicly declares that each `Point` has an `int` field named `x`, initialized to zero: +[source, java] .... public int Point.x = 0; .... @@ -724,6 +755,7 @@ has a field named `x` (defined by `Point` or by another aspect). This declares that the `Point` class implements the `Comparable` interface: +[source, java] .... declare parents: Point implements Comparable; .... @@ -734,6 +766,7 @@ required by `Comparable`. This declares that the `Point` class extends the `GeometricObject` class. +[source, java] .... declare parents: Point extends GeometricObject; .... @@ -741,6 +774,7 @@ declare parents: Point extends GeometricObject; An aspect can have several inter-type declarations. For example, the following declarations +[source, java] .... public String Point.name; public void Point.setName(String name) { this.name = name; } @@ -754,6 +788,7 @@ An inter-type member can only have one target type, but often you may wish to declare the same member on more than one type. This can be done by using an inter-type member in combination with a private interface: +[source, java] .... aspect A { private interface HasName {} @@ -782,18 +817,20 @@ declarations in addition to public inter-type declarations. Private means private in relation to the aspect, not necessarily the target type. So, if an aspect makes a private inter-type declaration of a field +[source, java] .... private int Foo.x; .... -Then code in the aspect can refer to `Foo`'s `x` field, but nobody else +Then code in the aspect can refer to ``Foo``'s `x` field, but nobody else can. Similarly, if an aspect makes a package-protected introduction, +[source, java] .... - int Foo.x; +int Foo.x; .... -then everything in the aspect's package (which may or may not be `Foo`'s +then everything in the aspect's package (which may or may not be ``Foo``'s package) can access `x`. ==== Example: `PointAssertions` @@ -806,6 +843,7 @@ other parts of the program (including the code in `Point`) have no business accessing the assert methods. Only the code inside of the aspect can call those methods. +[source, java] .... class Point { int x, y; @@ -856,6 +894,7 @@ One way to use it is simply to print it out. Like all Java objects, `thisJoinPoint` has a `toString()` method that makes quick-and-dirty tracing easy: +[source, java] .... aspect TraceNonStaticMethods { before(Point p): target(p) && call(* *(..)) { @@ -868,6 +907,7 @@ The type of `thisJoinPoint` includes a rich reflective class hierarchy of signatures, and can be used to access both static and dynamic information about join points such as the arguments of the join point: +[source, java] .... thisJoinPoint.getArgs() .... @@ -876,6 +916,7 @@ In addition, it holds an object consisting of all the static information about the join point such as corresponding line number and static signature: +[source, java] .... thisJoinPoint.getStaticPart() .... @@ -888,6 +929,7 @@ necessary when using `thisJoinPoint` directly. It is always the case that +[source, java] .... thisJoinPointStaticPart == thisJoinPoint.getStaticPart() @@ -903,8 +945,9 @@ but it is not the current but the enclosing join point. So, for example, it is possible to print out the calling source location (if available) with +[source, java] .... - before() : execution (* *(..)) { - System.err.println(thisEnclosingJoinPointStaticPart.getSourceLocation()) - } +before() : execution (* *(..)) { + System.err.println(thisEnclosingJoinPointStaticPart.getSourceLocation()) +} .... diff --git a/docs/progGuideDB/pitfalls.adoc b/docs/progGuideDB/pitfalls.adoc index b1769ce26..0bbe6f5f5 100644 --- a/docs/progGuideDB/pitfalls.adoc +++ b/docs/progGuideDB/pitfalls.adoc @@ -11,6 +11,7 @@ surprising behavior and how to understand them. Here is a Java program with peculiar behavior +[source, java] .... public class Main { public static void main(String[] args) { @@ -39,6 +40,7 @@ the completely silent abort. The following short aspect will also generate this behavior: +[source, java] .... aspect A { before(): call(* *(..)) { System.out.println("before"); } @@ -50,6 +52,7 @@ Why? Because the call to println is also a call matched by the pointcut `call (* *(..))`. We get no output because we used simple after() advice. If the aspect were changed to +[source, java] .... aspect A { before(): call(* *(..)) { System.out.println("before"); } @@ -65,6 +68,7 @@ There's a simple idiom to use if you ever have a worry that your advice might apply in this way. Just restrict the advice from occurring in join points caused within the aspect. So: +[source, java] .... aspect A { before(): call(* *(..)) && !within(A) { System.out.println("before"); } @@ -75,6 +79,7 @@ aspect A { Other solutions might be to more closely restrict the pointcut in other ways, for example: +[source, java] .... aspect A { before(): call(* MyObject.*(..)) { System.out.println("before"); } diff --git a/docs/progGuideDB/quickreference.adoc b/docs/progGuideDB/quickreference.adoc index 01b152e31..6d8febc56 100644 --- a/docs/progGuideDB/quickreference.adoc +++ b/docs/progGuideDB/quickreference.adoc @@ -9,16 +9,16 @@ |*Methods and Constructors* | |`call(Signature)` |every call to any method or constructor matching -<Signature> at the call site +`<Signature>` at the call site |`execution(Signature)` |every execution of any method or constructor -matching <Signature> +matching `<Signature>` |*Fields* | -|`get(Signature)` |every reference to any field matching <Signature> +|`get(Signature)` |every reference to any field matching `<Signature>` -|`set(Signature)` |every assignment to any field matching <Signature>. +|`set(Signature)` |every assignment to any field matching `<Signature>`. The assigned value can be exposed with an `args` pointcut |*Exception Handlers* | @@ -37,12 +37,12 @@ pointcut initializer for any type in <TypePattern> |`initialization(Signature)` |every initialization of an object when the -first constructor called in the type matches <Signature>, encompassing +first constructor called in the type matches `<Signature>`, encompassing the return from the super constructor call to the return of the first-called constructor |`preinitialization(Signature)` |every pre-initialization of an object -when the first constructor called in the type matches <Signature>, +when the first constructor called in the type matches `<Signature>`, encompassing the entry of the first-called constructor to the call to the super constructor @@ -52,7 +52,7 @@ the super constructor <TypePattern> |`withincode(Signature)` |every join point from code defined in a method -or constructor matching <Signature> +or constructor matching `<Signature>` |=== [[quick-typePatterns]] @@ -62,290 +62,118 @@ A type pattern is one of [cols=",",] |=== -|<TypeNamePattern> |all types in <TypeNamePattern> +|*Type pattern* | -|<SubtypePattern> |all types in <SubtypePattern>, a pattern with a +. +|`<TypeNamePattern>` |all types in `<TypeNamePattern>` -|<ArrayTypePattern> |all types in <ArrayTypePattern>, a pattern with one -or more []s. +|`<SubtypePattern>` |all types in `<SubtypePattern>`, a pattern with a `+` + +|`<ArrayTypePattern>` |all types in `<ArrayTypePattern>`, a pattern with one or more ``[]``s. |`!TypePattern` |all types not in <TypePattern> -|`TypePattern0 - && TypePattern1` |all types in both <TypePattern0> and -<TypePattern1> +|`TypePattern0 && TypePattern1` |all types in both `<TypePattern0>` and `<TypePattern1>` -|`TypePattern0 || TypePattern1` |all types in either <TypePattern0> or -<TypePattern1> +|`TypePattern0 \|\| TypePattern1` |all types in either `<TypePattern0>` or `<TypePattern1>` -|`( TypePattern )` |all types in <TypePattern> +|`( TypePattern )` |all types in `<TypePattern>` |=== -where <TypeNamePattern> can either be a plain type name, the wildcard -`*` (indicating all types), or an identifier with embedded `*` and `..` +where `<TypeNamePattern>` can either be a plain type name, the wildcard +`\*` (indicating all types), or an identifier with embedded `*` and `..` wildcards. An embedded `*` in an identifier matches any sequence of characters, but -does not match the package (or inner-type) separator ".". +does not match the package (or inner-type) separator `.`. An embedded `..` in an identifier matches any sequence of characters -that starts and ends with the package (or inner-type) separator ".". +that starts and ends with the package (or inner-type) separator `.`. [[quick-advice]] === Advice Each piece of advice is of the form -____ -[ strictfp ] - -AdviceSpec - -[ throws - -TypeList - -] : - -Pointcut +[source, text] +.... +[ strictfp ] AdviceSpec [ throws TypeList ] : Pointcut { Body } +.... -\{ +where `<AdviceSpec>` is one of -Body - -} -____ - -where <AdviceSpec> is one of - -`before( Formals ) `:: +`before( Formals )`:: runs before each join point -`after( Formals ) returning - [ ( Formal ) ] `:: +`after( Formals ) returning [ ( Formal ) ]`:: runs after each join point that returns normally. The optional formal gives access to the returned value -`after( Formals ) throwing [ - ( Formal ) ] `:: - runs after each join point that throws a - + - Throwable - + - . If the optional formal is present, runs only after each join point - that throws a - + - Throwable - + - of the type of - + - Formal - + - , and - + - Formal - + - gives access to the - + - Throwable - + - exception value -`after( Formals ) `:: +`after( Formals ) throwing [ ( Formal ) ]`:: + runs after each join point that throws a `Throwable`. + If the optional formal is present, runs only after each join point + that throws a `Throwable` of the type of `Formal`, and `Formal` gives access to the + `Throwable` exception value +`after( Formals )`:: runs after each join point regardless of whether it returns normally - or throws a - + - Throwable -`Type - around( Formals ) `:: + or throws a `Throwable` +`Type around( Formals )`:: runs in place of each join point. The join point can be executed by - calling - + - proceed - + - , which takes the same number and types of arguments as the around + calling `proceed`, which takes the same number and types of arguments as the around advice. Three special variables are available inside of advice bodies: `thisJoinPoint`:: - an object of type - + - org.aspectj.lang.JoinPoint - + - representing the join point at which the advice is executing. + an object of type `org.aspectj.lang.JoinPoint` representing the join point + at which the advice is executing `thisJoinPointStaticPart`:: - equivalent to - + - thisJoinPoint.getStaticPart() - + - , but may use fewer runtime resources. + equivalent to `thisJoinPoint.getStaticPart()`, but may use fewer runtime resources `thisEnclosingJoinPointStaticPart`:: - the static part of the dynamically enclosing join point. + the static part of the dynamically enclosing join point [[quick-interType]] === Inter-type member declarations Each inter-type member is one of -` - Modifiers ReturnType OnType . Id - ( Formals ) - [ throws TypeList ] - { Body } - `:: - a method on - + - OnType - + - . -` - abstract Modifiers ReturnType OnType . Id - ( Formals ) - [ throws TypeList ] ; - `:: - an abstract method on - + - OnType - + - . -` - Modifiers OnType . new - ( Formals ) - [ throws TypeList ] - { Body } - `:: - a constructor on - + - OnType - + - . -` - Modifiers Type OnType . Id - [ = Expression ] ; - `:: - a field on - + - OnType - + - . +`Modifiers ReturnType OnType . Id ( Formals ) [ throws TypeList ] { Body }`:: + a method on `OnType` +`abstract Modifiers ReturnType OnType . Id ( Formals ) [ throws TypeList ] ;`:: + an abstract method on `OnType` +`Modifiers OnType . new ( Formals ) [ throws TypeList ] { Body }`:: + a constructor on `OnType` +`Modifiers Type OnType . Id [ = Expression ] ;`:: + a field on `OnType` [[quick-other]] === Other declarations -` - declare parents : - TypePattern extends - Type ; - `:: - the types in - + - TypePattern - + - extend - + - Type - + - . -` - declare parents : TypePattern - implements TypeList ; - `:: - the types in - + - TypePattern - + - implement the types in - + - TypeList - + - . -` - declare warning : Pointcut : - String ; - `:: - if any of the join points in - + - Pointcut - + - possibly exist in the program, the compiler emits the warning - + - String - + - . -` - declare error : Pointcut : - String ; - `:: - if any of the join points in - + - Pointcut - + - could possibly exist in the program, the compiler emits the error - + - String - + - . -` - declare soft : - Type : - Pointcut ; - `:: - any - + - Type - + - exception that gets thrown at any join point picked out by - + - Pointcut - + - is wrapped in - + - org.aspectj.lang.SoftException - + - . -` - declare precedence : - TypePatternList ; - `:: +`declare parents : TypePattern extends Type ;`:: + the types in `TypePattern` extend `Type` +`declare parents : TypePattern implements TypeList ;`:: + the types in `TypePattern` implement the types in `TypeList` +`declare warning : Pointcut : String ;`:: + if any of the join points in `Pointcut` possibly exist in the program, + the compiler emits the warning `String` +`declare error : Pointcut : String ;`:: + if any of the join points in `Pointcut` could possibly exist in the program, + the compiler emits the error `String` +`declare soft : Type : Pointcut ;`:: + any `Type` exception that gets thrown at any join point picked out by `Pointcut` + is wrapped in `org.aspectj.lang.SoftException` +`declare precedence : TypePatternList ;`:: at any join point where multiple pieces of advice apply, the advice - precedence at that join point is in - + - TypePatternList - + - order. + precedence at that join point is in `TypePatternList` order [[quick-aspectAssociations]] === Aspects Each aspect is of the form -____ -[ privileged ] - -Modifiers - -aspect - -Id - -[ extends - -Type - -] [ implements - -TypeList - -] [ - -PerClause - -] \{ - -Body - -} -____ +[source, text] +.... +[ privileged ] Modifiers aspect Id [ extends Type ] [ implements TypeList ] [ PerClause ] { Body } +.... -where <PerClause> defines how the aspect is instantiated and associated +where `<PerClause>` defines how the aspect is instantiated and associated (`issingleton()` by default): [cols=",,",options="header",] @@ -355,18 +183,18 @@ where <PerClause> defines how the aspect is instantiated and associated default. |`aspectOf()` at all join points |`perthis(Pointcut)` |An instance is associated with each object that is -the currently executing object at any join point in <Pointcut>. +the currently executing object at any join point in `<Pointcut>`. |`aspectOf(Object)` at all join points |`pertarget(Pointcut)` |An instance is associated with each object that -is the target object at any join point in <Pointcut>. +is the target object at any join point in `<Pointcut>`. |`aspectOf(Object)` at all join points |`percflow(Pointcut)` |The aspect is defined for each entrance to the -control flow of the join points defined by <Pointcut>. |`aspectOf()` at +control flow of the join points defined by `<Pointcut>`. |`aspectOf()` at join points in `cflow(Pointcut)` |`percflowbelow(Pointcut)` |The aspect is defined for each entrance to -the control flow below the join points defined by <Pointcut>. +the control flow below the join points defined by `<Pointcut>`. |`aspectOf()` at join points in `cflowbelow(Pointcut)` |=== diff --git a/docs/progGuideDB/semantics.adoc b/docs/progGuideDB/semantics.adoc index 1943aa609..aa46cf18d 100644 --- a/docs/progGuideDB/semantics.adoc +++ b/docs/progGuideDB/semantics.adoc @@ -63,11 +63,7 @@ Constructor call:: Constructor execution:: When the body of code for an actual constructor executes, after its this or super constructor call. The object being constructed is the - currently executing object, and so may be accessed with the - + - this - + - pointcut. The constructor execution join point for a constructor that + currently executing object, and so may be accessed with the `_this_` pointcut. The constructor execution join point for a constructor that calls a super constructor also includes any non-static initializers of enclosing class. No value is returned from a constructor execution join point, so its return type is considered to be void. @@ -80,15 +76,7 @@ Object pre-initialization:: This encompasses the time between the start of its first called constructor and the start of its parent's constructor. Thus, the execution of these join points encompass the join points of the - evaluation of the arguments of - + - this() - + - and - + - super() - + - constructor calls. No value is returned from an object + evaluation of the arguments of `_this()_` and `_super()_` constructor calls. No value is returned from an object pre-initialization join point, so its return type is considered to be void. Object initialization:: @@ -97,11 +85,7 @@ Object initialization:: and the return of its first called constructor. It includes all the dynamic initializers and constructors used to create the object. The object being constructed is the currently executing object, and so may - be accessed with the - + - this - + - pointcut. No value is returned from a constructor execution join + be accessed with the `_this_` pointcut. No value is returned from a constructor execution join point, so its return type is considered to be void. Field reference:: When a non-constant field is referenced. [Note that references to @@ -180,219 +164,84 @@ build up other pointcuts. The primitive pointcuts and combinators provided by the language are: `call(MethodPattern)`:: - Picks out each method call join point whose signature matches - + - MethodPattern - + - . + Picks out each method call join point whose signature matches `_MethodPattern_`. `execution(MethodPattern)`:: - Picks out each method execution join point whose signature matches - + - MethodPattern - + - . + Picks out each method execution join point whose signature matches `_MethodPattern_`. `get(FieldPattern)`:: - Picks out each field reference join point whose signature matches - + - FieldPattern - + - . [Note that references to constant fields (static final fields bound + Picks out each field reference join point whose signature matches `_FieldPattern_`. [Note that references to constant fields (static final fields bound to a constant string object or primitive value) are not join points, since Java requires them to be inlined.] `set(FieldPattern)`:: - Picks out each field set join point whose signature matches - + - FieldPattern - + - . [Note that the initializations of constant fields (static final + Picks out each field set join point whose signature matches `_FieldPattern_`. [Note that the initializations of constant fields (static final fields where the initializer is a constant string object or primitive value) are not join points, since Java requires their references to be inlined.] `call(ConstructorPattern)`:: - Picks out each constructor call join point whose signature matches - + - ConstructorPattern - + - . + Picks out each constructor call join point whose signature matches `_ConstructorPattern_`. `execution(ConstructorPattern)`:: Picks out each constructor execution join point whose signature - matches - + - ConstructorPattern - + - . + matches `_ConstructorPattern_`. `initialization(ConstructorPattern)`:: Picks out each object initialization join point whose signature - matches - + - ConstructorPattern - + - . + matches `_ConstructorPattern_`. `preinitialization(ConstructorPattern)`:: Picks out each object pre-initialization join point whose signature - matches - + - ConstructorPattern - + - . + matches `_ConstructorPattern_`. `staticinitialization(TypePattern)`:: Picks out each static initializer execution join point whose signature - matches - + - TypePattern - + - . + matches `_TypePattern_`. `handler(TypePattern)`:: - Picks out each exception handler join point whose signature matches - + - TypePattern - + - . + Picks out each exception handler join point whose signature matches `_TypePattern_`. `adviceexecution()`:: Picks out all advice execution join points. `within(TypePattern)`:: Picks out each join point where the executing code is defined in a - type matched by - + - TypePattern - + - . + type matched by `_TypePattern_`. `withincode(MethodPattern)`:: Picks out each join point where the executing code is defined in a - method whose signature matches - + - MethodPattern - + - . + method whose signature matches `_MethodPattern_`. `withincode(ConstructorPattern)`:: Picks out each join point where the executing code is defined in a - constructor whose signature matches - + - ConstructorPattern - + - . + constructor whose signature matches `_ConstructorPattern_`. `cflow(Pointcut)`:: - Picks out each join point in the control flow of any join point - + - P - + - picked out by - + - Pointcut - + - , including - + - P - + - itself. + Picks out each join point in the control flow of any join point `_P_` picked out by `_Pointcut_` , including `_P_` itself. `cflowbelow(Pointcut)`:: - Picks out each join point in the control flow of any join point - + - P - + - picked out by - + - Pointcut - + - , but not - + - P - + - itself. + Picks out each join point in the control flow of any join point `_P_` picked out by `_Pointcut_`, but not `_P_` itself. `this(Type or Id)`:: Picks out each join point where the currently executing object (the - object bound to - + - this - + - ) is an instance of - + - Type - + - , or of the type of the identifier - + - Id - + - (which must be bound in the enclosing advice or pointcut definition). + object bound to `_this_`) is an instance of `_Type_` , or of the type of the identifier `_Id_` (which must be bound in the enclosing advice or pointcut definition). Will not match any join points from static contexts. `target(Type or Id)`:: Picks out each join point where the target object (the object on which - a call or field operation is applied to) is an instance of - + - Type - + - , or of the type of the identifier - + - Id - + - (which must be bound in the enclosing advice or pointcut definition). + a call or field operation is applied to) is an instance of `_Type_` , or of the type of the identifier `_Id_` (which must be bound in the enclosing advice or pointcut definition). Will not match any calls, gets, or sets of static members. `args(Type or Id, ...)`:: Picks out each join point where the arguments are instances of the - appropriate type (or type of the identifier if using that form). A - + - null - + - argument is matched iff the static type of the argument (declared + appropriate type (or type of the identifier if using that form). A `_null_` argument is matched iff the static type of the argument (declared parameter type or field type) is the same as, or a subtype of, the specified args type. `PointcutId(TypePattern or Id, ...)`:: Picks out each join point that is picked out by the user-defined - pointcut designator named by - + - PointcutId - + - . + pointcut designator named by `_PointcutId_` . `if(BooleanExpression)`:: - Picks out each join point where the boolean expression evaluates to - + - true - + - . The boolean expression used can only access static members, - parameters exposed by the enclosing pointcut or advice, and - + - thisJoinPoint - + - forms. In particular, it cannot call non-static methods on the aspect + Picks out each join point where the boolean expression evaluates to `_true_` . The boolean expression used can only access static members, + parameters exposed by the enclosing pointcut or advice, and `_thisJoinPoint_` forms. In particular, it cannot call non-static methods on the aspect or use return values or exceptions exposed by after advice. `! Pointcut`:: - Picks out each join point that is not picked out by - + - Pointcut - + - . + Picks out each join point that is not picked out by `_Pointcut_` . `Pointcut0 && Pointcut1`:: - Picks out each join points that is picked out by both - + - Pointcut0 - + - and - + - Pointcut1 - + - . + Picks out each join points that is picked out by both `_Pointcut0_` and `_Pointcut1_` . `Pointcut0 || Pointcut1`:: - Picks out each join point that is picked out by either pointcuts. - + - Pointcut0 - + - or - + - Pointcut1 - + - . + Picks out each join point that is picked out by either pointcuts. `_Pointcut0_` or `_Pointcut1_` . `( Pointcut )`:: - Picks out each join points picked out by - + - Pointcut - + - . + Picks out each join points picked out by `_Pointcut_` . ==== Pointcut definition Pointcuts are defined and named by the programmer with the `pointcut` declaration. +[source, java] .... pointcut publicIntCall(int i): call(public * *(int)) && args(i); @@ -402,6 +251,7 @@ A named pointcut may be defined in either a class or aspect, and is treated as a member of the class or aspect where it is found. As a member, it may have an access modifier such as `public` or `private`. +[source, java] .... class C { pointcut publicCall(int i): @@ -418,6 +268,7 @@ Pointcuts that are not final may be declared abstract, and defined without a body. Abstract pointcuts may only be declared within abstract aspects. +[source, java] .... abstract aspect A { abstract pointcut publicCall(int i); @@ -426,6 +277,7 @@ abstract aspect A { In such a case, an extending aspect may override the abstract pointcut. +[source, java] .... aspect B extends A { pointcut publicCall(int i): call(public Foo.m(int)) && args(i); @@ -444,6 +296,7 @@ is different than the scope of other members; the scope of other members is the enclosing class _body_. This means that the following code is legal: +[source, java] .... aspect B percflow(publicCall()) { pointcut publicCall(): call(public Foo.m(int)); @@ -466,6 +319,7 @@ collection of types. The pointcut designators that allow this are rather than a type does two things. First, it selects join points as based on the type of the formal parameter. So the pointcut +[source, java] .... pointcut intArg(int i): args(i); .... @@ -477,6 +331,7 @@ advice or pointcut. Values can be exposed from named pointcuts as well, so +[source, java] .... pointcut publicCall(int x): call(public *.*(int)) && intArg(x); pointcut intArg(int i): args(i); @@ -489,6 +344,7 @@ There is one special case for this kind of exposure. Exposing an argument of type Object will also match primitive typed arguments, and expose a "boxed" version of the primitive. So, +[source, java] .... pointcut publicCall(): call(public *.*(..)) && args(Object); .... @@ -496,6 +352,7 @@ pointcut publicCall(): call(public *.*(..)) && args(Object); will pick out all unary methods that take, as their only argument, subtypes of Object (i.e., not primitive types like `int`), but +[source, java] .... pointcut publicCall(Object o): call(public *.*(..)) && args(o); .... @@ -507,6 +364,7 @@ argument was an `int`, then the value passed to advice will be of type The "boxing" of the primitive value is based on the _original_ primitive type. So in the following program +[source, java] .... public class InstanceOf { @@ -569,6 +427,7 @@ field is being set to, so at a set join point, that value can be accessed with an `args` pointcut. So an aspect guarding a static integer variable x declared in type T might be written as +[source, java] .... aspect GuardedX { static final int MAX_CHANGE = 100; @@ -632,6 +491,7 @@ the exception being handled. That value can be accessed with an `args` pointcut. So an aspect used to put `FooException` objects into some normal form before they are handled could be written as +[source, java] .... aspect NormalizeFooException { before(FooException e): handler(FooException) && args(e) { @@ -650,6 +510,7 @@ of advice This can be used, for example, to filter out any join point in the control flow of advice from a particular aspect. +[source, java] .... aspect TraceStuff { pointcut myAdvice(): adviceexecution() && within(TraceStuff); @@ -719,6 +580,7 @@ Object). If it is the "*" wildcard, then any argument will match, and if it is the special wildcard "..", then any number of arguments will match, just like in signature patterns. So the pointcut +[source, java] .... args(int, .., String) .... @@ -762,6 +624,7 @@ Anytime such state is accessed, it is accessed through the _most recent_ control flow that matched. So the "current arg" that would be printed by the following program is zero, even though it is in many control flows. +[source, java] .... class Test { public static void main(String[] args) { @@ -842,6 +705,7 @@ false. Within this expression, the `thisJoinPoint` object is available. So one (extremely inefficient) way of picking out all call join points would be to use the pointcut +[source, java] .... if(thisJoinPoint.getKind().equals("call")) .... @@ -922,6 +786,7 @@ while constructor declarations omit the return type and replace the method name with the class name. The start of a particular method declaration, in class `Test`, for example, might be +[source, java] .... class C { public final void foo() throws ArrayOutOfBoundsException { ... } @@ -931,12 +796,14 @@ class C { In AspectJ, method signature patterns have all these, but most elements can be replaced by wildcards. So +[source, java] .... call(public final void C.foo() throws ArrayOutOfBoundsException) .... picks out call join points to that method, and the pointcut +[source, java] .... call(public final void *.*() throws ArrayOutOfBoundsException) .... @@ -949,12 +816,14 @@ throw `ArrayOutOfBounds` exceptions. The defining type name, if not present, defaults to *, so another way of writing that pointcut would be +[source, java] .... call(public final void *() throws ArrayOutOfBoundsException) .... The wildcard `..` indicates zero or more parameters, so +[source, java] .... execution(void m(..)) .... @@ -962,6 +831,7 @@ execution(void m(..)) picks out execution join points for void methods named `m`, of any number of arguments, while +[source, java] .... execution(void m(.., int)) .... @@ -974,6 +844,7 @@ signature pattern should match methods without a particular modifier, such as all non-public methods, the appropriate modifier should be negated with the `!` operator. So, +[source, java] .... withincode(!public void foo()) .... @@ -981,6 +852,7 @@ withincode(!public void foo()) picks out all join points associated with code in null non-public void methods named `foo`, while +[source, java] .... withincode(void foo()) .... @@ -991,12 +863,14 @@ named `foo`, regardless of access modifier. Method names may contain the * wildcard, indicating any number of characters in the method name. So +[source, java] .... call(int *()) .... picks out all call join points to `int` methods regardless of name, but +[source, java] .... call(int get*()) .... @@ -1009,6 +883,7 @@ than using a particular class name. So the execution join points of private null constructor of a class C defined to throw an ArithmeticException can be picked out with +[source, java] .... execution(private C.new() throws ArithmeticException) .... @@ -1027,6 +902,7 @@ type used to access the method. A common mistake is to specify a declaring type for the `call` pointcut that is a subtype of the originally-declaring type. For example, given the class +[source, java] .... class Service implements Runnable { public void run() { ... } @@ -1035,12 +911,14 @@ class Service implements Runnable { the following pointcut +[source, java] .... call(void Service.run()) .... would fail to pick out the join point for the code +[source, java] .... ((Runnable) new Service()).run(); .... @@ -1049,6 +927,7 @@ Specifying the originally-declaring type is correct, but would pick out any such call (here, calls to the `run()` method of any Runnable). In this situation, consider instead picking out the target type: +[source, java] .... call(void run()) && target(Service) .... @@ -1058,6 +937,7 @@ method signature specifies a declaring type, the pointcut will only match methods declared in that type, or methods that override methods declared in or inherited by that type. So the pointcut +[source, java] .... execution(public void Middle.*()) .... @@ -1068,6 +948,7 @@ Middle, even if those methods are overridden in a subclass of Middle. So the pointcut would pick out the method-execution join point for Sub.m() in this code: +[source, java] .... class Super { protected void m() { ... } @@ -1085,6 +966,7 @@ Type patterns may 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 @@ -1190,6 +1072,7 @@ So exact type patterns match based on usual Java scope rules. There is a special type name, *, which is also a type pattern. * picks out all types, including primitive types. So +[source, java] .... call(void foo(*)) .... @@ -1202,6 +1085,7 @@ patterns. The * wildcard matches zero or more characters characters except for ".", so it can be used when types have a certain naming convention. So +[source, java] .... handler(java.util.*Map) .... @@ -1209,6 +1093,7 @@ handler(java.util.*Map) picks out the types java.util.Map and java.util.java.util.HashMap, among others, and +[source, java] .... handler(java.util.*) .... @@ -1221,6 +1106,7 @@ The "`..`" wildcard matches any sequence of characters that start and end with a ".", so it can be used to pick out all types in any subpackage, or all inner types. So +[source, java] .... within(com.xerox..*) .... @@ -1238,6 +1124,7 @@ It is possible to pick out all subtypes of a type (or a collection of types) with the "+" wildcard. The "+" wildcard follows immediately a type name pattern. So, while +[source, java] .... call(Foo.new()) .... @@ -1245,6 +1132,7 @@ call(Foo.new()) picks out all constructor call join points where an instance of exactly type Foo is constructed, +[source, java] .... call(Foo+.new()) .... @@ -1252,6 +1140,7 @@ call(Foo+.new()) picks out all constructor call join points where an instance of any subtype of Foo (including Foo itself) is constructed, and the unlikely +[source, java] .... call(*Handler+.new()) .... @@ -1271,6 +1160,7 @@ Type patterns are built up out of type name patterns, subtype patterns, and array type patterns, and constructed with boolean operators `&&`, `||`, and `!`. So +[source, java] .... staticinitialization(Foo || Bar) .... @@ -1278,6 +1168,7 @@ staticinitialization(Foo || Bar) picks out the static initializer execution join points of either Foo or Bar, and +[source, java] .... call((Foo+ && ! Foo).new(..)) .... @@ -1289,6 +1180,7 @@ not Foo itself, is constructed. Here is a summary of the pattern syntax used in AspectJ: +[source, text] .... MethodPattern = [ModifiersPattern] TypePattern @@ -1397,6 +1289,7 @@ interpretations of after advice: After the execution of a join point completes normally, after it throws an exception, or after it does either one. AspectJ allows after advice for any of these situations. +[source, java] .... aspect A { pointcut publicCall(): call(public Object *(..)); @@ -1415,6 +1308,7 @@ aspect A { After returning advice may not care about its returned object, in which case it may be written +[source, java] .... after() returning: call(public Object *(..)) { System.out.println("Returned normally"); @@ -1448,6 +1342,7 @@ must be declared with a return type, like a method. Thus, a simple use of around advice is to make a particular method constant: +[source, java] .... aspect A { int around(): call(int C.foo()) { @@ -1459,6 +1354,7 @@ aspect A { Within the body of around advice, though, the computation of the original join point can be executed with the special syntax +[source, java] .... proceed( ... ) .... @@ -1468,6 +1364,7 @@ pointcut, and returns whatever the around is declared to return. So the following around advice will double the second argument to `foo` whenever it is called, and then halve its result: +[source, java] .... aspect A { int around(int i): call(int C.foo(Object, int)) && args(i) { @@ -1483,6 +1380,7 @@ is originally a primitive value. And when the advice returns an Object value, that value is converted back to whatever representation it was originally. So another way to write the doubling and halving advice is: +[source, java] .... aspect A { Object around(int i): call(int C.foo(Object, int)) && args(i) { @@ -1500,6 +1398,7 @@ program the first call to proceed will be treated as a method call to the `ICanProceed` instance, whereas the second call to proceed is treated as the special proceed form. +[source, java] .... aspect A { Object around(ICanProceed canProceed) : execution(* *(..)) && this(canProceed) { @@ -1519,6 +1418,7 @@ method parameters. In particular, assigning to any parameter affects only the value of the parameter, not the value that it came from. This means that +[source, java] .... aspect A { after() returning (int i): call(int C.foo()) { @@ -1536,6 +1436,7 @@ less-precedent advice and the underlying join point by supplying different values for the variables. For example, this aspect replaces the string bound to `s` in the named pointcut `privateData`: +[source, java] .... aspect A { Object around(String s): MyPointcuts.privateData(s) { @@ -1551,6 +1452,7 @@ In the following aspect, the around advice replaces the declared target `List` with an `ArrayList`. This is valid code at compile-time since the types match. +[source, java] .... import java.util.*; @@ -1565,6 +1467,7 @@ But imagine a simple program where the actual target is `LinkedList`. In this case, the advice would cause a `ClassCastException` at runtime, and `peek()` is not declared in `ArrayList`. +[source, java] .... public class Test { public static void main(String[] args) { @@ -1577,6 +1480,7 @@ The `ClassCastException` can occur even in situations where it appears to be unnecessary, e.g., if the program is changed to call `size()`, declared in `List`: +[source, java] .... public class Test { public static void main(String[] args) { @@ -1605,6 +1509,7 @@ signalled by the compiler. For example, in the following declarations: +[source, java] .... import java.io.FileNotFoundException; @@ -1626,22 +1531,14 @@ aspect A { both pieces of advice are illegal. The first because the body throws an undeclared checked exception, and the second because field get join -points cannot throw `FileNotFoundException`s. +points cannot throw ``FileNotFoundException``s. The exceptions that each kind of join point in AspectJ may throw are: method call and execution:: - the checked exceptions declared by the target method's - + - throws - + - clause. + the checked exceptions declared by the target method's `_throws_` clause. constructor call and execution:: - the checked exceptions declared by the target constructor's - + - throws - + - clause. + the checked exceptions declared by the target constructor's `_throws_` clause. field get and set:: no checked exceptions can be thrown from these join points. exception handler execution:: @@ -1649,11 +1546,7 @@ exception handler execution:: static initializer execution:: no checked exceptions can be thrown from these join points. pre-initialization and initialization:: - any exception that is in the throws clause of - + - all - + - constructors of the initialized class. + any exception that is in the throws clause of all constructors of the initialized class. advice execution:: any exception that is in the throws clause of the advice. @@ -1700,6 +1593,7 @@ precedence over the one that appears later. These rules can lead to circularity, such as +[source, java] .... aspect A { before(): execution(void main(String[] args)) {} @@ -1747,6 +1641,7 @@ encapsulates some of the context of the advice's current or enclosing join point. These variables exist because some pointcuts may pick out very large collections of join points. For example, the pointcut +[source, java] .... pointcut publicCall(): call(public * *(..)); .... @@ -1843,6 +1738,7 @@ The effect of such a declaration is to make <OnType> support the new method. Even if <OnType> is an interface. Even if the method is neither public nor abstract. So the following is legal AspectJ code: +[source, java] .... interface Iface {} @@ -1979,6 +1875,7 @@ Inter-type declarations raise the possibility of conflicts among locally declared members and inter-type members. For example, assuming `otherPackage` is not the package containing the aspect `A`, the code +[source, java] .... aspect A { private Registry otherPackage.onType.r; @@ -2001,6 +1898,7 @@ there is no conflict: The aspect cannot see such a field, and no code in If `onType` defines a public field "`r`", there is a conflict: The expression +[source, java] .... this.r = r .... @@ -2071,6 +1969,7 @@ might define appropriate inter-type `void fulfills the `Runnable` interface. In order to implement the methods in the `Runnable` interface, the inter-type `run()` method must be public: +[source, java] .... aspect A { declare parents: SomeClass implements Runnable; @@ -2091,9 +1990,10 @@ initializers. The order of super-interface instantiation is observable. We fix this order with the following properties: A supertype is initialized before a subtype, initialized code runs only once, and the initializers for a type's superclass are run before the initializers for -its superinterfaces. Consider the following hierarchy where \{`Object`, -`C`, `D`, `E`} are classes, \{`M`, `N`, `O`, `P`, `Q`} are interfaces. +its superinterfaces. Consider the following hierarchy where {`Object`, +`C`, `D`, `E`} are classes, {`M`, `N`, `O`, `P`, `Q`} are interfaces. +[source, text] .... Object M O \ / \ / @@ -2106,6 +2006,7 @@ its superinterfaces. Consider the following hierarchy where \{`Object`, when a new `E` is instantiated, the initializers run in this order: +[source, text] .... Object M C O N D Q P E .... @@ -2158,6 +2059,7 @@ Pointcut For example, the aspect +[source, java] .... aspect A { declare soft: Exception: execution(void main(String[] args)); @@ -2169,6 +2071,7 @@ Would, at the execution join point, catch any `Exception` and rethrow a This is similar to what the following advice would do +[source, java] .... aspect A { void around() execution(void main(String[] args)) { @@ -2187,6 +2090,7 @@ Like advice, the declare soft form has no effect in an abstract aspect that is not extended by a concreate aspect. So the following code will not compile unless it is compiled with an extending concrete aspect: +[source, java] .... abstract aspect A { abstract pointcut softeningPC(); @@ -2223,6 +2127,7 @@ of their name should have precedence over all other aspects, and (2) the Logging aspect (and any aspect that extends it) should have precedence over all non-security aspects, can be expressed by: +[source, java] .... declare precedence: *..*Security*, Logging+, *; .... @@ -2235,6 +2140,7 @@ accomplished by stating that CountEntry has precedence over DisallowNulls. This declaration could be in either aspect, or in another, ordering aspect: +[source, java] .... aspect Ordering { declare precedence: CountEntry, DisallowNulls; @@ -2259,6 +2165,7 @@ aspect CountEntry { It is an error for any aspect to be matched by more than one TypePattern in a single decare precedence, so: +[source, java] .... declare precedence: A, B, A ; // error .... @@ -2267,6 +2174,7 @@ 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; @@ -2280,6 +2188,7 @@ idiom that can be used to enforce that A and B are strongly independent. Consider the following library aspects: +[source, java] .... abstract aspect Logging { abstract pointcut logged(); @@ -2313,12 +2222,14 @@ aspects, say, MyLogging and MyProfiling. Because advice only applies from concrete aspects, the declare precedence form only matters when declaring precedence with concrete aspects. So +[source, java] .... declare precedence: Logging, Profiling; .... has no effect, but both +[source, java] .... declare precedence: MyLogging, MyProfiling; declare precedence: Logging+, Profiling+; @@ -2526,6 +2437,7 @@ All advice runs in the context of an aspect instance, but it is possible to write a piece of advice with a pointcut that picks out a join point that must occur before asopect instantiation. For example: +[source, java] .... public class Client { @@ -2574,6 +2486,7 @@ private or protected resources of other types. To allow this, aspects may be declared `privileged`. Code in priviliged aspects has access to all members, even private ones. +[source, java] .... class C { private int i = 0; @@ -2594,6 +2507,7 @@ If a privileged aspect can access multiple versions of a particular member, then those that it could see if it were not privileged take precedence. For example, in the code +[source, java] .... class C { private int i = 0; diff --git a/docs/sandbox/readme-sandbox.adoc b/docs/sandbox/readme-sandbox.adoc index 8d796128a..da4e69cbe 100644 --- a/docs/sandbox/readme-sandbox.adoc +++ b/docs/sandbox/readme-sandbox.adoc @@ -34,6 +34,7 @@ tells how. extracts samples of the following form from any "source" file (currently source, html, text, and shell scripts): +[source, text] .... ... some text, possibly including @author tags {comment} START-SAMPLE [anchorName] [anchor title] {end-comment} @@ -63,6 +64,7 @@ indented only once in the source code, even though they might normally be indented more. ** In AspectJ, indent advice pointcuts beyond the block code: + +[source, java] .... before() : call(!public * com.company.library..*.*(String,..)) && within(Runnable+) { // indent once more than code @@ -107,6 +109,7 @@ suffixes necessary for clarity and to make sure there are unique titles for each test. E.g., for a sample with the anchor "`language-initialization`", + +[source, xml] .... <ajc-test dir="common" @@ -124,6 +127,7 @@ compile. by verifying that the error message is produced, checking either or both of the line number and the message text. E.g., + +[source, xml] .... <compile files="declares/Declares.java, {others}" <message kind="error" line="15" text="Factory"/> @@ -135,6 +139,7 @@ message and the target code in sync. You can help with this by adding a comment in the target code so people editing the code know not to fix or move the code. E.g., + +[source, java] .... void spawn() { new Thread(this, toString()).start(); // KEEP CE 15 declares-factory @@ -151,6 +156,7 @@ make it easier to find the test that will break if the code is modified. If the code is broken (e.g., if it no longer works in the latest version of AspectJ), then prefix SAMPLE with BROKEN in the tag: +[source, text] .... {comment} START-BROKEN-SAMPLE ... ... sample code ... diff --git a/docs/sandbox/trails/j2ee.adoc b/docs/sandbox/trails/j2ee.adoc index 2697175f0..a483a7b79 100644 --- a/docs/sandbox/trails/j2ee.adoc +++ b/docs/sandbox/trails/j2ee.adoc @@ -37,6 +37,7 @@ up ajc as the compiler, do the following before starting Tomcat: tell Ant to use `ajc` by setting the compiler property to the AspectJ compiler adapter: + +[source, xml] .... <servlet> <servlet-name>jsp</servlet-name> |