Hi all,
A feature that i would like to see in AspectJ would
be the ability to perform narrowing conversions on exceptions thrown inside
advice. For example, i have some advice that runs on many method
execution joinpoints. All of these methods, however, throw different kinds
of checked exceptions. In my advice, i would like to have the ability to
throw the most generic type of exception that i want to handle (a Throwable) and
have it be automatically casted into the c type of exception that the method the
advice is executing around declares. For example, if one method could
throw an IOException and another could throw a FileNotFoundException then i
would like to be able to throw these exceptions as Throwables from the body of
my advice and have them be casted to an IOException and a
FileNotFoundException.
My primary reason for wanting this bit of
functionality is because i am trying to implement a mock object framework based
on aspects. This approach has some very powerful possibilities that
include the ability to create mocks based on concrete classes hassle free, mock
up static methods and set expectations on objects that are created inside the
method being tested. These are features that a non-aspect based framework
would never be able to provide.
Basically, the framework mocks-up objects by
having an aspect which wraps around() advice on all public methods that will be
involved in a test. This method intercepting aspect allows us to
by-pass the actual implementation of a method so that the user can set up
expectations and dummy values to be returned by the method in
question. In addition to allowing the user to set up return values, a
good mock framework must also allow the user to make a method throw an
exception.
This is where narrowing exception
conversions come in. My mock method intercepting aspect needs to be
able to throw any kind of exception so that i can simulate the mock methods
throwing the kind of exception that they were set up to throw. Let me
illustrate what i want to do with a code snippet:
public classToMock { public int
getNumber()
{ ...
}
public void canThrowException() throws
IOException
{ ...
} }
aspect MethodInterceptor { pointcut
allPublicMethods(): exection(public * *.*(..));
Object
around() throws Throwable: allPublicMethods()
{
... if
(someCondition)
{ // this
could return an IOException or any other kind of throwable!
// it must be casted into
throw getThrowable();
} ...
}
private Throwable
getThrowable()
{
...
}
}
As we all know, this code will cause all sorts
of compile errors because not all of the public methods that i want to test will
throw a Throwable (or anything at all!) However, code such as this is what
i want because i do need to be able to throw exceptions and errors of any
type. Indeed, classes dynamically generated by the java.lang.reflect.Proxy
class delegate the implementation of their methods to the
java.lang.reflect.InvocationHandler.invoke(...) method which does this
exact thing. Invoke(...) throws a Throwable even though the method that
delegated to it may only declare an IOException or no exceptions at all.
In the case where the InvocationHandler.invoke(...) method throws a throwable
that isn't declared by the delegating method, an UndeclaredThrowableException is
thrown.
At first glance it would appear that all that
is necessary to implement such a feature is to generate a try/catch block around
the advice a weave time so that the throwable could caught and then re-thrown as
the correct type. However, i really don't have a good grasp on
anything else that would have to change so don't how much work this feature would be to implement. I would
appreciate knowing if it can be done (or if anyone knows of some other way
of doing what i need) and when it could be done because without it i will
have to scrap my ideas for an aspect-based framework.
Thanks for reading this far ;) Take it
easy,
Sean Kirby
|