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 a declare 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+):
This doesn’t work, mostly because interfaces don’t have much real code associated with them, so there aren’t enough join points to match.

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.

Through trial and error, I figured out that if you put these interfaces in dedicated packages, say ..foo and ..bar, respectively, the following does work:
declare error: within(*..foo.*+) && !within(*..foo.*) && !within(*..bar.*+):
The second expression !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).

Posted in ,  | 3 comments

Comments

  1. Eric said about 6 hours later:

    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

  2. Debasish Ghosh said about 13 hours later:

    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

  3. Dean Wampler said 2 days later:

    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

(leave url/email »)

   Preview comment