|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- <chapter id="varargs" xreflabel="Varargs">
-
- <title>Varargs</title>
-
- <sect1 id="varargs-inJava5" xreflabel="Varargs in Java 5">
- <title>Variable-length Argument Lists in Java 5</title>
-
- <para>
- 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:
- </para>
-
- <programlisting><![CDATA[
- public void foo(int i, String... strings) {
- }
- ]]></programlisting>
-
- <para>
- A method or constructor may take at most one variable length argument, and
- this must always be the last declared argument in the signature.
- </para>
-
- <sect2>
- <title>Calling Methods and Constructors with variable-length arguments</title>
-
- <para>
- A <emphasis>varargs</emphasis> method may be called with zero or more arguments
- in the variable argument position. For example, given the definition of
- <literal>foo</literal> above, the following calls are all legal:
- </para>
-
- <programlisting><![CDATA[
- foo(5);
- foo(5,"One String");
- foo(7,"One String","Two Strings");
- foo(3,"One String","Two Strings","Three Strings");
- ]]></programlisting>
-
- <para>A <emphasis>varargs</emphasis> parameter is treated as an array within the
- defining member. So in the body of <literal>foo</literal> we could write for example:
- </para>
-
- <programlisting><![CDATA[
- public void foo(int i, String... strings) {
- String[] someStrings = strings;
- // rest of method body
- }
- ]]></programlisting>
-
- <para>One consequence of this treatment of a varargs parameter as an array
- is that you can also call a varargs method with an array:</para>
-
- <programlisting><![CDATA[
- foo(7,new String[] {"One String","Two Strings"});
- ]]></programlisting>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="varargs-in-pcds">
- <title>Using Variable-length arguments in advice and pointcut expressions</title>
-
- <para>AspectJ 5 allows variable-length arguments to be used for methods declared within
- aspects, and for inter-type declared methods and constructors, in accordance with the rules
- outlined in the previous section.</para>
-
- <para>
- AspectJ 5 also allows variable length arguments to be matched by pointcut expressions and
- bound as formals in advice.
- </para>
-
- <sect2>
- <title>Matching signatures based on variable length argument types</title>
-
- <para>
- Recall from the definition of signature patterns given in the chapter on
- annotations (<xref linkend="signaturePatterns"/>), that <literal>MethodPattern</literal>
- and <literal>ConstructorPattern</literal> are extended to allow a <literal>varargs</literal>
- pattern in the last argument position of a method or constructor signature.
- </para>
-
- <programlisting><![CDATA[
- FormalsPattern := '..' (',' FormalsPatternAfterDotDot)? |
- OptionalParensTypePattern (',' FormalsPattern)* |
- TypePattern '...'
-
- FormalsPatternAfterDotDot :=
- OptionalParensTypePattern (',' FormalsPatternAfterDotDot)* |
- TypePattern '...'
-
- ]]></programlisting>
-
- <para>
- Method and constructor patterns are used in the <literal>call</literal>,
- <literal>execution</literal>, <literal>initialization</literal>,
- <literal>preinitialization</literal>, and <literal>withincode</literal>
- pointcut designators. Some examples of usage follow:
- </para>
-
- <variablelist>
-
- <varlistentry>
- <term>call(* org.xyz.*.*(int, String...))</term>
- <listitem>
- <para>
- Matches a call join point for a call to a method defined in the
- <literal>org.xyz</literal> package, taking an <literal>int</literal>
- and a <literal>String vararg</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>execution(* org.xyz.*.*(Integer...))</term>
- <listitem>
- <para>
- Matches an execution join point for the execution of a method defined in the
- <literal>org.xyz</literal> package, taking an <literal>Integer vararg</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>initialization(org.xyz.*.new((Foo || Goo)...))</term>
- <listitem>
- <para>
- Matches the initialization join point for the construction of an
- object in the <literal>org.xyz</literal> package via a constructor
- taking either a variable number of <literal>Foo</literal> parameters or
- a variable number of <literal>Goo</literal> parameters. (This example
- illustrating the use of a type pattern with ...).
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- <para>A variable argument parameter and an array parameter are treated as distinct
- signature elements, so given the method definitions:
- </para>
-
- <programlisting><![CDATA[
- void foo(String...);
- void bar(String[]);
- ]]></programlisting>
-
- <para>
- The pointcut <literal>execution(* *.*(String...))</literal> matches the execution join point
- for <literal>foo</literal>, but not <literal>bar</literal>. The pointcut
- <literal>execution(* *.*(String[]))</literal> matches the execution join point
- for <literal>bar</literal> but not <literal>foo</literal>.
- </para>
-
- </sect2>
-
- <sect2>
- <title>Exposing variable-length arguments as context in pointcuts and advice</title>
-
- <para>
- When a varargs parameter is used within the body of a method, it has
- an array type, as discussed in the introduction to this section. We follow the
- same convention when binding a varargs parameter via the <literal>args</literal>
- pointcut designator. Given a method
- </para>
-
- <programlisting><![CDATA[
- public void foo(int i, String... strings) {
- }
- ]]></programlisting>
-
- <para>
- The call or execution join points for <literal>foo</literal> will be matched
- by the pointcut <literal>args(int,String[])</literal>. It is not permitted
- to use the varargs syntax within an args pointcut designator - so you
- <emphasis>cannot</emphasis> write <literal>args(int,String...)</literal>.
- </para>
-
- <para>
- Binding of a varargs parameter in an advice statement is straightforward:
- </para>
-
- <programlisting><![CDATA[
- before(int i, String[] ss) : call(* foo(int,String...)) && args(i,ss) {
- // varargs String... argument is accessible in advice body through ss
- // ...
- }
- ]]></programlisting>
-
- <para>Since you cannot use the varargs syntax in the <literal>args</literal>
- pointcut designator, you also cannot use the varargs syntax to declare
- advice parameters.</para>
-
- <para>Note: the proposal in this section does not allow you to
- distinguish between a join point with a signature (int, String...)
- and a join point with a signature (int, String[]) based
- <emphasis>solely</emphasis> on the use of the <literal>args</literal>
- pointcut designator. If this distinction is required, <literal>args</literal>
- can always be coupled with <literal>call</literal> or
- <literal>execution</literal>.</para>
-
- </sect2>
-
- </sect1>
-
- </chapter>
-
|