Modifying structure with static crosscutting
133Softening checked exceptions
A typical use of these constructs is enforcing rules, such as prohibiting calls to certain unsupported methods, or issuing a warning about such calls. The following code exam- ple causes the AspectJ compiler to produce a compile-time error if a join point matching the callToUnsafeCode() pointcut is found anywhere in the code that is being compiled: declare error : callToUnsafeCode()
: "This third-party code is known to result in a crash";
The following code is similar, except it produces a compile-time warning instead of an error:
declare warning : callToBlockingOperation()
: "Please ensure you are not calling this from an AWT thread";
You’ll see more examples of how to use compile-time errors and warnings for policy enforcement in chapter 11.
Let’s complete our discussion of static crosscutting support in AspectJ by examin- ing a construct that lets you demote checked exceptions to unchecked at selected join points.
5.6
Softening checked exceptions
Java specifies two categories of exceptions that a method may throw: checked and un- checked. When an exception is checked, callers must deal with it either by catching the exception or by declaring that they can throw it. When an exception is unchecked (which directly or indirectly extends RuntimeException or Error), callers need not deal with it explicitly and the exception is automatically propagated up the call stack. Exception softening lets you treat checked exceptions thrown by specified pointcuts as unchecked ones and thus eliminates the need to explicitly deal with them in the caller code.
The exception-softening feature helps modularize the crosscutting concerns of exception handling. For example, you can soften a RemoteException thrown in a Remote Method Invocation (RMI)-based system to avoid handling the exception at each level. This may be a useful strategy in some situations. For instance, if you know you’re using local objects of RMI-capable classes that won’t throw any RemoteExcep- tion, you can soften those exceptions.
To soften exceptions, you use the declare soft construct, which takes the follow- ing form:
declare soft : <ExceptionTypePattern> : <pointcut>;
If a method is throwing more than one checked exceptions, you must soften each one individually. In listing 5.19, the aspect declares the softening of an exception thrown by the TestSoftening.perform() method in listing 5.18. The method behaves as if it’s throwing an org.aspectj.lang.SoftException, which extends RuntimeException.
package ajia;
import java.rmi.RemoteException;
public class TestSoftening {
public static void main(String[] args) { TestSoftening test = new TestSoftening(); test.perform();
}
public void perform() throws RemoteException { throw new RemoteException();
} }
Compiling the TestSoftening class by itself results in a compiler error, because main() neither catches the exception nor declares that it’s throwing that exception: > ajc ajia\TestSoftening.java
...\src\ajia\TestSoftening.java:10
[error] Unhandled exception type RemoteException test.perform();
^^^^^
Listing 5.19 shows SofteningTestAspect, which softens the RemoteException thrown by the join point that corresponds to the call to the TestSoftening.perform() method.
package ajia; import ...
public aspect SofteningTestAspect {
declare soft : RemoteException : call(void TestSoftening.perform()); }
By softening the exception, you can compile the code without errors. When you run the program, you see a call stack due to a thrown SoftException:
> ajc ajia\TestSoftening.java ajia\SofteningTestAspect.aj > java ajia.TestSoftening
Exception in thread "main" org.aspectj.lang.SoftException at ajia.TestSoftening.main(TestSoftening.java:10) Caused by: java.rmi.RemoteException
at ajia.TestSoftening.perform(TestSoftening.java:13) ... 1 more
Exception softening is a quick way to avoid tangling the concern of exception han- dling with the core logic. But be careful about overusing this technique: one of the reasons to use checked exceptions is that it forces you to handle them by making a conscious decision about processing the exceptions or propagating them to the caller. The use of exception softening short-circuits this.
5.7
Summary
Static crosscutting offers ways to affect the static structure of the system. Static cross- cutting, which you can use by itself or in support of dynamic crosscutting, includes the
135 Summary
following constructs: member introduction, annotation supplementation, type hierar- chy modification, weave-time declarations, and exception softening.
The member-introduction facility helps with code scattering and tangling resulting from duplicated common structure needed across multiple types. The ability to mod- ify the type hierarchy offers a way to deal with multiple types uniformly even though the types don’t share a common type. The annotation-declaration feature allows aspects to reduce annotation clutter by encapsulating annotations from multiple ele- ments into one concise statement. Annotations declared in this manner can be con- sumed using dynamic crosscutting through annotation-based pointcuts. Weave-time errors and warnings provide a way to detect the presence of join points that may be in violation of some programming wisdom. Last, exception softening simplifies dealing with checked exceptions. The overall result is a simple, programmer-friendly language that supports AOP in Java. You’ll see many of these facilities used to implement com- plex crosscutting concerns in part 2 of this book.
In the next chapter, we’ll discuss the construct of an aspect that provides a unit to express both dynamic and static crosscutting elements.
136