• No results found

93Advice in depth

In document InAction-AspectJ in Action 2nd Edition (Page 140-142)

Modifying behavior with dynamic crosscutting

93Advice in depth

after() returning : call(* Account.*(..)) { ... log the successful completion }

This advice executes after the successful completion of a call to any method in the

Account class. If the advised method throws an exception, the advice doesn’t execute. AspectJ offers a variation of the after returning advice that collects the return value. It has the following syntax:

after() returning(<ReturnType returnObject>)

You can use the collected return object in the advice as shown in figure 4.2. Although you can modify the collected return object (for example, remove elements from a col- lection), there is no way to return a new object. If you need such possibility, you’ll have to use the around advice.

In figure 4.2, you collect the return value of DriverManager.getConnection() by spec- ifying the type and the name of the return object in the returning() part of the advice specification. You then use the return object in the advice body to print its value.

After advice implicitly limits join point selection to only those that are compatible with the specified return type inside returning(). For example, in figure 4.2, if you used the call(* DriverManager.*(..)), it still would select only methods that return a type that is Connection or its subtype.

Another variation of the after advice advises join points upon throwing an exception.

AFTER THROWING

Similar to after returning advice, AspectJ offers after throwing advice. Such advice exe- cutes only when the advised join point throws an exception. The following code shows the form for after throwing advice:

after() throwing : execution(* Controller+.*(..)) { ... log the failure

}

This advice executes after execution of any method in the Controller class or its sub- type (note the +) if it throws an exception. If a method returns normally, the advice doesn’t execute. Similar to the variation of the after returning advice, AspectJ offers a variation of the after throwing advice that captures the thrown exception object. The advice has the following syntax:

after() throwing (<ExceptionType exceptionObject>)

You can use this form of the after throwing advice when you want to collect the exception thrown by the advised method so that you can use it in the advice body. In figure 4.3, you collect the exception thrown by any method by specifying the exception type and

Connection conn

conn

Connection DriverManager getConnection Obtained database connection after() returning( ) :

call( . (..)) {

System.out.println(" : " + );

}

Figure 4.2 Passing a return object context to an advice body. The return object is collected in returning() by specifying the type and object identifier.

a name in the throwing() part. Much like the return value and any other context, you can use this exception object in the advice body.

Note that thisJoinPoint is a special type of variable that carries join point context information. We’ll look at these types of vari- ables in section 4.5. Similar to the after returning type, the selected join points are implicitly limited to the join points that throw exceptions compatible with the type specified inside throwing().

Unless the after throwing advice itself throws an exception, the original exception processing continues up the call stack. Specifically, after throwing advice can’t swallow an exception, and the caller of the join point receives the exception thrown by the join point.

Now, let’s move on to the omnipotent around advice that is capable of implement- ing all other types of advice.

4.3.3 Around advice

Around advice surrounds join points. It has the ability to execute the join point with

the same or different context any number (including zero) of times. This implies that an around advice may bypass the advised join point or execute the advised join point multiple times, each with different context. Some typical usages of around advice are as follows:

Perform additional logic before and after the advised join point (for example,

profiling)

■ Bypass the original operation and perform some alternative logic (for example, caching)

Surround the operation with a try/catch block to perform an exception-

handling policy (for example, transaction management)

Around advice is the most potent form in that it can be always used instead of before or after advice; but in order to precisely express programming intent, it’s best to use the simplest form of advice appropriate for the task.

Around advice has explicit control over the advised join point’s execution. Let’s see how.

PROCEEDING WITH ADVISED JOIN POINT

If within the around advice you want to execute the advised join point, you must use a special keyword—proceed()—in the body of the advice. Unless you call proceed(), the advised join point is bypassed. When using proceed(), you can pass the context col- lected by the advice, if any, as the arguments; or you can pass a different set of argu- ments. The important thing to remember is that you must pass the same number and types of arguments as collected by the advice. Because proceed() causes the execution

after() throwing(Throwable ex ) : execution(* *(..)) { System.out.println("Exception " + ex + " while executing " + thisJoinPoint ); }

Figure 4.3 Passing a thrown exception to an advice body. The exception object is captured in throwing() by specifying the type and object identifier. Advice may access the special variables such as thisJoinPoint

in a similar manner to the this variable inside an instance method.

95

In document InAction-AspectJ in Action 2nd Edition (Page 140-142)