From d1df9cbfeedf7d53b1e28dd8927f91d2a5f7a6e2 Mon Sep 17 00:00:00 2001 From: "Wisniewski, Kamil" Date: Thu, 8 Jan 2015 09:56:53 +0100 Subject: [PATCH] adding ability to detect handlers from super class. --- .../squareup/otto/AnnotatedHandlerFinder.java | 135 ++++++++++-------- .../com/squareup/otto/InheritSubscribers.java | 17 +++ 2 files changed, 89 insertions(+), 63 deletions(-) create mode 100644 otto/src/main/java/com/squareup/otto/InheritSubscribers.java diff --git a/otto/src/main/java/com/squareup/otto/AnnotatedHandlerFinder.java b/otto/src/main/java/com/squareup/otto/AnnotatedHandlerFinder.java index c7fb155..8a254be 100644 --- a/otto/src/main/java/com/squareup/otto/AnnotatedHandlerFinder.java +++ b/otto/src/main/java/com/squareup/otto/AnnotatedHandlerFinder.java @@ -49,69 +49,78 @@ private static void loadAnnotatedMethods(Class listenerClass) { Map, Set> subscriberMethods = new HashMap, Set>(); Map, Method> producerMethods = new HashMap, Method>(); - for (Method method : listenerClass.getDeclaredMethods()) { - // The compiler sometimes creates synthetic bridge methods as part of the - // type erasure process. As of JDK8 these methods now include the same - // annotations as the original declarations. They should be ignored for - // subscribe/produce. - if (method.isBridge()) { - continue; - } - if (method.isAnnotationPresent(Subscribe.class)) { - Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length != 1) { - throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation but requires " - + parameterTypes.length + " arguments. Methods must require a single argument."); - } - - Class eventType = parameterTypes[0]; - if (eventType.isInterface()) { - throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType - + " which is an interface. Subscription must be on a concrete class type."); - } - - if ((method.getModifiers() & Modifier.PUBLIC) == 0) { - throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType - + " but is not 'public'."); - } - - Set methods = subscriberMethods.get(eventType); - if (methods == null) { - methods = new HashSet(); - subscriberMethods.put(eventType, methods); - } - methods.add(method); - } else if (method.isAnnotationPresent(Produce.class)) { - Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length != 0) { - throw new IllegalArgumentException("Method " + method + "has @Produce annotation but requires " - + parameterTypes.length + " arguments. Methods must require zero arguments."); - } - if (method.getReturnType() == Void.class) { - throw new IllegalArgumentException("Method " + method - + " has a return type of void. Must declare a non-void type."); - } - - Class eventType = method.getReturnType(); - if (eventType.isInterface()) { - throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType - + " which is an interface. Producers must return a concrete class type."); - } - if (eventType.equals(Void.TYPE)) { - throw new IllegalArgumentException("Method " + method + " has @Produce annotation but has no return type."); - } - - if ((method.getModifiers() & Modifier.PUBLIC) == 0) { - throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType - + " but is not 'public'."); - } - - if (producerMethods.containsKey(eventType)) { - throw new IllegalArgumentException("Producer for type " + eventType + " has already been registered."); - } - producerMethods.put(eventType, method); - } - } + Class clazz = listenerClass; + + do { + for (Method method : clazz.getDeclaredMethods()) { + // The compiler sometimes creates synthetic bridge methods as part of the + // type erasure process. As of JDK8 these methods now include the same + // annotations as the original declarations. They should be ignored for + // subscribe/produce. + if (method.isBridge()) { + continue; + } + if (method.isAnnotationPresent(Subscribe.class)) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != 1) { + throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation but requires " + + parameterTypes.length + " arguments. Methods must require a single argument."); + } + + Class eventType = parameterTypes[0]; + if (eventType.isInterface()) { + throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType + + " which is an interface. Subscription must be on a concrete class type."); + } + + if ((method.getModifiers() & Modifier.PUBLIC) == 0) { + throw new IllegalArgumentException("Method " + method + " has @Subscribe annotation on " + eventType + + " but is not 'public'."); + } + + Set methods = subscriberMethods.get(eventType); + if (methods == null) { + methods = new HashSet(); + subscriberMethods.put(eventType, methods); + } + methods.add(method); + } else if (method.isAnnotationPresent(Produce.class)) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != 0) { + throw new IllegalArgumentException("Method " + method + "has @Produce annotation but requires " + + parameterTypes.length + " arguments. Methods must require zero arguments."); + } + if (method.getReturnType() == Void.class) { + throw new IllegalArgumentException("Method " + method + + " has a return type of void. Must declare a non-void type."); + } + + Class eventType = method.getReturnType(); + if (eventType.isInterface()) { + throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType + + " which is an interface. Producers must return a concrete class type."); + } + if (eventType.equals(Void.TYPE)) { + throw new IllegalArgumentException("Method " + method + " has @Produce annotation but has no return type."); + } + + if ((method.getModifiers() & Modifier.PUBLIC) == 0) { + throw new IllegalArgumentException("Method " + method + " has @Produce annotation on " + eventType + + " but is not 'public'."); + } + + if (producerMethods.containsKey(eventType)) { + throw new IllegalArgumentException("Producer for type " + eventType + " has already been registered."); + } + producerMethods.put(eventType, method); + } + } + if(clazz.isAnnotationPresent(InheritSubscribers.class)) { + clazz = clazz.getSuperclass(); + } else { + clazz = null; + } + } while (clazz != null); PRODUCERS_CACHE.put(listenerClass, producerMethods); SUBSCRIBERS_CACHE.put(listenerClass, subscriberMethods); diff --git a/otto/src/main/java/com/squareup/otto/InheritSubscribers.java b/otto/src/main/java/com/squareup/otto/InheritSubscribers.java new file mode 100644 index 0000000..535450c --- /dev/null +++ b/otto/src/main/java/com/squareup/otto/InheritSubscribers.java @@ -0,0 +1,17 @@ +package com.squareup.otto; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created with IntelliJ IDEA. + * User: SG0891787 + * Date: 1/6/2015 + * Time: 8:05 PM + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface InheritSubscribers { +}