<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 id="calling-methods-and-constructors-with-variable-length-arguments" xreflabel="calling-methods-and-constructors-with-variable-length-arguments"> <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 id="matching-signatures-based-on-variable-length-argument-types" xreflabel="matching-signatures-based-on-variable-length-argument-types"> <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 id="exposing-variable-length-arguments-as-context-in-pointcuts-and-advice" xreflabel="exposing-variable-length-arguments-as-context-in-pointcuts-and-advice"> <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>