Using Variable-length arguments in advice and pointcut expressions
Prev | Chapter 6. Varargs | Next

## 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 (Signature Patterns), that `MethodPattern` and `ConstructorPattern` are extended to allow a `varargs` pattern in the last argument position of a method or constructor signature.

     		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:

        	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

    		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:

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

Prev | Home | Next
Chapter 6. Varargs | Up | Chapter 7. Enumerated Types