org.aspectj/docs/adk15ProgGuideDB/varargs.xml
2004-12-09 08:59:22 +00:00

209 řádky
8.1 KiB
XML

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