zrcadlo
https://github.com/eclipse-aspectj/aspectj.git
synchronizováno 2024-08-26 17:58:43 +02:00
209 řádky
8.1 KiB
XML
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>
|
|
|