Applying advice based on type
Posted by danielmeyer on November 25, 2008
When we add JMS queue support to our architecture, we’ll want to apply some AOP advice each time a listener receives a message. We want to have a convention for how the listeners will be set up so that our advice will find them.
In a recent communication with the design leads, I proposed that one of the ways we recognize a MessageListener be by having a convention that its class name must be *MessageListener.
One of the design leads asked a great question: Could we go based on the class implementing the MessageListener interface instead of being named a certain way? That would be slick, wouldn’t it? I didn’t know the answer, though. I only knew about matching based on name of the class/package/method/signature.
Too much advice
This pointcut expression works, but applies to too much:
We want to modify it to only apply to classes that implement the javax.jms.MessageListener interface.
A ineffectual plus
At first it looked like the plus sign was what we needed. The AspectJTM Programming Guide Appendix B. Language Semantics: Type patterns section on Subtype patterns says:
It is possible to pick out all subtypes of a type (or a collection of types) with the “+” wildcard. The “+” wildcard follows immediately a type name pattern.
And the Spring manual contains an example of the + wildcard on an execution pointcut.
My first attempt was a misuse of the plus sign, though I didn’t know it right away:
That didn’t work– when I deployed the project, the advice wasn’t applied to my listener. (I could tell because the listener relies on something the AOP advice sets up, and it blew up when that wasn’t there.)
I see now that I was misusing the plus operator — I wanted the advice to apply to any implementor/subclass of javax.jms.MessageListener, but the way I was using it it was as if I was trying to have the advice apply to any implementor/subclass of com.ontsys..svc..MessageListener.
Escaping from the Ampersands
The Spring manual’s AOP pointcut examples section shows an example using “target”:
and says it matches “any join point (method execution only in Spring AOP) where the target object implements the AccountService interface”
I tried this:
execution(void com.ontsys..svc..*.onMessage(..)) && target(MessageListener)
On deployment, though, I got an error about one of the ampersands…
I modified the pointcut expression to use the word and instead:
execution(void com.ontsys..svc..*.onMessage(..)) and target(MessageListener)
Now I got this error:
warning no match for this type name: MessageListener [Xlint:invalidAbsoluteTypeName]
Noticing that the Spring manual’s AOP pointcut examples all seemed to show fully-qualified types, I thought I’d try fully qualifying the name of the MessageListener interface:
execution(void com.ontsys..svc..*.onMessage(..)) and target(javax.jms.MessageListener)
This one worked. Woohoo!
Maybe I’m on my way to being a fully-qualified pointcut-expression writer. :D