views:

63

answers:

2

Are there any annotations in java which mark a method as unsupported? E.g. Let's say I'm writing a new class which implements the java.util.List interface. The add() methods in this interface are optional and I don't need them in my implementation and so I to do the following:

public void add(Object obj) {
   throw new UnsupportedOperationException("This impl doesn't support add");
}

Unfortunately, with this, it's not until runtime that one might discover that, in fact, this operation is unsupported.

Ideally, this would have been caught at compile time and such an annotation (e.g. maybe @UnsupportedOperation) would nudge the IDE to say to any users of this method, "Hey, you're using an unsupported operation" in the way that using @Deprecated flags Eclipse to highlight any uses of the deprecated item.

+6  A: 

Although on the surface this sounds useful, in reality it would not help much. How do you usually use a list? I generally do something like this:

List<String> list = new XXXList<String>();

There's already one indirection there, so if I call list.add("Hi"), how should the compiler know that this specific implementation of list doesn't support that?

How about this:

void populate(List<String> list) {
    list.add("1");
    list.add("2");
}

Now it's even harder: The compiler would need to verify that all calls to that function used lists that support the add() operation.

So no, there is no way to do what you are asking, sorry.

Jonathan
Fair points. However, I would expect that it would be possible for the compiler to pick up near-direct references such as your first example. The second one, I admit, is much trickier, but I'm sure static code analysis tools would be able to handle your second indirectly referenced scenario. Oh well, thanks for your answer!
Chris Knight
I agree that it's possible (some compilers, such as Haskell I believe) do perform this kind of checking, basically proving that every type is safely used everywhere. But it's a really hard problem, with limited use in this case. Just be careful where you pass your list-without-add. :-)
Jonathan
+3  A: 

You can do it using AspectJ if you are familiar with it. You must first create a point-cut, then give an advice or declare error/warning for joint points matching this point cut. Of course you need your own @UnsupportedOperation annotation interface. I gave a simple code fragment about this.

// This the point-cut matching calls to methods annotated with your 
// @UnsupportedOperation annotation.
pointcut unsupportedMethodCalls() : call(@UnsupportedOperation * *.*(..));

// Declare an error for such calls. This causes a compilation error 
// if the point-cut matches any unsupported calls.
declare error: unsupportedMethodCalls() : "This call is not supported."

// Or you can just throw an exception just before this call executed at runtime
// instead of a compile-time error.
before() : unsupportedMethodCalls() {
    throw new UnsupportedOperationException(thisJoinPoint.getSignature()
        .getName());
}
ovunccetin
I am unfamiliar with AspectJ; would that catch uses of `List` that could be traced backwards to possibly/definitely referring to `XXXList` (where `XXXList` has its `add()` method annotated with `@UnsupportedOperation`)?
Jonathan
AspectJ mostly uses a compile-time weaving. That is, while your code is being compiled AspectJ's weaver inserts some code lines according to the aspects. If you are able to compile your list class with an aspect that I wrote, it works.
ovunccetin
Thanks,this looks really interesting and I've been meaning to look further into AspectJ. However, I can't see how it could resolve the issue of code using an interface of the concrete object, such as Jonathan's second example.
Chris Knight