Reputation: 1125
Annotation from interface methods are not inherited to objects implementing that interface, afaik. SO search results.
I wanted to use an interface together with Guava's EventBus, which requires that an object has a callback method annotated with @Subscribe
.
I was wondering if I could simply put that annotation into the interface and let the object implement that listener interface. According to above, this should not work. However, it does work (see code below).
Why?
My machine is Java 1.8.0_151 (32 bit) with Windows 7.
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
/**
* This test should fail, but... it works!
*/
public class EventTests {
@Test
public void test_events_are_heard() {
MyListener listener = new MyListener();
DeafListener deafListener = new DeafListener();
EventBus bus = new EventBus();
bus.register(listener);
bus.register(deafListener);
bus.post(new MyEvent());
assertEquals(1, listener.eventCount); // ok
assertEquals(0, deafListener.eventCount); // ok
}
// this interface includes the @Subscribe annotation
private interface Listener {
@Subscribe
public void onEvent(MyEvent event);
}
// this interface does not include the @Subscribe annotation
private interface NoListener {
public void onEvent(MyEvent event);
}
// just something different from Object
private static class MyEvent {
}
// implementation of "Listener" (with @Subscribe in interface)
private static class MyListener implements Listener {
int eventCount = 0;
@Override
public void onEvent(MyEvent event) {
eventCount ++;
}
}
// IDENTICAL implementation as above, but of "NoListener"
// (without @Subscribe in interface)
private static class DeafListener implements NoListener {
int eventCount = 0;
@Override
public void onEvent(MyEvent event) {
eventCount ++;
}
}
}
Upvotes: 1
Views: 1436
Reputation: 35437
You are right in that the @Subscribe
annotation is not inherited. You can check it by having such a test MyListener.class.getMethod("onEvent", MyEvent.class).getAnnotation(Subscribe.class) != null
.
However, it feels right to have a subscribing method to be registered if it's defined in the interface.
So this was discussed at length within the Guava team in the past and the Principle of Least Surprise made it that if any of the declaring methods is annotated, then their registered implementations are subscribed.
I have to admit that I checked the documentation and the Javadoc and didn't see anything about your question specifically, even though it feels a necessary mention. I remembered the discussion from years ago and had to find the answer in closed issues.
Upvotes: 4