aboutsummaryrefslogtreecommitdiffstats
path: root/docs/adk15notebook/varargs.adoc
blob: 3f13ab31a0f33d37c09c9c9b5756433988520223 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
== Varargs

[[varargs-inJava5]]
=== Variable-length Argument Lists in Java 5

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:

[source, java]
....
public void foo(int i, String... strings) {}
....

A method or constructor may take at most one variable length argument,
and this must always be the last declared argument in the signature.

==== Calling Methods and Constructors with variable-length arguments

A _varargs_ method may be called with zero or more arguments in the
variable argument position. For example, given the definition of `foo`
above, the following calls are all legal:

[source, java]
....
foo(5);
foo(5,"One String");
foo(7,"One String","Two Strings");
foo(3,"One String","Two Strings","Three Strings");
....

A _varargs_ parameter is treated as an array within the defining member.
So in the body of `foo` we could write for example:

[source, java]
....
public void foo(int i, String... strings) {
  String[] someStrings = strings;
  // rest of method body
}
....

One consequence of this treatment of a varargs parameter as an array is
that you can also call a varargs method with an array:

[source, java]
....
foo(7,new String[] {"One String","Two Strings"});
....

[[varargs-in-pcds]]
=== Using Variable-length arguments in advice and pointcut expressions

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.

AspectJ 5 also allows variable length arguments to be matched by
pointcut expressions and bound as formals in advice.

==== Matching signatures based on variable length argument types

Recall from the definition of signature patterns given in the chapter on
annotations (xref:annotations.adoc#signaturePatterns[Signature Patterns]), that `MethodPattern` and
`ConstructorPattern` are extended to allow a `varargs` pattern in the
last argument position of a method or constructor signature.

[source, text]
....
FormalsPattern :=
  '..' (',' FormalsPatternAfterDotDot)? |
  OptionalParensTypePattern (',' FormalsPattern)* |
  TypePattern '...'

FormalsPatternAfterDotDot :=
  OptionalParensTypePattern (',' FormalsPatternAfterDotDot)* |
  TypePattern '...'
....

Method and constructor patterns are used in the `call`, `execution`,
`initialization`, `preinitialization`, and `withincode` pointcut
designators. Some examples of usage follow:

`call(* org.xyz.*.*(int, String...))`::
  Matches a call join point for a call to a method defined in the
  `org.xyz` package, taking an `int` and a `String` _vararg_.
`execution(* org.xyz.*.*(Integer...))`::
  Matches an execution join point for the execution of a method defined
  in the `org.xyz` package, taking an `Integer` _vararg_.
`initialization(org.xyz.*.new((Foo || Goo)...))`::
  Matches the initialization join point for the construction of an
  object in the `org.xyz` package via a constructor taking either a
  variable number of `Foo` parameters or a variable number of `Goo`
  parameters. (This example illustrating the use of a type pattern with
  `...`).

A variable argument parameter and an array parameter are treated as
distinct signature elements, so given the method definitions:

[source, java]
....
void foo(String...);
void bar(String[]);
....

The pointcut `execution(* *.*(String...))` matches the execution join
point for `foo`, but not `bar`. The pointcut
`execution(* *.*(String[]))` matches the execution join point for `bar`
but not `foo`.

==== Exposing variable-length arguments as context in pointcuts and advice

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 `args`
pointcut designator. Given a method

[source, java]
....
public void foo(int i, String... strings) {}
....

The call or execution join points for `foo` will be matched by the
pointcut `args(int,String[])`. It is not permitted to use the varargs
syntax within an args pointcut designator - so you _cannot_ write
`args(int,String...)`.

Binding of a varargs parameter in an advice statement is
straightforward:

[source, java]
....
before(int i, String[] ss) : call(* foo(int,String...)) && args(i,ss) {
  // varargs String... argument is accessible in advice body through ss
  // ...
}
....

Since you cannot use the varargs syntax in the `args` pointcut
designator, you also cannot use the varargs syntax to declare advice
parameters.

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 _solely_ on the use of the `args`
pointcut designator. If this distinction is required, `args` can always
be coupled with `call` or `execution`.