<abstract>
<para>
This guide describes the changes to the AspectJ language
- and tools in AspectJ 5. These include support for Java 5 (Tiger) features,
- enhancements to load-time weaving, an support for an annotation-based
- development style for aspects.
+ in AspectJ 5. These include support for Java 5 (Tiger) features,
+ support for an annotation-based development style for aspects,
+ and new reflection and tools APIs.
If you are new to AspectJ, we recommend you start
by reading the programming guide.
</para>
- <para>
- This is a draft document and is <emphasis>subject to change</emphasis> before
- the design and implementation is complete. There is also no guarantee that all
- of the features in this document will be implemented in a 1.5.0 release - some
- may be deferred until 1.5.1 or even later. In general, features in which we
- have more confidence in the design will be implemented earlier, providing a
- framework for user feedback and direction setting on features for which the
- use cases are less obvious at time of writing.
- </para>
-
</abstract>
</bookinfo>
&reflection;
&miscellaneous;
<w;
- &grammar;
</book>
<para>
For any kind of annotated element (type, method, constructor, package, etc.),
an annotation pattern can be used to match against the set of annotations
- on the annotated element. Annotation patterns are defined by the following
- grammar.
- </para>
-
- <programlisting><![CDATA[
- AnnotationPattern := '!'? '@' AnnotationTypePattern AnnotationPattern*
-
- AnnotationTypePattern := FullyQualifiedName |
- '(' TypePattern ')'
-
- FullyQualifiedName := JavaIdentifierCharacter+ ('.' JavaIdentifierCharacter+)*
- ]]></programlisting>
-
- <para>In simple terms, an annotation pattern element has one of two basic
- forms:</para>
+ on the annotated element.An annotation pattern element has one of two basic
+ forms:
+ </para>
<itemizedlist>
<listitem>@<qualified-name>, for example, @Foo, or
<title>Type Patterns</title>
<para>AspectJ 1.5 extends type patterns to allow an optional <literal>AnnotationPattern</literal>
- prefix. (Extensions to this definition for generics are shown in the next chapter).</para>
+ prefix.</para>
<programlisting><![CDATA[
TypePattern := SimpleTypePattern |
<para>Note that in most cases when annotations are used as part of a type pattern,
the parenthesis are required (as in <literal>(@Foo Hello+)</literal>). In
- some cases (such as a type pattern used within a <literal>this</literal>
- pointcut expression, the parenthesis are optional:</para>
+ some cases (such as a type pattern used within a <literal>within</literal> or
+ <literal>handler</literal>
+ pointcut expression), the parenthesis are optional:</para>
<programlisting><![CDATA[
OptionalParensTypePattern := AnnotationPattern? TypePattern
<sect2 id="signaturePatterns" xreflabel="Signature Patterns">
<title>Signature Patterns</title>
- <para>A <literal>FieldPattern</literal> is described by the following
- grammar:</para>
+ <sect3 id="fieldPatterns" xreflabel="Field Patterns">
+ <title>Field Patterns</title>
+ <para>A <literal>FieldPattern</literal> can optionally specify an annotation-matching
+ pattern as the first element:</para>
+
<programlisting><![CDATA[
FieldPattern :=
AnnotationPattern? FieldModifiersPattern?
]]></programlisting>
<para>
- The optional <literal>AnnotationPattern</literal> restricts matches to fields with
+ If present, the <literal>AnnotationPattern</literal> restricts matches to fields with
annotations that match the pattern. For example:
</para>
</variablelist>
- <para>A <literal>MethodPattern</literal> is of the form</para>
+ </sect3>
+
+ <sect3 id="methodPatterns" xreflabel="Method Patterns">
+ <title>Method and Constructor Patterns</title>
+
+ <para>A <literal>MethodPattern</literal> can optionally specify an annotation-matching
+ pattern as the first element.</para>
<programlisting><![CDATA[
MethodPattern :=
]]></programlisting>
- <para><emphasis>Note: compared to the previous version, this definition of MethodPattern does
- not allow parameter annotation matching (only matching on annotations of parameter types).</emphasis></para>
<para>A <literal>ConstructorPattern</literal> has the form</para>
</listitem>
</varlistentry>
</variablelist>
+
+ </sect3>
</sect2>
@args(*,*,untrustedDataSource);
]]></programlisting>
- <para>
- <emphasis>Note: an alternative design would be to allow both annotation
- patterns and type patterns to be specified in the existing args pcd.
- This works well for matching, but is more awkward when it comes to
- exposing context.</emphasis>
- </para>
-
- <para>Access to <literal>AnnotatedElement</literal> information is available
+ <para>In addition to accessing annotation information at runtime through context binding,
+ access to <literal>AnnotatedElement</literal> information is also available
reflectively with the body of advice through the <literal>thisJoinPoint</literal>,
<literal>thisJoinPointStaticPart</literal>, and
<literal>thisEnclosingJoinPointStaticPart</literal> variables. To access
Annotation[] firstParamAnnotations = thisJoinPoint.getArgs()[0].getClass().getAnnotations();
]]></programlisting>
- <para>
- <emphasis>Note: it would be nicer to provide direct helper methods in
- the JoinPoint interface or a sub-interface that provide the annotations
- directly, something like "AnnotatedElement getThisAnnotationInfo()".
- The problem here is that the "AnnotatedElement" type is only in the
- Java 5 runtime libraries, and we don't want to tie the AspectJ runtime
- library to Java 5. A sub-interface and downcast solution could be used
- if these helpers were felt to be sufficiently important.</emphasis>
- </para>
-
<para>
The <literal>@within</literal> and <literal>@withincode</literal> pointcut designators
match any join point where the executing code is defined within a type (<literal>@within</literal>),
<title>Package and Parameter Annotations</title>
<para>
- <emphasis>Note: A previous design allowed package annotation patterns to be specified
- directly in type patterns, and parameter annotation patterns to be
- specified directly in method and constructor signature patterns. Because
- this made some pointcut expressions hard to read and understand, we moved
- in favour of the design presented below, which also has its drawbacks.
- Matching on package and parameter annotations will be
- deferred until after the 1.5.0 release so that we can gain more understanding
- of the kinds of uses AspectJ users are making of annotations in pointcut
- expressions before commiting to any one approach.</emphasis>
+ <emphasis>Matching on package and parameter annotations is not supported
+ in AspectJ 1.5.0. Support for this capability may be considered in a future
+ release.</emphasis>
</para>
<!-- @withinpackage ??? -->
</sect2>
- <sect2 id="limitations" xreflabel="limitations">
- <title>Limitations</title>
+ <sect2 id="matchingOnAnnotationValues" xreflabel="matchingOnAnnotationValues">
+ <title>Matching based on annotation values</title>
<para>
- It would be useful to be able to match join points based on
- annotation values, rather than merely the presence of a
- class-file retention annotation of a given type. This facility may be supported in a future version of AspectJ, by expanding the
- definition of <literal>AnnotationPattern</literal>. Matching annotation values for
- annotations with runtime retention can be done by exposing the annotation value
- as a pointcut parameter and then using an <literal>if</literal> pointcut expression
- to test the value.
+ The <literal>if</literal> pointcut designator can be used to write pointcuts
+ that match based on the values annotation members. For example:
</para>
+
+ <programlisting><![CDATA[
+ pointcut txRequiredMethod(Tx transactionAnnotation) :
+ execution(* *(..)) && @this(transactionAnnotation)
+ && if(transactionAnnotation.policy() == TxPolicy.REQUIRED);
+ ]]></programlisting>
+
</sect2>
</sect1>
public aspect Foo {}
]]></programlisting>
- <para>And since issingleton() is the default aspect instantiation model it is equivalent to:</para>
-
- <programlisting><![CDATA[
- @Aspect("issingleton()")
- public class Foo {}
- ]]></programlisting>
-
<para>To specify an aspect an aspect instantiation model (the default is
singleton), provide the perclause as the
<literal>@Aspect</literal>
pointcut anyCall(int i, Foo callee) : call(* *.*(int)) && args(i) && target(callee);
]]></programlisting>
- <para>An example with modifiers (it is also good to remember that Java 5 annotations are not
- inherited):</para>
+ <para>An example with modifiers (Remember that Java 5 annotations are not
+ inherited, so the <literal>@Pointcut</literal> annotation must be
+ present on the extending aspect's pointcut declaration too):</para>
<programlisting><![CDATA[
@Pointcut("")
</para>
<para>
- When using the annotation style, it would be really a pain to write a valid Java expression within
- the annotation value so the syntax differs sligthly, whilst providing the very same
+ When using the annotation style, it is not possible to write a full Java expression
+ within
+ the annotation value so the syntax differs slightly, whilst providing the very same
semantics and runtime behaviour. An
<literal>if()</literal>
pointcut expression can be
declared in an
<literal>@Pointcut</literal>
- , but must either an empty body, or be one
- of the expression
+ , but must have either an empty body (<literal>if()</literal>, or be one
+ of the expression forms
<literal>if(true)</literal>
or
<literal>if(false)</literal>
<para>
Inter-type declarations are challenging to support using an annotation style.
- It's very important to preserve the exact same semantics between the code style
+ It's very important to preserve the same semantics between the code style
and the annotation style. We also want to support compilation of a large set
- of AspectJ applications using a standard Java 5 compiler. For these reasons, in
- the initial release of AspectJ 5 we will only support inter-type declarations
- backed by interfaces when using the annotation style - which means it is not possible to
- introduce constructors or fields, as it would not be not possible to call those unless already
- weaved and available on a binary form.
+ of @AspectJ applications using a standard Java 5 compiler. For these reasons,
+ the 1.5.0 release of AspectJ 5 only supports inter-type declarations
+ backed by interfaces when using the annotation style -
+ which means it is not possible to
+ introduce constructors or fields, as it would not be not possible to call
+ those unless already woven and available on a binary form.
</para>
<para>
}
}
- // here is the actual ITD syntax when using @AspectJ
- // public static is mandatory
// the field type must be the introduced interface. It can't be a class.
- @DeclareParents("org.xzy..*")
- public static Moody introduced = new MoodyImpl();
+ @DeclareParents(value="org.xzy..*",defaultImpl="MoodyImpl")
+ private Moody implementedInterface;
@Before("execution(* *.*(..)) && this(m)")
void feelingMoody(Moody m) {
<literal>@DeclareParents</literal>
annotation is equivalent to
a declare parents statement that all types matching the type pattern implement
- the interface whose @DeclareParents annotated aspect' field is type of (in this case Moody).
- Each method declaration of this interface are treated as inter-type declarations.
+ the given interface (in this case Moody).
+ Each method declared in the interface is treated as an inter-type declaration.
Note how this scheme operates within the constraints
of Java type checking and ensures that
<literal>this</literal>
has access
to the exact same set of members as in the code style example.
</para>
-
- <para>
- Note that it is illegal to use the @DeclareParents annotation on an aspect' field whose type
- is not an interface. Indeed, the interface is the inter-type declaration contract that dictates
- which methods are introduced.
- </para>
-
+
<para>
- It is important to remember that the @DeclareParents annotated aspect' field that serves as a host
- for the inter-type declaration must be <literal>public static</literal> and <literal>initialized by some means</literal>.
- The weaved code will indeed delegate calls to this field when f.e. invoking:
+ Note that it is illegal to use the @DeclareParents annotation on an 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.
</para>
<programlisting><![CDATA[
- // this type will be affected by the inter-type declaration as the type pattern match
+ // this type will be affected by the inter-type declaration as the type pattern matches
package org.xyz;
public class MoodTest {
public void test() {
- // see here the cast to the introduced interface
+ // see here the cast to the introduced interface (required)
Mood mood = ((Moody)this).getMood();
- // will delegate to the aspect field "introduced" that host this inter-type declaration
...
}
}
]]></programlisting>
- <para>
- It is perfectly possible to use an IoC framework to initialize the @DeclaredParents aspect' field. You must
- ensure though that the aspect field will be initialed prior the first inter-type declaration invocation it hosts.
- </para>
-
-
- <para>
- If you need to only introduce a marker interface which defines no method - such as <literal>java.io.Serializable</literal>
- it is possible to use the following syntax.
+ <para>The <literal>@DeclareParents</literal> annotation can also be used without specifying
+ a <literal>defaultImpl</literal> value (for example,
+ <literal>@DeclareParents("org.xyz..*")</literal>). This is equivalent to a
+ <literal>declare parents ... implements</literal> clause, and does <emphasis>not</emphasis>
+ make any inter-type declarations for default implementation of the interface methods.
</para>
<para>
@Aspect
public class SerializableMarker {
- @DeclareImplements("org.xyz..*")
- Serializable introducedNoMethods;
+ @DeclareParents("org.xyz..*")
+ Serializable implementedInterface;
}
]]></programlisting>
- <para>
- The <literal>@DeclareImplements</literal> annotation on the aspect' field dictates the type pattern
- on which to introduce the marker interface.
- </para>
<para>
- In that case, as there is no method introduced, it is perfectly possible to have the aspect' field
- private, or not initialized. Remember that the field' type must be the introduced interface and cannot be class.
+ If the interface defines one or more operations, and these are not implemented by
+ the target type, an error will be issued during weaving.
</para>
</sect1>
<title>Declare statements</title>
<para>The previous section on inter-type declarations covered the case
- of declare parents ... implements. The 1.5.0 release of AspectJ 5 will
+ of declare parents ... implements. The 1.5.0 release of AspectJ 5 does
not support annotation style declarations for declare parents ... extends
and declare soft (programs with these declarations would not in general
be compilable by a regular Java 5 compiler, reducing the priority of
their implementation). These may be supported in a future release.</para>
<para>
- Declare annotation is not supported neither in the 1.5.0 release of AspectJ 5. Given that Java 5
- compilers enforce the annotation target (@java.lang.annotation.Target) to be respected, this would cause
- adding a lot of dummy members in the aspect (such as dummy constructors, methods etc), which would break the
- object oriented design of the @AspectJ aspect itself.
+ Declare annotation is also not supported in the 1.5.0 release of AspectJ 5.
</para>
<para>Declare precedence <emphasis>is</emphasis>
code style). Declare warning and error declarations are made by annotating
a string constant whose value is the message to be issued.</para>
- <para>Note that the String must be a constant and not the result of the invocation
+ <para>Note that the String must be a literal and not the result of the invocation
of a static method for example.</para>
<programlisting><![CDATA[
@DeclareError("execution(* IFoo+.*(..)) && !within(org.foo..*)")
static final String badIFooImplementors = "Only foo types can implement IFoo";
- // the following is not valid since the message is not a String constant
+ // the following is not valid since the message is not a String literal
@DeclareError("execution(* IFoo+.*(..)) && !within(org.foo..*)")
static final String badIFooImplementorsCorrupted = getMessage();
static String getMessage() {
<sect3>
<title>Declaring pointcuts inside generic types</title>
- <para><emphasis>This language feature will not be supported until AspectJ 5 M4.</emphasis></para>
-
<para>Pointcuts can be declared in both classes and aspects. A pointcut declared in a generic
type may use the type variables of the type in which it is declared. All references to
a pointcut declared in a generic type from outside of that type must be via a parameterized type reference,
<sect2 id="generic-aspects" xreflabel="generic-aspects">
<title>Generic Aspects</title>
- <para><emphasis>This feature will not be fully implemented until AspectJ5 M4.</emphasis></para>
-
<para>
AspectJ 5 allows an <emphasis>abstract</emphasis> aspect to be declared as a generic type. Any concrete
aspect extending a generic abstract aspect must extend a parameterized version of the abstract aspect.
<sect1 id="ltw-introduction">
<title>Introduction</title>
- <para>See Developer's Guide.</para>
+ <para>See Developer's Guide for information on
+ load-time weaving support in AspectJ 5.</para>
</sect1>
</chapter>
<sect1>
<title>Pointcuts</title>
- <sect2 id="binding-of-formals" xreflabel="binding-of-formals">
- <title>Binding of formals</title>
<para>
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
are mutually exclusive.
</para>
- </sect2>
-
- <sect2 id="additional-lint-warnings" xreflabel="additional-lint-warnings">
- <title>Additional lint warnings</title>
- <para>
- Discuss detection of common errors -> warning/error, eg. conjunction of more than one
- kind of join point. Differing numbers of args in method signature / args / @args /
- @parameters.
- </para>
- </sect2>
</sect1>
<sect1 id="declare-soft">
</sect1>
- <sect1>
- <title>Tools</title>
-
- <sect2 id="aspectpath" xreflabel="aspectpath">
- <title>Aspectpath</title>
-
- <para>AspectJ 5 allows the specification of directories (containing .class files) on the aspectpath in
- addition to jar/zip files.</para>
- </sect2>
-
- </sect1>
+
</chapter>
<title>New Reflection Interfaces</title>
<para>
- AspectJ 5 provides support for runtime reflection of aspect types. The class <literal>Aspect</literal> is
- analogous to the Java class <literal>Class</literal> and provides access to the members of an aspect.
+ AspectJ 5 provides a full set of reflection APIs analogous to the
+ <literal>java.lang.reflect</literal> package, but fully aware of the
+ AspectJ type system. See the javadoc for the runtime and tools APIs
+ for the full details. The reflection APIs are only supported when
+ running under Java 5 and for code compiled by the AspectJ 5 compiler
+ at target level 1.5.
</para>
<sect1 id="reflection_api">
- <title>The Aspect Class</title>
+ <title>Using AjTypeSystem</title>
<para>
-
+ The starting point for using the reflection apis is
+ <literal>org.aspectj.lang.reflect.AjTypeSystem</literal> which
+ provides the method <literal>getAjType(Class)</literal> which will
+ return the <literal>AjType</literal> corresponding to a given
+ Java class. The <literal>AjType</literal> interface corresponds to
+ <literal>java.lang.Class</literal> and gives you access to all of the
+ method, field, constructor, and also pointcut, advice, declare
+ statement and inter-type declaration members in the type.
</para>
</sect1>
</varlistentry>
<varlistentry>
- <term>-aspectpath <replaceable>JarList</replaceable></term>
+ <term>-aspectpath <replaceable>Path</replaceable></term>
<listitem><para>
- Weave binary aspects from JarList zip files into all sources.
+ Weave binary aspects from Jars and directories on path into all sources.
The aspects should have been output by the same version
of the compiler.
To run the output classes requires putting all the
aspectpath entries on the run classpath.
- JarList, like classpath, is a single argument containing
+ Path, like classpath, is a single argument containing
a list of paths to jar files, delimited by the platform-
specific classpath delimiter.
</para></listitem>