AspectJ: Testing that Classes Implement All Required Interfaces
Posted by Dean Wampler Sun, 25 Feb 2007 15:31:00 GMT
There was a recent post to the aspectj-users group from “Frustrated Newbie” who was trying to write adeclare error that would enforce the requirement that all classes implementing one interface, let’s call it Foo, also implement a second interface Bar. He tried something like the following:
declare error: within(*..Foo+) && !within(*..*Bar+):As an experiment (which he tried…), if you drop the second expression, leaving just within(*..Foo+) you get an error just on the Foo interface, not on any implementing classes or extending interfaces.
..foo and ..bar, respectively, the following does work:
declare error: within(*..foo.*+) && !within(*..foo.*) && !within(*..bar.*+): !within(*..foo.*) prevents errors on the interfaces in package foo itself.
This isn’t especially obvious and you may find it inconvenient to package your interfaces like this, but it does work. Actually, there’s a good case to be made for putting interfaces in separate packages like this, based on the Stable Abstractions Principle (PDF, see also here).

Hi, Dean.
I am glad that it somehow worked in the end. However, I was wondering why people repeatedly misuse AOP for such purposes. IMHO the one and only correct way to enforce that an interface Foo also implements a second interface Bar is to make it a subtype of Bar. It’s no surprise that people struggle applying AOP for purposes it was not developed for, in particular if they already don’t get OOP right.
Eric
I fully agree with Eric. These types of usages of AOP will give it a bad name. Obviously the declare error that Dean has come up with does not look pretty on the face of it. Particularly in the days of DSLs, these usages will lead people to believe that AOP is a technology to fit a square peg in a round hole.
Cheers. - Debasish
I agree with both of you that it’s ugly. It would be better for languages to offer something more native or for AspectJ to provide the expressiveness necessary for a more elegant solution.
I don’t necessarily agree that this is a misuse of AOP. I thought about this issue when I developed Contract4J, my DbC tool for Java. On the one hand, the contract of a component IS part of its concern, not a cross-cutting concern. On the other hand, how you USE that contract, e.g., for “proving correctness” through DbC is not part of the primary concern of the application. In that sense, DbC is a cross-cutting concern.
Maybe this is a silly academic argument ;) Whether or not that’s true, I don’t have a problem with using a tool to solve a problem I can’t solve by other means, even if that usage seems to be outside the tool’s main application area.
Eric, concerning the idea that Foo should extend Bar, I think that solution won’t work in all cases. You can come up with different “mixin” interfaces that are unrelated and hence should not have an artificial inheritance relationship.
However, “Frustrated Newbie” could probably declare an implementation-specific interface that extends both Foo and Bar and then requires all his classes to implement that interface.
Thanks for you comments. Dean