diff --git a/library/src/main/java/com/squareup/otto/AnnotatedHandlerFinder.java b/library/src/main/java/com/squareup/otto/AnnotatedHandlerFinder.java
index 861113b..3ce3acc 100644
--- a/library/src/main/java/com/squareup/otto/AnnotatedHandlerFinder.java
+++ b/library/src/main/java/com/squareup/otto/AnnotatedHandlerFinder.java
@@ -19,6 +19,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -49,7 +50,12 @@ private static void loadAnnotatedMethods(Class> listenerClass) {
Map, Set> subscriberMethods = new HashMap, Set>();
Map, Method> producerMethods = new HashMap, Method>();
- for (Method method : listenerClass.getDeclaredMethods()) {
+ Set allMethods = new HashSet();
+ Collections.addAll(allMethods, listenerClass.getDeclaredMethods());
+
+ addSuperMethodsRecursively(allMethods, listenerClass);
+
+ for (Method method : allMethods) {
if (method.isAnnotationPresent(Subscribe.class)) {
Class>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1) {
@@ -110,6 +116,14 @@ private static void loadAnnotatedMethods(Class> listenerClass) {
SUBSCRIBERS_CACHE.put(listenerClass, subscriberMethods);
}
+ private static void addSuperMethodsRecursively(Set allMethods, Class> listenerClass) {
+ Class> superclass = listenerClass.getSuperclass();
+ if (superclass != null && listenerClass.isAnnotationPresent(ProcessSuperClass.class)) {
+ Collections.addAll(allMethods, superclass.getDeclaredMethods());
+ addSuperMethodsRecursively(allMethods, superclass);
+ }
+ }
+
/** This implementation finds all methods marked with a {@link Produce} annotation. */
static Map, EventProducer> findAllProducers(Object listener) {
final Class> listenerClass = listener.getClass();
diff --git a/library/src/main/java/com/squareup/otto/ProcessSuperClass.java b/library/src/main/java/com/squareup/otto/ProcessSuperClass.java
new file mode 100644
index 0000000..8914c07
--- /dev/null
+++ b/library/src/main/java/com/squareup/otto/ProcessSuperClass.java
@@ -0,0 +1,16 @@
+package com.squareup.otto;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Allows a class to tell otto to look for {@link Produce} and {@link Subscribe} annotated methods in super classes.
+ * Recursion only proceeds on classes which are annotated with this annotation, meaning in an inheritance
+ * hierarchy each sub-class must have this annotation.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ProcessSuperClass {
+}
diff --git a/library/src/test/java/com/squareup/otto/ProcessSuperClassTest.java b/library/src/test/java/com/squareup/otto/ProcessSuperClassTest.java
new file mode 100644
index 0000000..f70274b
--- /dev/null
+++ b/library/src/test/java/com/squareup/otto/ProcessSuperClassTest.java
@@ -0,0 +1,55 @@
+package com.squareup.otto;
+
+import org.junit.Test;
+import static org.fest.assertions.api.Assertions.assertThat;
+
+public class ProcessSuperClassTest {
+
+ private final Bus bus = new Bus(ThreadEnforcer.ANY, "test-bus");
+
+ @Test
+ public void allowsSuperClassSubscription() {
+
+ class Parent {
+
+ protected boolean messageReceived;
+
+ @Subscribe
+ public void onMessage(String message) {
+ messageReceived = true;
+ }
+ }
+
+ @ProcessSuperClass
+ class Child extends Parent {}
+
+ final Child child = new Child();
+ bus.register(child);
+ bus.post("Foo");
+
+ assertThat(child.messageReceived).isTrue();
+ }
+
+ @Test
+ public void doesNotProcessSuperClassWhenAnnotationIsMissing() {
+
+ class Parent {
+
+ protected boolean messageReceived;
+
+ @Subscribe
+ public void onMessage(String message) {
+ messageReceived = true;
+ }
+ }
+
+ class Child extends Parent {}
+
+ final Child child = new Child();
+ bus.register(child);
+ bus.post("Foo");
+
+ assertThat(child.messageReceived).isFalse();
+ }
+
+}
\ No newline at end of file
diff --git a/website/index.html b/website/index.html
index 14daebe..28eb615 100644
--- a/website/index.html
+++ b/website/index.html
@@ -76,10 +76,13 @@ Subscribing
to an instance of the class in which the previous method was present, we can register using the
following:
bus.register(this);
- Registering will only find methods on the immediate class type. Unlike the Guava event
+
Registering defaults to only find methods on the immediate class type. Unlike the Guava event
bus, Otto will not traverse the class hierarchy and add methods from base classes or interfaces that are
annotated. This is an explicit design decision to improve performance of the library as well as keep your
code simple and unambiguous.
+ In case you want to register inherited methods anyway you can annotate your classes with
+ @ProcessSuperClass. Otto will recursively traverse the inheritance hierarchy until it finds a class
+ which is not being annotated with this annotation or no more super classes can be found.
Remember to also call the unregister method when appropriate. See the sample application
included in the download for a complete example.