From 91a7980443696fda25198520e1ce538f2b534798 Mon Sep 17 00:00:00 2001 From: Rick Brock Date: Fri, 14 Nov 2014 15:31:16 -0800 Subject: [PATCH 001/112] Changed method subscription to use Annotations - Removed use of onEvent, onEventThreadName - Added @Subscribe annotation with an optional threadMode arg --- .../de/greenrobot/event/SubscriberMethod.java | 4 +- .../event/SubscriberMethodFinder.java | 56 ++++++++----------- .../event/annotations/Subscribe.java | 18 ++++++ .../eventperf/TestRunnerActivity.java | 4 ++ .../testsubject/PerfTestEventBus.java | 6 ++ .../test/EventBusBackgroundThreadTest.java | 3 + .../event/test/EventBusBasicTest.java | 9 +++ .../event/test/EventBusBuilderTest.java | 4 ++ .../test/EventBusCancelEventDeliveryTest.java | 5 ++ .../event/test/EventBusInheritanceTest.java | 7 +++ .../test/EventBusMainThreadRacingTest.java | 3 + .../event/test/EventBusMainThreadTest.java | 3 + .../test/EventBusMethodModifiersTest.java | 29 ++-------- .../event/test/EventBusMultithreadedTest.java | 10 ++++ .../test/EventBusNoSubscriberEventTest.java | 5 ++ .../EventBusOrderedSubscriptionsTest.java | 5 ++ .../test/EventBusRegistrationRacingTest.java | 3 + .../event/test/EventBusStickyEventTest.java | 5 ++ .../test/EventBusSubscriberExceptionTest.java | 4 ++ .../test/EventBusSubscriberLegalTest.java | 6 ++ 20 files changed, 133 insertions(+), 56 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/annotations/Subscribe.java diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/de/greenrobot/event/SubscriberMethod.java index 5e0df398..cf13c292 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethod.java @@ -32,7 +32,9 @@ final class SubscriberMethod { @Override public boolean equals(Object other) { - if (other instanceof SubscriberMethod) { + if (other == this) { + return true; + } else if (other instanceof SubscriberMethod) { checkMethodString(); SubscriberMethod otherSubscriberMethod = (SubscriberMethod)other; otherSubscriberMethod.checkMethodString(); diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 823cb0ec..9caa7b9f 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -16,6 +16,7 @@ package de.greenrobot.event; import android.util.Log; +import de.greenrobot.event.annotations.Subscribe; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -27,11 +28,10 @@ import java.util.concurrent.ConcurrentHashMap; class SubscriberMethodFinder { - private static final String ON_EVENT_METHOD_NAME = "onEvent"; /* * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. - * EventBus must ignore both. There modifiers are not public but defined in the Java class file format: + * EventBus must ignore both. Their modifiers are not public but defined in the Java class file format: * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 */ private static final int BRIDGE = 0x40; @@ -75,49 +75,41 @@ List findSubscriberMethods(Class subscriberClass) { Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { String methodName = method.getName(); - if (methodName.startsWith(ON_EVENT_METHOD_NAME)) { + + // Now we find acceptable methods via annotations + if (method.isAnnotationPresent(Subscribe.class)) { + Log.e("EventBus", "Annotation is present for " + methodName); int modifiers = method.getModifiers(); if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1) { - String modifierString = methodName.substring(ON_EVENT_METHOD_NAME.length()); - ThreadMode threadMode; - if (modifierString.length() == 0) { - threadMode = ThreadMode.PostThread; - } else if (modifierString.equals("MainThread")) { - threadMode = ThreadMode.MainThread; - } else if (modifierString.equals("BackgroundThread")) { - threadMode = ThreadMode.BackgroundThread; - } else if (modifierString.equals("Async")) { - threadMode = ThreadMode.Async; - } else { - if (skipMethodVerificationForClasses.containsKey(clazz)) { - continue; - } else { - throw new EventBusException("Illegal onEvent method, check for typos: " + method); + Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); + if (subscribeAnnotation != null && subscribeAnnotation.threadMode() != null) { + ThreadMode threadMode = subscribeAnnotation.threadMode(); + Class eventType = parameterTypes[0]; + + methodKeyBuilder.setLength(0); + methodKeyBuilder.append(methodName); + methodKeyBuilder.append('>').append(eventType.getName()); + String methodKey = methodKeyBuilder.toString(); + if (eventTypesFound.add(methodKey)) { + // Only add if not already found in a sub class + subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); } } - Class eventType = parameterTypes[0]; - methodKeyBuilder.setLength(0); - methodKeyBuilder.append(methodName); - methodKeyBuilder.append('>').append(eventType.getName()); - String methodKey = methodKeyBuilder.toString(); - if (eventTypesFound.add(methodKey)) { - // Only add if not already found in a sub class - subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); - } } - } else if (!skipMethodVerificationForClasses.containsKey(clazz)) { - Log.d(EventBus.TAG, "Skipping method (not public, static or abstract): " + clazz + "." - + methodName); } + + } else { + Log.e("EventBus", "Annotation is NOT present for " + methodName); } } + clazz = clazz.getSuperclass(); } if (subscriberMethods.isEmpty()) { - throw new EventBusException("Subscriber " + subscriberClass + " has no public methods called " - + ON_EVENT_METHOD_NAME); + throw new EventBusException("Subscriber " + subscriberClass + + " has no public methods called with the @Subscribe annotation"); } else { synchronized (methodCache) { methodCache.put(key, subscriberMethods); diff --git a/EventBus/src/de/greenrobot/event/annotations/Subscribe.java b/EventBus/src/de/greenrobot/event/annotations/Subscribe.java new file mode 100644 index 00000000..cf8af04c --- /dev/null +++ b/EventBus/src/de/greenrobot/event/annotations/Subscribe.java @@ -0,0 +1,18 @@ +package de.greenrobot.event.annotations; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import de.greenrobot.event.ThreadMode; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD}) +public @interface Subscribe { + ThreadMode threadMode() default ThreadMode.PostThread; +} + diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java index 127d528b..a9dcf7a5 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java @@ -1,5 +1,8 @@ package de.greenrobot.eventperf; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; + import android.app.Activity; import android.os.Bundle; import android.os.Process; @@ -43,6 +46,7 @@ protected void onResume() { } } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(TestFinishedEvent event) { Test test = event.test; String text = "" + test.getDisplayName() + "
" + // diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 16920dc3..ca7a3d92 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -6,6 +6,8 @@ import android.content.Context; import de.greenrobot.event.EventBus; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; import de.greenrobot.eventperf.TestParams; @@ -174,6 +176,7 @@ public String getDisplayName() { } public class SubscribeClassEventBusDefault { + @Subscribe public void onEvent(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -195,6 +198,7 @@ public void dummy5() { } public class SubscribeClassEventBusMain { + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -216,6 +220,7 @@ public void dummy5() { } public class SubscribeClassEventBusBackground { + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -237,6 +242,7 @@ public void dummy5() { } public class SubscriberClassEventBusAsync { + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(TestEvent event) { eventsReceivedCount.incrementAndGet(); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java index 888b37d5..1d9dae38 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java @@ -16,6 +16,8 @@ package de.greenrobot.event.test; import android.os.Looper; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -40,6 +42,7 @@ public void testPostFromMain() throws InterruptedException { assertFalse(lastThread.equals(Looper.getMainLooper().getThread())); } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(String event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index c34feb38..ae0313de 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -18,6 +18,7 @@ import android.app.Activity; import android.util.Log; import de.greenrobot.event.EventBus; +import de.greenrobot.event.annotations.Subscribe; import junit.framework.TestCase; import java.lang.ref.WeakReference; @@ -187,6 +188,7 @@ public void testHasSubscriberForEventSuperclass() { assertFalse(eventBus.hasSubscriberForEvent(String.class)); Object subscriber = new Object() { + @Subscribe public void onEvent(Object event) { } }; @@ -201,6 +203,7 @@ public void testHasSubscriberForEventImplementedInterface() { assertFalse(eventBus.hasSubscriberForEvent(String.class)); Object subscriber = new Object() { + @Subscribe public void onEvent(CharSequence event) { } }; @@ -213,20 +216,24 @@ public void onEvent(CharSequence event) { assertFalse(eventBus.hasSubscriberForEvent(String.class)); } + @Subscribe public void onEvent(String event) { lastStringEvent = event; countStringEvent++; } + @Subscribe public void onEvent(Integer event) { lastIntEvent = event; countIntEvent++; } + @Subscribe public void onEvent(MyEvent event) { countMyEvent++; } + @Subscribe public void onEvent(MyEventExtended event) { countMyEventExtended++; } @@ -234,6 +241,7 @@ public void onEvent(MyEventExtended event) { static class TestActivity extends Activity { public String lastStringEvent; + @Subscribe public void onEvent(String event) { lastStringEvent = event; } @@ -249,6 +257,7 @@ class RepostInteger { public int lastEvent; public int countEvent; + @Subscribe public void onEvent(Integer event) { lastEvent = event; countEvent++; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java index 58b6bc8d..3bfd9733 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java @@ -20,6 +20,7 @@ import de.greenrobot.event.EventBusException; import de.greenrobot.event.NoSubscriberEvent; import de.greenrobot.event.SubscriberExceptionEvent; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -75,18 +76,21 @@ public void testEventInheritance() { } class SubscriberExceptionEventTracker { + @Subscribe public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } } class NoSubscriberEventTracker { + @Subscribe public void onEvent(NoSubscriberEvent event) { trackEvent(event); } } class ThrowingSubscriber { + @Subscribe public void onEvent(Object event) { throw new RuntimeException(); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 027d74f9..3b026db0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -19,6 +19,8 @@ import android.test.UiThreadTest; import de.greenrobot.event.EventBusException; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -82,6 +84,7 @@ public Subscriber(boolean cancel) { this.cancel = cancel; } + @Subscribe public void onEvent(String event) { trackEvent(event); if (cancel) { @@ -91,6 +94,7 @@ public void onEvent(String event) { } class SubscriberCancelOtherEvent { + @Subscribe public void onEvent(String event) { try { eventBus.cancelEventDelivery(this); @@ -103,6 +107,7 @@ public void onEvent(String event) { class SubscriberMainThread { final CountDownLatch done = new CountDownLatch(1); + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { try { eventBus.cancelEventDelivery(event); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 27e3d7b7..1d54f5d0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -15,6 +15,7 @@ */ package de.greenrobot.event.test; +import de.greenrobot.event.annotations.Subscribe; import junit.framework.TestCase; import de.greenrobot.event.EventBus; @@ -91,22 +92,27 @@ public void testSubscriberClassHierarchy() { assertEquals(2, subscriber.countMyEventOverwritten); } + @Subscribe public void onEvent(Object event) { countObjectEvent++; } + @Subscribe public void onEvent(MyEvent event) { countMyEvent++; } + @Subscribe public void onEvent(MyEventExtended event) { countMyEventExtended++; } + @Subscribe public void onEvent(MyEventInterface event) { countMyEventInterface++; } + @Subscribe public void onEvent(MyEventInterfaceExtended event) { countMyEventInterfaceExtended++; } @@ -126,6 +132,7 @@ static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended static class SubscriberExtended extends EventBusInheritanceTest { private int countMyEventOverwritten; + @Subscribe public void onEvent(MyEvent event) { countMyEventOverwritten++; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index 0b3ac3a8..e740dd44 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -20,6 +20,8 @@ import android.os.Handler; import android.os.Looper; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -84,6 +86,7 @@ public void run() { awaitLatch(doneLatch, 10); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { trackEvent(event); if (unregistered) { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 41b6302b..6f60c24d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -19,6 +19,8 @@ import java.util.List; import android.os.Looper; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -57,6 +59,7 @@ public void testPostInBackgroundThread() throws InterruptedException { assertEquals(Looper.getMainLooper().getThread(), lastThread); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index 6d664b9c..8f54b91b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -18,6 +18,8 @@ import android.os.Looper; import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBusException; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -31,47 +33,28 @@ public void testRegisterForEventTypeAndPost() throws InterruptedException { waitForEventCount(4, 1000); } - public void testIllegalMethodNameThrow() { - try { - eventBus.register(new IllegalEventMethodName()); - fail("Illegal name registered"); - } catch (EventBusException ex) { - // OK, expected - } - } - - public void testIllegalMethodNameSkip() { - eventBus=EventBus.builder().skipMethodVerificationFor(IllegalEventMethodName.class).build(); - eventBus.register(new IllegalEventMethodName()); - eventBus.post(new Object()); - } - + @Subscribe public void onEvent(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { trackEvent(event); assertSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } - public static class IllegalEventMethodName { - public void onEventIllegalName(Object event) { - fail("onEventIllegalName got called"); - } - - public void onEvent(IntTestEvent event) { - } - } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index be68fd12..61032a7d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -23,6 +23,8 @@ import android.os.Looper; import android.util.Log; import de.greenrobot.event.EventBus; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -164,24 +166,28 @@ private List startThreads(CountDownLatch latch, int threadCount, i return threads; } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(String event) { lastStringEvent = event; countStringEvent.incrementAndGet(); trackEvent(event); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(Integer event) { lastIntegerEvent = event; countIntegerEvent.incrementAndGet(); trackEvent(event); } + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(IntTestEvent event) { countIntTestEvent.incrementAndGet(); lastIntTestEvent = event; trackEvent(event); } + @Subscribe public void onEvent(Object event) { countObjectEvent.incrementAndGet(); trackEvent(event); @@ -239,18 +245,22 @@ public void run() { } } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(String event) { assertSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(Integer event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe public void onEvent(Object event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(Object event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index ffe48f10..5d87ff4e 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -18,6 +18,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.NoSubscriberEvent; import de.greenrobot.event.SubscriberExceptionEvent; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -37,6 +38,7 @@ public void testNoSubscriberEvent() { public void testNoSubscriberEventAfterUnregister() { Object subscriber = new Object() { @SuppressWarnings("unused") + @Subscribe public void onEvent(String dummy) { } }; @@ -57,15 +59,18 @@ public void testBadNoSubscriberSubscriber() { assertEquals("Foo", noSub.originalEvent); } + @Subscribe public void onEvent(NoSubscriberEvent event) { trackEvent(event); } + @Subscribe public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } class BadNoSubscriberSubscriber { + @Subscribe public void onEvent(NoSubscriberEvent event) { throw new RuntimeException("I'm bad"); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 0cb794ac..67e26f96 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -20,6 +20,8 @@ import de.greenrobot.event.EventBus; import android.util.Log; +import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -96,14 +98,17 @@ public PrioSubscriber(int prio) { // TODO Auto-generated constructor stub } + @Subscribe public void onEvent(String event) { handleEvent(event); } + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(IntTestEvent event) { handleEvent(event); } + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(Integer event) { handleEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index 41808dc7..9289a547 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -15,6 +15,8 @@ */ package de.greenrobot.event.test; +import de.greenrobot.event.annotations.Subscribe; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -87,6 +89,7 @@ public void run() { unregisteredLatch.countDown(); } + @Subscribe public void onEvent(String event) { eventCount++; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 04be4d91..b17ccd60 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -15,6 +15,8 @@ */ package de.greenrobot.event.test; +import de.greenrobot.event.annotations.Subscribe; + /** * @author Markus Junginger, greenrobot */ @@ -119,6 +121,7 @@ public void testPostStickyRemoveAll() throws InterruptedException { public void testRemoveStickyEventInSubscriber() throws InterruptedException { eventBus.registerSticky(new Object() { @SuppressWarnings("unused") + @Subscribe public void onEvent(String event) { eventBus.removeStickyEvent(event); } @@ -130,10 +133,12 @@ public void onEvent(String event) { assertNull(eventBus.getStickyEvent(String.class)); } + @Subscribe public void onEvent(String event) { trackEvent(event); } + @Subscribe public void onEvent(IntTestEvent event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index f9acaa7e..8a610a6d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -17,6 +17,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.SubscriberExceptionEvent; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -43,15 +44,18 @@ public void testBadExceptionSubscriber() { assertEventCount(1); } + @Subscribe public void onEvent(String event) { throw new RuntimeException("Bar"); } + @Subscribe public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } class BadExceptionSubscriber { + @Subscribe public void onEvent(SubscriberExceptionEvent event) { throw new RuntimeException("Bad"); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index ee435219..b7b0fbf3 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -16,6 +16,7 @@ package de.greenrobot.event.test; import de.greenrobot.event.EventBusException; +import de.greenrobot.event.annotations.Subscribe; /** * @author Markus Junginger, greenrobot @@ -51,6 +52,7 @@ public void testSubscriberLegalAbstract() { eventBus.register(new Abstract() { @Override + @Subscribe public void onEvent(String event) { trackEvent(event); } @@ -61,20 +63,24 @@ public void onEvent(String event) { assertEquals(1, eventCount.intValue()); } + @Subscribe public void onEvent(String event) { trackEvent(event); } static class NotPublic { + @Subscribe void onEvent(String event) { } } static abstract class Abstract { + @Subscribe public abstract void onEvent(String event); } static class Static { + @Subscribe public static void onEvent(String event) { } } From 3b66bcd114fa010d6c93e4457185a8ddfcd71b54 Mon Sep 17 00:00:00 2001 From: Rick Brock Date: Fri, 14 Nov 2014 16:15:17 -0800 Subject: [PATCH 002/112] Updated documentation to reflect annotations --- HOWTO.md | 27 ++++++++++++++------------- README.md | 13 +++++++------ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/HOWTO.md b/HOWTO.md index 740ad573..eeff213a 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -19,7 +19,7 @@ public class MessageEvent { ``` ### 2: Prepare subscribers ### -Subscribers implement event handling `onEvent` methods that will be called when an event is received. They also need to register and unregister themselves to the bus. +Subscribers implement event handling methods that will be called when an event is received. These are defined with the ``@Subscribe`` annotation. They also need to register and unregister themselves to the bus. ```java @Override @@ -35,11 +35,13 @@ Subscribers implement event handling `onEvent` methods that will be called when } // This method will be called when a MessageEvent is posted - public void onEvent(MessageEvent event){ + @Subscribe + public void onMessageEvent(MessageEvent event){ Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show(); } // This method will be called when a SomeOtherEvent is posted + @Subscribe public void onEvent(SomeOtherEvent event){ doSomethingWith(event); } @@ -58,11 +60,12 @@ EventBus can handle threading for you: events can be posted in threads different A common use case is dealing with UI changes. In Android, UI changes must be done in the UI (main) thread. On the other hand, networking, or any time consuming task, must not run on the main thread. EventBus helps you to deal with those tasks and synchronize with the UI thread (without having to delve into thread transitions, using AsyncTask, etc). -In EventBus, you may define the thread that will call the event handling method `onEvent` by using a **ThreadMode**: +In EventBus, you may define the thread that will call the event handling method by using a **ThreadMode**: * **PostThread:** Subscriber will be called in the same thread, which is posting the event. This is the default. Event delivery implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers using this mode should return quickly to avoid blocking the posting thread, which may be the main thread. Example: ```java // Called in the same thread (default) + @Subscribe public void onEvent(MessageEvent event) { log(event.message); } @@ -71,6 +74,7 @@ Example: Example: ```java // Called in Android UI's main thread + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(MessageEvent event) { textField.setText(event.message); } @@ -78,6 +82,7 @@ Example: * **BackgroundThread:** Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single background thread that will deliver all its events sequentially. Event handlers using this mode should try to return quickly to avoid blocking the background thread. ```java // Called in the background thread + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(MessageEvent event){ saveToDisk(event.message); } @@ -85,12 +90,13 @@ Example: * **Async:** Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. ```java // Called in a separate thread + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(MessageEvent event){ backend.send(event.message); } ``` -*Note:* EventBus takes care of calling the `onEvent` method in the proper thread depending on its name (onEvent, onEventAsync, etc.). +*Note:* EventBus takes care of calling the subscribing method in the proper thread depending on its annotations threadMode argument (threadMode=ThreadMode.Async, MainThread, etc...). Subscriber priorities and ordered event delivery ------------------------------------------------ @@ -164,7 +170,8 @@ After that, a new Activity gets started. During registration using registerStick super.onStart(); EventBus.getDefault().registerSticky(this); } - + + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(MessageEvent event) { textField.setText(event.message); } @@ -185,9 +192,8 @@ ProGuard configuration ---------------------- ProGuard obfuscates method names. However, the onEvent methods must not renamed because they are accessed using reflection. Use the following snip in your ProGuard configuration file (proguard.cfg):
-keepclassmembers class ** {
-    public void onEvent*(**);
-}
-
+ @de.greenrobot.event.annotations.Subscribe public *; +} Comparison with Square's Otto @@ -199,11 +205,6 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E EventBus Otto - - Declare event handling methods - Name conventions - Annotations - Event inheritance Yes diff --git a/README.md b/README.md index 3e5a457e..00bd8a8d 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,16 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) -EventBus in 3 steps +EventBus in 4 steps ------------------- 1. Define events:
public class MessageEvent { /* Additional fields if needed */ }

-2. Prepare subscribers:
-eventBus.register(this);
+2. Register your subscriber (in your onCreate or in a constructor):
+eventBus.register(this);

+3. Declare your subscribing method
+@Subscribe
public void onEvent(AnyEventType event) {/* Do something */};

-3. Post events:
+4. Post events:
eventBus.post(event); Add EventBus to your project @@ -54,8 +56,7 @@ Details on EventBus and its API are available in the [HOWTO document](HOWTO.md). Additional Features and Notes ----------------------------- -* **NOT based on annotations:** Querying annotations are slow on Android, especially before Android 4.0. Have a look at this [Android bug report](http://code.google.com/p/android/issues/detail?id=7811). -* **Based on conventions:** Event handling methods are called "onEvent". +* **Based on annotations:** Event handling methods can be named however you want, and only need to be annotated with **@Subscribe**. * **Performance optimized:** It's probably the fastest event bus for Android. * **Convenience singleton:** You can get a process wide event bus instance by calling EventBus.getDefault(). You can still call new EventBus() to create any number of local busses. * **Subscriber and event inheritance:** Event handler methods may be defined in super classes, and events are posted to handlers of the event's super classes including any implemented interfaces. For example, subscriber may register to events of the type Object to receive all events posted on the event bus. From df91aeba6ae163a759ba88c2be728fb7b6e4d4bb Mon Sep 17 00:00:00 2001 From: Rick Brock Date: Mon, 17 Nov 2014 14:14:28 -0800 Subject: [PATCH 003/112] Added logging and sped up method finding - Moved check for bridge and synthetic methods up to rule them out asap - Reorganized method finding to be more clear - Added comments - Added logging to method finding if the user enables it --- .../src/de/greenrobot/event/EventBus.java | 3 +- .../event/SubscriberMethodFinder.java | 96 +++++++++++++------ 2 files changed, 68 insertions(+), 31 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 4bac5cbe..4ba22a7c 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -160,7 +160,8 @@ public void registerSticky(Object subscriber, int priority) { } private synchronized void register(Object subscriber, boolean sticky, int priority) { - List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); + List subscriberMethods + = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(), logSubscriberExceptions); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod, sticky, priority); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 9caa7b9f..57d9c8c2 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -29,15 +29,8 @@ class SubscriberMethodFinder { - /* - * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. - * EventBus must ignore both. Their modifiers are not public but defined in the Java class file format: - * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 - */ - private static final int BRIDGE = 0x40; - private static final int SYNTHETIC = 0x1000; - private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; + private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC; private static final Map> methodCache = new HashMap>(); private final Map, Class> skipMethodVerificationForClasses; @@ -51,7 +44,7 @@ class SubscriberMethodFinder { } } - List findSubscriberMethods(Class subscriberClass) { + List findSubscriberMethods(Class subscriberClass, boolean logSubscriberExceptions) { String key = subscriberClass.getName(); List subscriberMethods; synchronized (methodCache) { @@ -71,37 +64,67 @@ List findSubscriberMethods(Class subscriberClass) { break; } + // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { String methodName = method.getName(); + + /* + * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. + * EventBus must ignore both. Their modifiers are not public but defined in the Java class file format: + * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 + */ + if (method.isBridge() || method.isSynthetic()) { + continue; + } + // Now we find acceptable methods via annotations if (method.isAnnotationPresent(Subscribe.class)) { - Log.e("EventBus", "Annotation is present for " + methodName); + + // make sure the method is public int modifiers = method.getModifiers(); - if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { - Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length == 1) { - Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); - if (subscribeAnnotation != null && subscribeAnnotation.threadMode() != null) { - ThreadMode threadMode = subscribeAnnotation.threadMode(); - Class eventType = parameterTypes[0]; - - methodKeyBuilder.setLength(0); - methodKeyBuilder.append(methodName); - methodKeyBuilder.append('>').append(eventType.getName()); - String methodKey = methodKeyBuilder.toString(); - if (eventTypesFound.add(methodKey)) { - // Only add if not already found in a sub class - subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); - } - } - } + if ((modifiers & Modifier.PUBLIC) == 0) { + logErrorIfEnabled(logSubscriberExceptions, methodName, + "Method (%s) has subscribe annotation but is not public"); + continue; + } + + // make sure the method is not static or abstract + if ((modifiers & MODIFIERS_IGNORE) != 0) { + logErrorIfEnabled(logSubscriberExceptions, methodName, + "Method (%s) has subscribe annotation but is either static or abstract"); + continue; + } + + // verify that there is exactly 1 parameter (the event) + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length != 1) { + logErrorIfEnabled(logSubscriberExceptions, methodName, + "Method (%s) does not have exactly 1 parameter"); + continue; + } + + // This method is valid, so now we get the threadMode and add to the cache + Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); + Class eventType = parameterTypes[0]; + ThreadMode threadMode; + if (subscribeAnnotation != null && subscribeAnnotation.threadMode() != null) { + threadMode = subscribeAnnotation.threadMode(); + } else { + threadMode = ThreadMode.PostThread; } - } else { - Log.e("EventBus", "Annotation is NOT present for " + methodName); + methodKeyBuilder.setLength(0); + methodKeyBuilder.append(methodName); + methodKeyBuilder.append('>').append(eventType.getName()); + + String methodKey = methodKeyBuilder.toString(); + if (eventTypesFound.add(methodKey)) { + // Only add if not already found in a sub class + subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); + } } } @@ -118,6 +141,19 @@ List findSubscriberMethods(Class subscriberClass) { } } + /** + * If the user has enabled logging subscriber errors, log the message to log.e + * + * @param logSubscriberErrors if logSubscriberErrors is enabled + * @param methodName method name + * @param error error message + */ + private void logErrorIfEnabled(boolean logSubscriberErrors, String methodName, String error) { + if (logSubscriberErrors) { + Log.e(EventBus.TAG, String.format(error, methodName)); + } + } + static void clearCaches() { synchronized (methodCache) { methodCache.clear(); From cf6f736057c3f4bfe23495c4fe562b4636fd872c Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 22 Feb 2015 19:02:03 +0100 Subject: [PATCH 004/112] improving annotation look-up performance --- .../src/de/greenrobot/event/EventBus.java | 5 +- .../event/SubscriberMethodFinder.java | 121 ++++++------------ 2 files changed, 43 insertions(+), 83 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 4ba22a7c..ba759d33 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -108,7 +108,7 @@ public EventBus() { mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); - subscriberMethodFinder = new SubscriberMethodFinder(builder.skipMethodVerificationForClasses); + subscriberMethodFinder = new SubscriberMethodFinder(/* TODO */ false); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; @@ -160,8 +160,7 @@ public void registerSticky(Object subscriber, int priority) { } private synchronized void register(Object subscriber, boolean sticky, int priority) { - List subscriberMethods - = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass(), logSubscriberExceptions); + List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod, sticky, priority); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 57d9c8c2..d6a21523 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -15,7 +15,6 @@ */ package de.greenrobot.event; -import android.util.Log; import de.greenrobot.event.annotations.Subscribe; import java.lang.reflect.Method; @@ -25,26 +24,26 @@ import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; class SubscriberMethodFinder { + /* + * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. + * EventBus must ignore both. There modifiers are not public but defined in the Java class file format: + * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 + */ + private static final int BRIDGE = 0x40; + private static final int SYNTHETIC = 0x1000; - private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC; + private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; private static final Map> methodCache = new HashMap>(); + private final boolean strictMethodVerification; - private final Map, Class> skipMethodVerificationForClasses; - - SubscriberMethodFinder(List> skipMethodVerificationForClassesList) { - skipMethodVerificationForClasses = new ConcurrentHashMap, Class>(); - if (skipMethodVerificationForClassesList != null) { - for (Class clazz : skipMethodVerificationForClassesList) { - skipMethodVerificationForClasses.put(clazz, clazz); - } - } + SubscriberMethodFinder(boolean strictMethodVerification) { + this.strictMethodVerification = strictMethodVerification; } - List findSubscriberMethods(Class subscriberClass, boolean logSubscriberExceptions) { + List findSubscriberMethods(Class subscriberClass) { String key = subscriberClass.getName(); List subscriberMethods; synchronized (methodCache) { @@ -64,67 +63,42 @@ List findSubscriberMethods(Class subscriberClass, boolean l break; } - // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { - String methodName = method.getName(); - - - /* - * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. - * EventBus must ignore both. Their modifiers are not public but defined in the Java class file format: - * http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.6-200-A.1 - */ - if (method.isBridge() || method.isSynthetic()) { - continue; - } - - // Now we find acceptable methods via annotations - if (method.isAnnotationPresent(Subscribe.class)) { - - // make sure the method is public - int modifiers = method.getModifiers(); - if ((modifiers & Modifier.PUBLIC) == 0) { - logErrorIfEnabled(logSubscriberExceptions, methodName, - "Method (%s) has subscribe annotation but is not public"); - continue; - } - - // make sure the method is not static or abstract - if ((modifiers & MODIFIERS_IGNORE) != 0) { - logErrorIfEnabled(logSubscriberExceptions, methodName, - "Method (%s) has subscribe annotation but is either static or abstract"); - continue; - } - - // verify that there is exactly 1 parameter (the event) + int modifiers = method.getModifiers(); + if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length != 1) { - logErrorIfEnabled(logSubscriberExceptions, methodName, - "Method (%s) does not have exactly 1 parameter"); - continue; + if (parameterTypes.length == 1) { + Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); + if (subscribeAnnotation != null) { + String methodName = method.getName(); + Class eventType = parameterTypes[0]; + methodKeyBuilder.setLength(0); + methodKeyBuilder.append(methodName); + methodKeyBuilder.append('>').append(eventType.getName()); + + String methodKey = methodKeyBuilder.toString(); + if (eventTypesFound.add(methodKey)) { + // Only add if not already found in a sub class + ThreadMode threadMode = subscribeAnnotation.threadMode(); + subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); + } + } + } else if (strictMethodVerification) { + if (method.isAnnotationPresent(Subscribe.class)) { + String methodName = name + "." + method.getName(); + throw new EventBusException("@Subscribe method " + methodName + + "must have exactly 1 parameter but has " + parameterTypes.length); + } } - - // This method is valid, so now we get the threadMode and add to the cache - Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); - Class eventType = parameterTypes[0]; - ThreadMode threadMode; - if (subscribeAnnotation != null && subscribeAnnotation.threadMode() != null) { - threadMode = subscribeAnnotation.threadMode(); - } else { - threadMode = ThreadMode.PostThread; + } else if (strictMethodVerification) { + if (method.isAnnotationPresent(Subscribe.class)) { + String methodName = name + "." + method.getName(); + throw new EventBusException(methodName + + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } - methodKeyBuilder.setLength(0); - methodKeyBuilder.append(methodName); - methodKeyBuilder.append('>').append(eventType.getName()); - - String methodKey = methodKeyBuilder.toString(); - if (eventTypesFound.add(methodKey)) { - // Only add if not already found in a sub class - subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); - } } } @@ -141,19 +115,6 @@ List findSubscriberMethods(Class subscriberClass, boolean l } } - /** - * If the user has enabled logging subscriber errors, log the message to log.e - * - * @param logSubscriberErrors if logSubscriberErrors is enabled - * @param methodName method name - * @param error error message - */ - private void logErrorIfEnabled(boolean logSubscriberErrors, String methodName, String error) { - if (logSubscriberErrors) { - Log.e(EventBus.TAG, String.format(error, methodName)); - } - } - static void clearCaches() { synchronized (methodCache) { methodCache.clear(); From daa7370c8fa833e477e42ef281fd7279fb079a88 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 22 Feb 2015 21:13:26 +0100 Subject: [PATCH 005/112] moved @Subscribe into main package --- .../src/de/greenrobot/event/{annotations => }/Subscribe.java | 2 +- EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java | 2 -- .../src/de/greenrobot/eventperf/TestRunnerActivity.java | 2 +- .../de/greenrobot/eventperf/testsubject/PerfTestEventBus.java | 2 +- .../de/greenrobot/event/test/EventBusBackgroundThreadTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusBasicTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusBuilderTest.java | 2 +- .../greenrobot/event/test/EventBusCancelEventDeliveryTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusInheritanceTest.java | 2 +- .../de/greenrobot/event/test/EventBusMainThreadRacingTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusMainThreadTest.java | 2 +- .../de/greenrobot/event/test/EventBusMethodModifiersTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusMultithreadedTest.java | 2 +- .../de/greenrobot/event/test/EventBusNoSubscriberEventTest.java | 2 +- .../greenrobot/event/test/EventBusOrderedSubscriptionsTest.java | 2 +- .../greenrobot/event/test/EventBusRegistrationRacingTest.java | 2 +- .../src/de/greenrobot/event/test/EventBusStickyEventTest.java | 2 +- .../greenrobot/event/test/EventBusSubscriberExceptionTest.java | 2 +- .../de/greenrobot/event/test/EventBusSubscriberLegalTest.java | 2 +- 19 files changed, 18 insertions(+), 20 deletions(-) rename EventBus/src/de/greenrobot/event/{annotations => }/Subscribe.java (90%) diff --git a/EventBus/src/de/greenrobot/event/annotations/Subscribe.java b/EventBus/src/de/greenrobot/event/Subscribe.java similarity index 90% rename from EventBus/src/de/greenrobot/event/annotations/Subscribe.java rename to EventBus/src/de/greenrobot/event/Subscribe.java index cf8af04c..76ff1c88 100644 --- a/EventBus/src/de/greenrobot/event/annotations/Subscribe.java +++ b/EventBus/src/de/greenrobot/event/Subscribe.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.annotations; +package de.greenrobot.event; import java.lang.annotation.Documented; diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index d6a21523..eb1ea759 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -15,8 +15,6 @@ */ package de.greenrobot.event; -import de.greenrobot.event.annotations.Subscribe; - import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java index a9dcf7a5..07f55777 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java @@ -1,7 +1,7 @@ package de.greenrobot.eventperf; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import android.app.Activity; import android.os.Bundle; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index ca7a3d92..66bf9131 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -7,7 +7,7 @@ import android.content.Context; import de.greenrobot.event.EventBus; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; import de.greenrobot.eventperf.TestParams; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java index 1d9dae38..99de5a32 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java @@ -17,7 +17,7 @@ import android.os.Looper; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index ae0313de..464079ea 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -18,7 +18,7 @@ import android.app.Activity; import android.util.Log; import de.greenrobot.event.EventBus; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import junit.framework.TestCase; import java.lang.ref.WeakReference; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java index 3bfd9733..6896264c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java @@ -20,7 +20,7 @@ import de.greenrobot.event.EventBusException; import de.greenrobot.event.NoSubscriberEvent; import de.greenrobot.event.SubscriberExceptionEvent; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 3b026db0..92d02f7b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -20,7 +20,7 @@ import android.test.UiThreadTest; import de.greenrobot.event.EventBusException; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 1d54f5d0..b7fcf9a9 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import junit.framework.TestCase; import de.greenrobot.event.EventBus; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index e740dd44..9fa4a487 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -21,7 +21,7 @@ import android.os.Handler; import android.os.Looper; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 6f60c24d..3d6b7541 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -20,7 +20,7 @@ import android.os.Looper; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index 8f54b91b..aad8d781 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -19,7 +19,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBusException; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index 61032a7d..7535de6d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -24,7 +24,7 @@ import android.util.Log; import de.greenrobot.event.EventBus; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index 5d87ff4e..41339796 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -18,7 +18,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.NoSubscriberEvent; import de.greenrobot.event.SubscriberExceptionEvent; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 67e26f96..e5e85c23 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -21,7 +21,7 @@ import de.greenrobot.event.EventBus; import android.util.Log; import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index 9289a547..f5510fcb 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; import java.util.ArrayList; import java.util.List; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index b17ccd60..084b1be6 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index 8a610a6d..988ce720 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -17,7 +17,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.SubscriberExceptionEvent; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index b7b0fbf3..1b5c57a8 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -16,7 +16,7 @@ package de.greenrobot.event.test; import de.greenrobot.event.EventBusException; -import de.greenrobot.event.annotations.Subscribe; +import de.greenrobot.event.Subscribe; /** * @author Markus Junginger, greenrobot From 9bd7391bf8fee11be781d34d1cbce4d861fd4249 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 11:20:46 +0100 Subject: [PATCH 006/112] EventBusAnnotationProcessor for creating a subscriber index during build --- .../event/SubscriberIndexEntry.java | 17 +++ .../event/SubscriberMethodFinder.java | 88 ++++++++++--- EventBusAnnotationProcessor/build.gradle | 122 ++++++++++++++++++ .../javax.annotation.processing.Processor | 1 + EventBusAnnotationProcessor/settings.gradle | 1 + .../EventBusAnnotationProcessor.java | 68 ++++++++++ EventBusPerformance/build.gradle | 1 + settings.gradle | 1 + 8 files changed, 284 insertions(+), 15 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java create mode 100644 EventBusAnnotationProcessor/build.gradle create mode 100644 EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor create mode 100644 EventBusAnnotationProcessor/settings.gradle create mode 100644 EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java b/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java new file mode 100644 index 00000000..7a051233 --- /dev/null +++ b/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java @@ -0,0 +1,17 @@ +package de.greenrobot.event; + +/** Preprocessed index as used with annotation-preprocessed code generation */ +public class SubscriberIndexEntry { + final Class subscriberType; + final String methodName; + final Class eventType; + final ThreadMode threadMode; + + public SubscriberIndexEntry(Class subscriberType, String methodName, Class eventType, + ThreadMode threadMode) { + this.subscriberType = subscriberType; + this.methodName = methodName; + this.eventType = eventType; + this.threadMode = threadMode; + } +} diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index eb1ea759..a0d70298 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -15,6 +15,8 @@ */ package de.greenrobot.event; +import android.util.Log; + import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -34,7 +36,37 @@ class SubscriberMethodFinder { private static final int SYNTHETIC = 0x1000; private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; - private static final Map> methodCache = new HashMap>(); + private static final Map> METHOD_CACHE = new HashMap>(); + + /** Optional generated index without entries from subscribers super classes */ + private static final Map> METHOD_INDEX; + + static { + Map> index = null; + try { + Class clazz = Class.forName("MyGeneratedEventBusSubscriberIndex"); + SubscriberIndexEntry[] entries = (SubscriberIndexEntry[]) clazz.getField("INDEX").get(null); + Map> newIndex = new HashMap>(); + for (SubscriberIndexEntry entry : entries) { + String key = entry.subscriberType.getName(); + List subscriberMethods = newIndex.get(key); + if (subscriberMethods == null) { + subscriberMethods = new ArrayList(); + newIndex.put(key, subscriberMethods); + } + Method method = entry.subscriberType.getMethod(entry.methodName, entry.eventType); + SubscriberMethod subscriberMethod = new SubscriberMethod(method, entry.threadMode, entry.eventType); + subscriberMethods.add(subscriberMethod); + } + index = newIndex; + } catch (ClassNotFoundException e) { + // Fine + } catch (Exception e) { + Log.w("Could not init @Subscribe index, reverting to dynamic look-up (slower)", e); + } + METHOD_INDEX = index; + } + private final boolean strictMethodVerification; SubscriberMethodFinder(boolean strictMethodVerification) { @@ -44,13 +76,47 @@ class SubscriberMethodFinder { List findSubscriberMethods(Class subscriberClass) { String key = subscriberClass.getName(); List subscriberMethods; - synchronized (methodCache) { - subscriberMethods = methodCache.get(key); + synchronized (METHOD_CACHE) { + subscriberMethods = METHOD_CACHE.get(key); } if (subscriberMethods != null) { return subscriberMethods; } - subscriberMethods = new ArrayList(); + if(METHOD_INDEX != null) { + subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); + } else { + subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); + } + if (subscriberMethods.isEmpty()) { + throw new EventBusException("Subscriber " + subscriberClass + + " and its super classes have no public methods with the @Subscribe annotation"); + } else { + synchronized (METHOD_CACHE) { + METHOD_CACHE.put(key, subscriberMethods); + } + return subscriberMethods; + } + } + + private List findSubscriberMethodsWithIndex(Class subscriberClass) { + List subscriberMethods = new ArrayList(); + Class clazz = subscriberClass; + while (clazz != null) { + String name = clazz.getName(); + if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { + // Skip system classes, this just degrades performance + break; + } + List flatList = METHOD_INDEX.get(name); + subscriberMethods.addAll(flatList); + + clazz = clazz.getSuperclass(); + } + return subscriberMethods; + } + + private List findSubscriberMethodsWithReflection(Class subscriberClass) { + List subscriberMethods = new ArrayList(); Class clazz = subscriberClass; HashSet eventTypesFound = new HashSet(); StringBuilder methodKeyBuilder = new StringBuilder(); @@ -102,20 +168,12 @@ List findSubscriberMethods(Class subscriberClass) { clazz = clazz.getSuperclass(); } - if (subscriberMethods.isEmpty()) { - throw new EventBusException("Subscriber " + subscriberClass - + " has no public methods called with the @Subscribe annotation"); - } else { - synchronized (methodCache) { - methodCache.put(key, subscriberMethods); - } - return subscriberMethods; - } + return subscriberMethods; } static void clearCaches() { - synchronized (methodCache) { - methodCache.clear(); + synchronized (METHOD_CACHE) { + METHOD_CACHE.clear(); } } diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle new file mode 100644 index 00000000..aa94d975 --- /dev/null +++ b/EventBusAnnotationProcessor/build.gradle @@ -0,0 +1,122 @@ +apply plugin: 'java' +apply plugin: 'maven' +apply plugin: 'signing' + +group = 'de.greenrobot' +version = '3.0.0' +sourceCompatibility = 1.7 + +def isSnapshot = version.endsWith('-SNAPSHOT') +def sonatypeRepositoryUrl +if(isSnapshot) { + sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" +} else { + sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +} + +repositories { + mavenCentral() +} + +// Still unsupported, see http://issues.gradle.org/browse/GRADLE-784 +// Like this, it won't appear at all in the POM +configurations { + provided + deployerJars +} + +dependencies { + compile project(':EventBus') + deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' +} + +sourceSets { + main { + compileClasspath += configurations.provided + java { + srcDir 'src' + } + resources { + srcDir 'res' + } + } +} + +task sourcesJar(type: Jar) { + from sourceSets.main.allSource + classifier = 'sources' +} + +artifacts { + archives jar + archives sourcesJar +} + +signing { + if(project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && + project.hasProperty('signing.secretKeyRingFile')) { + sign configurations.archives + } else { + println "Signing information missing/incomplete for ${project.name}" + } +} + +uploadArchives { + repositories { + mavenDeployer { + if(project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') + && project.hasProperty('preferedPassword')) { + configuration = configurations.deployerJars + repository(url: preferedRepo) { + authentication(userName: preferedUsername, password: preferedPassword) + } + } else if(project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + repository(url: sonatypeRepositoryUrl) { + authentication(userName: sonatypeUsername, password: sonatypePassword) + } + } else { + println "Settings sonatypeUsername/sonatypePassword missing/incomplete for ${project.name}" + } + + pom.artifactId = 'eventbus-annotation-processor' + pom.project { + name 'EventBus Annotation Processor' + packaging 'jar' + description 'Precompiler for EventBus Annotations.' + url 'https://github.com/greenrobot/EventBus' + + scm { + url 'https://github.com/greenrobot/EventBus' + connection 'scm:git@github.com:greenrobot/EventBus.git' + developerConnection 'scm:git@github.com:greenrobot/EventBus.git' + } + + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + + developers { + developer { + id 'greenrobot' + name 'greenrobot' + } + } + + issueManagement { + system 'GitHub Issues' + url 'https://github.com/greenrobot/EventBus/issues' + } + + organization { + name 'greenrobot' + url 'http://greenrobot.de' + } + } + } + } +} \ No newline at end of file diff --git a/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor b/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 00000000..ec7e34b6 --- /dev/null +++ b/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1 @@ +de.greenrobot.event.annotationprocessor.EventBusAnnotationProcessor diff --git a/EventBusAnnotationProcessor/settings.gradle b/EventBusAnnotationProcessor/settings.gradle new file mode 100644 index 00000000..51ebbb79 --- /dev/null +++ b/EventBusAnnotationProcessor/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'eventbus-annotation-processor' \ No newline at end of file diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java new file mode 100644 index 00000000..b4390607 --- /dev/null +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -0,0 +1,68 @@ +package de.greenrobot.event.annotationprocessor; + +import de.greenrobot.event.Subscribe; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Messager; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.tools.Diagnostic; +import javax.tools.JavaFileObject; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.List; +import java.util.Set; + +@SupportedAnnotationTypes("de.greenrobot.event.Subscribe") +public class EventBusAnnotationProcessor extends AbstractProcessor { + @Override + public boolean process(Set annotations, RoundEnvironment env) { + if (annotations.isEmpty()) { + return false; + } + Messager messager = processingEnv.getMessager(); + try { + String className = "MyGeneratedEventBusSubscriberIndex"; + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(className); + try (BufferedWriter writer = new BufferedWriter(sourceFile.openWriter())) { + writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); + writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("/** This class is generated by EventBus, do not edit. */\n"); + writer.write("public class " + className + " {\n"); + writer.write(" public static final SubscriberIndexEntry[] INDEX = {\n"); + + for (TypeElement annotation : annotations) { + Set elements = env.getElementsAnnotatedWith(annotation); + for (Element element : elements) { + writeIndexEntry(writer, element, messager); + } + } + writer.write(" };\n}\n"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return true; + } + + private void writeIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { + Subscribe subscribe = element.getAnnotation(Subscribe.class); + String subscriberClass = element.getEnclosingElement().asType().toString(); + messager.printMessage(Diagnostic.Kind.NOTE, "Found @Subscribe in " + subscriberClass); + List parameters = ((ExecutableElement) element).getParameters(); + if (parameters.size() != 1) { + throw new RuntimeException("Must have exactly 1 parameter"); + } + String eventType = parameters.get(0).asType().toString(); + writer.append(" new SubscriberIndexEntry(\n"); + writer.append(" ").append(subscriberClass).append(".class,\n"); + writer.append(" \"").append(element.getSimpleName()).append("\",\n"); + writer.append(" ").append(eventType).append(".class,\n"); + writer.append(" ThreadMode.").append(subscribe.threadMode().name()).append("),\n"); + } +} diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 570c64b0..a0b4b276 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -16,6 +16,7 @@ repositories { dependencies { compile project(':EventBus') + compile project(':EventBusAnnotationProcessor') compile 'com.squareup:otto:1.3.5' } diff --git a/settings.gradle b/settings.gradle index 76c570b0..d51c4e7b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ include 'EventBus' +include 'EventBusAnnotationProcessor' include 'EventBusTest' include 'EventBusPerformance' From 0c89485f73911d57a0d2a6d33c17733e92a8bd02 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 15:40:41 +0100 Subject: [PATCH 007/112] more checks for EventBusAnnotationProcessor --- .../EventBusAnnotationProcessor.java | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index b4390607..19be88b0 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -6,11 +6,15 @@ import javax.annotation.processing.Messager; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import java.io.BufferedWriter; @@ -19,6 +23,7 @@ import java.util.Set; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") +@SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { @Override public boolean process(Set annotations, RoundEnvironment env) { @@ -52,17 +57,42 @@ public boolean process(Set annotations, RoundEnvironment private void writeIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { Subscribe subscribe = element.getAnnotation(Subscribe.class); - String subscriberClass = element.getEnclosingElement().asType().toString(); - messager.printMessage(Diagnostic.Kind.NOTE, "Found @Subscribe in " + subscriberClass); + if (element.getModifiers().contains(Modifier.STATIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); + return; + } + + Set subscriberClassModifiers = element.getEnclosingElement().getModifiers(); + if (!subscriberClassModifiers.contains(Modifier.PUBLIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber class must be public", + element.getEnclosingElement()); + return; + } + List parameters = ((ExecutableElement) element).getParameters(); if (parameters.size() != 1) { - throw new RuntimeException("Must have exactly 1 parameter"); + messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must have exactly 1 parameter", element); + return; } - String eventType = parameters.get(0).asType().toString(); + + VariableElement param = parameters.get(0); + DeclaredType paramType = (DeclaredType) param.asType(); + Set eventClassModifiers = paramType.asElement().getModifiers(); + if (!eventClassModifiers.contains(Modifier.PUBLIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Event type must be public: " + paramType, param); + return; + } + + String subscriberClass = element.getEnclosingElement().asType().toString(); + Name methodName = element.getSimpleName(); writer.append(" new SubscriberIndexEntry(\n"); writer.append(" ").append(subscriberClass).append(".class,\n"); - writer.append(" \"").append(element.getSimpleName()).append("\",\n"); - writer.append(" ").append(eventType).append(".class,\n"); + writer.append(" \"").append(methodName).append("\",\n"); + writer.append(" ").append(paramType.toString()).append(".class,\n"); writer.append(" ThreadMode.").append(subscribe.threadMode().name()).append("),\n"); + + messager.printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + + element.getEnclosingElement().getSimpleName() + "." + methodName + + "(" + paramType.asElement().getSimpleName() + ")"); } } From 41409f616ca0ef24fdf6cb8ce173a469c25ed3b0 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 15:41:03 +0100 Subject: [PATCH 008/112] set version to 3.0.0-alpha1 --- EventBus/build.gradle | 2 +- EventBusAnnotationProcessor/build.gradle | 92 ++++++++++++------------ 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 153a6440..ef61ec44 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '2.4.0' +version = '3.0.0-alpha1' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index aa94d975..84304201 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,15 +3,17 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0' +version = '3.0.0-alpha1' + sourceCompatibility = 1.7 +targetCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') def sonatypeRepositoryUrl -if(isSnapshot) { - sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" +if (isSnapshot) { + sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/" } else { - sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" } repositories { @@ -53,8 +55,8 @@ artifacts { } signing { - if(project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && - project.hasProperty('signing.secretKeyRingFile')) { + if (project.hasProperty('signing.keyId') && project.hasProperty('signing.password') && + project.hasProperty('signing.secretKeyRingFile')) { sign configurations.archives } else { println "Signing information missing/incomplete for ${project.name}" @@ -64,13 +66,13 @@ signing { uploadArchives { repositories { mavenDeployer { - if(project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') - && project.hasProperty('preferedPassword')) { + if (project.hasProperty('preferedRepo') && project.hasProperty('preferedUsername') + && project.hasProperty('preferedPassword')) { configuration = configurations.deployerJars repository(url: preferedRepo) { authentication(userName: preferedUsername, password: preferedPassword) } - } else if(project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) { + } else if (project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')) { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } repository(url: sonatypeRepositoryUrl) { authentication(userName: sonatypeUsername, password: sonatypePassword) @@ -81,42 +83,42 @@ uploadArchives { pom.artifactId = 'eventbus-annotation-processor' pom.project { - name 'EventBus Annotation Processor' - packaging 'jar' - description 'Precompiler for EventBus Annotations.' - url 'https://github.com/greenrobot/EventBus' - - scm { - url 'https://github.com/greenrobot/EventBus' - connection 'scm:git@github.com:greenrobot/EventBus.git' - developerConnection 'scm:git@github.com:greenrobot/EventBus.git' - } - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } - } - - developers { - developer { - id 'greenrobot' - name 'greenrobot' - } - } - - issueManagement { - system 'GitHub Issues' - url 'https://github.com/greenrobot/EventBus/issues' - } - - organization { - name 'greenrobot' - url 'http://greenrobot.de' - } - } + name 'EventBus Annotation Processor' + packaging 'jar' + description 'Precompiler for EventBus Annotations.' + url 'https://github.com/greenrobot/EventBus' + + scm { + url 'https://github.com/greenrobot/EventBus' + connection 'scm:git@github.com:greenrobot/EventBus.git' + developerConnection 'scm:git@github.com:greenrobot/EventBus.git' + } + + licenses { + license { + name 'The Apache Software License, Version 2.0' + url 'http://www.apache.org/licenses/LICENSE-2.0.txt' + distribution 'repo' + } + } + + developers { + developer { + id 'greenrobot' + name 'greenrobot' + } + } + + issueManagement { + system 'GitHub Issues' + url 'https://github.com/greenrobot/EventBus/issues' + } + + organization { + name 'greenrobot' + url 'http://greenrobot.de' + } + } } } } \ No newline at end of file From 65b080697364a5760551f1c8e60b184966e7b9df Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 15:41:21 +0100 Subject: [PATCH 009/112] provided scope for EventBusAnnotationProcessor --- EventBusPerformance/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index a0b4b276..46adb91b 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -16,8 +16,8 @@ repositories { dependencies { compile project(':EventBus') - compile project(':EventBusAnnotationProcessor') - compile 'com.squareup:otto:1.3.5' + provided project(':EventBusAnnotationProcessor') + compile 'com.squareup:otto:1.3.6' } android { From b492674030e1c0cbe64be8c496dbb66a20f8fb5e Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:08:33 +0100 Subject: [PATCH 010/112] changed log tag to EventBus --- EventBus/src/de/greenrobot/event/EventBus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index ba759d33..dfaefeab 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -39,7 +39,7 @@ public class EventBus { /** Log tag, apps may override it. */ - public static String TAG = "Event"; + public static String TAG = "EventBus"; static volatile EventBus defaultInstance; From 83e193c78b18720ba150ef9cdc12d4d2a475c522 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:08:59 +0100 Subject: [PATCH 011/112] added "Subscriber method must be public" check --- .../annotationprocessor/EventBusAnnotationProcessor.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 19be88b0..61bdd3da 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -62,6 +62,11 @@ private void writeIndexEntry(BufferedWriter writer, Element element, Messager me return; } + if (!element.getModifiers().contains(Modifier.PUBLIC)) { + messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must be public", element); + return; + } + Set subscriberClassModifiers = element.getEnclosingElement().getModifiers(); if (!subscriberClassModifiers.contains(Modifier.PUBLIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber class must be public", From 72e080b330b12773daa47585559fd99a66fd93d5 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:09:38 +0100 Subject: [PATCH 012/112] fixed a null problem, added index logging --- .../event/SubscriberMethodFinder.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index a0d70298..5e816b91 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -54,15 +54,24 @@ class SubscriberMethodFinder { subscriberMethods = new ArrayList(); newIndex.put(key, subscriberMethods); } - Method method = entry.subscriberType.getMethod(entry.methodName, entry.eventType); - SubscriberMethod subscriberMethod = new SubscriberMethod(method, entry.threadMode, entry.eventType); - subscriberMethods.add(subscriberMethod); + try { + Method method = entry.subscriberType.getMethod(entry.methodName, entry.eventType); + SubscriberMethod subscriberMethod = new SubscriberMethod(method, entry.threadMode, entry.eventType); + subscriberMethods.add(subscriberMethod); + } catch (NoSuchMethodException e) { + // Offending class is not part of standard message + throw new NoSuchMethodException(entry.subscriberType.getName() + "." + + entry.methodName + "(" + entry.eventType.getName() + ")"); + } } index = newIndex; + Log.d(EventBus.TAG, "Initialized subscriber index with " + entries.length + " entries for " + index.size() + + " classes"); } catch (ClassNotFoundException e) { + Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up (slower)"); // Fine } catch (Exception e) { - Log.w("Could not init @Subscribe index, reverting to dynamic look-up (slower)", e); + Log.w(EventBus.TAG, "Could not init subscriber index, reverting to dynamic look-up (slower)", e); } METHOD_INDEX = index; } @@ -82,7 +91,7 @@ List findSubscriberMethods(Class subscriberClass) { if (subscriberMethods != null) { return subscriberMethods; } - if(METHOD_INDEX != null) { + if (METHOD_INDEX != null) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); } else { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); @@ -108,7 +117,9 @@ private List findSubscriberMethodsWithIndex(Class subscribe break; } List flatList = METHOD_INDEX.get(name); - subscriberMethods.addAll(flatList); + if(flatList != null) { + subscriberMethods.addAll(flatList); + } clazz = clazz.getSuperclass(); } From 19f86df6b57cf0d9673297a5b72f2ffd92a9ab8f Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:12:39 +0100 Subject: [PATCH 013/112] adjusted tests to work with subscriber index (made subscriber methods and classes public) --- EventBusTest/build.gradle | 3 + .../event/test/EventBusBasicTest.java | 8 +-- .../event/test/EventBusBuilderTest.java | 6 +- .../test/EventBusCancelEventDeliveryTest.java | 6 +- .../event/test/EventBusInheritanceTest.java | 10 ++-- .../event/test/EventBusMultithreadedTest.java | 2 +- .../test/EventBusNoSubscriberEventTest.java | 2 +- .../EventBusOrderedSubscriptionsTest.java | 2 +- .../test/EventBusRegistrationRacingTest.java | 2 +- .../test/EventBusSubscriberExceptionTest.java | 2 +- .../test/EventBusSubscriberLegalTest.java | 55 ++++++++++--------- 11 files changed, 51 insertions(+), 47 deletions(-) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 2f48f9c5..5983a7ab 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -5,16 +5,19 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' } } apply plugin: 'com.android.application' +apply plugin: 'com.neenbedankt.android-apt' repositories { mavenCentral() } dependencies { + androidTestApt project(':EventBusAnnotationProcessor') androidTestCompile project(':EventBus') } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 464079ea..57a65d22 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -238,7 +238,7 @@ public void onEvent(MyEventExtended event) { countMyEventExtended++; } - static class TestActivity extends Activity { + public static class TestActivity extends Activity { public String lastStringEvent; @Subscribe @@ -247,13 +247,13 @@ public void onEvent(String event) { } } - class MyEvent { + public class MyEvent { } - class MyEventExtended extends MyEvent { + public class MyEventExtended extends MyEvent { } - class RepostInteger { + public class RepostInteger { public int lastEvent; public int countEvent; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java index 6896264c..2bab15e0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java @@ -75,21 +75,21 @@ public void testEventInheritance() { eventBus.post("Foo"); } - class SubscriberExceptionEventTracker { + public class SubscriberExceptionEventTracker { @Subscribe public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } } - class NoSubscriberEventTracker { + public class NoSubscriberEventTracker { @Subscribe public void onEvent(NoSubscriberEvent event) { trackEvent(event); } } - class ThrowingSubscriber { + public class ThrowingSubscriber { @Subscribe public void onEvent(Object event) { throw new RuntimeException(); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 92d02f7b..0950f71c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -77,7 +77,7 @@ public void testCancelInMainThread() { assertNotNull(failed); } - class Subscriber { + public class Subscriber { private final boolean cancel; public Subscriber(boolean cancel) { @@ -93,7 +93,7 @@ public void onEvent(String event) { } } - class SubscriberCancelOtherEvent { + public class SubscriberCancelOtherEvent { @Subscribe public void onEvent(String event) { try { @@ -104,7 +104,7 @@ public void onEvent(String event) { } } - class SubscriberMainThread { + public class SubscriberMainThread { final CountDownLatch done = new CountDownLatch(1); @Subscribe(threadMode = ThreadMode.MainThread) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index b7fcf9a9..bfaac04d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -117,19 +117,19 @@ public void onEvent(MyEventInterfaceExtended event) { countMyEventInterfaceExtended++; } - static interface MyEventInterface { + public static interface MyEventInterface { } - static class MyEvent implements MyEventInterface { + public static class MyEvent implements MyEventInterface { } - static interface MyEventInterfaceExtended extends MyEventInterface { + public static interface MyEventInterfaceExtended extends MyEventInterface { } - static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { + public static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { } - static class SubscriberExtended extends EventBusInheritanceTest { + public static class SubscriberExtended extends EventBusInheritanceTest { private int countMyEventOverwritten; @Subscribe diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index 7535de6d..87d89d13 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -220,7 +220,7 @@ public void run() { } } - class SubscribeUnsubscribeThread extends Thread { + public class SubscribeUnsubscribeThread extends Thread { boolean running = true; public void shutdown() { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index 41339796..846816bf 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -69,7 +69,7 @@ public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } - class BadNoSubscriberSubscriber { + public class BadNoSubscriberSubscriber { @Subscribe public void onEvent(NoSubscriberEvent event) { throw new RuntimeException("I'm bad"); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index e5e85c23..1864da54 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -89,7 +89,7 @@ protected PrioSubscriber register(int priority, boolean sticky) { return subscriber; } - private final class PrioSubscriber { + public final class PrioSubscriber { final int prio; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index f5510fcb..7c4dbf9d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -72,7 +72,7 @@ private List startThreads() { return threads; } - class SubscriberThread implements Runnable { + public class SubscriberThread implements Runnable { volatile int eventCount; @Override diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index 988ce720..21c79f95 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -54,7 +54,7 @@ public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } - class BadExceptionSubscriber { + public class BadExceptionSubscriber { @Subscribe public void onEvent(SubscriberExceptionEvent event) { throw new RuntimeException("Bad"); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index 1b5c57a8..d122ece9 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -30,23 +30,24 @@ public void testSubscriberLegal() { assertEquals(1, eventCount.intValue()); } - public void testSubscriberNotPublic() { - try { - eventBus.register(new NotPublic()); - fail("Registration of ilegal subscriber successful"); - } catch (EventBusException e) { - // Expected - } - } + // With build time verification, some of these tests are obsolete (and cause problems during build) +// public void testSubscriberNotPublic() { +// try { +// eventBus.register(new NotPublic()); +// fail("Registration of ilegal subscriber successful"); +// } catch (EventBusException e) { +// // Expected +// } +// } - public void testSubscriberStatic() { - try { - eventBus.register(new Static()); - fail("Registration of ilegal subscriber successful"); - } catch (EventBusException e) { - // Expected - } - } +// public void testSubscriberStatic() { +// try { +// eventBus.register(new Static()); +// fail("Registration of ilegal subscriber successful"); +// } catch (EventBusException e) { +// // Expected +// } +// } public void testSubscriberLegalAbstract() { eventBus.register(new Abstract() { @@ -68,21 +69,21 @@ public void onEvent(String event) { trackEvent(event); } - static class NotPublic { - @Subscribe - void onEvent(String event) { - } - } +// public static class NotPublic { +// @Subscribe +// void onEvent(String event) { +// } +// } - static abstract class Abstract { + public static abstract class Abstract { @Subscribe public abstract void onEvent(String event); } - static class Static { - @Subscribe - public static void onEvent(String event) { - } - } +// public static class Static { +// @Subscribe +// public static void onEvent(String event) { +// } +// } } From 255128d043c85274ec2c0125e46bddd190a902bd Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:35:40 +0100 Subject: [PATCH 014/112] set version to 3.0.0-SNAPSHOT --- EventBus/build.gradle | 2 +- EventBusAnnotationProcessor/build.gradle | 5 ++--- README.md | 7 +++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index ef61ec44..b8ad8c0f 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-alpha1' +version = '3.0.0-SNAPSHOT' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 84304201..ffe5eba5 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,10 +3,9 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-alpha1' +version = '3.0.0-SNAPSHOT' -sourceCompatibility = 1.7 -targetCompatibility = 1.7 +sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') def sonatypeRepositoryUrl diff --git a/README.md b/README.md index e8bf090f..e20a9bcd 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,12 @@ Add EventBus to your project ---------------------------- EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22) +Note: This SNAPSHOT version is only available on Sonatype's snapshot repository (https://oss.sonatype.org/content/repositories/snapshots). + Gradle: ``` - compile 'de.greenrobot:eventbus:2.4.0' + compile 'de.greenrobot:eventbus:3.0.0-SNAPSHOT' + provided 'de.greenrobot:eventbus-annotation-processor:3.0.0-SNAPSHOT' ``` Maven: @@ -43,7 +46,7 @@ Maven: de.greenrobot eventbus - 2.4.0 + 3.0.0-SNAPSHOT ``` From a1b9e3e9d50ba018088c70cb9330c83b0a851b5a Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 16:54:30 +0100 Subject: [PATCH 015/112] removed Java 7 try() from EventBusAnnotationProcessor --- .../annotationprocessor/EventBusAnnotationProcessor.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 61bdd3da..63eaf54b 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -34,7 +34,8 @@ public boolean process(Set annotations, RoundEnvironment try { String className = "MyGeneratedEventBusSubscriberIndex"; JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(className); - try (BufferedWriter writer = new BufferedWriter(sourceFile.openWriter())) { + BufferedWriter writer = new BufferedWriter(sourceFile.openWriter()); + try { writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); @@ -44,10 +45,12 @@ public boolean process(Set annotations, RoundEnvironment for (TypeElement annotation : annotations) { Set elements = env.getElementsAnnotatedWith(annotation); for (Element element : elements) { - writeIndexEntry(writer, element, messager); + checkAndWriteIndexEntry(writer, element, messager); } } writer.write(" };\n}\n"); + } finally { + writer.close(); } } catch (IOException e) { throw new RuntimeException(e); @@ -55,7 +58,7 @@ public boolean process(Set annotations, RoundEnvironment return true; } - private void writeIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { + private void checkAndWriteIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { Subscribe subscribe = element.getAnnotation(Subscribe.class); if (element.getModifiers().contains(Modifier.STATIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); From aa7022eea162f43c10e8bbb5f1ef47c569fad979 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Feb 2015 20:41:04 +0100 Subject: [PATCH 016/112] README.md: added section "Limitations of the SNAPSHOT version" --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index e20a9bcd..808d044a 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,14 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) +Limitations of the SNAPSHOT version +----------------------------------- +The "subscriber index" is an optional optimization to speed up initial subscriber registration. The subscriber index is created during build time using an annotation processor. There are a couple of limitations of the current implementation: + + * Subscriber classes must be public + * Event classes must be public + * @Subscribe seems to be not recognized when inside of anonymous classes + EventBus in 4 steps ------------------- 1. Define events:
From 6a37ce715294cccc57586fd4f00352319c0899f7 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Feb 2015 22:36:34 +0100 Subject: [PATCH 017/112] reworked EventBusAnnotationProcessor, dynamic creation of SubscriberMethod by subscriber index --- .../de/greenrobot/event/SubscriberIndex.java | 35 ++++ .../event/SubscriberIndexEntry.java | 17 -- .../event/SubscriberMethodFinder.java | 47 ++--- .../EventBusAnnotationProcessor.java | 179 ++++++++++++++---- 4 files changed, 188 insertions(+), 90 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/SubscriberIndex.java delete mode 100644 EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndex.java b/EventBus/src/de/greenrobot/event/SubscriberIndex.java new file mode 100644 index 00000000..a442d1cc --- /dev/null +++ b/EventBus/src/de/greenrobot/event/SubscriberIndex.java @@ -0,0 +1,35 @@ +package de.greenrobot.event; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ +abstract class SubscriberIndex { + private Map, SubscriberMethod[]> map = new HashMap, SubscriberMethod[]>(); + + SubscriberMethod[] getSubscribersFor(Class subscriberClass) { + SubscriberMethod[] entries = map.get(subscriberClass); + if (entries == null) { + entries = createSubscribersFor(subscriberClass); + if (entries != null) { + map.put(subscriberClass, entries); + } + } + return entries; + } + + abstract SubscriberMethod[] createSubscribersFor(Class subscriberClass); + + SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, + ThreadMode threadMode) { + try { + Method method = subscriberClass.getDeclaredMethod(methodName, eventType); + return new SubscriberMethod(method, threadMode, eventType); + } catch (NoSuchMethodException e) { + throw new EventBusException("Could not find subscriber method in " + subscriberClass + + ". Maybe a missing ProGuard rule?", e); + } + } + +} diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java b/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java deleted file mode 100644 index 7a051233..00000000 --- a/EventBus/src/de/greenrobot/event/SubscriberIndexEntry.java +++ /dev/null @@ -1,17 +0,0 @@ -package de.greenrobot.event; - -/** Preprocessed index as used with annotation-preprocessed code generation */ -public class SubscriberIndexEntry { - final Class subscriberType; - final String methodName; - final Class eventType; - final ThreadMode threadMode; - - public SubscriberIndexEntry(Class subscriberType, String methodName, Class eventType, - ThreadMode threadMode) { - this.subscriberType = subscriberType; - this.methodName = methodName; - this.eventType = eventType; - this.threadMode = threadMode; - } -} diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 5e816b91..29af9226 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -26,7 +26,6 @@ import java.util.Map; class SubscriberMethodFinder { - /* * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. * EventBus must ignore both. There modifiers are not public but defined in the Java class file format: @@ -39,41 +38,20 @@ class SubscriberMethodFinder { private static final Map> METHOD_CACHE = new HashMap>(); /** Optional generated index without entries from subscribers super classes */ - private static final Map> METHOD_INDEX; + private static final SubscriberIndex INDEX; static { - Map> index = null; + SubscriberIndex newIndex = null; try { - Class clazz = Class.forName("MyGeneratedEventBusSubscriberIndex"); - SubscriberIndexEntry[] entries = (SubscriberIndexEntry[]) clazz.getField("INDEX").get(null); - Map> newIndex = new HashMap>(); - for (SubscriberIndexEntry entry : entries) { - String key = entry.subscriberType.getName(); - List subscriberMethods = newIndex.get(key); - if (subscriberMethods == null) { - subscriberMethods = new ArrayList(); - newIndex.put(key, subscriberMethods); - } - try { - Method method = entry.subscriberType.getMethod(entry.methodName, entry.eventType); - SubscriberMethod subscriberMethod = new SubscriberMethod(method, entry.threadMode, entry.eventType); - subscriberMethods.add(subscriberMethod); - } catch (NoSuchMethodException e) { - // Offending class is not part of standard message - throw new NoSuchMethodException(entry.subscriberType.getName() + "." + - entry.methodName + "(" + entry.eventType.getName() + ")"); - } - } - index = newIndex; - Log.d(EventBus.TAG, "Initialized subscriber index with " + entries.length + " entries for " + index.size() - + " classes"); + Class clazz = Class.forName("de.greenrobot.event.MyGeneratedSubscriberIndex"); + newIndex = (SubscriberIndex) clazz.newInstance(); } catch (ClassNotFoundException e) { - Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up (slower)"); + Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up"); // Fine } catch (Exception e) { - Log.w(EventBus.TAG, "Could not init subscriber index, reverting to dynamic look-up (slower)", e); + Log.w(EventBus.TAG, "Could not init subscriber index, reverting to dynamic look-up", e); } - METHOD_INDEX = index; + INDEX = newIndex; } private final boolean strictMethodVerification; @@ -91,7 +69,7 @@ List findSubscriberMethods(Class subscriberClass) { if (subscriberMethods != null) { return subscriberMethods; } - if (METHOD_INDEX != null) { + if (INDEX != null) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); } else { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); @@ -116,9 +94,12 @@ private List findSubscriberMethodsWithIndex(Class subscribe // Skip system classes, this just degrades performance break; } - List flatList = METHOD_INDEX.get(name); - if(flatList != null) { - subscriberMethods.addAll(flatList); + SubscriberMethod[] flatList = INDEX.getSubscribersFor(clazz); + if (flatList != null) { + // TODO check + for (SubscriberMethod subscriberMethod : flatList) { + subscriberMethods.add(subscriberMethod); + } } clazz = clazz.getSuperclass(); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 63eaf54b..906e3bc2 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -11,7 +11,6 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; @@ -19,68 +18,87 @@ import javax.tools.JavaFileObject; import java.io.BufferedWriter; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") @SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { + private final Map> methodsByClass = new HashMap>(); + private boolean writerRoundDone; + private int round; + @Override public boolean process(Set annotations, RoundEnvironment env) { + Messager messager = processingEnv.getMessager(); + round++; + messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + + !annotations.isEmpty() + ", processingOver: " + env.processingOver()); + if (env.processingOver()) { + if (!annotations.isEmpty()) { + messager.printMessage(Diagnostic.Kind.ERROR, + "Unexpected processing state: annotations still available after processing over"); + return false; + } + } if (annotations.isEmpty()) { return false; } - Messager messager = processingEnv.getMessager(); - try { - String className = "MyGeneratedEventBusSubscriberIndex"; - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(className); - BufferedWriter writer = new BufferedWriter(sourceFile.openWriter()); - try { - writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); - writer.write("import de.greenrobot.event.ThreadMode;\n\n"); - writer.write("/** This class is generated by EventBus, do not edit. */\n"); - writer.write("public class " + className + " {\n"); - writer.write(" public static final SubscriberIndexEntry[] INDEX = {\n"); - - for (TypeElement annotation : annotations) { - Set elements = env.getElementsAnnotatedWith(annotation); - for (Element element : elements) { - checkAndWriteIndexEntry(writer, element, messager); + + if (writerRoundDone) { + messager.printMessage(Diagnostic.Kind.ERROR, + "Unexpected processing state: annotations still available after writing."); + } + for (TypeElement annotation : annotations) { + Set elements = env.getElementsAnnotatedWith(annotation); + for (Element element : elements) { + if (checkElement(element, messager)) { + Element classElement = element.getEnclosingElement(); + List methods = methodsByClass.get(classElement); + if (methods == null) { + methods = new ArrayList(); + methodsByClass.put(classElement, methods); } + methods.add(element); } - writer.write(" };\n}\n"); - } finally { - writer.close(); } - } catch (IOException e) { - throw new RuntimeException(e); } + + if (!methodsByClass.isEmpty()) { + writeSources(); + } else { + messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); + } + writerRoundDone = true; + return true; } - private void checkAndWriteIndexEntry(BufferedWriter writer, Element element, Messager messager) throws IOException { - Subscribe subscribe = element.getAnnotation(Subscribe.class); + private boolean checkElement(Element element, Messager messager) { if (element.getModifiers().contains(Modifier.STATIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); - return; + return false; } if (!element.getModifiers().contains(Modifier.PUBLIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must be public", element); - return; + return false; } Set subscriberClassModifiers = element.getEnclosingElement().getModifiers(); if (!subscriberClassModifiers.contains(Modifier.PUBLIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber class must be public", element.getEnclosingElement()); - return; + return false; } List parameters = ((ExecutableElement) element).getParameters(); if (parameters.size() != 1) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must have exactly 1 parameter", element); - return; + return false; } VariableElement param = parameters.get(0); @@ -88,19 +106,100 @@ private void checkAndWriteIndexEntry(BufferedWriter writer, Element element, Mes Set eventClassModifiers = paramType.asElement().getModifiers(); if (!eventClassModifiers.contains(Modifier.PUBLIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Event type must be public: " + paramType, param); - return; + return false; + } + return true; + } + + private void writeSources() { + String pack = "de.greenrobot.event"; + String className = "MyGeneratedSubscriberIndex"; + BufferedWriter writer = null; + try { + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(pack + '.' + className); + writer = new BufferedWriter(sourceFile.openWriter()); + writer.write("package de.greenrobot.event;\n\n"); + // writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); + // writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("/** This class is generated by EventBus, do not edit. */\n"); + writer.write("class " + className + " extends SubscriberIndex {\n"); + writer.write(" SubscriberMethod[] createSubscribersFor(Class subscriberClass) {\n"); + + boolean first = true; + for (Map.Entry> entry : methodsByClass.entrySet()) { + String ifPrefix; + if (first) { + ifPrefix = ""; + first = false; + } else { + ifPrefix = "} else "; + } + writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", entry.getKey().asType() + ".class) {"); + writer.write(" return new SubscriberMethod[] {\n"); + writeIndexEntries(writer, entry.getValue()); + writer.write(" };\n"); + } + if (!methodsByClass.isEmpty()) { + writer.write(" }\n"); + } + writer.write(" return null;\n"); + writer.write(" };\n}\n"); + } catch (IOException e) { + throw new RuntimeException("Could not write source for " + className, e); + } finally { + try { + writer.close(); + } catch (IOException e) { + //Silent + } } + } + + + private void writeIndexEntries(BufferedWriter writer, List elements) throws IOException { + for (Element element : elements) { + Subscribe subscribe = element.getAnnotation(Subscribe.class); - String subscriberClass = element.getEnclosingElement().asType().toString(); - Name methodName = element.getSimpleName(); - writer.append(" new SubscriberIndexEntry(\n"); - writer.append(" ").append(subscriberClass).append(".class,\n"); - writer.append(" \"").append(methodName).append("\",\n"); - writer.append(" ").append(paramType.toString()).append(".class,\n"); - writer.append(" ThreadMode.").append(subscribe.threadMode().name()).append("),\n"); - - messager.printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + - element.getEnclosingElement().getSimpleName() + "." + methodName + - "(" + paramType.asElement().getSimpleName() + ")"); + List parameters = ((ExecutableElement) element).getParameters(); + VariableElement param = parameters.get(0); + DeclaredType paramType = (DeclaredType) param.asType(); + + String methodName = element.getSimpleName().toString(); + writeLine(writer, 4, "createSubscriberMethod(subscriberClass,", + "\"" + methodName + "\",", + paramType.toString() + ".class,", + "ThreadMode." + subscribe.threadMode().name() + "),"); + + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + + element.getEnclosingElement().getSimpleName() + "." + methodName + + "(" + paramType.asElement().getSimpleName() + ")"); + } + } + + private void writeLine(BufferedWriter writer, int indentLevel, String... parts) throws IOException { + writeIndent(writer, indentLevel); + int len = indentLevel * 4; + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (len + part.length() > 118) { + writer.write("\n"); + if (indentLevel < 12) { + indentLevel += 2; + } + writeIndent(writer, indentLevel); + len = indentLevel * 4; + } else if (i != 0) { + writer.write(" "); + } + writer.write(part); + len += part.length(); + } + writer.write("\n"); + } + + private void writeIndent(BufferedWriter writer, int indentLevel) throws IOException { + for (int i = 0; i < indentLevel; i++) { + writer.write(" "); + } } } From 44b7004cf37ff4c2c5ce1b649d58a3a443fca891 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Feb 2015 23:25:22 +0100 Subject: [PATCH 018/112] We cannot get @Subscribe annotations from anonymous classes, so fail fast --- EventBus/src/de/greenrobot/event/EventBus.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index dfaefeab..b901a209 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -160,7 +160,12 @@ public void registerSticky(Object subscriber, int priority) { } private synchronized void register(Object subscriber, boolean sticky, int priority) { - List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriber.getClass()); + Class subscriberClass = subscriber.getClass(); + if(subscriberClass.isAnonymousClass()) { + // We cannot get @Subscribe annotations from anonymous classes, so fail fast + throw new EventBusException("Anonymous class cannot be registered: "+ subscriberClass); + } + List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod, sticky, priority); } From 89bb5357d7ac0bcf45696a86832cc9ee67650039 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Feb 2015 23:27:07 +0100 Subject: [PATCH 019/112] generate super class hierarchy and consider method inheritance --- .../event/SubscriberMethodFinder.java | 26 +++----- .../EventBusAnnotationProcessor.java | 63 +++++++++++++------ 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 29af9226..ae15620e 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -20,6 +20,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -86,25 +87,16 @@ List findSubscriberMethods(Class subscriberClass) { } private List findSubscriberMethodsWithIndex(Class subscriberClass) { - List subscriberMethods = new ArrayList(); - Class clazz = subscriberClass; - while (clazz != null) { - String name = clazz.getName(); - if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { - // Skip system classes, this just degrades performance - break; + SubscriberMethod[] array = INDEX.getSubscribersFor(subscriberClass); + if (array != null && array.length > 0) { + List subscriberMethods = new ArrayList(); + for (SubscriberMethod subscriberMethod : array) { + subscriberMethods.add(subscriberMethod); } - SubscriberMethod[] flatList = INDEX.getSubscribersFor(clazz); - if (flatList != null) { - // TODO check - for (SubscriberMethod subscriberMethod : flatList) { - subscriberMethods.add(subscriberMethod); - } - } - - clazz = clazz.getSuperclass(); + return subscriberMethods; + } else { + return Collections.EMPTY_LIST; } - return subscriberMethods; } private List findSubscriberMethodsWithReflection(Class subscriberClass) { diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 906e3bc2..6fdec9f5 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -14,12 +14,14 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; import java.io.BufferedWriter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -52,20 +54,7 @@ public boolean process(Set annotations, RoundEnvironment messager.printMessage(Diagnostic.Kind.ERROR, "Unexpected processing state: annotations still available after writing."); } - for (TypeElement annotation : annotations) { - Set elements = env.getElementsAnnotatedWith(annotation); - for (Element element : elements) { - if (checkElement(element, messager)) { - Element classElement = element.getEnclosingElement(); - List methods = methodsByClass.get(classElement); - if (methods == null) { - methods = new ArrayList(); - methodsByClass.put(classElement, methods); - } - methods.add(element); - } - } - } + collectSubscribers(annotations, env, messager); if (!methodsByClass.isEmpty()) { writeSources(); @@ -111,6 +100,23 @@ private boolean checkElement(Element element, Messager messager) { return true; } + private void collectSubscribers(Set annotations, RoundEnvironment env, Messager messager) { + for (TypeElement annotation : annotations) { + Set elements = env.getElementsAnnotatedWith(annotation); + for (Element element : elements) { + if (checkElement(element, messager)) { + Element classElement = element.getEnclosingElement(); + List methods = methodsByClass.get(classElement); + if (methods == null) { + methods = new ArrayList(); + methodsByClass.put(classElement, methods); + } + methods.add(element); + } + } + } + } + private void writeSources() { String pack = "de.greenrobot.event"; String className = "MyGeneratedSubscriberIndex"; @@ -134,9 +140,19 @@ private void writeSources() { } else { ifPrefix = "} else "; } - writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", entry.getKey().asType() + ".class) {"); + TypeElement subscriberClass = (TypeElement) entry.getKey(); + writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", subscriberClass.asType() + ".class) {"); writer.write(" return new SubscriberMethod[] {\n"); - writeIndexEntries(writer, entry.getValue()); + + Set methodSignatures = new HashSet(); + writeIndexEntries(writer, null, entry.getValue(), methodSignatures); + while (subscriberClass.getSuperclass().getKind() == TypeKind.DECLARED) { + subscriberClass = (TypeElement) processingEnv.getTypeUtils().asElement(subscriberClass.getSuperclass()); + List superClassMethods = methodsByClass.get(subscriberClass); + if (superClassMethods != null) { + writeIndexEntries(writer, subscriberClass, superClassMethods, methodSignatures); + } + } writer.write(" };\n"); } if (!methodsByClass.isEmpty()) { @@ -155,17 +171,24 @@ private void writeSources() { } } - - private void writeIndexEntries(BufferedWriter writer, List elements) throws IOException { + private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClass, List elements, Set methodSignatures) throws IOException { for (Element element : elements) { - Subscribe subscribe = element.getAnnotation(Subscribe.class); List parameters = ((ExecutableElement) element).getParameters(); VariableElement param = parameters.get(0); DeclaredType paramType = (DeclaredType) param.asType(); + String methodSignature = element+">"+paramType; + if(!methodSignatures.add(methodSignature)) { + continue; + } + String methodName = element.getSimpleName().toString(); - writeLine(writer, 4, "createSubscriberMethod(subscriberClass,", + String subscriberClassString = subscriberClass == null ? "subscriberClass" : + subscriberClass.asType().toString() + ".class"; + + Subscribe subscribe = element.getAnnotation(Subscribe.class); + writeLine(writer, 4, "createSubscriberMethod(" + subscriberClassString + ",", "\"" + methodName + "\",", paramType.toString() + ".class,", "ThreadMode." + subscribe.threadMode().name() + "),"); From 251f64ec7d442a43f3d04c0a686adc4117a6ce76 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 8 Mar 2015 20:05:02 +0100 Subject: [PATCH 020/112] adjustments in test project for annotations: no anonymous subscriber classes, public event and subscriber classes --- .../event/test/EventBusBasicTest.java | 24 +++++++++++-------- .../test/EventBusInheritanceDisabledTest.java | 17 +++++++++---- .../test/EventBusNoSubscriberEventTest.java | 14 ++++++----- .../event/test/EventBusStickyEventTest.java | 15 ++++++------ .../test/EventBusSubscriberLegalTest.java | 20 +++++++++------- 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 57a65d22..7ee87e68 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -187,11 +187,7 @@ public void testHasSubscriberForEvent() { public void testHasSubscriberForEventSuperclass() { assertFalse(eventBus.hasSubscriberForEvent(String.class)); - Object subscriber = new Object() { - @Subscribe - public void onEvent(Object event) { - } - }; + Object subscriber = new ObjectSubscriber(); eventBus.register(subscriber); assertTrue(eventBus.hasSubscriberForEvent(String.class)); @@ -202,11 +198,7 @@ public void onEvent(Object event) { public void testHasSubscriberForEventImplementedInterface() { assertFalse(eventBus.hasSubscriberForEvent(String.class)); - Object subscriber = new Object() { - @Subscribe - public void onEvent(CharSequence event) { - } - }; + Object subscriber = new CharSequenceSubscriber(); eventBus.register(subscriber); assertTrue(eventBus.hasSubscriberForEvent(CharSequence.class)); assertTrue(eventBus.hasSubscriberForEvent(String.class)); @@ -247,6 +239,18 @@ public void onEvent(String event) { } } + public static class CharSequenceSubscriber { + @Subscribe + public void onEvent(CharSequence event) { + } + } + + public static class ObjectSubscriber { + @Subscribe + public void onEvent(Object event) { + } + } + public class MyEvent { } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 43aaf467..20a5195c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -16,6 +16,7 @@ package de.greenrobot.event.test; import de.greenrobot.event.EventBus; +import de.greenrobot.event.Subscribe; import junit.framework.TestCase; /** @@ -118,41 +119,47 @@ public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { assertEquals(1, subscriber.countMyEventExtended); } + @Subscribe public void onEvent(Object event) { countObjectEvent++; } + @Subscribe public void onEvent(MyEvent event) { countMyEvent++; } + @Subscribe public void onEvent(MyEventExtended event) { countMyEventExtended++; } + @Subscribe public void onEvent(MyEventInterface event) { countMyEventInterface++; } + @Subscribe public void onEvent(MyEventInterfaceExtended event) { countMyEventInterfaceExtended++; } - static interface MyEventInterface { + public static interface MyEventInterface { } - static class MyEvent implements MyEventInterface { + public static class MyEvent implements MyEventInterface { } - static interface MyEventInterfaceExtended extends MyEventInterface { + public static interface MyEventInterfaceExtended extends MyEventInterface { } - static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { + public static class MyEventExtended extends MyEvent implements MyEventInterfaceExtended { } - static class SubscriberExtended extends EventBusInheritanceDisabledTest { + public static class SubscriberExtended extends EventBusInheritanceDisabledTest { private int countMyEventOverwritten; + @Subscribe public void onEvent(MyEvent event) { countMyEventOverwritten++; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index 846816bf..f6d7516b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -36,12 +36,7 @@ public void testNoSubscriberEvent() { } public void testNoSubscriberEventAfterUnregister() { - Object subscriber = new Object() { - @SuppressWarnings("unused") - @Subscribe - public void onEvent(String dummy) { - } - }; + Object subscriber = new DummySubscriber(); eventBus.register(subscriber); eventBus.unregister(subscriber); testNoSubscriberEvent(); @@ -69,6 +64,13 @@ public void onEvent(SubscriberExceptionEvent event) { trackEvent(event); } + public static class DummySubscriber { + @SuppressWarnings("unused") + @Subscribe + public void onEvent(String dummy) { + } + } + public class BadNoSubscriberSubscriber { @Subscribe public void onEvent(NoSubscriberEvent event) { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 084b1be6..9223bb32 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -119,13 +119,7 @@ public void testPostStickyRemoveAll() throws InterruptedException { } public void testRemoveStickyEventInSubscriber() throws InterruptedException { - eventBus.registerSticky(new Object() { - @SuppressWarnings("unused") - @Subscribe - public void onEvent(String event) { - eventBus.removeStickyEvent(event); - } - }); + eventBus.registerSticky(new RemoveStickySubscriber()); eventBus.postSticky("Sticky"); eventBus.registerSticky(this); assertNull(lastEvent); @@ -143,4 +137,11 @@ public void onEvent(IntTestEvent event) { trackEvent(event); } + public class RemoveStickySubscriber { + @SuppressWarnings("unused") + @Subscribe + public void onEvent(String event) { + eventBus.removeStickyEvent(event); + } + } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index d122ece9..1c84dda6 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -50,15 +50,7 @@ public void testSubscriberLegal() { // } public void testSubscriberLegalAbstract() { - eventBus.register(new Abstract() { - - @Override - @Subscribe - public void onEvent(String event) { - trackEvent(event); - } - - }); + eventBus.register(new AbstractImpl()); eventBus.post("42"); assertEquals(1, eventCount.intValue()); @@ -80,6 +72,16 @@ public static abstract class Abstract { public abstract void onEvent(String event); } + public class AbstractImpl extends Abstract { + + @Override + @Subscribe + public void onEvent(String event) { + trackEvent(event); + } + + } + // public static class Static { // @Subscribe // public static void onEvent(String event) { From 232a70fa22f21c3f675badb4415c34760e63af51 Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 8 Mar 2015 20:17:51 +0100 Subject: [PATCH 021/112] fix: query superclasses when using subscriber index --- .../event/SubscriberMethodFinder.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index ae15620e..35b982e3 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -87,16 +87,25 @@ List findSubscriberMethods(Class subscriberClass) { } private List findSubscriberMethodsWithIndex(Class subscriberClass) { - SubscriberMethod[] array = INDEX.getSubscribersFor(subscriberClass); - if (array != null && array.length > 0) { - List subscriberMethods = new ArrayList(); - for (SubscriberMethod subscriberMethod : array) { - subscriberMethods.add(subscriberMethod); + Class clazz = subscriberClass; + while (clazz != null) { + SubscriberMethod[] array = INDEX.getSubscribersFor(clazz); + if (array != null && array.length > 0) { + List subscriberMethods = new ArrayList(); + for (SubscriberMethod subscriberMethod : array) { + subscriberMethods.add(subscriberMethod); + } + return subscriberMethods; + } else { + String name = clazz.getName(); + if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { + // Skip system classes, this just degrades performance + break; + } + clazz = clazz.getSuperclass(); } - return subscriberMethods; - } else { - return Collections.EMPTY_LIST; } + return Collections.EMPTY_LIST; } private List findSubscriberMethodsWithReflection(Class subscriberClass) { From 8084e31e5a85c198df7119b6195449589f40b58d Mon Sep 17 00:00:00 2001 From: Markus Date: Sun, 8 Mar 2015 20:25:39 +0100 Subject: [PATCH 022/112] added testMultipleSubscribeMethodsForEvent --- .../greenrobot/event/test/EventBusBasicTest.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 7ee87e68..ad8c20f2 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -35,6 +35,7 @@ public class EventBusBasicTest extends TestCase { private int lastIntEvent; private int countMyEventExtended; private int countMyEvent; + private int countMyEvent2; protected void setUp() throws Exception { super.setUp(); @@ -130,6 +131,14 @@ public void testPostMultipleTimes() { assertEquals(count, countMyEvent); } + public void testMultipleSubscribeMethodsForEvent() { + eventBus.register(this); + MyEvent event = new MyEvent(); + eventBus.post(event); + assertEquals(1, countMyEvent); + assertEquals(1, countMyEvent2); + } + public void testPostAfterUnregister() { eventBus.register(this); eventBus.unregister(this); @@ -225,6 +234,11 @@ public void onEvent(MyEvent event) { countMyEvent++; } + @Subscribe + public void onEvent2(MyEvent event) { + countMyEvent2++; + } + @Subscribe public void onEvent(MyEventExtended event) { countMyEventExtended++; From ecfc93a28059c021eadea45381bcb891cd2aa9b8 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 25 May 2015 03:38:52 +0200 Subject: [PATCH 023/112] @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection --- .../src/de/greenrobot/event/EventBus.java | 9 +++--- .../event/SubscriberMethodFinder.java | 4 +-- .../EventBusAnnotationProcessor.java | 4 +-- .../event/test/EventBusInheritanceTest.java | 29 +++++++++++++++++++ 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 85075b7c..bd2b95a0 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -162,11 +162,10 @@ public void registerSticky(Object subscriber, int priority) { private synchronized void register(Object subscriber, boolean sticky, int priority) { Class subscriberClass = subscriber.getClass(); - if(subscriberClass.isAnonymousClass()) { - // We cannot get @Subscribe annotations from anonymous classes, so fail fast - throw new EventBusException("Anonymous class cannot be registered: "+ subscriberClass); - } - List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); + // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection + boolean forceReflection = subscriberClass.isAnonymousClass(); + List subscriberMethods = + subscriberMethodFinder.findSubscriberMethods(subscriberClass, forceReflection); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod, sticky, priority); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 35b982e3..10864cc8 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -61,7 +61,7 @@ class SubscriberMethodFinder { this.strictMethodVerification = strictMethodVerification; } - List findSubscriberMethods(Class subscriberClass) { + List findSubscriberMethods(Class subscriberClass, boolean forceReflection) { String key = subscriberClass.getName(); List subscriberMethods; synchronized (METHOD_CACHE) { @@ -70,7 +70,7 @@ List findSubscriberMethods(Class subscriberClass) { if (subscriberMethods != null) { return subscriberMethods; } - if (INDEX != null) { + if (INDEX != null && !forceReflection) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); } else { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 6fdec9f5..30aa8024 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -178,8 +178,8 @@ private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClas VariableElement param = parameters.get(0); DeclaredType paramType = (DeclaredType) param.asType(); - String methodSignature = element+">"+paramType; - if(!methodSignatures.add(methodSignature)) { + String methodSignature = element + ">" + paramType; + if (!methodSignatures.add(methodSignature)) { continue; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 1de6943a..7bcea781 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -19,6 +19,9 @@ import junit.framework.TestCase; import de.greenrobot.event.EventBus; +import java.util.ArrayList; +import java.util.List; + /** * @author Markus Junginger, greenrobot */ @@ -102,6 +105,32 @@ public void testSubscriberClassHierarchy() { assertEquals(2, subscriber.countMyEventOverwritten); } + public void testSubscriberClassHierarchyAnonymousExtension() { + SubscriberExtended subscriber = new SubscriberExtended() { + + }; + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals(1, subscriber.countObjectEvent); + } + + public void testSubscriberClassHierarchyAnonymous() { + final List received = new ArrayList(); + Object subscriber = new Object() { + @Subscribe + public void onEvent(String event) { + received.add(event); + } + }; + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals(1, received.size()); + assertEquals("Hello", received.get(0)); + } + + public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); eventBus.register(subscriber); From db5bf136c4fb017eec203784dd9d6671255eb34a Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 26 May 2015 02:43:02 +0200 Subject: [PATCH 024/112] Extracted 2 test into EventBusFallbackToReflectionTest --- .../EventBusFallbackToReflectionTest.java | 56 +++++++++++++++++++ .../event/test/EventBusInheritanceTest.java | 26 --------- 2 files changed, 56 insertions(+), 26 deletions(-) create mode 100644 EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java new file mode 100644 index 00000000..dc04cd1d --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -0,0 +1,56 @@ +package de.greenrobot.event.test; + +import de.greenrobot.event.Subscribe; + +import java.util.ArrayList; +import java.util.List; + +/** TODO */ +public class EventBusFallbackToReflectionTest extends AbstractEventBusTest { + public class PublicSuperClass { + @Subscribe + public void onEvent(Object any) { + trackEvent(any); + } + } + +// private class PrivateSuperClass { +// @Subscribe +// public void onEvent(Object any) { +// trackEvent(any); +// } +// } + + public EventBusFallbackToReflectionTest() { + super(true); + } + + public void testAnonymousSubscriberClass() { + Object subscriber = new Object() { + @Subscribe + public void onEvent(String event) { + trackEvent(event); + } + }; + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals("Hello", lastEvent); + assertEquals(1, eventsReceived.size()); + } + + public void testAnonymousSubscriberClassWithPublicSuperclass() { + Object subscriber = new PublicSuperClass() { + @Subscribe + public void onEvent(String event) { + trackEvent(event); + } + }; + eventBus.register(subscriber); + + eventBus.post("Hello"); + assertEquals("Hello", lastEvent); + assertEquals(2, eventsReceived.size()); + } + +} diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 7bcea781..dd93a757 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -105,32 +105,6 @@ public void testSubscriberClassHierarchy() { assertEquals(2, subscriber.countMyEventOverwritten); } - public void testSubscriberClassHierarchyAnonymousExtension() { - SubscriberExtended subscriber = new SubscriberExtended() { - - }; - eventBus.register(subscriber); - - eventBus.post("Hello"); - assertEquals(1, subscriber.countObjectEvent); - } - - public void testSubscriberClassHierarchyAnonymous() { - final List received = new ArrayList(); - Object subscriber = new Object() { - @Subscribe - public void onEvent(String event) { - received.add(event); - } - }; - eventBus.register(subscriber); - - eventBus.post("Hello"); - assertEquals(1, received.size()); - assertEquals("Hello", received.get(0)); - } - - public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); eventBus.register(subscriber); From f5106bc144f2f0ba89c90b0b64766f06a248ec90 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Jun 2015 23:21:08 +0200 Subject: [PATCH 025/112] subscriber index: skip subscriber classes that are non-public or use non-public events (directly or in superclasses) --- .../event/SubscriberMethodFinder.java | 5 +- .../EventBusAnnotationProcessor.java | 192 ++++++++++++------ .../EventBusFallbackToReflectionTest.java | 29 ++- 3 files changed, 152 insertions(+), 74 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 10864cc8..f6699f70 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -44,7 +44,7 @@ class SubscriberMethodFinder { static { SubscriberIndex newIndex = null; try { - Class clazz = Class.forName("de.greenrobot.event.MyGeneratedSubscriberIndex"); + Class clazz = Class.forName("de.greenrobot.event.GeneratedSubscriberIndex"); newIndex = (SubscriberIndex) clazz.newInstance(); } catch (ClassNotFoundException e) { Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up"); @@ -72,6 +72,9 @@ List findSubscriberMethods(Class subscriberClass, boolean f } if (INDEX != null && !forceReflection) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); + if (subscriberMethods.isEmpty()) { + subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); + } } else { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); } diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 30aa8024..1af29114 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -29,44 +29,75 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") @SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { - private final Map> methodsByClass = new HashMap>(); + private final Map> methodsByClass = + new HashMap>(); + private final Set classesToSkip = new HashSet(); + private boolean writerRoundDone; private int round; @Override public boolean process(Set annotations, RoundEnvironment env) { Messager messager = processingEnv.getMessager(); - round++; - messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + - !annotations.isEmpty() + ", processingOver: " + env.processingOver()); - if (env.processingOver()) { - if (!annotations.isEmpty()) { - messager.printMessage(Diagnostic.Kind.ERROR, - "Unexpected processing state: annotations still available after processing over"); + try { + round++; + messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + + !annotations.isEmpty() + ", processingOver: " + env.processingOver()); + if (env.processingOver()) { + if (!annotations.isEmpty()) { + messager.printMessage(Diagnostic.Kind.ERROR, + "Unexpected processing state: annotations still available after processing over"); + return false; + } + } + if (annotations.isEmpty()) { return false; } - } - if (annotations.isEmpty()) { - return false; - } - if (writerRoundDone) { - messager.printMessage(Diagnostic.Kind.ERROR, - "Unexpected processing state: annotations still available after writing."); - } - collectSubscribers(annotations, env, messager); + if (writerRoundDone) { + messager.printMessage(Diagnostic.Kind.ERROR, + "Unexpected processing state: annotations still available after writing."); + } + collectSubscribers(annotations, env, messager); + checkForSubscribersToSkip(messager); - if (!methodsByClass.isEmpty()) { - writeSources(); - } else { - messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); + if (!methodsByClass.isEmpty()) { + writeSources(); + } else { + messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); + } + writerRoundDone = true; + } catch (RuntimeException e) { + // IntelliJ does not handle exceptions nicely, so log and print a message + e.printStackTrace(); + messager.printMessage(Diagnostic.Kind.ERROR, "Unexpected error in EventBusAnnotationProcessor: " + e); } - writerRoundDone = true; - return true; } - private boolean checkElement(Element element, Messager messager) { + private void collectSubscribers(Set annotations, RoundEnvironment env, Messager messager) { + for (TypeElement annotation : annotations) { + Set elements = env.getElementsAnnotatedWith(annotation); + for (Element element : elements) { + if (element instanceof ExecutableElement) { + ExecutableElement method = (ExecutableElement) element; + if (checkHasErrors(method, messager)) { + Element classElement = method.getEnclosingElement(); + List methods = methodsByClass.get(classElement); + if (methods == null) { + methods = new ArrayList(); + methodsByClass.put((TypeElement) classElement, methods); + } + methods.add(method); + } + } else { + messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid for methods", element); + } + } + } + } + + private boolean checkHasErrors(ExecutableElement element, Messager messager) { if (element.getModifiers().contains(Modifier.STATIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); return false; @@ -77,49 +108,78 @@ private boolean checkElement(Element element, Messager messager) { return false; } - Set subscriberClassModifiers = element.getEnclosingElement().getModifiers(); - if (!subscriberClassModifiers.contains(Modifier.PUBLIC)) { - messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber class must be public", - element.getEnclosingElement()); - return false; - } - List parameters = ((ExecutableElement) element).getParameters(); if (parameters.size() != 1) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must have exactly 1 parameter", element); return false; } - - VariableElement param = parameters.get(0); - DeclaredType paramType = (DeclaredType) param.asType(); - Set eventClassModifiers = paramType.asElement().getModifiers(); - if (!eventClassModifiers.contains(Modifier.PUBLIC)) { - messager.printMessage(Diagnostic.Kind.ERROR, "Event type must be public: " + paramType, param); - return false; - } return true; } - private void collectSubscribers(Set annotations, RoundEnvironment env, Messager messager) { - for (TypeElement annotation : annotations) { - Set elements = env.getElementsAnnotatedWith(annotation); - for (Element element : elements) { - if (checkElement(element, messager)) { - Element classElement = element.getEnclosingElement(); - List methods = methodsByClass.get(classElement); - if (methods == null) { - methods = new ArrayList(); - methodsByClass.put(classElement, methods); + private void checkForSubscribersToSkip(Messager messager) { + for (Map.Entry> entry : methodsByClass.entrySet()) { + TypeElement skipCandidate = entry.getKey(); + TypeElement subscriberClass = skipCandidate; + while (subscriberClass != null) { + if (!subscriberClass.getModifiers().contains(Modifier.PUBLIC)) { + boolean added = classesToSkip.add(skipCandidate); + if (added) { + String msg; + if (subscriberClass.equals(skipCandidate)) { + msg = "Falling back to reflection because class is not public"; + } else { + msg = "Falling back to reflection because " + skipCandidate + + " has a non-public super class"; + } + messager.printMessage(Diagnostic.Kind.NOTE, msg, subscriberClass); } - methods.add(element); + break; } + List methods = methodsByClass.get(subscriberClass); + if (methods != null) { + for (ExecutableElement method : methods) { + VariableElement param = method.getParameters().get(0); + DeclaredType paramType = (DeclaredType) param.asType(); + Set eventClassModifiers = paramType.asElement().getModifiers(); + if (!eventClassModifiers.contains(Modifier.PUBLIC)) { + boolean added = classesToSkip.add(skipCandidate); + if (added) { + String msg; + if (subscriberClass.equals(skipCandidate)) { + msg = "Falling back to reflection because event type is not public"; + } else { + msg = "Falling back to reflection because " + skipCandidate + + " has a super class using a non-public event type"; + } + messager.printMessage(Diagnostic.Kind.NOTE, msg, subscriberClass); + } + break; + } + } + } + subscriberClass = getSuperclass(subscriberClass); } } } + private TypeElement getSuperclass(TypeElement type) { + if (type.getSuperclass().getKind() == TypeKind.DECLARED) { + TypeElement superclass = (TypeElement) processingEnv.getTypeUtils().asElement(type.getSuperclass()); + String name = superclass.getQualifiedName().toString(); + if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { + // Skip system classes, this just degrades performance + return null; + } else { + return superclass; + } + } else { + return null; + } + } + private void writeSources() { String pack = "de.greenrobot.event"; - String className = "MyGeneratedSubscriberIndex"; + String className = "GeneratedSubscriberIndex"; BufferedWriter writer = null; try { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(pack + '.' + className); @@ -132,7 +192,11 @@ private void writeSources() { writer.write(" SubscriberMethod[] createSubscribersFor(Class subscriberClass) {\n"); boolean first = true; - for (Map.Entry> entry : methodsByClass.entrySet()) { + for (Map.Entry> entry : methodsByClass.entrySet()) { + TypeElement subscriberClass = entry.getKey(); + if (classesToSkip.contains(subscriberClass)) { + continue; + } String ifPrefix; if (first) { ifPrefix = ""; @@ -140,18 +204,18 @@ private void writeSources() { } else { ifPrefix = "} else "; } - TypeElement subscriberClass = (TypeElement) entry.getKey(); writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", subscriberClass.asType() + ".class) {"); writer.write(" return new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); writeIndexEntries(writer, null, entry.getValue(), methodSignatures); - while (subscriberClass.getSuperclass().getKind() == TypeKind.DECLARED) { - subscriberClass = (TypeElement) processingEnv.getTypeUtils().asElement(subscriberClass.getSuperclass()); - List superClassMethods = methodsByClass.get(subscriberClass); + TypeElement superclass = getSuperclass(subscriberClass); + while (superclass != null) { + List superClassMethods = methodsByClass.get(superclass); if (superClassMethods != null) { - writeIndexEntries(writer, subscriberClass, superClassMethods, methodSignatures); + writeIndexEntries(writer, superclass, superClassMethods, methodSignatures); } + superclass = getSuperclass(superclass); } writer.write(" };\n"); } @@ -171,30 +235,30 @@ private void writeSources() { } } - private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClass, List elements, Set methodSignatures) throws IOException { - for (Element element : elements) { + private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClass, List methods, Set methodSignatures) throws IOException { + for (ExecutableElement method : methods) { - List parameters = ((ExecutableElement) element).getParameters(); + List parameters = method.getParameters(); VariableElement param = parameters.get(0); DeclaredType paramType = (DeclaredType) param.asType(); - String methodSignature = element + ">" + paramType; + String methodSignature = method + ">" + paramType; if (!methodSignatures.add(methodSignature)) { continue; } - String methodName = element.getSimpleName().toString(); + String methodName = method.getSimpleName().toString(); String subscriberClassString = subscriberClass == null ? "subscriberClass" : subscriberClass.asType().toString() + ".class"; - Subscribe subscribe = element.getAnnotation(Subscribe.class); + Subscribe subscribe = method.getAnnotation(Subscribe.class); writeLine(writer, 4, "createSubscriberMethod(" + subscriberClassString + ",", "\"" + methodName + "\",", paramType.toString() + ".class,", "ThreadMode." + subscribe.threadMode().name() + "),"); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + - element.getEnclosingElement().getSimpleName() + "." + methodName + + method.getEnclosingElement().getSimpleName() + "." + methodName + "(" + paramType.asElement().getSimpleName() + ")"); } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java index dc04cd1d..7c5d46ae 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -2,9 +2,6 @@ import de.greenrobot.event.Subscribe; -import java.util.ArrayList; -import java.util.List; - /** TODO */ public class EventBusFallbackToReflectionTest extends AbstractEventBusTest { public class PublicSuperClass { @@ -14,12 +11,19 @@ public void onEvent(Object any) { } } -// private class PrivateSuperClass { -// @Subscribe -// public void onEvent(Object any) { -// trackEvent(any); -// } -// } + private class PrivateSuperClass { + @Subscribe + public void onEvent(Object any) { + trackEvent(any); + } + } + + public class PublicWithPrivateSuperClass extends PrivateSuperClass { + @Subscribe + public void onEvent(String any) { + trackEvent(any); + } + } public EventBusFallbackToReflectionTest() { super(true); @@ -53,4 +57,11 @@ public void onEvent(String event) { assertEquals(2, eventsReceived.size()); } + public void testAnonymousSubscriberClassWithPrivateSuperclass() { + eventBus.register(new PublicWithPrivateSuperClass()); + eventBus.post("Hello"); + assertEquals("Hello", lastEvent); + assertEquals(2, eventsReceived.size()); + } + } From 8f2088e4e407e33d0b953409c8f916d92bd71760 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 2 Jun 2015 20:09:30 +0200 Subject: [PATCH 026/112] added tests for private event classes --- .../EventBusFallbackToReflectionTest.java | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java index 7c5d46ae..a85cfcaf 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -4,27 +4,44 @@ /** TODO */ public class EventBusFallbackToReflectionTest extends AbstractEventBusTest { - public class PublicSuperClass { + private class PrivateEvent { + } + + public class PublicClass { @Subscribe public void onEvent(Object any) { trackEvent(any); } } - private class PrivateSuperClass { + private class PrivateClass { @Subscribe public void onEvent(Object any) { trackEvent(any); } } - public class PublicWithPrivateSuperClass extends PrivateSuperClass { + public class PublicWithPrivateSuperClass extends PrivateClass { @Subscribe public void onEvent(String any) { trackEvent(any); } } + public class PublicClassWithPrivateEvent { + @Subscribe + public void onEvent(PrivateEvent any) { + trackEvent(any); + } + } + + public class PublicWithPrivateEventInSuperclass extends PublicClassWithPrivateEvent { + @Subscribe + public void onEvent(Object any) { + trackEvent(any); + } + } + public EventBusFallbackToReflectionTest() { super(true); } @@ -44,7 +61,7 @@ public void onEvent(String event) { } public void testAnonymousSubscriberClassWithPublicSuperclass() { - Object subscriber = new PublicSuperClass() { + Object subscriber = new PublicClass() { @Subscribe public void onEvent(String event) { trackEvent(event); @@ -64,4 +81,20 @@ public void testAnonymousSubscriberClassWithPrivateSuperclass() { assertEquals(2, eventsReceived.size()); } + public void testSubscriberClassWithPrivateEvent() { + eventBus.register(new PublicClassWithPrivateEvent()); + PrivateEvent privateEvent = new PrivateEvent(); + eventBus.post(privateEvent); + assertEquals(privateEvent, lastEvent); + assertEquals(1, eventsReceived.size()); + } + + public void testSubscriberExtendingClassWithPrivateEvent() { + eventBus.register(new PublicWithPrivateEventInSuperclass()); + PrivateEvent privateEvent = new PrivateEvent(); + eventBus.post(privateEvent); + assertEquals(privateEvent, lastEvent); + assertEquals(2, eventsReceived.size()); + } + } From 4c225398eebf037802f95bd6a11448f0f3bb7151 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 2 Jun 2015 20:09:55 +0200 Subject: [PATCH 027/112] updated android build tools --- EventBusPerformance/build.gradle | 4 ++-- EventBusTest/build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 46adb91b..46f10f86 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.android.tools.build:gradle:1.2.3' } } @@ -21,7 +21,7 @@ dependencies { } android { - buildToolsVersion '21.1.2' + buildToolsVersion '22.0.1' compileSdkVersion 19 sourceSets { diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 5983a7ab..80248410 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -4,7 +4,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.1.0' + classpath 'com.android.tools.build:gradle:1.2.3' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' } } @@ -22,7 +22,7 @@ dependencies { } android { - buildToolsVersion '21.1.2' + buildToolsVersion '22.0.1' compileSdkVersion 19 sourceSets { From 7952c05234bb845552599fe86148112eb2bcf20c Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 2 Jun 2015 22:36:27 +0200 Subject: [PATCH 028/112] subscriber priority and stickyness are now part of @Subscribe --- .../src/de/greenrobot/event/EventBus.java | 91 ++++----- .../src/de/greenrobot/event/Subscribe.java | 12 ++ .../de/greenrobot/event/SubscriberIndex.java | 4 +- .../de/greenrobot/event/SubscriberMethod.java | 6 +- .../event/SubscriberMethodFinder.java | 3 +- .../src/de/greenrobot/event/Subscription.java | 4 +- .../EventBusAnnotationProcessor.java | 3 +- .../test/EventBusCancelEventDeliveryTest.java | 46 +++-- .../test/EventBusInheritanceDisabledTest.java | 29 ++- .../event/test/EventBusInheritanceTest.java | 29 ++- .../EventBusOrderedSubscriptionsTest.java | 176 +++++++++++++----- .../event/test/EventBusStickyEventTest.java | 46 +++-- 12 files changed, 303 insertions(+), 146 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index bd2b95a0..22a99f63 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -31,9 +31,10 @@ /** * EventBus is a central publish/subscribe event system for Android. Events are posted ({@link #post(Object)}) to the * bus, which delivers it to subscribers that have a matching handler method for the event type. To receive events, - * subscribers must register themselves to the bus using {@link #register(Object)}. Once registered, - * subscribers receive events until {@link #unregister(Object)} is called. By convention, event handling methods must - * be named "onEvent", be public, return nothing (void), and have exactly one parameter (the event). + * subscribers must register themselves to the bus using {@link #register(Object)}. Once registered, subscribers + * receive events until {@link #unregister(Object)} is called. Event handling methods must be annotated by + * {@link de.greenrobot.event.Subscribe}, must be public, return nothing (void), and have exactly one parameter + * (the event). * * @author Markus Junginger, greenrobot */ @@ -58,7 +59,6 @@ protected PostingThreadState initialValue() { } }; - private final HandlerPoster mainThreadPoster; private final BackgroundPoster backgroundPoster; private final AsyncPoster asyncPoster; @@ -124,58 +124,26 @@ public EventBus() { * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they * are no longer interested in receiving events. *

- * Subscribers have event handling methods that are identified by their name, typically called "onEvent". Event - * handling methods must have exactly one parameter, the event. If the event handling method is to be called in a - * specific thread, a modifier is appended to the method name. Valid modifiers match one of the {@link ThreadMode} - * enums. For example, if a method is to be called in the UI/main thread by EventBus, it would be called - * "onEventMainThread". + * Subscribers have event handling methods that must be annotated by {@link de.greenrobot.event.Subscribe}. + * The {@link de.greenrobot.event.Subscribe} annotation also allows configuration like {@link + * de.greenrobot.event.ThreadMode} and priority. */ public void register(Object subscriber) { - register(subscriber, false, 0); - } - - /** - * Like {@link #register(Object)} with an additional subscriber priority to influence the order of event delivery. - * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before - * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of - * delivery among subscribers with different {@link ThreadMode}s! - */ - public void register(Object subscriber, int priority) { - register(subscriber, false, priority); - } - - /** - * Like {@link #register(Object)}, but also triggers delivery of the most recent sticky event (posted with - * {@link #postSticky(Object)}) to the given subscriber. - */ - public void registerSticky(Object subscriber) { - register(subscriber, true, 0); - } - - /** - * Like {@link #register(Object, int)}, but also triggers delivery of the most recent sticky event (posted with - * {@link #postSticky(Object)}) to the given subscriber. - */ - public void registerSticky(Object subscriber, int priority) { - register(subscriber, true, priority); - } - - private synchronized void register(Object subscriber, boolean sticky, int priority) { Class subscriberClass = subscriber.getClass(); // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection boolean forceReflection = subscriberClass.isAnonymousClass(); List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass, forceReflection); for (SubscriberMethod subscriberMethod : subscriberMethods) { - subscribe(subscriber, subscriberMethod, sticky, priority); + subscribe(subscriber, subscriberMethod); } } // Must be called in synchronized block - private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boolean sticky, int priority) { + private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class eventType = subscriberMethod.eventType; CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); - Subscription newSubscription = new Subscription(subscriber, subscriberMethod, priority); + Subscription newSubscription = new Subscription(subscriber, subscriberMethod); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList(); subscriptionsByEventType.put(eventType, subscriptions); @@ -189,11 +157,14 @@ private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boo // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) // subscriberMethod.method.setAccessible(true); - int size = subscriptions.size(); - for (int i = 0; i <= size; i++) { - if (i == size || newSubscription.priority > subscriptions.get(i).priority) { - subscriptions.add(i, newSubscription); - break; + // Got to synchronize to avoid shifted positions when adding/removing concurrently + synchronized (subscriptions) { + int size = subscriptions.size(); + for (int i = 0; i <= size; i++) { + if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { + subscriptions.add(i, newSubscription); + break; + } } } @@ -204,7 +175,7 @@ private void subscribe(Object subscriber, SubscriberMethod subscriberMethod, boo } subscribedEvents.add(eventType); - if (sticky) { + if (subscriberMethod.sticky) { if (eventInheritance) { // Existing sticky events of all subclasses of eventType have to be considered. // Note: Iterating over all events may be inefficient with lots of sticky events, @@ -241,14 +212,17 @@ public synchronized boolean isRegistered(Object subscriber) { private void unubscribeByEventType(Object subscriber, Class eventType) { List subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { - int size = subscriptions.size(); - for (int i = 0; i < size; i++) { - Subscription subscription = subscriptions.get(i); - if (subscription.subscriber == subscriber) { - subscription.active = false; - subscriptions.remove(i); - i--; - size--; + // Got to synchronize to avoid shifted positions when adding/removing concurrently + synchronized (subscriptions) { + int size = subscriptions.size(); + for (int i = 0; i < size; i++) { + Subscription subscription = subscriptions.get(i); + if (subscription.subscriber == subscriber) { + subscription.active = false; + subscriptions.remove(i); + i--; + size--; + } } } } @@ -294,7 +268,7 @@ public void post(Object event) { * Called from a subscriber's event handling method, further event delivery will be canceled. Subsequent * subscribers * won't receive the event. Events are usually canceled by higher priority subscribers (see - * {@link #register(Object, int)}). Canceling is restricted to event handling methods running in posting thread + * {@link Subscribe#priority()}). Canceling is restricted to event handling methods running in posting thread * {@link ThreadMode#PostThread}. */ public void cancelEventDelivery(Object event) { @@ -315,8 +289,7 @@ public void cancelEventDelivery(Object event) { /** * Posts the given event to the event bus and holds on to the event (because it is sticky). The most recent sticky - * event of an event's type is kept in memory for future access. This can be {@link #registerSticky(Object)} or - * {@link #getStickyEvent(Class)}. + * event of an event's type is kept in memory for future access by subscribers using {@link Subscribe#sticky()}. */ public void postSticky(Object event) { synchronized (stickyEvents) { diff --git a/EventBus/src/de/greenrobot/event/Subscribe.java b/EventBus/src/de/greenrobot/event/Subscribe.java index 76ff1c88..82cf51fc 100644 --- a/EventBus/src/de/greenrobot/event/Subscribe.java +++ b/EventBus/src/de/greenrobot/event/Subscribe.java @@ -14,5 +14,17 @@ @Target({ElementType.METHOD}) public @interface Subscribe { ThreadMode threadMode() default ThreadMode.PostThread; + + /** + * If true, delivers the most recent sticky event (posted with + * {@link de.greenrobot.event.EventBus#postSticky(Object)}) to this subscriber (if event available). + */ + boolean sticky() default false; + + /** Subscriber priority to influence the order of event delivery. + * Within the same delivery thread ({@link ThreadMode}), higher priority subscribers will receive events before + * others with a lower priority. The default priority is 0. Note: the priority does *NOT* affect the order of + * delivery among subscribers with different {@link ThreadMode}s! */ + int priority() default 0; } diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndex.java b/EventBus/src/de/greenrobot/event/SubscriberIndex.java index a442d1cc..8dbee7f6 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberIndex.java +++ b/EventBus/src/de/greenrobot/event/SubscriberIndex.java @@ -22,10 +22,10 @@ SubscriberMethod[] getSubscribersFor(Class subscriberClass) { abstract SubscriberMethod[] createSubscribersFor(Class subscriberClass); SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, - ThreadMode threadMode) { + ThreadMode threadMode, int priority, boolean sticky) { try { Method method = subscriberClass.getDeclaredMethod(methodName, eventType); - return new SubscriberMethod(method, threadMode, eventType); + return new SubscriberMethod(method, eventType, threadMode, priority, sticky); } catch (NoSuchMethodException e) { throw new EventBusException("Could not find subscriber method in " + subscriberClass + ". Maybe a missing ProGuard rule?", e); diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/de/greenrobot/event/SubscriberMethod.java index cf13c292..1dcd74f1 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethod.java @@ -21,13 +21,17 @@ final class SubscriberMethod { final Method method; final ThreadMode threadMode; final Class eventType; + final int priority; + final boolean sticky; /** Used for efficient comparison */ String methodString; - SubscriberMethod(Method method, ThreadMode threadMode, Class eventType) { + SubscriberMethod(Method method, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { this.method = method; this.threadMode = threadMode; this.eventType = eventType; + this.priority = priority; + this.sticky = sticky; } @Override diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index f6699f70..830f8893 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -142,7 +142,8 @@ private List findSubscriberMethodsWithReflection(Class subs if (eventTypesFound.add(methodKey)) { // Only add if not already found in a sub class ThreadMode threadMode = subscribeAnnotation.threadMode(); - subscriberMethods.add(new SubscriberMethod(method, threadMode, eventType)); + subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, + subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification) { diff --git a/EventBus/src/de/greenrobot/event/Subscription.java b/EventBus/src/de/greenrobot/event/Subscription.java index 6c84c440..868cbebe 100644 --- a/EventBus/src/de/greenrobot/event/Subscription.java +++ b/EventBus/src/de/greenrobot/event/Subscription.java @@ -18,17 +18,15 @@ final class Subscription { final Object subscriber; final SubscriberMethod subscriberMethod; - final int priority; /** * Becomes false as soon as {@link EventBus#unregister(Object)} is called, which is checked by queued event delivery * {@link EventBus#invokeSubscriber(PendingPost)} to prevent race conditions. */ volatile boolean active; - Subscription(Object subscriber, SubscriberMethod subscriberMethod, int priority) { + Subscription(Object subscriber, SubscriberMethod subscriberMethod) { this.subscriber = subscriber; this.subscriberMethod = subscriberMethod; - this.priority = priority; active = true; } diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 1af29114..3add6d64 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -255,7 +255,8 @@ private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClas writeLine(writer, 4, "createSubscriberMethod(" + subscriberClassString + ",", "\"" + methodName + "\",", paramType.toString() + ".class,", - "ThreadMode." + subscribe.threadMode().name() + "),"); + "ThreadMode." + subscribe.threadMode().name() + ", " + + subscribe.priority() + ", " + subscribe.sticky(), "),"); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + method.getEnclosingElement().getSimpleName() + "." + methodName + diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 0950f71c..748adcaa 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -30,10 +30,10 @@ public class EventBusCancelEventDeliveryTest extends AbstractEventBusTest { private Throwable failed; public void testCancel() { - Subscriber canceler = new Subscriber(true); - eventBus.register(new Subscriber(false)); - eventBus.register(canceler, 1); - eventBus.register(new Subscriber(false)); + Subscriber canceler = new Subscriber(1, true); + eventBus.register(new Subscriber(0, false)); + eventBus.register(canceler); + eventBus.register(new Subscriber(0, false)); eventBus.post("42"); assertEquals(1, eventCount.intValue()); @@ -43,10 +43,9 @@ public void testCancel() { } public void testCancelInBetween() { - Subscriber canceler = new Subscriber(true); - eventBus.register(canceler, 2); - eventBus.register(new Subscriber(false), 1); - eventBus.register(new Subscriber(false), 3); + eventBus.register(new Subscriber(2, true)); + eventBus.register(new Subscriber(1, false)); + eventBus.register(new Subscriber(3, false)); eventBus.post("42"); assertEquals(2, eventCount.intValue()); } @@ -78,17 +77,40 @@ public void testCancelInMainThread() { } public class Subscriber { + private final int prio; private final boolean cancel; - public Subscriber(boolean cancel) { + public Subscriber(int prio, boolean cancel) { + this.prio = prio; this.cancel = cancel; } @Subscribe public void onEvent(String event) { - trackEvent(event); - if (cancel) { - eventBus.cancelEventDelivery(event); + handleEvent(event, 0); + } + + @Subscribe(priority = 1) + public void onEvent1(String event) { + handleEvent(event, 1); + } + + @Subscribe(priority = 2) + public void onEvent2(String event) { + handleEvent(event, 2); + } + + @Subscribe(priority = 3) + public void onEvent3(String event) { + handleEvent(event, 3); + } + + private void handleEvent(String event, int prio) { + if(this.prio == prio) { + trackEvent(event); + if (cancel) { + eventBus.cancelEventDelivery(event); + } } } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 20a5195c..70eb9bde 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -57,7 +57,7 @@ public void testEventClassHierarchySticky() { eventBus.postSticky("Hello"); eventBus.postSticky(new MyEvent()); eventBus.postSticky(new MyEventExtended()); - eventBus.registerSticky(this); + eventBus.register(new StickySubscriber()); assertEquals(1, countMyEventExtended); assertEquals(1, countMyEvent); assertEquals(0, countObjectEvent); @@ -168,4 +168,31 @@ public void onEvent(MyEvent event) { static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceDisabledTest { } + public class StickySubscriber { + @Subscribe(sticky = true) + public void onEvent(Object event) { + countObjectEvent++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEvent event) { + countMyEvent++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventExtended event) { + countMyEventExtended++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventInterface event) { + countMyEventInterface++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventInterfaceExtended event) { + countMyEventInterfaceExtended++; + } + } + } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index dd93a757..183fe89d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -60,7 +60,7 @@ public void testEventClassHierarchySticky() { eventBus.postSticky("Hello"); eventBus.postSticky(new MyEvent()); eventBus.postSticky(new MyEventExtended()); - eventBus.registerSticky(this); + eventBus.register(new StickySubscriber()); assertEquals(1, countMyEventExtended); assertEquals(2, countMyEvent); assertEquals(3, countObjectEvent); @@ -171,4 +171,31 @@ public void onEvent(MyEvent event) { static class SubscriberExtendedWithoutNewSubscriberMethod extends EventBusInheritanceTest { } + public class StickySubscriber { + @Subscribe(sticky = true) + public void onEvent(Object event) { + countObjectEvent++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEvent event) { + countMyEvent++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventExtended event) { + countMyEventExtended++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventInterface event) { + countMyEventInterface++; + } + + @Subscribe(sticky = true) + public void onEvent(MyEventInterfaceExtended event) { + countMyEventInterfaceExtended++; + } + } + } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 1864da54..5bba1a64 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -15,13 +15,13 @@ */ package de.greenrobot.event.test; -import java.util.ArrayList; -import java.util.List; - -import de.greenrobot.event.EventBus; import android.util.Log; -import de.greenrobot.event.ThreadMode; +import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; + +import java.util.ArrayList; +import java.util.List; /** * @author Markus Junginger, greenrobot @@ -33,87 +33,167 @@ public class EventBusOrderedSubscriptionsTest extends AbstractEventBusTest { private String fail; public void testOrdered() { - runTestOrdered("42", false); + runTestOrdered("42", false, 5); } public void testOrderedMainThread() { - runTestOrdered(new IntTestEvent(42), false); + runTestOrdered(new IntTestEvent(42), false, 3); } public void testOrderedBackgroundThread() { - runTestOrdered(Integer.valueOf(42), false); + runTestOrdered(Integer.valueOf(42), false, 3); } - + public void testOrderedSticky() { - runTestOrdered("42", true); + runTestOrdered("42", true, 5); } public void testOrderedMainThreadSticky() { - runTestOrdered(new IntTestEvent(42), true); + runTestOrdered(new IntTestEvent(42), true, 3); } public void testOrderedBackgroundThreadSticky() { - runTestOrdered(Integer.valueOf(42), true); + runTestOrdered(Integer.valueOf(42), true, 3); } - protected void runTestOrdered(Object event, boolean sticky) { - register(1, sticky); - register(-1, sticky); - register(10, sticky); - register(0, sticky); - register(-100, sticky); - assertEquals(5, registered.size()); - + protected void runTestOrdered(Object event, boolean sticky, int expectedEventCount) { + Object subscriber = sticky ? new PrioSubscriberSticky() : new PrioSubscriber(); + eventBus.register(subscriber); eventBus.post(event); - waitForEventCount(5, 10000); + waitForEventCount(expectedEventCount, 10000); assertEquals(null, fail); - unregisterAll(); + eventBus.unregister(subscriber); } - private void unregisterAll() { - for (PrioSubscriber subscriber : registered) { - eventBus.unregister(subscriber); + public final class PrioSubscriber { + @Subscribe(priority = 1) + public void onEventP1(String event) { + handleEvent(1, event); } - } - protected PrioSubscriber register(int priority, boolean sticky) { - PrioSubscriber subscriber = new PrioSubscriber(priority); - if (sticky) { - eventBus.registerSticky(subscriber, priority); - } else { - eventBus.register(subscriber, priority); + @Subscribe(priority = -1) + public void onEventM1(String event) { + handleEvent(-1, event); } - registered.add(subscriber); - return subscriber; - } - public final class PrioSubscriber { + @Subscribe(priority = 0) + public void onEventP0(String event) { + handleEvent(0, event); + } - final int prio; + @Subscribe(priority = 10) + public void onEventP10(String event) { + handleEvent(10, event); + } - public PrioSubscriber(int prio) { - this.prio = prio; - // TODO Auto-generated constructor stub + @Subscribe(priority = -100) + public void onEventM100(String event) { + handleEvent(-100, event); } - @Subscribe - public void onEvent(String event) { - handleEvent(event); + + @Subscribe(threadMode = ThreadMode.MainThread, priority = -1) + public void onEventMainThreadM1(IntTestEvent event) { + handleEvent(-1, event); } @Subscribe(threadMode = ThreadMode.MainThread) - public void onEventMainThread(IntTestEvent event) { - handleEvent(event); + public void onEventMainThreadP0(IntTestEvent event) { + handleEvent(0, event); + } + + @Subscribe(threadMode = ThreadMode.MainThread, priority = 1) + public void onEventMainThreadP1(IntTestEvent event) { + handleEvent(1, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = 1) + public void onEventBackgroundThreadP1(Integer event) { + handleEvent(1, event); } @Subscribe(threadMode = ThreadMode.BackgroundThread) - public void onEventBackgroundThread(Integer event) { - handleEvent(event); + public void onEventBackgroundThreadP0(Integer event) { + handleEvent(0, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = -1) + public void onEventBackgroundThreadM1(Integer event) { + handleEvent(-1, event); + } + + protected void handleEvent(int prio, Object event) { + if (prio > lastPrio) { + fail = "Called prio " + prio + " after " + lastPrio; + } + lastPrio = prio; + + Log.d(EventBus.TAG, "Subscriber " + prio + " got: " + event); + trackEvent(event); + } + + } + + public final class PrioSubscriberSticky { + @Subscribe(priority = 1, sticky = true) + public void onEventP1(String event) { + handleEvent(1, event); + } + + + @Subscribe(priority = -1, sticky = true) + public void onEventM1(String event) { + handleEvent(-1, event); + } + + @Subscribe(priority = 0, sticky = true) + public void onEventP0(String event) { + handleEvent(0, event); + } + + @Subscribe(priority = 10, sticky = true) + public void onEventP10(String event) { + handleEvent(10, event); + } + + @Subscribe(priority = -100, sticky = true) + public void onEventM100(String event) { + handleEvent(-100, event); + } + + @Subscribe(threadMode = ThreadMode.MainThread, priority = -1, sticky = true) + public void onEventMainThreadM1(IntTestEvent event) { + handleEvent(-1, event); + } + + @Subscribe(threadMode = ThreadMode.MainThread, sticky = true) + public void onEventMainThreadP0(IntTestEvent event) { + handleEvent(0, event); + } + + @Subscribe(threadMode = ThreadMode.MainThread, priority = 1, sticky = true) + public void onEventMainThreadP1(IntTestEvent event) { + handleEvent(1, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = 1, sticky = true) + public void onEventBackgroundThreadP1(Integer event) { + handleEvent(1, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, sticky = true) + public void onEventBackgroundThreadP0(Integer event) { + handleEvent(0, event); + } + + @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = -1, sticky = true) + public void onEventBackgroundThreadM1(Integer event) { + handleEvent(-1, event); } - protected void handleEvent(Object event) { + protected void handleEvent(int prio, Object event) { if (prio > lastPrio) { fail = "Called prio " + prio + " after " + lastPrio; } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 9223bb32..d092ae8d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -24,7 +24,7 @@ public class EventBusStickyEventTest extends AbstractEventBusTest { public void testPostSticky() throws InterruptedException { eventBus.postSticky("Sticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals("Sticky", lastEvent); assertEquals(Thread.currentThread(), lastThread); } @@ -32,20 +32,20 @@ public void testPostSticky() throws InterruptedException { public void testPostStickyTwoEvents() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky(new IntTestEvent(7)); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals(2, eventCount.intValue()); } public void testPostStickyRegisterNonSticky() throws InterruptedException { eventBus.postSticky("Sticky"); - eventBus.register(this); + eventBus.register(new NonStickySubscriber()); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } public void testPostNonStickyRegisterSticky() throws InterruptedException { eventBus.post("NonSticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } @@ -53,24 +53,24 @@ public void testPostNonStickyRegisterSticky() throws InterruptedException { public void testPostStickyTwice() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky("NewSticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals("NewSticky", lastEvent); } public void testPostStickyThenPostNormal() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.post("NonSticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals("Sticky", lastEvent); } public void testPostStickyWithRegisterAndUnregister() throws InterruptedException { - eventBus.registerSticky(this); + eventBus.register(this); eventBus.postSticky("Sticky"); assertEquals("Sticky", lastEvent); eventBus.unregister(this); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals("Sticky", lastEvent); assertEquals(2, eventCount.intValue()); @@ -79,7 +79,7 @@ public void testPostStickyWithRegisterAndUnregister() throws InterruptedExceptio assertEquals("NewSticky", lastEvent); eventBus.unregister(this); - eventBus.registerSticky(this); + eventBus.register(this); assertEquals(4, eventCount.intValue()); assertEquals("NewSticky", lastEvent); } @@ -93,7 +93,7 @@ public void testPostStickyRemoveClass() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.removeStickyEvent(String.class); assertNull(eventBus.getStickyEvent(String.class)); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } @@ -102,7 +102,7 @@ public void testPostStickyRemoveEvent() throws InterruptedException { eventBus.postSticky("Sticky"); assertTrue(eventBus.removeStickyEvent("Sticky")); assertNull(eventBus.getStickyEvent(String.class)); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } @@ -113,35 +113,47 @@ public void testPostStickyRemoveAll() throws InterruptedException { eventBus.removeAllStickyEvents(); assertNull(eventBus.getStickyEvent(String.class)); assertNull(eventBus.getStickyEvent(IntTestEvent.class)); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); } public void testRemoveStickyEventInSubscriber() throws InterruptedException { - eventBus.registerSticky(new RemoveStickySubscriber()); + eventBus.register(new RemoveStickySubscriber()); eventBus.postSticky("Sticky"); - eventBus.registerSticky(this); + eventBus.register(this); assertNull(lastEvent); assertEquals(0, eventCount.intValue()); assertNull(eventBus.getStickyEvent(String.class)); } - @Subscribe + @Subscribe(sticky = true) public void onEvent(String event) { trackEvent(event); } - @Subscribe + @Subscribe(sticky = true) public void onEvent(IntTestEvent event) { trackEvent(event); } public class RemoveStickySubscriber { @SuppressWarnings("unused") - @Subscribe + @Subscribe(sticky = true) public void onEvent(String event) { eventBus.removeStickyEvent(event); } } + + public class NonStickySubscriber { + @Subscribe + public void onEvent(String event) { + trackEvent(event); + } + + @Subscribe + public void onEvent(IntTestEvent event) { + trackEvent(event); + } + } } From 56787cdabbdc3985e7917860689297b9eebc3051 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Jun 2015 10:50:41 +0200 Subject: [PATCH 029/112] version 3.0.0-beta1 --- EventBus/build.gradle | 2 +- EventBusAnnotationProcessor/build.gradle | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index b8ad8c0f..7fac0de5 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-SNAPSHOT' +version = '3.0.0-beta1' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index ffe5eba5..bd761ddc 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-SNAPSHOT' +version = '3.0.0-beta1' sourceCompatibility = 1.6 @@ -43,6 +43,17 @@ sourceSets { } } +javadoc { + classpath += configurations.provided + title = "EventBus Annotation Processor ${version} API" + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015 greenrobot.de. All Rights Reserved.' +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from 'build/docs/javadoc' +} + task sourcesJar(type: Jar) { from sourceSets.main.allSource classifier = 'sources' @@ -50,6 +61,7 @@ task sourcesJar(type: Jar) { artifacts { archives jar + archives javadocJar archives sourcesJar } From 06ae2be5cddff51fd12e22d8e2102ba78d3823e1 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Jun 2015 12:09:08 +0200 Subject: [PATCH 030/112] upgrade otto to 1.3.7 --- EventBusPerformance/build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 46f10f86..d391c75b 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { compile project(':EventBus') provided project(':EventBusAnnotationProcessor') - compile 'com.squareup:otto:1.3.6' + compile 'com.squareup:otto:1.3.7' } android { @@ -30,7 +30,6 @@ android { java.srcDirs = ['src'] res.srcDirs = ['res'] } - } } From 0b3fbb9ba26ee98d4337c13bc96775ea67f93d58 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Jun 2015 12:10:37 +0200 Subject: [PATCH 031/112] work around for Class.isAnonymousClass() that is super slow, added ignoreGeneratedIndex builder flag, updated performance app with the new flag --- .../src/de/greenrobot/event/EventBus.java | 10 ++++++++-- .../de/greenrobot/event/EventBusBuilder.java | 7 +++++++ .../event/SubscriberMethodFinder.java | 6 ++++-- .../res/layout/activity_setuptests.xml | 8 ++++++++ EventBusPerformance/res/values/strings.xml | 1 + .../de/greenrobot/eventperf/TestParams.java | 9 +++++++++ .../eventperf/TestSetupActivity.java | 1 + .../testsubject/PerfTestEventBus.java | 20 +++++++++++++------ 8 files changed, 52 insertions(+), 10 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 22a99f63..a8b6e0bb 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -109,7 +109,7 @@ public EventBus() { mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); - subscriberMethodFinder = new SubscriberMethodFinder(/* TODO */ false); + subscriberMethodFinder = new SubscriberMethodFinder(/* TODO */ false, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; @@ -130,8 +130,14 @@ public EventBus() { */ public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); + // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection - boolean forceReflection = subscriberClass.isAnonymousClass(); + // Note: Avoid Class.isAnonymousClass() because it is super slow (getSimpleName() is super slow, too) + String name = subscriberClass.getName(); + int dollarIndex = name.lastIndexOf('$'); + boolean forceReflection = dollarIndex != -1 && dollarIndex < name.length() - 1 && + Character.isDigit(name.charAt(dollarIndex + 1)); + List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass, forceReflection); for (SubscriberMethod subscriberMethod : subscriberMethods) { diff --git a/EventBus/src/de/greenrobot/event/EventBusBuilder.java b/EventBus/src/de/greenrobot/event/EventBusBuilder.java index 06350609..c8b75a6d 100644 --- a/EventBus/src/de/greenrobot/event/EventBusBuilder.java +++ b/EventBus/src/de/greenrobot/event/EventBusBuilder.java @@ -33,6 +33,7 @@ public class EventBusBuilder { boolean sendNoSubscriberEvent = true; boolean throwSubscriberException; boolean eventInheritance = true; + boolean ignoreGeneratedIndex; ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List> skipMethodVerificationForClasses; @@ -111,6 +112,12 @@ public EventBusBuilder skipMethodVerificationFor(Class clazz) { return this; } + /** Forces the use of reflection even if there's a generated index (default: false). */ + public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) { + this.ignoreGeneratedIndex = ignoreGeneratedIndex; + return this; + } + /** * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be * done only once before the first usage of the default EventBus. diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 830f8893..4951a7f2 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -56,9 +56,11 @@ class SubscriberMethodFinder { } private final boolean strictMethodVerification; + private final boolean ignoreGeneratedIndex; - SubscriberMethodFinder(boolean strictMethodVerification) { + SubscriberMethodFinder(boolean strictMethodVerification, boolean ignoreGeneratedIndex) { this.strictMethodVerification = strictMethodVerification; + this.ignoreGeneratedIndex = ignoreGeneratedIndex; } List findSubscriberMethods(Class subscriberClass, boolean forceReflection) { @@ -70,7 +72,7 @@ List findSubscriberMethods(Class subscriberClass, boolean f if (subscriberMethods != null) { return subscriberMethods; } - if (INDEX != null && !forceReflection) { + if (!ignoreGeneratedIndex && INDEX != null && !forceReflection) { subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); if (subscriberMethods.isEmpty()) { subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); diff --git a/EventBusPerformance/res/layout/activity_setuptests.xml b/EventBusPerformance/res/layout/activity_setuptests.xml index da77afe6..27064758 100644 --- a/EventBusPerformance/res/layout/activity_setuptests.xml +++ b/EventBusPerformance/res/layout/activity_setuptests.xml @@ -51,6 +51,14 @@ android:layout_marginLeft="48dp" android:text="@string/test_eventBusEventHierarchy" /> + + Event Performance EventBus Event Inheritance + Ignore generated index OttoBus Broadcast Local Broadcast diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java index 1cebfec2..0776bd53 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java @@ -13,6 +13,7 @@ public class TestParams implements Serializable { private int publisherCount; private ThreadMode threadMode; private boolean eventInheritance; + private boolean ignoreGeneratedIndex; private int testNumber; private ArrayList> testClasses; @@ -56,6 +57,14 @@ public void setEventInheritance(boolean eventInheritance) { this.eventInheritance = eventInheritance; } + public boolean isIgnoreGeneratedIndex() { + return ignoreGeneratedIndex; + } + + public void setIgnoreGeneratedIndex(boolean ignoreGeneratedIndex) { + this.ignoreGeneratedIndex = ignoreGeneratedIndex; + } + public ArrayList> getTestClasses() { return testClasses; } diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java index 2b018b41..6b760baf 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java @@ -61,6 +61,7 @@ public void startClick(View v) { params.setThreadMode(threadMode); params.setEventInheritance(((CheckBox) findViewById(R.id.checkBoxEventBusEventHierarchy)).isChecked()); + params.setIgnoreGeneratedIndex(((CheckBox) findViewById(R.id.checkBoxEventBusIgnoreGeneratedIndex)).isChecked()); EditText editTextEvent = (EditText) findViewById(R.id.editTextEvent); params.setEventCount(Integer.parseInt(editTextEvent.getText().toString())); diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 66bf9131..df8b13a3 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -22,7 +22,8 @@ public abstract class PerfTestEventBus extends Test { public PerfTestEventBus(Context context, TestParams params) { super(context, params); - eventBus = EventBus.builder().eventInheritance(params.isEventInheritance()).build(); + eventBus = EventBus.builder().eventInheritance(params.isEventInheritance()) + .ignoreGeneratedIndex(params.isIgnoreGeneratedIndex()).build(); subscribers = new ArrayList(); eventCount = params.getEventCount(); expectedEventCount = eventCount * params.getSubscriberCount(); @@ -57,6 +58,13 @@ private Class getSubscriberClassForThreadMode() { } } + private static String getDisplayModifier(TestParams params) { + String inheritance = params.isEventInheritance() ? "" : ", no event inheritance"; + String ignoreIndex = params.isIgnoreGeneratedIndex() ? ", ignore index" : ""; + return inheritance + ignoreIndex; + } + + public static class Post extends PerfTestEventBus { public Post(Context context, TestParams params) { super(context, params); @@ -91,9 +99,9 @@ public void runTest() { @Override public String getDisplayName() { - String inheritance = params.isEventInheritance() ? ", event inheritance" : ", no event inheritance"; - return "EventBus Post Events, " + params.getThreadMode() + inheritance; + return "EventBus Post Events, " + params.getThreadMode() + getDisplayModifier(params); } + } public static class RegisterAll extends PerfTestEventBus { @@ -110,7 +118,7 @@ public void runTest() { @Override public String getDisplayName() { - return "EventBus Register, no unregister"; + return "EventBus Register, no unregister" + getDisplayModifier(params); } } @@ -151,7 +159,7 @@ public void runTest() { @Override public String getDisplayName() { - return "EventBus Register"; + return "EventBus Register" + getDisplayModifier(params); } } @@ -170,7 +178,7 @@ public RegisterFirstTime(Context context, TestParams params) { @Override public String getDisplayName() { - return "EventBus Register, first time"; + return "EventBus Register, first time"+ getDisplayModifier(params); } } From b2f02b92297066d56a3be2d002e1a3140992c4e7 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Jun 2015 22:08:43 +0200 Subject: [PATCH 032/112] typo with unsubscribeByEventType --- EventBus/src/de/greenrobot/event/EventBus.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index a8b6e0bb..33817aa8 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -215,7 +215,7 @@ public synchronized boolean isRegistered(Object subscriber) { } /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */ - private void unubscribeByEventType(Object subscriber, Class eventType) { + private void unsubscribeByEventType(Object subscriber, Class eventType) { List subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { // Got to synchronize to avoid shifted positions when adding/removing concurrently @@ -239,7 +239,7 @@ public synchronized void unregister(Object subscriber) { List> subscribedTypes = typesBySubscriber.get(subscriber); if (subscribedTypes != null) { for (Class eventType : subscribedTypes) { - unubscribeByEventType(subscriber, eventType); + unsubscribeByEventType(subscriber, eventType); } typesBySubscriber.remove(subscriber); } else { From 1b556731c410b49639d668ff2c76dcb1ddcbaffb Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 5 Jun 2015 07:49:28 +0200 Subject: [PATCH 033/112] added EventBusSubscriberInJarTest --- EventBusTest/build.gradle | 1 + ...ventBusTestSubscriberInJar-3.0.0-beta1.jar | Bin 0 -> 1351 bytes .../test/EventBusSubscriberInJarTest.java | 17 +++++++++++++++ EventBusTestSubscriberInJar/build.gradle | 17 +++++++++++++++ .../event/test/SubscriberInJar.java | 20 ++++++++++++++++++ settings.gradle | 1 + 6 files changed, 56 insertions(+) create mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar create mode 100644 EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java create mode 100644 EventBusTestSubscriberInJar/build.gradle create mode 100644 EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 80248410..3e30de69 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -19,6 +19,7 @@ repositories { dependencies { androidTestApt project(':EventBusAnnotationProcessor') androidTestCompile project(':EventBus') + compile fileTree(dir: 'libs', include: '*.jar') } android { diff --git a/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar b/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar new file mode 100644 index 0000000000000000000000000000000000000000..bdfeab2124918adea44f041f85c5d9586c515c7c GIT binary patch literal 1351 zcmWIWW@h1HVBp|jxNd#ajR6RlKm-tQ0iYh?4Z8)YQD9{G|L6ysAO20~&~=I<+h{55FFeudwMUNiD|IXn8&3)H6l~hUq}3 z>*3QFT$)szT$GuVTI8AMl~|;goRe5w+#8geeZ@hb?pvJD`&swqUJqNVzxGo0CwT2S};(iG;UL5F*NL{HxQw|Wk@>Xf}= z+{HUgF8oW_VRLD(>IeDe9RJHP?T=<|X^xD4@q451#|Md1yW%g&W}Lkr?Z+Q}q3Gj* z!*X&)Jpan)ZDF0B6nEBtg<{*e`Bg8kf6|DOD3P?5+qYP?IO8jWn|$Yj-M(SG+AAje zcD;NfV5C{Iz}$*my4LyaTgzATFaC&dDSx?THFr|RgsaM@wI3IX{%xw~eJzr>bKa%g zWwP2_4FH@7WzoyVv7Ld@p+sT*C#qoi95W7Kai{OxvdU*~Mm-Tw2|-r4d-UN2)V z)0_WlYa;`v@!nT@Q_B)Ls5=cDi~uk+ Bqmuvt literal 0 HcmV?d00001 diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java new file mode 100644 index 00000000..60882fc7 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java @@ -0,0 +1,17 @@ +package de.greenrobot.event.test; + +import de.greenrobot.event.EventBus; +import junit.framework.Assert; +import junit.framework.TestCase; + +public class EventBusSubscriberInJarTest extends TestCase { + public void testSubscriberInJar() { + SubscriberInJar subscriber = new SubscriberInJar(); + EventBus eventBus = EventBus.builder().build(); + eventBus.register(subscriber); + eventBus.post("Hi Jar"); + eventBus.post(42); + Assert.assertEquals(1, subscriber.getCollectedStrings().size()); + Assert.assertEquals("Hi Jar", subscriber.getCollectedStrings().get(0)); + } +} diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle new file mode 100644 index 00000000..7eab9494 --- /dev/null +++ b/EventBusTestSubscriberInJar/build.gradle @@ -0,0 +1,17 @@ +apply plugin: 'java' + +group = 'de.greenrobot' +version = '3.0.0-beta1' +sourceCompatibility = 1.6 + +dependencies { + compile project(':EventBus') +} + +sourceSets { + main { + java { + srcDir 'src' + } + } +} diff --git a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java b/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java new file mode 100644 index 00000000..ea3bba4e --- /dev/null +++ b/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java @@ -0,0 +1,20 @@ +package de.greenrobot.event.test; + +import de.greenrobot.event.Subscribe; + +import java.util.ArrayList; +import java.util.List; + +/** Helper class used by test inside a jar. */ +public class SubscriberInJar { + List collectedStrings = new ArrayList(); + + @Subscribe + public void collectString(String string) { + collectedStrings.add(string); + } + + public List getCollectedStrings() { + return collectedStrings; + } +} diff --git a/settings.gradle b/settings.gradle index d51c4e7b..a11c17d8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,4 +1,5 @@ include 'EventBus' include 'EventBusAnnotationProcessor' include 'EventBusTest' +include 'EventBusTestSubscriberInJar' include 'EventBusPerformance' From e9bc508737685db41e5469a62567fded7b6e82c1 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 15 Jun 2015 18:27:49 +0200 Subject: [PATCH 034/112] fix code gen for ignored classes --- .../EventBusAnnotationProcessor.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 3add6d64..65630d92 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -219,7 +219,7 @@ private void writeSources() { } writer.write(" };\n"); } - if (!methodsByClass.isEmpty()) { + if (!first) { writer.write(" }\n"); } writer.write(" return null;\n"); @@ -227,10 +227,12 @@ private void writeSources() { } catch (IOException e) { throw new RuntimeException("Could not write source for " + className, e); } finally { - try { - writer.close(); - } catch (IOException e) { - //Silent + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + //Silent + } } } } From fd8a4c837cd80cd13879f97128b14500ab236508 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 19 Jun 2015 17:26:24 +0200 Subject: [PATCH 035/112] generating one SubscriberInfo per subscriber class --- EventBus/build.gradle | 2 +- .../de/greenrobot/event/SubscriberIndex.java | 35 ----- .../de/greenrobot/event/SubscriberInfo.java | 47 ++++++ .../de/greenrobot/event/SubscriberMethod.java | 3 +- .../event/SubscriberMethodFinder.java | 8 +- EventBusAnnotationProcessor/build.gradle | 2 +- .../EventBusAnnotationProcessor.java | 138 +++++++++++------- EventBusTestSubscriberInJar/build.gradle | 3 +- 8 files changed, 145 insertions(+), 93 deletions(-) delete mode 100644 EventBus/src/de/greenrobot/event/SubscriberIndex.java create mode 100644 EventBus/src/de/greenrobot/event/SubscriberInfo.java diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 7fac0de5..0193f2dd 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-beta1' +version = '3.0.0-beta2' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/EventBus/src/de/greenrobot/event/SubscriberIndex.java b/EventBus/src/de/greenrobot/event/SubscriberIndex.java deleted file mode 100644 index 8dbee7f6..00000000 --- a/EventBus/src/de/greenrobot/event/SubscriberIndex.java +++ /dev/null @@ -1,35 +0,0 @@ -package de.greenrobot.event; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -/** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ -abstract class SubscriberIndex { - private Map, SubscriberMethod[]> map = new HashMap, SubscriberMethod[]>(); - - SubscriberMethod[] getSubscribersFor(Class subscriberClass) { - SubscriberMethod[] entries = map.get(subscriberClass); - if (entries == null) { - entries = createSubscribersFor(subscriberClass); - if (entries != null) { - map.put(subscriberClass, entries); - } - } - return entries; - } - - abstract SubscriberMethod[] createSubscribersFor(Class subscriberClass); - - SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, - ThreadMode threadMode, int priority, boolean sticky) { - try { - Method method = subscriberClass.getDeclaredMethod(methodName, eventType); - return new SubscriberMethod(method, eventType, threadMode, priority, sticky); - } catch (NoSuchMethodException e) { - throw new EventBusException("Could not find subscriber method in " + subscriberClass + - ". Maybe a missing ProGuard rule?", e); - } - } - -} diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java new file mode 100644 index 00000000..f544528f --- /dev/null +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -0,0 +1,47 @@ +package de.greenrobot.event; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ +public abstract class SubscriberInfo { + public static class Data { + public final Class subscriberClass; + public final SubscriberMethod[] subscriberMethods; + public final Class nextInfo; + + public Data(Class subscriberClass, SubscriberMethod[] subscriberMethods, Class nextInfo) { + this.subscriberClass = subscriberClass; + this.subscriberMethods = subscriberMethods; + this.nextInfo = nextInfo; + } + } + + private Map, Data> map = new HashMap, Data>(); + + Data getSubscriberData(Class subscriberClass) { + Data data = map.get(subscriberClass); + if (data == null) { + data = createSubscriberData(); + if (data != null) { + map.put(subscriberClass, data); + } + } + return data; + } + + abstract protected Data createSubscriberData(); + + protected SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, + ThreadMode threadMode, int priority, boolean sticky) { + try { + Method method = subscriberClass.getDeclaredMethod(methodName, eventType); + return new SubscriberMethod(method, eventType, threadMode, priority, sticky); + } catch (NoSuchMethodException e) { + throw new EventBusException("Could not find subscriber method in " + subscriberClass + + ". Maybe a missing ProGuard rule?", e); + } + } + +} diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/de/greenrobot/event/SubscriberMethod.java index 1dcd74f1..4d77446a 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethod.java @@ -17,7 +17,8 @@ import java.lang.reflect.Method; -final class SubscriberMethod { +/** Used internally by EventBus and generated subscriber indexes. */ +public class SubscriberMethod { final Method method; final ThreadMode threadMode; final Class eventType; diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 4951a7f2..da737f48 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -39,13 +39,13 @@ class SubscriberMethodFinder { private static final Map> METHOD_CACHE = new HashMap>(); /** Optional generated index without entries from subscribers super classes */ - private static final SubscriberIndex INDEX; + private static final SubscriberInfo INDEX; static { - SubscriberIndex newIndex = null; + SubscriberInfo newIndex = null; try { Class clazz = Class.forName("de.greenrobot.event.GeneratedSubscriberIndex"); - newIndex = (SubscriberIndex) clazz.newInstance(); + newIndex = (SubscriberInfo) clazz.newInstance(); } catch (ClassNotFoundException e) { Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up"); // Fine @@ -94,7 +94,7 @@ List findSubscriberMethods(Class subscriberClass, boolean f private List findSubscriberMethodsWithIndex(Class subscriberClass) { Class clazz = subscriberClass; while (clazz != null) { - SubscriberMethod[] array = INDEX.getSubscribersFor(clazz); + SubscriberMethod[] array = null; //TODO INDEX.getSubscriberData(clazz); if (array != null && array.length > 0) { List subscriberMethods = new ArrayList(); for (SubscriberMethod subscriberMethod : array) { diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index bd761ddc..72b0ac29 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'maven' apply plugin: 'signing' group = 'de.greenrobot' -version = '3.0.0-beta1' +version = '3.0.0-beta2' sourceCompatibility = 1.6 diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 65630d92..e3310c6a 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -11,6 +11,7 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; +import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; @@ -29,6 +30,7 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") @SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { + public static final String CLASS_POSTFIX = "_EventBusInfo"; private final Map> methodsByClass = new HashMap>(); private final Set classesToSkip = new HashSet(); @@ -178,66 +180,101 @@ private TypeElement getSuperclass(TypeElement type) { } private void writeSources() { - String pack = "de.greenrobot.event"; - String className = "GeneratedSubscriberIndex"; - BufferedWriter writer = null; - try { - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(pack + '.' + className); - writer = new BufferedWriter(sourceFile.openWriter()); - writer.write("package de.greenrobot.event;\n\n"); - // writer.write("import de.greenrobot.event.SubscriberIndexEntry;\n"); - // writer.write("import de.greenrobot.event.ThreadMode;\n\n"); - writer.write("/** This class is generated by EventBus, do not edit. */\n"); - writer.write("class " + className + " extends SubscriberIndex {\n"); - writer.write(" SubscriberMethod[] createSubscribersFor(Class subscriberClass) {\n"); + List>> entries = + new ArrayList>>(methodsByClass.entrySet()); + for (int i = 0; i < entries.size(); i++) { + Map.Entry> entry = entries.get(i); + TypeElement subscriberClass = entry.getKey(); + if (classesToSkip.contains(subscriberClass)) { + continue; + } - boolean first = true; - for (Map.Entry> entry : methodsByClass.entrySet()) { - TypeElement subscriberClass = entry.getKey(); - if (classesToSkip.contains(subscriberClass)) { - continue; - } - String ifPrefix; - if (first) { - ifPrefix = ""; - first = false; - } else { - ifPrefix = "} else "; - } - writeLine(writer, 2, ifPrefix + "if(subscriberClass ==", subscriberClass.asType() + ".class) {"); - writer.write(" return new SubscriberMethod[] {\n"); + BufferedWriter writer = null; + try { + PackageElement packageElement = getPackageElement(subscriberClass); + String myPackage = packageElement.getQualifiedName().toString(); + String subscriberClassName = getClassString(subscriberClass, myPackage); + String infoClassName = subscriberClassName.replace('.', '_') + CLASS_POSTFIX; + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); + writer = new BufferedWriter(sourceFile.openWriter()); + writer.write("package " + myPackage + ";\n\n"); + writer.write("import de.greenrobot.event.SubscriberInfo;\n"); + writer.write("import de.greenrobot.event.SubscriberInfo.Data;\n"); + writer.write("import de.greenrobot.event.SubscriberMethod;\n"); + writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("/** This class is generated by EventBus, do not edit. */\n"); + writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); + writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); + writer.write(" protected Data createSubscriberData() {\n"); + writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); + writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); - writeIndexEntries(writer, null, entry.getValue(), methodSignatures); - TypeElement superclass = getSuperclass(subscriberClass); - while (superclass != null) { - List superClassMethods = methodsByClass.get(superclass); - if (superClassMethods != null) { - writeIndexEntries(writer, superclass, superClassMethods, methodSignatures); + writeMethods(writer, null, entry.getValue(), methodSignatures); + writer.write(" };\n"); + TypeElement nextEntry = nextEntry(entries, entry, i); + writeNextEntry(writer, myPackage, nextEntry); + writer.write(" return new Data(subscriberClass, subscriberMethods, next);\n"); + writer.write(" }\n}\n"); + } catch (IOException e) { + throw new RuntimeException("Could not write source for " + subscriberClass.getQualifiedName(), e); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + //Silent } - superclass = getSuperclass(superclass); } - writer.write(" };\n"); } - if (!first) { - writer.write(" }\n"); + } + } + + private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement nextEntry) throws IOException { + if (nextEntry != null) { + PackageElement nextPackageElement = getPackageElement(nextEntry); + String nextPackage = nextPackageElement.getQualifiedName().toString(); + String nextSubscriberClassName = getClassString(nextEntry, nextPackage); + String nextInfoClassName = nextSubscriberClassName.replace('.', '_') + CLASS_POSTFIX; + if (!myPackage.equals(nextPackage)) { + nextInfoClassName = nextPackage + "." + nextInfoClassName; } - writer.write(" return null;\n"); - writer.write(" };\n}\n"); - } catch (IOException e) { - throw new RuntimeException("Could not write source for " + className, e); - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - //Silent - } + writer.write(" Class next = " + nextInfoClassName + ".class" + ";\n"); + } else { + writer.write(" Class next = null;\n"); + } + } + + private String getClassString(TypeElement subscriberClass, String subscriberPackage) { + int beginIndex = subscriberPackage.length() == 0 ? 0 : subscriberPackage.length() + 1; + return subscriberClass.getQualifiedName().toString().substring(beginIndex); + } + + private PackageElement getPackageElement(TypeElement subscriberClass) { + Element candidate = subscriberClass.getEnclosingElement(); + while (!(candidate instanceof PackageElement)) { + candidate = candidate.getEnclosingElement(); + } + return (PackageElement) candidate; + } + + private TypeElement nextEntry(List>> entries, + Map.Entry> current, int currentIdx) { + for (int i = currentIdx + 1; ; i++) { + if (i == entries.size()) { + i = 0; + } + if (i == currentIdx) { + return null; + } else { + Map.Entry> candidate = entries.get(i); + System.out.println(); + return candidate.getKey(); } } } - private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClass, List methods, Set methodSignatures) throws IOException { + private void writeMethods(BufferedWriter writer, TypeElement subscriberClass, List methods, Set methodSignatures) throws IOException { for (ExecutableElement method : methods) { List parameters = method.getParameters(); @@ -254,7 +291,7 @@ private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClas subscriberClass.asType().toString() + ".class"; Subscribe subscribe = method.getAnnotation(Subscribe.class); - writeLine(writer, 4, "createSubscriberMethod(" + subscriberClassString + ",", + writeLine(writer, 3, "createSubscriberMethod(" + subscriberClassString + ",", "\"" + methodName + "\",", paramType.toString() + ".class,", "ThreadMode." + subscribe.threadMode().name() + ", " + @@ -263,6 +300,7 @@ private void writeIndexEntries(BufferedWriter writer, TypeElement subscriberClas processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + method.getEnclosingElement().getSimpleName() + "." + methodName + "(" + paramType.asElement().getSimpleName() + ")"); + } } diff --git a/EventBusTestSubscriberInJar/build.gradle b/EventBusTestSubscriberInJar/build.gradle index 7eab9494..19afffbf 100644 --- a/EventBusTestSubscriberInJar/build.gradle +++ b/EventBusTestSubscriberInJar/build.gradle @@ -1,11 +1,12 @@ apply plugin: 'java' group = 'de.greenrobot' -version = '3.0.0-beta1' +version = '3.0.0-beta2' sourceCompatibility = 1.6 dependencies { compile project(':EventBus') + compile project(':EventBusAnnotationProcessor') } sourceSets { From 9d7e19298a111097696a50b007d3e985b70c862c Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 22 Jun 2015 18:37:15 +0200 Subject: [PATCH 036/112] reworked SubscriberMethodFinder to use SubscriberInfo whenever possible --- .../de/greenrobot/event/SubscriberInfo.java | 9 +- .../event/SubscriberMethodFinder.java | 189 ++++++++++-------- .../EventBusAnnotationProcessor.java | 5 +- 3 files changed, 109 insertions(+), 94 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index f544528f..00b9ca17 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -6,6 +6,7 @@ /** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ public abstract class SubscriberInfo { + // TODO move class fields into SubscriberInfo public static class Data { public final Class subscriberClass; public final SubscriberMethod[] subscriberMethods; @@ -18,15 +19,11 @@ public Data(Class subscriberClass, SubscriberMethod[] subscriberMethods, Clas } } - private Map, Data> map = new HashMap, Data>(); + private volatile Data data; - Data getSubscriberData(Class subscriberClass) { - Data data = map.get(subscriberClass); + Data getSubscriberData() { if (data == null) { data = createSubscriberData(); - if (data != null) { - map.put(subscriberClass, data); - } } return data; } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index da737f48..96635ef9 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -15,12 +15,9 @@ */ package de.greenrobot.event; -import android.util.Log; - import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -38,23 +35,6 @@ class SubscriberMethodFinder { private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; private static final Map> METHOD_CACHE = new HashMap>(); - /** Optional generated index without entries from subscribers super classes */ - private static final SubscriberInfo INDEX; - - static { - SubscriberInfo newIndex = null; - try { - Class clazz = Class.forName("de.greenrobot.event.GeneratedSubscriberIndex"); - newIndex = (SubscriberInfo) clazz.newInstance(); - } catch (ClassNotFoundException e) { - Log.d(EventBus.TAG, "No subscriber index available, reverting to dynamic look-up"); - // Fine - } catch (Exception e) { - Log.w(EventBus.TAG, "Could not init subscriber index, reverting to dynamic look-up", e); - } - INDEX = newIndex; - } - private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; @@ -72,13 +52,10 @@ List findSubscriberMethods(Class subscriberClass, boolean f if (subscriberMethods != null) { return subscriberMethods; } - if (!ignoreGeneratedIndex && INDEX != null && !forceReflection) { - subscriberMethods = findSubscriberMethodsWithIndex(subscriberClass); - if (subscriberMethods.isEmpty()) { - subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); - } + if (!ignoreGeneratedIndex && !forceReflection) { + subscriberMethods = findUsingInfo(subscriberClass); } else { - subscriberMethods = findSubscriberMethodsWithReflection(subscriberClass); + subscriberMethods = findUsingReflection(subscriberClass); } if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass @@ -91,83 +68,85 @@ List findSubscriberMethods(Class subscriberClass, boolean f } } - private List findSubscriberMethodsWithIndex(Class subscriberClass) { - Class clazz = subscriberClass; - while (clazz != null) { - SubscriberMethod[] array = null; //TODO INDEX.getSubscriberData(clazz); - if (array != null && array.length > 0) { - List subscriberMethods = new ArrayList(); + private List findUsingInfo(Class subscriberClass) { + FindState findState = new FindState(); + findState.initForSubscriber(subscriberClass); + while (findState.clazz != null) { + SubscriberInfo info = getSubscriberInfo(subscriberClass); + if (info != null) { + SubscriberInfo.Data subscriberData = info.getSubscriberData(); + SubscriberMethod[] array = subscriberData.subscriberMethods; for (SubscriberMethod subscriberMethod : array) { - subscriberMethods.add(subscriberMethod); + if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { + findState.subscriberMethods.add(subscriberMethod); + } } - return subscriberMethods; } else { - String name = clazz.getName(); - if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { - // Skip system classes, this just degrades performance - break; - } - clazz = clazz.getSuperclass(); + findUsingReflectionInSingleClass(findState); } + findState.nextClass(); } - return Collections.EMPTY_LIST; + return findState.subscriberMethods; } - private List findSubscriberMethodsWithReflection(Class subscriberClass) { - List subscriberMethods = new ArrayList(); - Class clazz = subscriberClass; - HashSet eventTypesFound = new HashSet(); - StringBuilder methodKeyBuilder = new StringBuilder(); - while (clazz != null) { - String name = clazz.getName(); - if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) { - // Skip system classes, this just degrades performance - break; + private SubscriberInfo getSubscriberInfo(Class subscriberClass) { + SubscriberInfo info = null; + String infoClass = subscriberClass.getName().replace('$', '_') + "_EventBusInfo"; + try { + Class aClass = Class.forName(infoClass); + Object object = aClass.newInstance(); + if (object instanceof SubscriberInfo) { + info = (SubscriberInfo) object; } + } catch (ClassNotFoundException e) { + // TODO don't try again + } catch (Exception e) { + throw new EventBusException("Could not get infos for " + subscriberClass, e); + } + return info; + } - // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) - Method[] methods = clazz.getDeclaredMethods(); - for (Method method : methods) { - int modifiers = method.getModifiers(); - if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { - Class[] parameterTypes = method.getParameterTypes(); - if (parameterTypes.length == 1) { - Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); - if (subscribeAnnotation != null) { - String methodName = method.getName(); - Class eventType = parameterTypes[0]; - methodKeyBuilder.setLength(0); - methodKeyBuilder.append(methodName); - methodKeyBuilder.append('>').append(eventType.getName()); - - String methodKey = methodKeyBuilder.toString(); - if (eventTypesFound.add(methodKey)) { - // Only add if not already found in a sub class - ThreadMode threadMode = subscribeAnnotation.threadMode(); - subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, - subscribeAnnotation.priority(), subscribeAnnotation.sticky())); - } - } - } else if (strictMethodVerification) { - if (method.isAnnotationPresent(Subscribe.class)) { - String methodName = name + "." + method.getName(); - throw new EventBusException("@Subscribe method " + methodName + - "must have exactly 1 parameter but has " + parameterTypes.length); + private List findUsingReflection(Class subscriberClass) { + FindState findState = new FindState(); + findState.initForSubscriber(subscriberClass); + while (findState.clazz != null) { + findUsingReflectionInSingleClass(findState); + findState.nextClass(); + } + return findState.subscriberMethods; + } + + private void findUsingReflectionInSingleClass(FindState findState) { + Method[] methods = findState.clazz.getDeclaredMethods(); + for (Method method : methods) { + int modifiers = method.getModifiers(); + if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { + Class[] parameterTypes = method.getParameterTypes(); + if (parameterTypes.length == 1) { + Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class); + if (subscribeAnnotation != null) { + Class eventType = parameterTypes[0]; + if (findState.checkAdd(method, eventType)) { + ThreadMode threadMode = subscribeAnnotation.threadMode(); + findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode, + subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } } else if (strictMethodVerification) { if (method.isAnnotationPresent(Subscribe.class)) { - String methodName = name + "." + method.getName(); - throw new EventBusException(methodName + - " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); + String methodName = findState.clazzName + "." + method.getName(); + throw new EventBusException("@Subscribe method " + methodName + + "must have exactly 1 parameter but has " + parameterTypes.length); } - + } + } else if (strictMethodVerification) { + if (method.isAnnotationPresent(Subscribe.class)) { + String methodName = findState.clazzName + "." + method.getName(); + throw new EventBusException(methodName + + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } - - clazz = clazz.getSuperclass(); } - return subscriberMethods; } static void clearCaches() { @@ -176,4 +155,42 @@ static void clearCaches() { } } + class FindState { + final List subscriberMethods = new ArrayList(); + final HashSet eventTypesFound = new HashSet(); + final StringBuilder methodKeyBuilder = new StringBuilder(); + Class subscriberClass; + Class clazz; + String clazzName; + + void initForSubscriber(Class subscriberClass) { + this.subscriberClass = clazz = subscriberClass; + } + + void recycle() { + subscriberMethods.clear(); + methodKeyBuilder.setLength(0); + eventTypesFound.clear(); + } + + boolean checkAdd(Method method, Class eventType) { + methodKeyBuilder.setLength(0); + methodKeyBuilder.append(method.getName()); + methodKeyBuilder.append('>').append(eventType.getName()); + + String methodKey = methodKeyBuilder.toString(); + return eventTypesFound.add(methodKey); + } + + void nextClass() { + clazz = clazz.getSuperclass(); + clazzName = clazz.getName(); + /** Skip system classes, this just degrades performance. */ + if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { + clazz = null; + clazzName = null; + } + } + } + } diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index e3310c6a..52b5b9ab 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -268,8 +268,9 @@ private TypeElement nextEntry(List> candidate = entries.get(i); - System.out.println(); - return candidate.getKey(); + if(!classesToSkip.contains(candidate.getKey())) { + return candidate.getKey(); + } } } } From f72fe79cea4ee12e59168c70c96051aa073f9b10 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 22 Jun 2015 23:06:11 +0200 Subject: [PATCH 037/112] travis: build-tools-22.0.1 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e086ce10..defb5481 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ jdk: # http://docs.travis-ci.com/user/languages/android/ android: components: - - build-tools-21.1.2 + - build-tools-22.0.1 - android-10 before_script: From afdbab048b0882cd918970c951723a68f8b27257 Mon Sep 17 00:00:00 2001 From: Evan Baker Date: Sat, 11 Jul 2015 12:01:20 -0400 Subject: [PATCH 038/112] Fully updated HOWTO.md to annotations Updated threading examples to annotations style. Updated priority example to annotations style. Updated sticky example to annotations style. --- HOWTO.md | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/HOWTO.md b/HOWTO.md index 4804f61f..c5f0f561 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -65,6 +65,7 @@ In EventBus, you may define the thread that will call the event handling method Example: ```java // Called in the same thread (default) + @Subscribe(threadmode = ThreadMode.PostThread) // ThreadMode is optional here public void onEvent(MessageEvent event) { log(event.message); } @@ -73,6 +74,7 @@ Example: Example: ```java // Called in Android UI's main thread + @Subscribe(threadMode = ThreadMode.MainThread) public void onEventMainThread(MessageEvent event) { textField.setText(event.message); } @@ -80,6 +82,7 @@ Example: * **BackgroundThread:** Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single background thread that will deliver all its events sequentially. Event handlers using this mode should try to return quickly to avoid blocking the background thread. ```java // Called in the background thread + @Subscribe(threadMode = ThreadMode.BackgroundThread) public void onEventBackgroundThread(MessageEvent event){ saveToDisk(event.message); } @@ -87,20 +90,23 @@ Example: * **Async:** Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. ```java // Called in a separate thread + @Subscribe(threadmode = ThreadMode.Async) public void onEventAsync(MessageEvent event){ backend.send(event.message); } ``` -*Note:* EventBus takes care of calling the `onEvent` method in the proper thread depending on its name (onEvent, onEventAsync, etc.). +*Note:* EventBus takes care of calling the `onEvent` method in the proper thread depending on its annotation. Subscriber priorities and ordered event delivery ------------------------------------------------ You may change the order of event delivery by providing a priority to the subscriber during registration. ```java - int priority = 1; - EventBus.getDefault().register(this, priority); + @Subscribe(priority = 1); + public void onEvent(MessageEvent event) { + ... + } ``` Within the same delivery thread (ThreadMode), higher priority subscribers will receive events before others with a lower priority. The default priority is 0. @@ -140,6 +146,7 @@ You may cancel the event delivery process by calling `cancelEventDelivery(Object Any further event delivery will be cancelled: subsequent subscribers won't receive the event. ```java // Called in the same thread (default) + @Subscribe public void onEvent(MessageEvent event){ // Process the event ... @@ -159,15 +166,17 @@ Let's say, an sticky event was posted some time ago: EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!")); ``` -After that, a new Activity gets started. During registration using registerSticky, it will immediately get the previously posted sticky event: +After that, a new Activity gets started. During registration, and sticky Subscriber methods will immediately get the previously posted sticky event: ```java @Override public void onStart() { super.onStart(); - EventBus.getDefault().registerSticky(this); + EventBus.getDefault().register(this); } - public void onEventMainThread(MessageEvent event) { + @Subscribe(sticky = true, threadmode = ThreadMode.MainThread) + public void onEvent(MessageEvent event) { + // UI updates must run on MainThread textField.setText(event.message); } @@ -185,11 +194,12 @@ You may also get the last sticky event of a certain type with: ProGuard configuration ---------------------- -ProGuard obfuscates method names. However, the onEvent methods must not renamed because they are accessed using reflection. Use the following snip in your ProGuard configuration file (proguard.cfg): +ProGuard obfuscates method names and may remove "unused" methods, including Subscriber methods. Use the following snip in your ProGuard configuration file (proguard.cfg) to prevent Subscribers from being removed: ``` +-keepattributes *Annotation* -keepclassmembers class ** { - public void onEvent*(**); + @de.greenrobot.event.Subscribe public *; } # Only required if you use AsyncExecutor @@ -210,7 +220,7 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E Declare event handling methods - Name conventions + Annotations Annotations From d887e0d57cff66aaab423c869b2136f7d566b86e Mon Sep 17 00:00:00 2001 From: Evan Baker Date: Sat, 11 Jul 2015 13:14:58 -0400 Subject: [PATCH 039/112] threadmode -> threadMode --- HOWTO.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HOWTO.md b/HOWTO.md index c5f0f561..093f61f7 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -65,7 +65,7 @@ In EventBus, you may define the thread that will call the event handling method Example: ```java // Called in the same thread (default) - @Subscribe(threadmode = ThreadMode.PostThread) // ThreadMode is optional here + @Subscribe(threadMode = ThreadMode.PostThread) // ThreadMode is optional here public void onEvent(MessageEvent event) { log(event.message); } @@ -90,7 +90,7 @@ Example: * **Async:** Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. ```java // Called in a separate thread - @Subscribe(threadmode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.Async) public void onEventAsync(MessageEvent event){ backend.send(event.message); } @@ -174,7 +174,7 @@ After that, a new Activity gets started. During registration, and sticky Subscri EventBus.getDefault().register(this); } - @Subscribe(sticky = true, threadmode = ThreadMode.MainThread) + @Subscribe(sticky = true, threadMode = ThreadMode.MainThread) public void onEvent(MessageEvent event) { // UI updates must run on MainThread textField.setText(event.message); From 8032b085a3c6b598b97ea2bc58d15d6a83bcd73c Mon Sep 17 00:00:00 2001 From: mormih Date: Sat, 5 Sep 2015 22:15:19 +0400 Subject: [PATCH 040/112] Fixes issue #188 --- .../annotationprocessor/EventBusAnnotationProcessor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 52b5b9ab..6a9cb8e9 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -28,7 +28,6 @@ import java.util.Set; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") -@SupportedSourceVersion(SourceVersion.RELEASE_6) public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String CLASS_POSTFIX = "_EventBusInfo"; private final Map> methodsByClass = @@ -38,6 +37,11 @@ public class EventBusAnnotationProcessor extends AbstractProcessor { private boolean writerRoundDone; private int round; + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + @Override public boolean process(Set annotations, RoundEnvironment env) { Messager messager = processingEnv.getMessager(); From 0697863f4f8e91da4cc5ec8a8f942b26d1756cc5 Mon Sep 17 00:00:00 2001 From: mormih Date: Sun, 6 Sep 2015 00:24:49 +0400 Subject: [PATCH 041/112] Fix artifactId when install in maven local repo failOnError = false on javadoc --- EventBusAnnotationProcessor/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 72b0ac29..e83462d5 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' +archivesBaseName = 'eventbus-annotation-processor' group = 'de.greenrobot' version = '3.0.0-beta2' @@ -44,6 +45,7 @@ sourceSets { } javadoc { + options. classpath += configurations.provided title = "EventBus Annotation Processor ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015 greenrobot.de. All Rights Reserved.' @@ -92,7 +94,6 @@ uploadArchives { println "Settings sonatypeUsername/sonatypePassword missing/incomplete for ${project.name}" } - pom.artifactId = 'eventbus-annotation-processor' pom.project { name 'EventBus Annotation Processor' packaging 'jar' From d3d478b05c4162df22bebc41ab00d6dbd623f557 Mon Sep 17 00:00:00 2001 From: mormih Date: Sun, 6 Sep 2015 00:31:19 +0400 Subject: [PATCH 042/112] options. removed --- EventBusAnnotationProcessor/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index e83462d5..3fb5d8fd 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -45,7 +45,6 @@ sourceSets { } javadoc { - options. classpath += configurations.provided title = "EventBus Annotation Processor ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015 greenrobot.de. All Rights Reserved.' From 4d21f93a5eea3caf89baaa9180ae60de88035b20 Mon Sep 17 00:00:00 2001 From: mormih Date: Tue, 8 Sep 2015 10:02:05 +0400 Subject: [PATCH 043/112] static part in processor was removed. --- .../event/annotationprocessor/EventBusAnnotationProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 6a9cb8e9..2072d671 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -209,7 +209,7 @@ private void writeSources() { writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); - writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); +// writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); writer.write(" protected Data createSubscriberData() {\n"); writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); From 91719682b2caf598573c2356f0133704b73b45ca Mon Sep 17 00:00:00 2001 From: mormih Date: Tue, 8 Sep 2015 10:04:57 +0400 Subject: [PATCH 044/112] archivesBaseName --- EventBus/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBus/build.gradle b/EventBus/build.gradle index 0193f2dd..9f866979 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' +archivesBaseName = 'eventbus' group = 'de.greenrobot' version = '3.0.0-beta2' sourceCompatibility = 1.6 @@ -45,6 +46,7 @@ sourceSets { } javadoc { + failOnError = false classpath += configurations.provided title = "EventBus ${version} API" options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2014 greenrobot.de. All Rights Reserved.' @@ -92,8 +94,6 @@ uploadArchives { } else { println "Settings sonatypeUsername/sonatypePassword missing/incomplete for ${project.name}" } - - pom.artifactId = 'eventbus' pom.project { name 'EventBus' packaging 'jar' From 8cdcedddbe4a9d5a7607f56f4a1cd04582b0590d Mon Sep 17 00:00:00 2001 From: Andrew Shu Date: Tue, 3 Nov 2015 17:39:43 -0800 Subject: [PATCH 045/112] ProGuard config for @Subscribe annotation --- HOWTO.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/HOWTO.md b/HOWTO.md index 4804f61f..8df11d0b 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -192,6 +192,12 @@ ProGuard obfuscates method names. However, the onEvent methods must not renamed public void onEvent*(**); } +# EventBus 3.0 annotation +-keepclassmembers class * { + @de.greenrobot.event.Subscribe ; +} +-keep enum de.greenrobot.event.ThreadMode { *; } + # Only required if you use AsyncExecutor -keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent { (java.lang.Throwable); From d5117be04565d1bf17cd6231cda9b994dbd82f1f Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 17 Nov 2015 19:44:56 -0800 Subject: [PATCH 046/112] adjusted COMPARISON.md --- COMPARISON.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/COMPARISON.md b/COMPARISON.md index d7733f8d..31fadc03 100644 --- a/COMPARISON.md +++ b/COMPARISON.md @@ -12,14 +12,14 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E Declare event handling methods - Name conventions + Annotations (since 3.0, can be precompiled for best performance) Annotations - + Event inheritance Yes Yes - + Subscriber inheritance Yes @@ -39,17 +39,17 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E Event delivery in posting thread Yes (Default) Yes - + Event delivery in main thread Yes No - + Event delivery in background thread Yes No - + Asynchronous event delivery Yes @@ -57,6 +57,8 @@ Otto is another event bus library for Android; actually it's a fork of Guava's E +_**Note:** the following information is outdated, preprocessed annotations are much faster than EventBus 2.x, on which the following table is based._ + Besides features, performance is another differentiator. To compare performance, we created an Android application, which is also part of this repository (EventBusPerformance). You can also run the app on your phone to benchmark different scenarios. Benchmark results indicate that EventBus is significantly faster in almost every scenario: From d2f950940547a74f0b7eed484ed6c76074606cfd Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 18 Nov 2015 13:19:30 +0100 Subject: [PATCH 047/112] minor formatting, javadoc, and rename --- .../EventBusAnnotationProcessor.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 2072d671..c333171d 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -6,7 +6,6 @@ import javax.annotation.processing.Messager; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -30,6 +29,8 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String CLASS_POSTFIX = "_EventBusInfo"; + + /** Found subscriber methods for a class (without superclasses). */ private final Map> methodsByClass = new HashMap>(); private final Set classesToSkip = new HashSet(); @@ -87,7 +88,7 @@ private void collectSubscribers(Set annotations, RoundEnv for (Element element : elements) { if (element instanceof ExecutableElement) { ExecutableElement method = (ExecutableElement) element; - if (checkHasErrors(method, messager)) { + if (checkHasNoErrors(method, messager)) { Element classElement = method.getEnclosingElement(); List methods = methodsByClass.get(classElement); if (methods == null) { @@ -103,7 +104,7 @@ private void collectSubscribers(Set annotations, RoundEnv } } - private boolean checkHasErrors(ExecutableElement element, Messager messager) { + private boolean checkHasNoErrors(ExecutableElement element, Messager messager) { if (element.getModifiers().contains(Modifier.STATIC)) { messager.printMessage(Diagnostic.Kind.ERROR, "Subscriber method must not be static", element); return false; @@ -209,7 +210,7 @@ private void writeSources() { writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); -// writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); + // writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); writer.write(" protected Data createSubscriberData() {\n"); writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); @@ -272,7 +273,7 @@ private TypeElement nextEntry(List> candidate = entries.get(i); - if(!classesToSkip.contains(candidate.getKey())) { + if (!classesToSkip.contains(candidate.getKey())) { return candidate.getKey(); } } From 9efffe13f2ffc68fb3deca09b9d2934ba91635f3 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 19:53:28 +0100 Subject: [PATCH 048/112] fixed getting SubscriberInfo for super class(es) --- .../src/de/greenrobot/event/SubscriberMethodFinder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 96635ef9..a02c8765 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -72,7 +72,7 @@ private List findUsingInfo(Class subscriberClass) { FindState findState = new FindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { - SubscriberInfo info = getSubscriberInfo(subscriberClass); + SubscriberInfo info = getSubscriberInfo(findState.clazz); if (info != null) { SubscriberInfo.Data subscriberData = info.getSubscriberData(); SubscriberMethod[] array = subscriberData.subscriberMethods; @@ -84,7 +84,7 @@ private List findUsingInfo(Class subscriberClass) { } else { findUsingReflectionInSingleClass(findState); } - findState.nextClass(); + findState.moveToSuperclass(); } return findState.subscriberMethods; } @@ -111,7 +111,7 @@ private List findUsingReflection(Class subscriberClass) { findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); - findState.nextClass(); + findState.moveToSuperclass(); } return findState.subscriberMethods; } @@ -182,7 +182,7 @@ boolean checkAdd(Method method, Class eventType) { return eventTypesFound.add(methodKey); } - void nextClass() { + void moveToSuperclass() { clazz = clazz.getSuperclass(); clazzName = clazz.getName(); /** Skip system classes, this just degrades performance. */ From 45846eb050c3b59fad166d9c9a0165b6e40b091f Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 22:24:39 +0100 Subject: [PATCH 049/112] minor --- EventBus/src/de/greenrobot/event/SubscriberInfo.java | 2 +- .../annotationprocessor/EventBusAnnotationProcessor.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 00b9ca17..5c907cfa 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -30,7 +30,7 @@ Data getSubscriberData() { abstract protected Data createSubscriberData(); - protected SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, + protected static SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { try { Method method = subscriberClass.getDeclaredMethod(methodName, eventType); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index c333171d..16cf695a 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -236,6 +236,7 @@ private void writeSources() { } private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement nextEntry) throws IOException { + String nextValue; if (nextEntry != null) { PackageElement nextPackageElement = getPackageElement(nextEntry); String nextPackage = nextPackageElement.getQualifiedName().toString(); @@ -244,10 +245,11 @@ private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement if (!myPackage.equals(nextPackage)) { nextInfoClassName = nextPackage + "." + nextInfoClassName; } - writer.write(" Class next = " + nextInfoClassName + ".class" + ";\n"); + nextValue = nextInfoClassName + ".class"; } else { - writer.write(" Class next = null;\n"); + nextValue = "null"; } + writer.write(" Class next = " + nextValue + ";\n"); } private String getClassString(TypeElement subscriberClass, String subscriberPackage) { From 8c765a88096121bc835a824e50e6684bd689d2ef Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 22:31:13 +0100 Subject: [PATCH 050/112] Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 - adapted be04a2de66981e819f40afd389e417e98c94c7da from master to annotation based version --- .../event/SubscriberMethodFinder.java | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index a02c8765..a03cfb37 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -19,7 +19,6 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; @@ -117,7 +116,15 @@ private List findUsingReflection(Class subscriberClass) { } private void findUsingReflectionInSingleClass(FindState findState) { - Method[] methods = findState.clazz.getDeclaredMethods(); + Method[] methods; + try { + // This is faster than getMethods, especially when subscribers a fat classes like Activities + methods = findState.clazz.getDeclaredMethods(); + } catch (Throwable th) { + // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 + methods = findState.clazz.getMethods(); + findState.skipSuperClasses = true; + } for (Method method : methods) { int modifiers = method.getModifiers(); if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) { @@ -134,14 +141,14 @@ private void findUsingReflectionInSingleClass(FindState findState) { } } else if (strictMethodVerification) { if (method.isAnnotationPresent(Subscribe.class)) { - String methodName = findState.clazzName + "." + method.getName(); + String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException("@Subscribe method " + methodName + "must have exactly 1 parameter but has " + parameterTypes.length); } } } else if (strictMethodVerification) { if (method.isAnnotationPresent(Subscribe.class)) { - String methodName = findState.clazzName + "." + method.getName(); + String methodName = method.getDeclaringClass().getName() + "." + method.getName(); throw new EventBusException(methodName + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } @@ -157,11 +164,12 @@ static void clearCaches() { class FindState { final List subscriberMethods = new ArrayList(); - final HashSet eventTypesFound = new HashSet(); + final Map eventTypesFound = new HashMap(); final StringBuilder methodKeyBuilder = new StringBuilder(); Class subscriberClass; Class clazz; String clazzName; + boolean skipSuperClasses; void initForSubscriber(Class subscriberClass) { this.subscriberClass = clazz = subscriberClass; @@ -179,16 +187,30 @@ boolean checkAdd(Method method, Class eventType) { methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); - return eventTypesFound.add(methodKey); + Class methodClass = method.getDeclaringClass(); + Class methodClassOld = eventTypesFound.put(methodKey, methodClass); + if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { + // Only add if not already found in a sub class + return true; + } else { + // Revert the put, old class is further down the class hierarchy + eventTypesFound.put(methodKey, methodClassOld); + return false; + } } void moveToSuperclass() { - clazz = clazz.getSuperclass(); - clazzName = clazz.getName(); - /** Skip system classes, this just degrades performance. */ - if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { + if (skipSuperClasses) { clazz = null; clazzName = null; + } else { + clazz = clazz.getSuperclass(); + clazzName = clazz.getName(); + /** Skip system classes, this just degrades performance. */ + if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { + clazz = null; + clazzName = null; + } } } } From 4cf3f4c040860d32cf82d30af35583d6afb28e9c Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 22:56:18 +0100 Subject: [PATCH 051/112] faster unit test: testUnregisterNotLeaking should only iterate heapMBytes * 2 --- .../src/de/greenrobot/event/test/EventBusBasicTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index bb0b1ca8..c81d2140 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -64,14 +64,16 @@ public void testUnregisterWithoutRegister() { eventBus.unregister(this); } + // This will throw "out of memory" if subscribers are leaked public void testUnregisterNotLeaking() { - // This will throw "out of memory" if subscribers are leaked - for (int i = 0; i < 300; i++) { + int heapMBytes = (int) (Runtime.getRuntime().maxMemory() / (1024L * 1024L)); + for (int i = 0; i < heapMBytes * 2; i++) { EventBusBasicTest subscriber = new EventBusBasicTest() { byte[] expensiveObject = new byte[1024 * 1024]; }; eventBus.register(subscriber); eventBus.unregister(subscriber); + Log.d("Test", "Iteration " + i + " / max heap: " + heapMBytes); } } From 9a4d845e4d86098e1fede8587b1fe2334caa72ba Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 19 Nov 2015 22:59:48 +0100 Subject: [PATCH 052/112] changed ThreadMode enum values (also fixes #203) --- .../src/de/greenrobot/event/EventBus.java | 12 +++++----- .../src/de/greenrobot/event/Subscribe.java | 4 +--- .../src/de/greenrobot/event/ThreadMode.java | 8 +++---- .../test/EventBusBackgroundThreadTest.java | 2 +- .../test/EventBusCancelEventDeliveryTest.java | 2 +- .../test/EventBusMainThreadRacingTest.java | 2 +- .../event/test/EventBusMainThreadTest.java | 2 +- .../test/EventBusMethodModifiersTest.java | 6 ++--- .../event/test/EventBusMultithreadedTest.java | 12 +++++----- .../EventBusOrderedSubscriptionsTest.java | 24 +++++++++---------- 10 files changed, 36 insertions(+), 38 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 33817aa8..af47c7b9 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -275,7 +275,7 @@ public void post(Object event) { * subscribers * won't receive the event. Events are usually canceled by higher priority subscribers (see * {@link Subscribe#priority()}). Canceling is restricted to event handling methods running in posting thread - * {@link ThreadMode#PostThread}. + * {@link ThreadMode#POSTING}. */ public void cancelEventDelivery(Object event) { PostingThreadState postingState = currentPostingThreadState.get(); @@ -286,7 +286,7 @@ public void cancelEventDelivery(Object event) { throw new EventBusException("Event may not be null"); } else if (postingState.event != event) { throw new EventBusException("Only the currently handled event may be aborted"); - } else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.PostThread) { + } else if (postingState.subscription.subscriberMethod.threadMode != ThreadMode.POSTING) { throw new EventBusException(" event handlers may only abort the incoming event"); } @@ -425,24 +425,24 @@ private boolean postSingleEventForEventType(Object event, PostingThreadState pos private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) { switch (subscription.subscriberMethod.threadMode) { - case PostThread: + case POSTING: invokeSubscriber(subscription, event); break; - case MainThread: + case MAIN: if (isMainThread) { invokeSubscriber(subscription, event); } else { mainThreadPoster.enqueue(subscription, event); } break; - case BackgroundThread: + case BACKGROUND: if (isMainThread) { backgroundPoster.enqueue(subscription, event); } else { invokeSubscriber(subscription, event); } break; - case Async: + case ASYNC: asyncPoster.enqueue(subscription, event); break; default: diff --git a/EventBus/src/de/greenrobot/event/Subscribe.java b/EventBus/src/de/greenrobot/event/Subscribe.java index 82cf51fc..6532c6cd 100644 --- a/EventBus/src/de/greenrobot/event/Subscribe.java +++ b/EventBus/src/de/greenrobot/event/Subscribe.java @@ -7,13 +7,11 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import de.greenrobot.event.ThreadMode; - @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface Subscribe { - ThreadMode threadMode() default ThreadMode.PostThread; + ThreadMode threadMode() default ThreadMode.POSTING; /** * If true, delivers the most recent sticky event (posted with diff --git a/EventBus/src/de/greenrobot/event/ThreadMode.java b/EventBus/src/de/greenrobot/event/ThreadMode.java index 4022ace5..bbe060cd 100644 --- a/EventBus/src/de/greenrobot/event/ThreadMode.java +++ b/EventBus/src/de/greenrobot/event/ThreadMode.java @@ -29,14 +29,14 @@ public enum ThreadMode { * simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers * using this mode must return quickly to avoid blocking the posting thread, which may be the main thread. */ - PostThread, + POSTING, /** * Subscriber will be called in Android's main thread (sometimes referred to as UI thread). If the posting thread is * the main thread, event handler methods will be called directly. Event handlers using this mode must return * quickly to avoid blocking the main thread. */ - MainThread, + MAIN, /** * Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods @@ -44,7 +44,7 @@ public enum ThreadMode { * background thread, that will deliver all its events sequentially. Event handlers using this mode should try to * return quickly to avoid blocking the background thread. */ - BackgroundThread, + BACKGROUND, /** * Event handler methods are called in a separate thread. This is always independent from the posting thread and the @@ -53,5 +53,5 @@ public enum ThreadMode { * of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus * uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. */ - Async + ASYNC } \ No newline at end of file diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java index 99de5a32..b590ed5e 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java @@ -42,7 +42,7 @@ public void testPostFromMain() throws InterruptedException { assertFalse(lastThread.equals(Looper.getMainLooper().getThread())); } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(String event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index 748adcaa..f9b05627 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -129,7 +129,7 @@ public void onEvent(String event) { public class SubscriberMainThread { final CountDownLatch done = new CountDownLatch(1); - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { try { eventBus.cancelEventDelivery(event); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index 9fa4a487..b7127db5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -86,7 +86,7 @@ public void run() { awaitLatch(doneLatch, 10); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { trackEvent(event); if (unregistered) { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 3d6b7541..2d62ab4d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -59,7 +59,7 @@ public void testPostInBackgroundThread() throws InterruptedException { assertEquals(Looper.getMainLooper().getThread(), lastThread); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { trackEvent(event); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index aad8d781..e3f6c9c5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -39,19 +39,19 @@ public void onEvent(String event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { trackEvent(event); assertSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(String event) { trackEvent(event); assertNotSame(Looper.getMainLooper(), Looper.myLooper()); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index 87d89d13..1efbcd92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -166,21 +166,21 @@ private List startThreads(CountDownLatch latch, int threadCount, i return threads; } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(String event) { lastStringEvent = event; countStringEvent.incrementAndGet(); trackEvent(event); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(Integer event) { lastIntegerEvent = event; countIntegerEvent.incrementAndGet(); trackEvent(event); } - @Subscribe(threadMode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(IntTestEvent event) { countIntTestEvent.incrementAndGet(); lastIntTestEvent = event; @@ -245,12 +245,12 @@ public void run() { } } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(String event) { assertSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(Integer event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } @@ -260,7 +260,7 @@ public void onEvent(Object event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } - @Subscribe(threadMode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(Object event) { assertNotSame(Looper.getMainLooper(), Looper.myLooper()); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 5bba1a64..7630ea64 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -94,32 +94,32 @@ public void onEventM100(String event) { } - @Subscribe(threadMode = ThreadMode.MainThread, priority = -1) + @Subscribe(threadMode = ThreadMode.MAIN, priority = -1) public void onEventMainThreadM1(IntTestEvent event) { handleEvent(-1, event); } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThreadP0(IntTestEvent event) { handleEvent(0, event); } - @Subscribe(threadMode = ThreadMode.MainThread, priority = 1) + @Subscribe(threadMode = ThreadMode.MAIN, priority = 1) public void onEventMainThreadP1(IntTestEvent event) { handleEvent(1, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = 1) + @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 1) public void onEventBackgroundThreadP1(Integer event) { handleEvent(1, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThreadP0(Integer event) { handleEvent(0, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = -1) + @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = -1) public void onEventBackgroundThreadM1(Integer event) { handleEvent(-1, event); } @@ -163,32 +163,32 @@ public void onEventM100(String event) { handleEvent(-100, event); } - @Subscribe(threadMode = ThreadMode.MainThread, priority = -1, sticky = true) + @Subscribe(threadMode = ThreadMode.MAIN, priority = -1, sticky = true) public void onEventMainThreadM1(IntTestEvent event) { handleEvent(-1, event); } - @Subscribe(threadMode = ThreadMode.MainThread, sticky = true) + @Subscribe(threadMode = ThreadMode.MAIN, sticky = true) public void onEventMainThreadP0(IntTestEvent event) { handleEvent(0, event); } - @Subscribe(threadMode = ThreadMode.MainThread, priority = 1, sticky = true) + @Subscribe(threadMode = ThreadMode.MAIN, priority = 1, sticky = true) public void onEventMainThreadP1(IntTestEvent event) { handleEvent(1, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = 1, sticky = true) + @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = 1, sticky = true) public void onEventBackgroundThreadP1(Integer event) { handleEvent(1, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, sticky = true) + @Subscribe(threadMode = ThreadMode.BACKGROUND, sticky = true) public void onEventBackgroundThreadP0(Integer event) { handleEvent(0, event); } - @Subscribe(threadMode = ThreadMode.BackgroundThread, priority = -1, sticky = true) + @Subscribe(threadMode = ThreadMode.BACKGROUND, priority = -1, sticky = true) public void onEventBackgroundThreadM1(Integer event) { handleEvent(-1, event); } From d0e4303b32b36c265b3e8550cb1e7f3f2bdfb3f6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 20 Nov 2015 17:26:37 +0100 Subject: [PATCH 053/112] added testPostStickyTwoSubscribers --- .../event/test/EventBusStickyEventTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index d092ae8d..6be32085 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -36,6 +36,21 @@ public void testPostStickyTwoEvents() throws InterruptedException { assertEquals(2, eventCount.intValue()); } + public void testPostStickyTwoSubscribers() throws InterruptedException { + eventBus.postSticky("Sticky"); + eventBus.postSticky(new IntTestEvent(7)); + eventBus.register(this); + StickyIntTestSubscriber subscriber2 = new StickyIntTestSubscriber(); + eventBus.register(subscriber2); + assertEquals(3, eventCount.intValue()); + + eventBus.postSticky("Sticky"); + assertEquals(4, eventCount.intValue()); + + eventBus.postSticky(new IntTestEvent(8)); + assertEquals(6, eventCount.intValue()); + } + public void testPostStickyRegisterNonSticky() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.register(new NonStickySubscriber()); @@ -156,4 +171,11 @@ public void onEvent(IntTestEvent event) { trackEvent(event); } } + + public class StickyIntTestSubscriber { + @Subscribe(sticky = true) + public void onEvent(IntTestEvent event) { + trackEvent(event); + } + } } From 5caf0c8e059a47e71675df2ed9af5a747530c370 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 23 Nov 2015 09:45:35 +0100 Subject: [PATCH 054/112] adjust perf project to new enum values --- EventBusPerformance/res/values/strings.xml | 8 ++++---- .../greenrobot/eventperf/TestRunnerActivity.java | 2 +- .../eventperf/testsubject/PerfTestEventBus.java | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/EventBusPerformance/res/values/strings.xml b/EventBusPerformance/res/values/strings.xml index dcaac60c..c7af6a88 100644 --- a/EventBusPerformance/res/values/strings.xml +++ b/EventBusPerformance/res/values/strings.xml @@ -19,10 +19,10 @@ Register Subscribers, 1. time - PostThread - MainThread - BackgroundThread - Async + POSTING + MAIN + BACKGROUND + ASYNC Test Is \nRunning! diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java index 07f55777..8ff7ff9f 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java @@ -46,7 +46,7 @@ protected void onResume() { } } - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(TestFinishedEvent event) { Test test = event.test; String text = "" + test.getDisplayName() + "
" + // diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index df8b13a3..16941e9b 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -45,13 +45,13 @@ public void prepareTest() { private Class getSubscriberClassForThreadMode() { switch (params.getThreadMode()) { - case MainThread: + case MAIN: return SubscribeClassEventBusMain.class; - case BackgroundThread: + case BACKGROUND: return SubscribeClassEventBusBackground.class; - case Async: + case ASYNC: return SubscriberClassEventBusAsync.class; - case PostThread: + case POSTING: return SubscribeClassEventBusDefault.class; default: throw new RuntimeException("Unknown: " + params.getThreadMode()); @@ -206,7 +206,7 @@ public void dummy5() { } public class SubscribeClassEventBusMain { - @Subscribe(threadMode = ThreadMode.MainThread) + @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -228,7 +228,7 @@ public void dummy5() { } public class SubscribeClassEventBusBackground { - @Subscribe(threadMode = ThreadMode.BackgroundThread) + @Subscribe(threadMode = ThreadMode.BACKGROUND) public void onEventBackgroundThread(TestEvent event) { eventsReceivedCount.incrementAndGet(); } @@ -250,7 +250,7 @@ public void dummy5() { } public class SubscriberClassEventBusAsync { - @Subscribe(threadMode = ThreadMode.Async) + @Subscribe(threadMode = ThreadMode.ASYNC) public void onEventAsync(TestEvent event) { eventsReceivedCount.incrementAndGet(); } From a6627316b57096ecf540851792ee5a3b43d309f9 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Nov 2015 20:38:21 +0100 Subject: [PATCH 055/112] fix for EventBusMainThreadTest.BackgroundPoster --- .../src/de/greenrobot/event/test/EventBusMainThreadTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 2d62ab4d..944dba21 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -116,7 +116,7 @@ void post(Object event) { eventQ.notifyAll(); } synchronized (eventsDone) { - while (eventsDone.remove(event)) { + while (!eventsDone.remove(event)) { try { eventsDone.wait(); } catch (InterruptedException e) { From 7b81bcb59e58e2c08424b52bbed29d22d777d36c Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 25 Nov 2015 20:41:36 +0100 Subject: [PATCH 056/112] simplified SubscriberInfo: no more inner Data class --- .../de/greenrobot/event/SubscriberInfo.java | 30 ++++++------------- .../event/SubscriberMethodFinder.java | 3 +- .../EventBusAnnotationProcessor.java | 17 ++++++----- 3 files changed, 19 insertions(+), 31 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 5c907cfa..11a496d0 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -1,34 +1,22 @@ package de.greenrobot.event; import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; /** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ public abstract class SubscriberInfo { - // TODO move class fields into SubscriberInfo - public static class Data { - public final Class subscriberClass; - public final SubscriberMethod[] subscriberMethods; - public final Class nextInfo; + final Class subscriberClass; + final Class superSubscriberInfoClass; + final Class nextSubscriberInfoClass; - public Data(Class subscriberClass, SubscriberMethod[] subscriberMethods, Class nextInfo) { - this.subscriberClass = subscriberClass; - this.subscriberMethods = subscriberMethods; - this.nextInfo = nextInfo; - } - } + protected SubscriberMethod[] subscriberMethods; - private volatile Data data; - - Data getSubscriberData() { - if (data == null) { - data = createSubscriberData(); - } - return data; + protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, Class nextSubscriberInfoClass) { + this.subscriberClass = subscriberClass; + this.superSubscriberInfoClass = superSubscriberInfoClass; + this.nextSubscriberInfoClass = nextSubscriberInfoClass; } - abstract protected Data createSubscriberData(); + abstract protected SubscriberMethod[] createSubscriberMethods(); protected static SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index a03cfb37..9c470e88 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -73,8 +73,7 @@ private List findUsingInfo(Class subscriberClass) { while (findState.clazz != null) { SubscriberInfo info = getSubscriberInfo(findState.clazz); if (info != null) { - SubscriberInfo.Data subscriberData = info.getSubscriberData(); - SubscriberMethod[] array = subscriberData.subscriberMethods; + SubscriberMethod[] array = info.createSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 16cf695a..c5989fea 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -205,21 +205,22 @@ private void writeSources() { writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); writer.write("import de.greenrobot.event.SubscriberInfo;\n"); - writer.write("import de.greenrobot.event.SubscriberInfo.Data;\n"); writer.write("import de.greenrobot.event.SubscriberMethod;\n"); writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); - // writer.write("\nstatic {new Exception(\"" + infoClassName + "created\").printStackTrace();}\n\n"); - writer.write(" protected Data createSubscriberData() {\n"); + writer.write(" public " + infoClassName + "() {\n"); + TypeElement nextEntry = nextEntry(entries, entry, i); + String next = getNextValue(myPackage, nextEntry); + writer.write(" super(" + subscriberClassName + ".class, null, " + next + ");\n"); + writer.write(" }\n\n"); + writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); writeMethods(writer, null, entry.getValue(), methodSignatures); writer.write(" };\n"); - TypeElement nextEntry = nextEntry(entries, entry, i); - writeNextEntry(writer, myPackage, nextEntry); - writer.write(" return new Data(subscriberClass, subscriberMethods, next);\n"); + writer.write(" return subscriberMethods;\n"); writer.write(" }\n}\n"); } catch (IOException e) { throw new RuntimeException("Could not write source for " + subscriberClass.getQualifiedName(), e); @@ -235,7 +236,7 @@ private void writeSources() { } } - private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement nextEntry) throws IOException { + private String getNextValue(String myPackage, TypeElement nextEntry) throws IOException { String nextValue; if (nextEntry != null) { PackageElement nextPackageElement = getPackageElement(nextEntry); @@ -249,7 +250,7 @@ private void writeNextEntry(BufferedWriter writer, String myPackage, TypeElement } else { nextValue = "null"; } - writer.write(" Class next = " + nextValue + ";\n"); + return nextValue; } private String getClassString(TypeElement subscriberClass, String subscriberPackage) { From 26a00665106eeadd3f8c6249fe9e670ffd3483db Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 20:27:57 +0100 Subject: [PATCH 057/112] SubscriberInfo super class --- .../event/SubscriberMethodFinder.java | 23 ++++++--- .../EventBusAnnotationProcessor.java | 50 +++++++++++++------ 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 9c470e88..18e740bd 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -71,9 +71,9 @@ private List findUsingInfo(Class subscriberClass) { FindState findState = new FindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { - SubscriberInfo info = getSubscriberInfo(findState.clazz); - if (info != null) { - SubscriberMethod[] array = info.createSubscriberMethods(); + findState.subscriberInfo = getSubscriberInfo(findState); + if (findState.subscriberInfo != null) { + SubscriberMethod[] array = findState.subscriberInfo.createSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); @@ -87,9 +87,19 @@ private List findUsingInfo(Class subscriberClass) { return findState.subscriberMethods; } - private SubscriberInfo getSubscriberInfo(Class subscriberClass) { + private SubscriberInfo getSubscriberInfo(FindState findState) { SubscriberInfo info = null; - String infoClass = subscriberClass.getName().replace('$', '_') + "_EventBusInfo"; + if (findState.subscriberInfo != null && findState.subscriberInfo.superSubscriberInfoClass != null) { + try { + SubscriberInfo superclassInfo = (SubscriberInfo) findState.subscriberInfo.superSubscriberInfoClass.newInstance(); + if (findState.clazz == superclassInfo.subscriberClass) { + return superclassInfo; + } + } catch (IllegalAccessException | InstantiationException e) { + throw new EventBusException(e); + } + } + String infoClass = findState.clazz.getName().replace('$', '_') + "_EventBusInfo"; try { Class aClass = Class.forName(infoClass); Object object = aClass.newInstance(); @@ -99,7 +109,7 @@ private SubscriberInfo getSubscriberInfo(Class subscriberClass) { } catch (ClassNotFoundException e) { // TODO don't try again } catch (Exception e) { - throw new EventBusException("Could not get infos for " + subscriberClass, e); + throw new EventBusException("Could not get infos for " + findState.clazz, e); } return info; } @@ -169,6 +179,7 @@ class FindState { Class clazz; String clazzName; boolean skipSuperClasses; + public SubscriberInfo subscriberInfo; void initForSubscriber(Class subscriberClass) { this.subscriberClass = clazz = subscriberClass; diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index c5989fea..29f7afe6 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -1,6 +1,13 @@ package de.greenrobot.event.annotationprocessor; -import de.greenrobot.event.Subscribe; +import java.io.BufferedWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Messager; @@ -17,14 +24,8 @@ import javax.lang.model.type.TypeKind; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import java.io.BufferedWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; + +import de.greenrobot.event.Subscribe; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { @@ -199,7 +200,7 @@ private void writeSources() { PackageElement packageElement = getPackageElement(subscriberClass); String myPackage = packageElement.getQualifiedName().toString(); String subscriberClassName = getClassString(subscriberClass, myPackage); - String infoClassName = subscriberClassName.replace('.', '_') + CLASS_POSTFIX; + String infoClassName = getInfoClass(subscriberClass, myPackage); JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); @@ -212,7 +213,8 @@ private void writeSources() { writer.write(" public " + infoClassName + "() {\n"); TypeElement nextEntry = nextEntry(entries, entry, i); String next = getNextValue(myPackage, nextEntry); - writer.write(" super(" + subscriberClassName + ".class, null, " + next + ");\n"); + String infoSuperClass = getSuperclassInfoClass(subscriberClass, myPackage); + writer.write(" super(" + subscriberClassName + ".class, " + infoSuperClass + ", " + next + ");\n"); writer.write(" }\n\n"); writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); @@ -236,13 +238,28 @@ private void writeSources() { } } + private String getSuperclassInfoClass(TypeElement subscriberClass, String myPackage) { + DeclaredType superclassType = (DeclaredType) subscriberClass.getSuperclass(); + if (superclassType != null) { + TypeElement superclass = (TypeElement) superclassType.asElement(); + if (methodsByClass.containsKey(superclass) && !classesToSkip.contains(superclass)) { + return getInfoClass(superclass, myPackage) + ".class"; + } + } + return "null"; + } + + private String getInfoClass(TypeElement subscriberClass, String myPackage) { + String subscriberClassName = getClassString(subscriberClass, myPackage); + return subscriberClassName.replace('.', '_') + CLASS_POSTFIX; + } + private String getNextValue(String myPackage, TypeElement nextEntry) throws IOException { String nextValue; if (nextEntry != null) { PackageElement nextPackageElement = getPackageElement(nextEntry); String nextPackage = nextPackageElement.getQualifiedName().toString(); - String nextSubscriberClassName = getClassString(nextEntry, nextPackage); - String nextInfoClassName = nextSubscriberClassName.replace('.', '_') + CLASS_POSTFIX; + String nextInfoClassName = getInfoClass(nextEntry, nextPackage); if (!myPackage.equals(nextPackage)) { nextInfoClassName = nextPackage + "." + nextInfoClassName; } @@ -254,8 +271,11 @@ private String getNextValue(String myPackage, TypeElement nextEntry) throws IOEx } private String getClassString(TypeElement subscriberClass, String subscriberPackage) { - int beginIndex = subscriberPackage.length() == 0 ? 0 : subscriberPackage.length() + 1; - return subscriberClass.getQualifiedName().toString().substring(beginIndex); + String className = subscriberClass.getQualifiedName().toString(); + if (!subscriberPackage.isEmpty() && className.startsWith(subscriberPackage)) { + className = className.substring(subscriberPackage.length() + 1); + } + return className; } private PackageElement getPackageElement(TypeElement subscriberClass) { From aa3e5dfcebe56e5f74c0d5a06524c32a4b2f3367 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 20:44:21 +0100 Subject: [PATCH 058/112] simplified createSubscriberMethod() calls --- EventBus/src/de/greenrobot/event/SubscriberInfo.java | 2 +- .../EventBusAnnotationProcessor.java | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 11a496d0..ba757b3a 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -18,7 +18,7 @@ protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, abstract protected SubscriberMethod[] createSubscriberMethods(); - protected static SubscriberMethod createSubscriberMethod(Class subscriberClass, String methodName, Class eventType, + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { try { Method method = subscriberClass.getDeclaredMethod(methodName, eventType); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 29f7afe6..2de30d1d 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -217,10 +217,9 @@ private void writeSources() { writer.write(" super(" + subscriberClassName + ".class, " + infoSuperClass + ", " + next + ");\n"); writer.write(" }\n\n"); writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); - writer.write(" Class subscriberClass = " + subscriberClassName + ".class;\n"); writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); - writeMethods(writer, null, entry.getValue(), methodSignatures); + writeMethods(writer, entry.getValue(), methodSignatures); writer.write(" };\n"); writer.write(" return subscriberMethods;\n"); writer.write(" }\n}\n"); @@ -303,7 +302,7 @@ private TypeElement nextEntry(List methods, Set methodSignatures) throws IOException { + private void writeMethods(BufferedWriter writer, List methods, Set methodSignatures) throws IOException { for (ExecutableElement method : methods) { List parameters = method.getParameters(); @@ -316,12 +315,9 @@ private void writeMethods(BufferedWriter writer, TypeElement subscriberClass, Li } String methodName = method.getSimpleName().toString(); - String subscriberClassString = subscriberClass == null ? "subscriberClass" : - subscriberClass.asType().toString() + ".class"; Subscribe subscribe = method.getAnnotation(Subscribe.class); - writeLine(writer, 3, "createSubscriberMethod(" + subscriberClassString + ",", - "\"" + methodName + "\",", + writeLine(writer, 3, "createSubscriberMethod(\"" + methodName + "\",", paramType.toString() + ".class,", "ThreadMode." + subscribe.threadMode().name() + ", " + subscribe.priority() + ", " + subscribe.sticky(), "),"); From 4e8259ccc0e7033e79151741f087543a8beddb5b Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 21:13:02 +0100 Subject: [PATCH 059/112] use overloaded createSubscriberMethod() with default parameters to make info classes more compact --- .../de/greenrobot/event/SubscriberInfo.java | 15 ++++++++++--- .../EventBusAnnotationProcessor.java | 22 +++++++++++++++---- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index ba757b3a..54b6db12 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -16,10 +16,19 @@ protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, this.nextSubscriberInfoClass = nextSubscriberInfoClass; } - abstract protected SubscriberMethod[] createSubscriberMethods(); + abstract protected SubscriberMethod[] createSubscriberMethods(); - protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, - ThreadMode threadMode, int priority, boolean sticky) { + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType) { + return createSubscriberMethod(methodName, eventType, ThreadMode.POSTING, 0, false); + + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode) { + return createSubscriberMethod(methodName, eventType, threadMode, 0, false); + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode, + int priority, boolean sticky) { try { Method method = subscriberClass.getDeclaredMethod(methodName, eventType); return new SubscriberMethod(method, eventType, threadMode, priority, sticky); diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 2de30d1d..942abd30 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -26,6 +26,7 @@ import javax.tools.JavaFileObject; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { @@ -317,10 +318,23 @@ private void writeMethods(BufferedWriter writer, List methods String methodName = method.getSimpleName().toString(); Subscribe subscribe = method.getAnnotation(Subscribe.class); - writeLine(writer, 3, "createSubscriberMethod(\"" + methodName + "\",", - paramType.toString() + ".class,", - "ThreadMode." + subscribe.threadMode().name() + ", " + - subscribe.priority() + ", " + subscribe.sticky(), "),"); + List parts = new ArrayList(); + parts.add("createSubscriberMethod(\"" + methodName + "\","); + String lineEnd = "),"; + if (subscribe.priority() == 0 && !subscribe.sticky()) { + if (subscribe.threadMode() == ThreadMode.POSTING) { + parts.add(paramType.toString() + ".class" + lineEnd); + } else { + parts.add(paramType.toString() + ".class,"); + parts.add("ThreadMode." + subscribe.threadMode().name() + lineEnd); + } + } else { + parts.add(paramType.toString() + ".class,"); + parts.add("ThreadMode." + subscribe.threadMode().name() + ","); + parts.add(subscribe.priority() + ","); + parts.add(subscribe.sticky() + lineEnd); + } + writeLine(writer, 3, parts.toArray(new String[parts.size()])); processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + method.getEnclosingElement().getSimpleName() + "." + methodName + From 0c289c664ff30f3412d3d2edf78766a1eadb9f08 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 21:19:42 +0100 Subject: [PATCH 060/112] minor improvements for generated info classes --- .../annotationprocessor/EventBusAnnotationProcessor.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 942abd30..b92492e2 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -215,14 +215,13 @@ private void writeSources() { TypeElement nextEntry = nextEntry(entries, entry, i); String next = getNextValue(myPackage, nextEntry); String infoSuperClass = getSuperclassInfoClass(subscriberClass, myPackage); - writer.write(" super(" + subscriberClassName + ".class, " + infoSuperClass + ", " + next + ");\n"); + writeLine(writer, 2, "super(" + subscriberClassName + ".class,", infoSuperClass + ",", next + ");"); writer.write(" }\n\n"); writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); - writer.write(" SubscriberMethod[] subscriberMethods = new SubscriberMethod[] {\n"); + writer.write(" return new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); writeMethods(writer, entry.getValue(), methodSignatures); writer.write(" };\n"); - writer.write(" return subscriberMethods;\n"); writer.write(" }\n}\n"); } catch (IOException e) { throw new RuntimeException("Could not write source for " + subscriberClass.getQualifiedName(), e); From db56e6e41250c1e35d788d37acb85f20841dbd30 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 21:25:26 +0100 Subject: [PATCH 061/112] SubscriberInfo clean up --- EventBus/src/de/greenrobot/event/SubscriberInfo.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 54b6db12..43ed290c 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -2,14 +2,12 @@ import java.lang.reflect.Method; -/** Preprocessed index: base class for generated "MyGeneratedSubscriberIndex" class by annotation processing. */ +/** Base class for generated index classes created by annotation processing. */ public abstract class SubscriberInfo { final Class subscriberClass; final Class superSubscriberInfoClass; final Class nextSubscriberInfoClass; - protected SubscriberMethod[] subscriberMethods; - protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, Class nextSubscriberInfoClass) { this.subscriberClass = subscriberClass; this.superSubscriberInfoClass = superSubscriberInfoClass; From 6fced7ef7d50c02a4a6a3f174b6426c931a5b5c6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 27 Nov 2015 22:05:06 +0100 Subject: [PATCH 062/112] added FIND_STATE_POOL --- .../event/SubscriberMethodFinder.java | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 18e740bd..3a6f62ef 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -37,6 +37,9 @@ class SubscriberMethodFinder { private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; + private static final int POOL_SIZE = 4; + private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE]; + SubscriberMethodFinder(boolean strictMethodVerification, boolean ignoreGeneratedIndex) { this.strictMethodVerification = strictMethodVerification; this.ignoreGeneratedIndex = ignoreGeneratedIndex; @@ -68,7 +71,7 @@ List findSubscriberMethods(Class subscriberClass, boolean f } private List findUsingInfo(Class subscriberClass) { - FindState findState = new FindState(); + FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findState.subscriberInfo = getSubscriberInfo(findState); @@ -84,7 +87,34 @@ private List findUsingInfo(Class subscriberClass) { } findState.moveToSuperclass(); } - return findState.subscriberMethods; + return getMethodsAndRelease(findState); + } + + private List getMethodsAndRelease(FindState findState) { + ArrayList subscriberMethods = new ArrayList<>(findState.subscriberMethods); + findState.recycle(); + synchronized (FIND_STATE_POOL) { + for (int i = 0; i < POOL_SIZE; i++) { + if (FIND_STATE_POOL[i] == null) { + FIND_STATE_POOL[i] = findState; + break; + } + } + } + return subscriberMethods; + } + + private FindState prepareFindState() { + synchronized (FIND_STATE_POOL) { + for (int i = 0; i < POOL_SIZE; i++) { + FindState state = FIND_STATE_POOL[i]; + if (state != null) { + FIND_STATE_POOL[i] = null; + return state; + } + } + } + return new FindState(); } private SubscriberInfo getSubscriberInfo(FindState findState) { @@ -115,13 +145,13 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { } private List findUsingReflection(Class subscriberClass) { - FindState findState = new FindState(); + FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); while (findState.clazz != null) { findUsingReflectionInSingleClass(findState); findState.moveToSuperclass(); } - return findState.subscriberMethods; + return getMethodsAndRelease(findState); } private void findUsingReflectionInSingleClass(FindState findState) { @@ -171,15 +201,16 @@ static void clearCaches() { } } - class FindState { + static class FindState { final List subscriberMethods = new ArrayList(); final Map eventTypesFound = new HashMap(); final StringBuilder methodKeyBuilder = new StringBuilder(); + Class subscriberClass; Class clazz; String clazzName; boolean skipSuperClasses; - public SubscriberInfo subscriberInfo; + SubscriberInfo subscriberInfo; void initForSubscriber(Class subscriberClass) { this.subscriberClass = clazz = subscriberClass; @@ -187,8 +218,12 @@ void initForSubscriber(Class subscriberClass) { void recycle() { subscriberMethods.clear(); - methodKeyBuilder.setLength(0); eventTypesFound.clear(); + methodKeyBuilder.setLength(0); + subscriberClass = null; + clazz = null; + skipSuperClasses = false; + subscriberInfo = null; } boolean checkAdd(Method method, Class eventType) { From e3bf68aeb05a7d2c79d2d61c5e429e29d7e563c5 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 2 Dec 2015 18:29:50 +0100 Subject: [PATCH 063/112] deduct timeMeasureOverhead from time measurement for RegisterOneByOne --- .../greenrobot/eventperf/testsubject/PerfTestEventBus.java | 5 ++++- .../de/greenrobot/eventperf/testsubject/PerfTestOtto.java | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 16941e9b..70d4a8cd 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -145,7 +145,10 @@ public void runTest() { } long beforeRegister = System.nanoTime(); super.eventBus.register(subscriber); - long timeRegister = System.nanoTime() - beforeRegister; + long afterRegister = System.nanoTime(); + long end = System.nanoTime(); + long timeMeasureOverhead = (end - afterRegister) * 2; + long timeRegister = end - beforeRegister - timeMeasureOverhead; time += timeRegister; super.eventBus.unregister(subscriber); if (canceled) { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java index 8e68adde..6e1cb890 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java @@ -124,7 +124,11 @@ public void runTest() { } long beforeRegister = System.nanoTime(); super.eventBus.register(subscriber); - long timeRegister = System.nanoTime() - beforeRegister; + + long afterRegister = System.nanoTime(); + long end = System.nanoTime(); + long timeMeasureOverhead = (end - afterRegister) * 2; + long timeRegister = end - beforeRegister - timeMeasureOverhead; time += timeRegister; super.eventBus.unregister(subscriber); if (canceled) { From 4e42ed943050cab8b71e0765e0e37c9df142b4a1 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 2 Dec 2015 20:33:30 +0100 Subject: [PATCH 064/112] realistic initial capacity for methodKeyBuilder --- EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 3a6f62ef..b8124e1e 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -204,7 +204,7 @@ static void clearCaches() { static class FindState { final List subscriberMethods = new ArrayList(); final Map eventTypesFound = new HashMap(); - final StringBuilder methodKeyBuilder = new StringBuilder(); + final StringBuilder methodKeyBuilder = new StringBuilder(128); Class subscriberClass; Class clazz; From ec8a1c2742cdb9f5c01a1d654c9a67a73ebc9dad Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 2 Dec 2015 21:32:01 +0100 Subject: [PATCH 065/112] methodCache uses Class as key type --- .../src/de/greenrobot/event/SubscriberMethodFinder.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index b8124e1e..b6e6779d 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -32,7 +32,7 @@ class SubscriberMethodFinder { private static final int SYNTHETIC = 0x1000; private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; - private static final Map> METHOD_CACHE = new HashMap>(); + private static final Map, List> METHOD_CACHE = new HashMap, List>(); private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; @@ -46,10 +46,9 @@ class SubscriberMethodFinder { } List findSubscriberMethods(Class subscriberClass, boolean forceReflection) { - String key = subscriberClass.getName(); List subscriberMethods; synchronized (METHOD_CACHE) { - subscriberMethods = METHOD_CACHE.get(key); + subscriberMethods = METHOD_CACHE.get(subscriberClass); } if (subscriberMethods != null) { return subscriberMethods; @@ -64,7 +63,7 @@ List findSubscriberMethods(Class subscriberClass, boolean f + " and its super classes have no public methods with the @Subscribe annotation"); } else { synchronized (METHOD_CACHE) { - METHOD_CACHE.put(key, subscriberMethods); + METHOD_CACHE.put(subscriberClass, subscriberMethods); } return subscriberMethods; } From 75543c42e087cf9c92ae71ffe38f7040494c6ea3 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 3 Dec 2015 18:23:38 +0100 Subject: [PATCH 066/112] checkAdd optimization: added faster 1st level check --- .../event/SubscriberMethodFinder.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index b6e6779d..45d0a29b 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -201,8 +201,9 @@ static void clearCaches() { } static class FindState { - final List subscriberMethods = new ArrayList(); - final Map eventTypesFound = new HashMap(); + final List subscriberMethods = new ArrayList<>(); + final Map anyMethodByEventType = new HashMap<>(); + final Map subscriberClassByMethodKey = new HashMap<>(); final StringBuilder methodKeyBuilder = new StringBuilder(128); Class subscriberClass; @@ -217,7 +218,8 @@ void initForSubscriber(Class subscriberClass) { void recycle() { subscriberMethods.clear(); - eventTypesFound.clear(); + anyMethodByEventType.clear(); + subscriberClassByMethodKey.clear(); methodKeyBuilder.setLength(0); subscriberClass = null; clazz = null; @@ -226,19 +228,38 @@ void recycle() { } boolean checkAdd(Method method, Class eventType) { + // 2 level check: 1st level with event type only (fast), 2nd level with complete signature when required. + // Usually a subscriber doesn't have methods listening to the same event type. + Object existing = anyMethodByEventType.put(eventType, method); + if (existing == null) { + return true; + } else { + if(existing instanceof Method) { + if(!checkAddWithMethodSignature((Method) existing, eventType)) { + // Paranoia check + throw new IllegalStateException(); + } + // Put any non-Method object to "consume" the existing Method + anyMethodByEventType.put(eventType, this); + } + return checkAddWithMethodSignature(method, eventType); + } + } + + private boolean checkAddWithMethodSignature(Method method, Class eventType) { methodKeyBuilder.setLength(0); methodKeyBuilder.append(method.getName()); methodKeyBuilder.append('>').append(eventType.getName()); String methodKey = methodKeyBuilder.toString(); Class methodClass = method.getDeclaringClass(); - Class methodClassOld = eventTypesFound.put(methodKey, methodClass); + Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { // Only add if not already found in a sub class return true; } else { // Revert the put, old class is further down the class hierarchy - eventTypesFound.put(methodKey, methodClassOld); + subscriberClassByMethodKey.put(methodKey, methodClassOld); return false; } } From 351d99084eb0ba7aacd51dfa1a379ba222df7576 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 3 Dec 2015 21:58:20 +0100 Subject: [PATCH 067/112] fix problem with generic event types, added test for it --- .../EventBusAnnotationProcessor.java | 36 ++++++++++++------- .../event/test/EventBusGenericsTest.java | 26 ++++++++++++++ 2 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index b92492e2..7b22887f 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -22,6 +22,7 @@ import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; import javax.tools.Diagnostic; import javax.tools.JavaFileObject; @@ -31,6 +32,8 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String CLASS_POSTFIX = "_EventBusInfo"; + public static final String JAVA_LANG_PREFIX = "java.lang."; + public static final int JAVA_LANG_PREFIX_LENGTH = JAVA_LANG_PREFIX.length(); /** Found subscriber methods for a class (without superclasses). */ private final Map> methodsByClass = @@ -220,7 +223,7 @@ private void writeSources() { writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); writer.write(" return new SubscriberMethod[] {\n"); Set methodSignatures = new HashSet(); - writeMethods(writer, entry.getValue(), methodSignatures); + writeMethods(writer, entry.getValue(), methodSignatures, myPackage); writer.write(" };\n"); writer.write(" }\n}\n"); } catch (IOException e) { @@ -269,10 +272,15 @@ private String getNextValue(String myPackage, TypeElement nextEntry) throws IOEx return nextValue; } - private String getClassString(TypeElement subscriberClass, String subscriberPackage) { - String className = subscriberClass.getQualifiedName().toString(); - if (!subscriberPackage.isEmpty() && className.startsWith(subscriberPackage)) { - className = className.substring(subscriberPackage.length() + 1); + private String getClassString(TypeElement typeElement, String myPackage) { + String className = typeElement.getQualifiedName().toString(); + int lastPeriod = className.lastIndexOf('.'); + if (!myPackage.isEmpty() && className.startsWith(myPackage) && lastPeriod == myPackage.length()) { + // TODO detect nested types also + + className = className.substring(myPackage.length() + 1); + } else if (className.startsWith(JAVA_LANG_PREFIX) && lastPeriod == JAVA_LANG_PREFIX_LENGTH - 1) { + className = className.substring(JAVA_LANG_PREFIX_LENGTH); } return className; } @@ -302,14 +310,16 @@ private TypeElement nextEntry(List methods, Set methodSignatures) throws IOException { + private void writeMethods(BufferedWriter writer, List methods, Set methodSignatures, + String myPackage) throws IOException { for (ExecutableElement method : methods) { List parameters = method.getParameters(); - VariableElement param = parameters.get(0); - DeclaredType paramType = (DeclaredType) param.asType(); + TypeMirror paramType = parameters.get(0).asType(); + TypeElement paramElement = (TypeElement) processingEnv.getTypeUtils().asElement(paramType); + String eventClass = getClassString(paramElement, myPackage) + ".class"; - String methodSignature = method + ">" + paramType; + String methodSignature = method + ">" + paramElement.getQualifiedName(); if (!methodSignatures.add(methodSignature)) { continue; } @@ -322,13 +332,13 @@ private void writeMethods(BufferedWriter writer, List methods String lineEnd = "),"; if (subscribe.priority() == 0 && !subscribe.sticky()) { if (subscribe.threadMode() == ThreadMode.POSTING) { - parts.add(paramType.toString() + ".class" + lineEnd); + parts.add(eventClass + lineEnd); } else { - parts.add(paramType.toString() + ".class,"); + parts.add(eventClass + ","); parts.add("ThreadMode." + subscribe.threadMode().name() + lineEnd); } } else { - parts.add(paramType.toString() + ".class,"); + parts.add(eventClass + ","); parts.add("ThreadMode." + subscribe.threadMode().name() + ","); parts.add(subscribe.priority() + ","); parts.add(subscribe.sticky() + lineEnd); @@ -337,7 +347,7 @@ private void writeMethods(BufferedWriter writer, List methods processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Indexed @Subscribe at " + method.getEnclosingElement().getSimpleName() + "." + methodName + - "(" + paramType.asElement().getSimpleName() + ")"); + "(" + paramElement.getSimpleName() + ")"); } } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java new file mode 100644 index 00000000..a8a31284 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java @@ -0,0 +1,26 @@ +package de.greenrobot.event.test; + +import de.greenrobot.event.EventBus; +import de.greenrobot.event.Subscribe; + +public class EventBusGenericsTest extends AbstractEventBusTest { + public static class GenericEvent { + T value; + } + + public class GenericSubscriber { + @Subscribe + public void onGenericEvent(GenericEvent event) { + trackEvent(event); + } + } + + public void testGenericEventAndSubscriber() { + GenericSubscriber genericSubscriber = new GenericSubscriber(); + eventBus.register(genericSubscriber); + eventBus.post(new GenericEvent()); + eventBus.unregister(genericSubscriber); + + assertEventCount(1); + } +} From d9833fd3e3a3149b50244421eacde2ac729b0c5a Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 10:18:54 +0100 Subject: [PATCH 068/112] update perf to otto 1.3.8 --- EventBusPerformance/build.gradle | 2 +- .../src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index b7a42f28..54801afa 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { compile project(':EventBus') provided project(':EventBusAnnotationProcessor') - compile 'com.squareup:otto:1.3.7' + compile 'com.squareup:otto:1.3.8' } android { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java index 6e1cb890..0d191aeb 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java @@ -4,6 +4,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import android.app.Activity; import android.content.Context; @@ -117,7 +118,7 @@ public void runTest() { for (Object subscriber : super.subscribers) { if (cacheField != null) { try { - cacheField.set(null, new HashMap()); + cacheField.set(null, new ConcurrentHashMap()); } catch (Exception e) { throw new RuntimeException(e); } From 966fa3ef5149db72f478be37509e489c0bfbf742 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 10:20:30 +0100 Subject: [PATCH 069/112] update test to android-apt 1.8 --- EventBusTest/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 4583d580..62ed11a5 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -5,7 +5,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:1.3.1' - classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' + classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } From d3e87d825422d4e3e24ce1ca28e1c4638fa61cd6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 10:23:07 +0100 Subject: [PATCH 070/112] fix cutting the package for getClassString --- .../EventBusAnnotationProcessor.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 7b22887f..0b59da79 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -32,8 +32,6 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String CLASS_POSTFIX = "_EventBusInfo"; - public static final String JAVA_LANG_PREFIX = "java.lang."; - public static final int JAVA_LANG_PREFIX_LENGTH = JAVA_LANG_PREFIX.length(); /** Found subscriber methods for a class (without superclasses). */ private final Map> methodsByClass = @@ -273,18 +271,29 @@ private String getNextValue(String myPackage, TypeElement nextEntry) throws IOEx } private String getClassString(TypeElement typeElement, String myPackage) { + PackageElement packageElement = getPackageElement(typeElement); + String packageString = packageElement.getQualifiedName().toString(); String className = typeElement.getQualifiedName().toString(); - int lastPeriod = className.lastIndexOf('.'); - if (!myPackage.isEmpty() && className.startsWith(myPackage) && lastPeriod == myPackage.length()) { - // TODO detect nested types also - - className = className.substring(myPackage.length() + 1); - } else if (className.startsWith(JAVA_LANG_PREFIX) && lastPeriod == JAVA_LANG_PREFIX_LENGTH - 1) { - className = className.substring(JAVA_LANG_PREFIX_LENGTH); + if (packageString != null && !packageString.isEmpty()) { + if (packageString.equals(myPackage)) { + className = cutPackage(myPackage, className); + } else if (packageString.equals("java.lang")) { + className = typeElement.getSimpleName().toString(); + } } return className; } + private String cutPackage(String paket, String className) { + if (className.startsWith(paket + '.')) { + // Don't use TypeElement.getSimpleName, it doesn't work for us with inner classes + return className.substring(paket.length() + 1); + } else { + // Paranoia + throw new IllegalStateException("Mismatching " + paket + " vs. " + className); + } + } + private PackageElement getPackageElement(TypeElement subscriberClass) { Element candidate = subscriberClass.getEnclosingElement(); while (!(candidate instanceof PackageElement)) { From 8c328d3b0ab9d9c51b68f1f73c94d497c4f8bad6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 11:03:11 +0100 Subject: [PATCH 071/112] move anonymous class detection after cache check --- .../src/de/greenrobot/event/EventBus.java | 10 +---- .../event/SubscriberMethodFinder.java | 41 +++++++++++++++---- .../src/de/greenrobot/eventperf/Test.java | 2 +- .../testsubject/PerfTestEventBus.java | 22 ---------- .../SubscribeClassEventBusDefault.java | 32 +++++++++++++++ 5 files changed, 68 insertions(+), 39 deletions(-) create mode 100644 EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index af47c7b9..1fab2e3e 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -130,16 +130,8 @@ public EventBus() { */ public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); - - // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection - // Note: Avoid Class.isAnonymousClass() because it is super slow (getSimpleName() is super slow, too) - String name = subscriberClass.getName(); - int dollarIndex = name.lastIndexOf('$'); - boolean forceReflection = dollarIndex != -1 && dollarIndex < name.length() - 1 && - Character.isDigit(name.charAt(dollarIndex + 1)); - List subscriberMethods = - subscriberMethodFinder.findSubscriberMethods(subscriberClass, forceReflection); + subscriberMethodFinder.findSubscriberMethods(subscriberClass); for (SubscriberMethod subscriberMethod : subscriberMethods) { subscribe(subscriber, subscriberMethod); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 45d0a29b..fa31afd3 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -45,7 +45,7 @@ class SubscriberMethodFinder { this.ignoreGeneratedIndex = ignoreGeneratedIndex; } - List findSubscriberMethods(Class subscriberClass, boolean forceReflection) { + List findSubscriberMethods(Class subscriberClass) { List subscriberMethods; synchronized (METHOD_CACHE) { subscriberMethods = METHOD_CACHE.get(subscriberClass); @@ -53,10 +53,12 @@ List findSubscriberMethods(Class subscriberClass, boolean f if (subscriberMethods != null) { return subscriberMethods; } - if (!ignoreGeneratedIndex && !forceReflection) { - subscriberMethods = findUsingInfo(subscriberClass); - } else { + + boolean forceReflection = isAnonymousClass(subscriberClass); + if (ignoreGeneratedIndex || forceReflection) { subscriberMethods = findUsingReflection(subscriberClass); + } else { + subscriberMethods = findUsingInfo(subscriberClass); } if (subscriberMethods.isEmpty()) { throw new EventBusException("Subscriber " + subscriberClass @@ -69,6 +71,15 @@ List findSubscriberMethods(Class subscriberClass, boolean f } } + private boolean isAnonymousClass(Class subscriberClass) { + // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection + // Note: Avoid Class.isAnonymousClass() because it is super slow (getSimpleName() is super slow, too) + String name = subscriberClass.getName(); + int dollarIndex = name.lastIndexOf('$'); + return dollarIndex != -1 && dollarIndex < name.length() - 1 && + Character.isDigit(name.charAt(dollarIndex + 1)); + } + private List findUsingInfo(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); @@ -128,7 +139,7 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { throw new EventBusException(e); } } - String infoClass = findState.clazz.getName().replace('$', '_') + "_EventBusInfo"; + String infoClass = getInfoClassName(findState); try { Class aClass = Class.forName(infoClass); Object object = aClass.newInstance(); @@ -143,6 +154,22 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { return info; } + // A simple replace(char, char) is surprisingly slow + private String getInfoClassName(FindState findState) { + String className = findState.clazz.getName(); + for (int i = className.length() - 1; i >= 0; i--) { + char c = className.charAt(i); + if (c == '.') { + break; + } else if (c == '$') { + className = className.replace('$', '_'); + break; + } + } + return className + "_EventBusInfo"; +// return className.replace('$', '_')+ "_EventBusInfo"; + } + private List findUsingReflection(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); @@ -234,8 +261,8 @@ boolean checkAdd(Method method, Class eventType) { if (existing == null) { return true; } else { - if(existing instanceof Method) { - if(!checkAddWithMethodSignature((Method) existing, eventType)) { + if (existing instanceof Method) { + if (!checkAddWithMethodSignature((Method) existing, eventType)) { // Paranoia check throw new IllegalStateException(); } diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java b/EventBusPerformance/src/de/greenrobot/eventperf/Test.java index 8c52d9aa..0c510d86 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/Test.java @@ -7,7 +7,7 @@ public abstract class Test { protected final Context context; protected final TestParams params; - protected AtomicLong eventsReceivedCount = new AtomicLong(); + public final AtomicLong eventsReceivedCount = new AtomicLong(); protected long primaryResultMicros; protected int primaryResultCount; protected String otherTestResults; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 70d4a8cd..4ad44afa 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -186,28 +186,6 @@ public String getDisplayName() { } - public class SubscribeClassEventBusDefault { - @Subscribe - public void onEvent(TestEvent event) { - eventsReceivedCount.incrementAndGet(); - } - - public void dummy() { - } - - public void dummy2() { - } - - public void dummy3() { - } - - public void dummy4() { - } - - public void dummy5() { - } - } - public class SubscribeClassEventBusMain { @Subscribe(threadMode = ThreadMode.MAIN) public void onEventMainThread(TestEvent event) { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java new file mode 100644 index 00000000..2deabf7d --- /dev/null +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java @@ -0,0 +1,32 @@ +package de.greenrobot.eventperf.testsubject; + +import de.greenrobot.event.Subscribe; +import de.greenrobot.eventperf.TestEvent; + +public class SubscribeClassEventBusDefault { + private PerfTestEventBus perfTestEventBus; + + public SubscribeClassEventBusDefault(PerfTestEventBus perfTestEventBus) { + this.perfTestEventBus = perfTestEventBus; + } + + @Subscribe + public void onEvent(TestEvent event) { + perfTestEventBus.eventsReceivedCount.incrementAndGet(); + } + + public void dummy() { + } + + public void dummy2() { + } + + public void dummy3() { + } + + public void dummy4() { + } + + public void dummy5() { + } +} From 254a27f411c374005f6b22de5d71d27dd60fb6ce Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 11:59:19 +0100 Subject: [PATCH 072/112] make METHOD_CACHE a ConcurrentHashMap --- .../greenrobot/event/SubscriberMethodFinder.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index fa31afd3..cd4e7187 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; class SubscriberMethodFinder { /* @@ -32,7 +33,7 @@ class SubscriberMethodFinder { private static final int SYNTHETIC = 0x1000; private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; - private static final Map, List> METHOD_CACHE = new HashMap, List>(); + private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>(); private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; @@ -46,10 +47,7 @@ class SubscriberMethodFinder { } List findSubscriberMethods(Class subscriberClass) { - List subscriberMethods; - synchronized (METHOD_CACHE) { - subscriberMethods = METHOD_CACHE.get(subscriberClass); - } + List subscriberMethods = METHOD_CACHE.get(subscriberClass); if (subscriberMethods != null) { return subscriberMethods; } @@ -64,9 +62,7 @@ List findSubscriberMethods(Class subscriberClass) { throw new EventBusException("Subscriber " + subscriberClass + " and its super classes have no public methods with the @Subscribe annotation"); } else { - synchronized (METHOD_CACHE) { - METHOD_CACHE.put(subscriberClass, subscriberMethods); - } + METHOD_CACHE.put(subscriberClass, subscriberMethods); return subscriberMethods; } } @@ -222,9 +218,7 @@ private void findUsingReflectionInSingleClass(FindState findState) { } static void clearCaches() { - synchronized (METHOD_CACHE) { - METHOD_CACHE.clear(); - } + METHOD_CACHE.clear(); } static class FindState { From 0a013ffcc55a96e8a5ce4d2ac862b33cf5e2cc00 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 12:05:20 +0100 Subject: [PATCH 073/112] some generic diamonds, minor --- EventBus/src/de/greenrobot/event/EventBus.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 1fab2e3e..725d4178 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,7 +46,7 @@ public class EventBus { static volatile EventBus defaultInstance; private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder(); - private static final Map, List>> eventTypesCache = new HashMap, List>>(); + private static final Map, List>> eventTypesCache = new HashMap<>(); private final Map, CopyOnWriteArrayList> subscriptionsByEventType; private final Map>> typesBySubscriber; @@ -103,9 +103,9 @@ public EventBus() { } EventBus(EventBusBuilder builder) { - subscriptionsByEventType = new HashMap, CopyOnWriteArrayList>(); - typesBySubscriber = new HashMap>>(); - stickyEvents = new ConcurrentHashMap, Object>(); + subscriptionsByEventType = new HashMap<>(); + typesBySubscriber = new HashMap<>(); + stickyEvents = new ConcurrentHashMap<>(); mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); @@ -140,8 +140,8 @@ public void register(Object subscriber) { // Must be called in synchronized block private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Class eventType = subscriberMethod.eventType; - CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); Subscription newSubscription = new Subscription(subscriber, subscriberMethod); + CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { subscriptions = new CopyOnWriteArrayList(); subscriptionsByEventType.put(eventType, subscriptions); From b8dc2f648f85e97cea9ebe13975b245883941aa3 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 12:30:46 +0100 Subject: [PATCH 074/112] fixed synchronization (introduced in 7952c05234bb845552599fe86148112eb2bcf20c - annotation branch only), minor clean up --- .../src/de/greenrobot/event/EventBus.java | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 725d4178..02548d34 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -130,10 +130,11 @@ public EventBus() { */ public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); - List subscriberMethods = - subscriberMethodFinder.findSubscriberMethods(subscriberClass); - for (SubscriberMethod subscriberMethod : subscriberMethods) { - subscribe(subscriber, subscriberMethod); + List subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass); + synchronized (this) { + for (SubscriberMethod subscriberMethod : subscriberMethods) { + subscribe(subscriber, subscriberMethod); + } } } @@ -143,7 +144,7 @@ private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { Subscription newSubscription = new Subscription(subscriber, subscriberMethod); CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions == null) { - subscriptions = new CopyOnWriteArrayList(); + subscriptions = new CopyOnWriteArrayList<>(); subscriptionsByEventType.put(eventType, subscriptions); } else { if (subscriptions.contains(newSubscription)) { @@ -152,23 +153,17 @@ private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) { } } - // Starting with EventBus 2.2 we enforced methods to be public (might change with annotations again) - // subscriberMethod.method.setAccessible(true); - - // Got to synchronize to avoid shifted positions when adding/removing concurrently - synchronized (subscriptions) { - int size = subscriptions.size(); - for (int i = 0; i <= size; i++) { - if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { - subscriptions.add(i, newSubscription); - break; - } + int size = subscriptions.size(); + for (int i = 0; i <= size; i++) { + if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) { + subscriptions.add(i, newSubscription); + break; } } List> subscribedEvents = typesBySubscriber.get(subscriber); if (subscribedEvents == null) { - subscribedEvents = new ArrayList>(); + subscribedEvents = new ArrayList<>(); typesBySubscriber.put(subscriber, subscribedEvents); } subscribedEvents.add(eventType); @@ -210,17 +205,14 @@ public synchronized boolean isRegistered(Object subscriber) { private void unsubscribeByEventType(Object subscriber, Class eventType) { List subscriptions = subscriptionsByEventType.get(eventType); if (subscriptions != null) { - // Got to synchronize to avoid shifted positions when adding/removing concurrently - synchronized (subscriptions) { - int size = subscriptions.size(); - for (int i = 0; i < size; i++) { - Subscription subscription = subscriptions.get(i); - if (subscription.subscriber == subscriber) { - subscription.active = false; - subscriptions.remove(i); - i--; - size--; - } + int size = subscriptions.size(); + for (int i = 0; i < size; i++) { + Subscription subscription = subscriptions.get(i); + if (subscription.subscriber == subscriber) { + subscription.active = false; + subscriptions.remove(i); + i--; + size--; } } } @@ -443,11 +435,11 @@ private void postToSubscription(Subscription subscription, Object event, boolean } /** Looks up all Class objects including super classes and interfaces. Should also work for interfaces. */ - private List> lookupAllEventTypes(Class eventClass) { + private static List> lookupAllEventTypes(Class eventClass) { synchronized (eventTypesCache) { List> eventTypes = eventTypesCache.get(eventClass); if (eventTypes == null) { - eventTypes = new ArrayList>(); + eventTypes = new ArrayList<>(); Class clazz = eventClass; while (clazz != null) { eventTypes.add(clazz); From c7b43c7d78bc1d41f83a16662df5dd3ef94ba020 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 12:39:14 +0100 Subject: [PATCH 075/112] removed anonymous class detection (will fallback to reflection anyway) --- .../greenrobot/event/SubscriberMethodFinder.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index cd4e7187..dde68fc1 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -52,8 +52,7 @@ List findSubscriberMethods(Class subscriberClass) { return subscriberMethods; } - boolean forceReflection = isAnonymousClass(subscriberClass); - if (ignoreGeneratedIndex || forceReflection) { + if (ignoreGeneratedIndex) { subscriberMethods = findUsingReflection(subscriberClass); } else { subscriberMethods = findUsingInfo(subscriberClass); @@ -67,15 +66,6 @@ List findSubscriberMethods(Class subscriberClass) { } } - private boolean isAnonymousClass(Class subscriberClass) { - // @Subscribe in anonymous classes is invisible to annotation processing, always fall back to reflection - // Note: Avoid Class.isAnonymousClass() because it is super slow (getSimpleName() is super slow, too) - String name = subscriberClass.getName(); - int dollarIndex = name.lastIndexOf('$'); - return dollarIndex != -1 && dollarIndex < name.length() - 1 && - Character.isDigit(name.charAt(dollarIndex + 1)); - } - private List findUsingInfo(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); From 637b27a89f754d1888c9a9c75f54319cf71eb064 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 13:19:37 +0100 Subject: [PATCH 076/112] prevent the compiler from introducing a new StringBuilder --- .../de/greenrobot/event/SubscriberMethodFinder.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index dde68fc1..99a5364f 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -140,7 +140,7 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { return info; } - // A simple replace(char, char) is surprisingly slow + // A simple replace(char, char) is surprisingly slow, so we try to avoid it private String getInfoClassName(FindState findState) { String className = findState.clazz.getName(); for (int i = className.length() - 1; i >= 0; i--) { @@ -152,8 +152,7 @@ private String getInfoClassName(FindState findState) { break; } } - return className + "_EventBusInfo"; -// return className.replace('$', '_')+ "_EventBusInfo"; + return className.concat("_EventBusInfo"); } private List findUsingReflection(Class subscriberClass) { @@ -219,12 +218,13 @@ static class FindState { Class subscriberClass; Class clazz; - String clazzName; boolean skipSuperClasses; SubscriberInfo subscriberInfo; void initForSubscriber(Class subscriberClass) { this.subscriberClass = clazz = subscriberClass; + skipSuperClasses = false; + subscriberInfo = null; } void recycle() { @@ -278,14 +278,12 @@ private boolean checkAddWithMethodSignature(Method method, Class eventType) { void moveToSuperclass() { if (skipSuperClasses) { clazz = null; - clazzName = null; } else { clazz = clazz.getSuperclass(); - clazzName = clazz.getName(); + String clazzName = clazz.getName(); /** Skip system classes, this just degrades performance. */ if (clazzName.startsWith("java.") || clazzName.startsWith("javax.") || clazzName.startsWith("android.")) { clazz = null; - clazzName = null; } } } From d6229b1598d8b989cf4422bf861dbffdfa64fb25 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 13:20:10 +0100 Subject: [PATCH 077/112] minor typo --- .../src/de/greenrobot/event/test/AbstractEventBusTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java index 2d997620..7df0e202 100644 --- a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ * @author Markus Junginger, greenrobot */ public class AbstractEventBusTest extends TestCase { - /** Activates long(er) running tests e.g. testing multi-threading more throughly. */ + /** Activates long(er) running tests e.g. testing multi-threading more thoroughly. */ protected static final boolean LONG_TESTS = false; protected EventBus eventBus; From 808a4ef847d31c516c9ed692bd0c4506890decad Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 14:51:01 +0100 Subject: [PATCH 078/112] minor --- EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 99a5364f..e52cb996 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -87,7 +87,7 @@ private List findUsingInfo(Class subscriberClass) { } private List getMethodsAndRelease(FindState findState) { - ArrayList subscriberMethods = new ArrayList<>(findState.subscriberMethods); + List subscriberMethods = new ArrayList<>(findState.subscriberMethods); findState.recycle(); synchronized (FIND_STATE_POOL) { for (int i = 0; i < POOL_SIZE; i++) { @@ -168,7 +168,7 @@ private List findUsingReflection(Class subscriberClass) { private void findUsingReflectionInSingleClass(FindState findState) { Method[] methods; try { - // This is faster than getMethods, especially when subscribers a fat classes like Activities + // This is faster than getMethods, especially when subscribers are fat classes like Activities methods = findState.clazz.getDeclaredMethods(); } catch (Throwable th) { // Workaround for java.lang.NoClassDefFoundError, see https://github.com/greenrobot/EventBus/issues/149 From 976ebbce1c5bd30c2faa8f62ec972ff580ca65d0 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 16:17:51 +0100 Subject: [PATCH 079/112] added SubscriberInfoIndex interface and generated implementation skeleton --- .../greenrobot/event/SubscriberInfoIndex.java | 8 +++ EventBusAnnotationProcessor/build.gradle | 2 +- .../EventBusAnnotationProcessor.java | 51 ++++++++++++++++++- EventBusPerformance/build.gradle | 14 +++-- 4 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java b/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java new file mode 100644 index 00000000..9107fc3a --- /dev/null +++ b/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java @@ -0,0 +1,8 @@ +package de.greenrobot.event; + +/** + * Interface for generated indexes. + */ +public interface SubscriberInfoIndex { + SubscriberInfo getSubscriberInfo(Class subscriberClass); +} diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index 3fb5d8fd..f8bf0b07 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -6,7 +6,7 @@ archivesBaseName = 'eventbus-annotation-processor' group = 'de.greenrobot' version = '3.0.0-beta2' -sourceCompatibility = 1.6 +sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') def sonatypeRepositoryUrl diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 0b59da79..37bebccc 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -73,6 +73,10 @@ public boolean process(Set annotations, RoundEnvironment if (!methodsByClass.isEmpty()) { writeSources(); + String index = processingEnv.getOptions().get("eventBusIndex"); + if (index != null) { + writeIndex(index); + } } else { messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); } @@ -188,8 +192,7 @@ private TypeElement getSuperclass(TypeElement type) { } private void writeSources() { - List>> entries = - new ArrayList>>(methodsByClass.entrySet()); + List>> entries = new ArrayList<>(methodsByClass.entrySet()); for (int i = 0; i < entries.size(); i++) { Map.Entry> entry = entries.get(i); TypeElement subscriberClass = entry.getKey(); @@ -361,6 +364,50 @@ private void writeMethods(BufferedWriter writer, List methods } } + private void writeIndex(String index) { + BufferedWriter writer = null; + try { + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index); + int period = index.lastIndexOf('.'); + String myPackage = period > 0 ? index.substring(0, period) : null; + String clazz = index.substring(period + 1); + writer = new BufferedWriter(sourceFile.openWriter()); + if (myPackage != null) { + writer.write("package " + myPackage + ";\n\n"); + } + writer.write("import de.greenrobot.event.SubscriberInfo;\n"); + writer.write("import de.greenrobot.event.SubscriberInfoIndex;\n\n"); + writer.write("import java.util.HashMap;\n"); + writer.write("import java.util.Map;\n\n"); + writer.write("/** This class is generated by EventBus, do not edit. */\n"); + writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n"); + writer.write(" private static final Map,Class> SUBSCRIBER_INDEX;\n\n"); + writer.write(" static {\n"); + writer.write(" SUBSCRIBER_INDEX = new HashMap,Class>();\n"); + writer.write(" }\n\n"); + writer.write(" @Override\n"); + writer.write(" public SubscriberInfo getSubscriberInfo(Class subscriberClass) {\n"); + writer.write(" Class infoClass = SUBSCRIBER_INDEX.get(subscriberClass);\n"); + writer.write(" try {\n"); + writer.write(" return infoClass != null? infoClass.newInstance(): null;\n"); + writer.write(" } catch(Exception ex) {\n"); + writer.write(" throw new RuntimeException(ex);\n"); + writer.write(" }\n"); + writer.write(" }\n"); + writer.write("}\n"); + } catch (IOException e) { + throw new RuntimeException("Could not write source for " + index, e); + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + //Silent + } + } + } + } + private void writeLine(BufferedWriter writer, int indentLevel, String... parts) throws IOException { writeIndent(writer, indentLevel); int len = indentLevel * 4; diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 54801afa..12f19fb6 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -4,11 +4,13 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'com.android.tools.build:gradle:1.5.0' + classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } } apply plugin: 'com.android.application' +apply plugin: 'com.neenbedankt.android-apt' repositories { jcenter() @@ -16,12 +18,18 @@ repositories { dependencies { compile project(':EventBus') - provided project(':EventBusAnnotationProcessor') + apt project(':EventBusAnnotationProcessor') compile 'com.squareup:otto:1.3.8' } +apt { + arguments { + eventBusIndex "de.greenrobot.eventperf.MyEventBusIndex" + } +} + android { - buildToolsVersion '23.0.1' + buildToolsVersion '23.0.2' compileSdkVersion 19 sourceSets { From 07969b2029d2499ae1d5eb575a047f7ff7b66af6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 20:03:09 +0100 Subject: [PATCH 080/112] index setup code generation --- .../EventBusAnnotationProcessor.java | 77 +++++++++++++++---- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 37bebccc..e1db0065 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -31,12 +31,12 @@ @SupportedAnnotationTypes("de.greenrobot.event.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { - public static final String CLASS_POSTFIX = "_EventBusInfo"; + public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; /** Found subscriber methods for a class (without superclasses). */ - private final Map> methodsByClass = - new HashMap>(); - private final Set classesToSkip = new HashSet(); + private final Map> methodsByClass = new HashMap<>(); + private final Map infoByClass = new HashMap<>(); + private final Set classesToSkip = new HashSet<>(); private boolean writerRoundDone; private int round; @@ -72,10 +72,10 @@ public boolean process(Set annotations, RoundEnvironment checkForSubscribersToSkip(messager); if (!methodsByClass.isEmpty()) { - writeSources(); + createInfoFiles(); String index = processingEnv.getOptions().get("eventBusIndex"); if (index != null) { - writeIndex(index); + createInfoIndexFile(index); } } else { messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); @@ -191,7 +191,7 @@ private TypeElement getSuperclass(TypeElement type) { } } - private void writeSources() { + private void createInfoFiles() { List>> entries = new ArrayList<>(methodsByClass.entrySet()); for (int i = 0; i < entries.size(); i++) { Map.Entry> entry = entries.get(i); @@ -207,6 +207,8 @@ private void writeSources() { String subscriberClassName = getClassString(subscriberClass, myPackage); String infoClassName = getInfoClass(subscriberClass, myPackage); + infoByClass.put(subscriberClass, myPackage + "." + infoClassName); + JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); @@ -254,7 +256,7 @@ private String getSuperclassInfoClass(TypeElement subscriberClass, String myPack private String getInfoClass(TypeElement subscriberClass, String myPackage) { String subscriberClassName = getClassString(subscriberClass, myPackage); - return subscriberClassName.replace('.', '_') + CLASS_POSTFIX; + return subscriberClassName.replace('.', '_') + INFO_CLASS_POSTFIX; } private String getNextValue(String myPackage, TypeElement nextEntry) throws IOException { @@ -364,7 +366,7 @@ private void writeMethods(BufferedWriter writer, List methods } } - private void writeIndex(String index) { + private void createInfoIndexFile(String index) { BufferedWriter writer = null; try { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(index); @@ -381,17 +383,22 @@ private void writeIndex(String index) { writer.write("import java.util.Map;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n"); - writer.write(" private static final Map,Class> SUBSCRIBER_INDEX;\n\n"); + writer.write(" private static final Map, Class> SUBSCRIBER_INDEX;\n\n"); writer.write(" static {\n"); - writer.write(" SUBSCRIBER_INDEX = new HashMap,Class>();\n"); + writer.write(" SUBSCRIBER_INDEX = new HashMap, Class>();\n"); + writeIndexLines(writer, myPackage); writer.write(" }\n\n"); writer.write(" @Override\n"); writer.write(" public SubscriberInfo getSubscriberInfo(Class subscriberClass) {\n"); - writer.write(" Class infoClass = SUBSCRIBER_INDEX.get(subscriberClass);\n"); - writer.write(" try {\n"); - writer.write(" return infoClass != null? infoClass.newInstance(): null;\n"); - writer.write(" } catch(Exception ex) {\n"); - writer.write(" throw new RuntimeException(ex);\n"); + writer.write(" Class infoClass = SUBSCRIBER_INDEX.get(subscriberClass);\n"); + writer.write(" if (infoClass != null) {\n"); + writer.write(" try {\n"); + writer.write(" return infoClass.newInstance();\n"); + writer.write(" } catch (Exception ex) {\n"); + writer.write(" throw new RuntimeException(ex);\n"); + writer.write(" }\n"); + writer.write(" } else {\n"); + writer.write(" return null;\n"); writer.write(" }\n"); writer.write(" }\n"); writer.write("}\n"); @@ -408,6 +415,44 @@ private void writeIndex(String index) { } } + private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException { + for (Map.Entry entry : infoByClass.entrySet()) { + TypeElement subscriberTypeElement = entry.getKey(); + String infoClass = entry.getValue(); + if (!classesToSkip.contains(subscriberTypeElement)) { + int infoPeriod = infoClass.lastIndexOf('.'); + String infoPackage = infoPeriod > 0 ? infoClass.substring(0, infoPeriod) : null; + if (infoPackage.equals(myPackage)) { + infoClass = infoClass.substring(infoPeriod + 1); + } + String subscriberClass = getClassString(subscriberTypeElement, myPackage); + if (isVisible(myPackage, subscriberTypeElement)) { + writeLine(writer, 2, "SUBSCRIBER_INDEX.put(", subscriberClass + ".class,", infoClass + ".class);\n"); + } else { + writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); + } + } + } + } + + private boolean isVisible(String myPackage, TypeElement typeElement) { + Set modifiers = typeElement.getModifiers(); + boolean visible; + if (modifiers.contains(Modifier.PUBLIC)) { + visible = true; + } else if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.PROTECTED)) { + visible = false; + } else { + String subscriberPackage = getPackageElement(typeElement).getQualifiedName().toString(); + if (myPackage == null) { + visible = subscriberPackage.length() == 0; + } else { + visible = myPackage.equals(subscriberPackage); + } + } + return visible; + } + private void writeLine(BufferedWriter writer, int indentLevel, String... parts) throws IOException { writeIndent(writer, indentLevel); int len = indentLevel * 4; From 9f8106982ceeb3d7d36fe9320e96ce57627106b6 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 20:51:23 +0100 Subject: [PATCH 081/112] configure indexes using builder, using it in SubscriberMethodFinder --- .../src/de/greenrobot/event/EventBus.java | 4 ++-- .../de/greenrobot/event/EventBusBuilder.java | 21 +++++++++++++++++-- .../event/SubscriberMethodFinder.java | 18 ++++++++++++---- .../testsubject/PerfTestEventBus.java | 3 ++- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index 02548d34..cbdd10ef 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -109,7 +109,8 @@ public EventBus() { mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); - subscriberMethodFinder = new SubscriberMethodFinder(/* TODO */ false, builder.ignoreGeneratedIndex); + subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, + builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; logNoSubscriberMessages = builder.logNoSubscriberMessages; sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent; @@ -119,7 +120,6 @@ public EventBus() { executorService = builder.executorService; } - /** * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they * are no longer interested in receiving events. diff --git a/EventBus/src/de/greenrobot/event/EventBusBuilder.java b/EventBus/src/de/greenrobot/event/EventBusBuilder.java index c8b75a6d..c51c69aa 100644 --- a/EventBus/src/de/greenrobot/event/EventBusBuilder.java +++ b/EventBus/src/de/greenrobot/event/EventBusBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2014-2015 Markus Junginger, greenrobot (http://greenrobot.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,8 +34,10 @@ public class EventBusBuilder { boolean throwSubscriberException; boolean eventInheritance = true; boolean ignoreGeneratedIndex; + boolean strictMethodVerification; ExecutorService executorService = DEFAULT_EXECUTOR_SERVICE; List> skipMethodVerificationForClasses; + List subscriberInfoIndexes; EventBusBuilder() { } @@ -106,7 +108,7 @@ public EventBusBuilder executorService(ExecutorService executorService) { */ public EventBusBuilder skipMethodVerificationFor(Class clazz) { if (skipMethodVerificationForClasses == null) { - skipMethodVerificationForClasses = new ArrayList>(); + skipMethodVerificationForClasses = new ArrayList<>(); } skipMethodVerificationForClasses.add(clazz); return this; @@ -118,6 +120,21 @@ public EventBusBuilder ignoreGeneratedIndex(boolean ignoreGeneratedIndex) { return this; } + /** Enables strict method verification (default: false). */ + public EventBusBuilder strictMethodVerification(boolean strictMethodVerification) { + this.strictMethodVerification = strictMethodVerification; + return this; + } + + /** Adds an index generated by EventBus' annotation preprocessor. */ + public EventBusBuilder addIndex(SubscriberInfoIndex index) { + if(subscriberInfoIndexes == null) { + subscriberInfoIndexes = new ArrayList<>(); + } + subscriberInfoIndexes.add(index); + return this; + } + /** * Installs the default EventBus returned by {@link EventBus#getDefault()} using this builders' values. Must be * done only once before the first usage of the default EventBus. diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index e52cb996..bc0ee8fd 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -35,13 +35,16 @@ class SubscriberMethodFinder { private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC | BRIDGE | SYNTHETIC; private static final Map, List> METHOD_CACHE = new ConcurrentHashMap<>(); + private List subscriberInfoIndexes; private final boolean strictMethodVerification; private final boolean ignoreGeneratedIndex; private static final int POOL_SIZE = 4; private static final FindState[] FIND_STATE_POOL = new FindState[POOL_SIZE]; - SubscriberMethodFinder(boolean strictMethodVerification, boolean ignoreGeneratedIndex) { + SubscriberMethodFinder(List subscriberInfoIndexes, boolean strictMethodVerification, + boolean ignoreGeneratedIndex) { + this.subscriberInfoIndexes = subscriberInfoIndexes; this.strictMethodVerification = strictMethodVerification; this.ignoreGeneratedIndex = ignoreGeneratedIndex; } @@ -114,7 +117,6 @@ private FindState prepareFindState() { } private SubscriberInfo getSubscriberInfo(FindState findState) { - SubscriberInfo info = null; if (findState.subscriberInfo != null && findState.subscriberInfo.superSubscriberInfoClass != null) { try { SubscriberInfo superclassInfo = (SubscriberInfo) findState.subscriberInfo.superSubscriberInfoClass.newInstance(); @@ -125,19 +127,27 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { throw new EventBusException(e); } } + if (subscriberInfoIndexes != null) { + for (SubscriberInfoIndex index : subscriberInfoIndexes) { + SubscriberInfo info = index.getSubscriberInfo(findState.clazz); + if (info != null) { + return info; + } + } + } String infoClass = getInfoClassName(findState); try { Class aClass = Class.forName(infoClass); Object object = aClass.newInstance(); if (object instanceof SubscriberInfo) { - info = (SubscriberInfo) object; + return (SubscriberInfo) object; } } catch (ClassNotFoundException e) { // TODO don't try again } catch (Exception e) { throw new EventBusException("Could not get infos for " + findState.clazz, e); } - return info; + return null; } // A simple replace(char, char) is surprisingly slow, so we try to avoid it diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index 4ad44afa..cd0ae167 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -8,6 +8,7 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.ThreadMode; import de.greenrobot.event.Subscribe; +import de.greenrobot.eventperf.MyEventBusIndex; import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; import de.greenrobot.eventperf.TestParams; @@ -22,7 +23,7 @@ public abstract class PerfTestEventBus extends Test { public PerfTestEventBus(Context context, TestParams params) { super(context, params); - eventBus = EventBus.builder().eventInheritance(params.isEventInheritance()) + eventBus = EventBus.builder().eventInheritance(params.isEventInheritance()).addIndex(new MyEventBusIndex()) .ignoreGeneratedIndex(params.isIgnoreGeneratedIndex()).build(); subscribers = new ArrayList(); eventCount = params.getEventCount(); From d6e2a6ae8fc6f7cc55277c9afcb4082da732dfa8 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 21:47:23 +0100 Subject: [PATCH 082/112] made SubscriberInfo an interface, removed next subscriber info class, added shouldCheckSuperclass --- .../event/AbstractSubscriberInfo.java | 67 +++++++++++++++++++ .../de/greenrobot/event/SubscriberInfo.java | 52 ++++++-------- .../greenrobot/event/SubscriberInfoIndex.java | 15 +++++ .../event/SubscriberMethodFinder.java | 8 +-- .../EventBusAnnotationProcessor.java | 38 +++-------- 5 files changed, 115 insertions(+), 65 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java diff --git a/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java b/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java new file mode 100644 index 00000000..df36f136 --- /dev/null +++ b/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.greenrobot.event; + +import java.lang.reflect.Method; + +/** Base class for generated subscriber meta info classes created by annotation processing. */ +public abstract class AbstractSubscriberInfo implements SubscriberInfo { + private final Class subscriberClass; + private final Class superSubscriberInfoClass; + private final boolean shouldCheckSuperclass; + + protected AbstractSubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, + boolean shouldCheckSuperclass) { + this.subscriberClass = subscriberClass; + this.superSubscriberInfoClass = superSubscriberInfoClass; + this.shouldCheckSuperclass = shouldCheckSuperclass; + } + + @Override + public Class getSubscriberClass() { + return subscriberClass; + } + + @Override + public Class getSuperSubscriberInfoClass() { + return superSubscriberInfoClass; + } + + @Override + public boolean shouldCheckSuperclass() { + return shouldCheckSuperclass; + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType) { + return createSubscriberMethod(methodName, eventType, ThreadMode.POSTING, 0, false); + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode) { + return createSubscriberMethod(methodName, eventType, threadMode, 0, false); + } + + protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode, + int priority, boolean sticky) { + try { + Method method = subscriberClass.getDeclaredMethod(methodName, eventType); + return new SubscriberMethod(method, eventType, threadMode, priority, sticky); + } catch (NoSuchMethodException e) { + throw new EventBusException("Could not find subscriber method in " + subscriberClass + + ". Maybe a missing ProGuard rule?", e); + } + } + +} diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/SubscriberInfo.java index 43ed290c..635a4a0a 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfo.java @@ -1,39 +1,27 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package de.greenrobot.event; -import java.lang.reflect.Method; - /** Base class for generated index classes created by annotation processing. */ -public abstract class SubscriberInfo { - final Class subscriberClass; - final Class superSubscriberInfoClass; - final Class nextSubscriberInfoClass; - - protected SubscriberInfo(Class subscriberClass, Class superSubscriberInfoClass, Class nextSubscriberInfoClass) { - this.subscriberClass = subscriberClass; - this.superSubscriberInfoClass = superSubscriberInfoClass; - this.nextSubscriberInfoClass = nextSubscriberInfoClass; - } - - abstract protected SubscriberMethod[] createSubscriberMethods(); - - protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType) { - return createSubscriberMethod(methodName, eventType, ThreadMode.POSTING, 0, false); - - } +public interface SubscriberInfo { + Class getSubscriberClass(); - protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode) { - return createSubscriberMethod(methodName, eventType, threadMode, 0, false); - } + SubscriberMethod[] getSubscriberMethods(); - protected SubscriberMethod createSubscriberMethod(String methodName, Class eventType, ThreadMode threadMode, - int priority, boolean sticky) { - try { - Method method = subscriberClass.getDeclaredMethod(methodName, eventType); - return new SubscriberMethod(method, eventType, threadMode, priority, sticky); - } catch (NoSuchMethodException e) { - throw new EventBusException("Could not find subscriber method in " + subscriberClass + - ". Maybe a missing ProGuard rule?", e); - } - } + Class getSuperSubscriberInfoClass(); + boolean shouldCheckSuperclass(); } diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java b/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java index 9107fc3a..f5772fb1 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java +++ b/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package de.greenrobot.event; /** diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index bc0ee8fd..8df6ae0b 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -75,7 +75,7 @@ private List findUsingInfo(Class subscriberClass) { while (findState.clazz != null) { findState.subscriberInfo = getSubscriberInfo(findState); if (findState.subscriberInfo != null) { - SubscriberMethod[] array = findState.subscriberInfo.createSubscriberMethods(); + SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods(); for (SubscriberMethod subscriberMethod : array) { if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) { findState.subscriberMethods.add(subscriberMethod); @@ -117,10 +117,10 @@ private FindState prepareFindState() { } private SubscriberInfo getSubscriberInfo(FindState findState) { - if (findState.subscriberInfo != null && findState.subscriberInfo.superSubscriberInfoClass != null) { + if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfoClass() != null) { try { - SubscriberInfo superclassInfo = (SubscriberInfo) findState.subscriberInfo.superSubscriberInfoClass.newInstance(); - if (findState.clazz == superclassInfo.subscriberClass) { + SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfoClass().newInstance(); + if (findState.clazz == superclassInfo.getSubscriberClass()) { return superclassInfo; } } catch (IllegalAccessException | InstantiationException e) { diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index e1db0065..b722a57b 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -212,21 +212,19 @@ private void createInfoFiles() { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); - writer.write("import de.greenrobot.event.SubscriberInfo;\n"); + writer.write("import de.greenrobot.event.AbstractSubscriberInfo;\n"); writer.write("import de.greenrobot.event.SubscriberMethod;\n"); writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); - writer.write("public class " + infoClassName + " extends SubscriberInfo {\n"); + writer.write("public class " + infoClassName + " extends AbstractSubscriberInfo {\n"); writer.write(" public " + infoClassName + "() {\n"); - TypeElement nextEntry = nextEntry(entries, entry, i); - String next = getNextValue(myPackage, nextEntry); String infoSuperClass = getSuperclassInfoClass(subscriberClass, myPackage); - writeLine(writer, 2, "super(" + subscriberClassName + ".class,", infoSuperClass + ",", next + ");"); + writeLine(writer, 2, "super(" + subscriberClassName + ".class,", infoSuperClass + ",", "/* TODO */ true);"); writer.write(" }\n\n"); - writer.write(" protected SubscriberMethod[] createSubscriberMethods() {\n"); + writer.write(" public SubscriberMethod[] getSubscriberMethods() {\n"); writer.write(" return new SubscriberMethod[] {\n"); - Set methodSignatures = new HashSet(); - writeMethods(writer, entry.getValue(), methodSignatures, myPackage); + Set methodSignatures = new HashSet<>(); + writeCreateSubscriberMethods(writer, entry.getValue(), methodSignatures, myPackage); writer.write(" };\n"); writer.write(" }\n}\n"); } catch (IOException e) { @@ -307,27 +305,9 @@ private PackageElement getPackageElement(TypeElement subscriberClass) { return (PackageElement) candidate; } - private TypeElement nextEntry(List>> entries, - Map.Entry> current, int currentIdx) { - for (int i = currentIdx + 1; ; i++) { - if (i == entries.size()) { - i = 0; - } - if (i == currentIdx) { - return null; - } else { - Map.Entry> candidate = entries.get(i); - if (!classesToSkip.contains(candidate.getKey())) { - return candidate.getKey(); - } - } - } - } - - private void writeMethods(BufferedWriter writer, List methods, Set methodSignatures, - String myPackage) throws IOException { + private void writeCreateSubscriberMethods(BufferedWriter writer, List methods, Set methodSignatures, + String myPackage) throws IOException { for (ExecutableElement method : methods) { - List parameters = method.getParameters(); TypeMirror paramType = parameters.get(0).asType(); TypeElement paramElement = (TypeElement) processingEnv.getTypeUtils().asElement(paramType); @@ -341,7 +321,7 @@ private void writeMethods(BufferedWriter writer, List methods String methodName = method.getSimpleName().toString(); Subscribe subscribe = method.getAnnotation(Subscribe.class); - List parts = new ArrayList(); + List parts = new ArrayList<>(); parts.add("createSubscriberMethod(\"" + methodName + "\","); String lineEnd = "),"; if (subscribe.priority() == 0 && !subscribe.sticky()) { From 8fdd73d4e4600c7f1a69da8438d861c387b5b89c Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 21:54:08 +0100 Subject: [PATCH 083/112] moved subscriber info classes into new meta package --- EventBus/src/de/greenrobot/event/EventBusBuilder.java | 2 ++ EventBus/src/de/greenrobot/event/SubscriberMethod.java | 2 +- .../src/de/greenrobot/event/SubscriberMethodFinder.java | 3 +++ .../greenrobot/event/{ => meta}/AbstractSubscriberInfo.java | 6 +++++- .../src/de/greenrobot/event/{ => meta}/SubscriberInfo.java | 4 +++- .../de/greenrobot/event/{ => meta}/SubscriberInfoIndex.java | 2 +- .../annotationprocessor/EventBusAnnotationProcessor.java | 6 +++--- 7 files changed, 18 insertions(+), 7 deletions(-) rename EventBus/src/de/greenrobot/event/{ => meta}/AbstractSubscriberInfo.java (94%) rename EventBus/src/de/greenrobot/event/{ => meta}/SubscriberInfo.java (92%) rename EventBus/src/de/greenrobot/event/{ => meta}/SubscriberInfoIndex.java (95%) diff --git a/EventBus/src/de/greenrobot/event/EventBusBuilder.java b/EventBus/src/de/greenrobot/event/EventBusBuilder.java index c51c69aa..4ee59fc2 100644 --- a/EventBus/src/de/greenrobot/event/EventBusBuilder.java +++ b/EventBus/src/de/greenrobot/event/EventBusBuilder.java @@ -20,6 +20,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import de.greenrobot.event.meta.SubscriberInfoIndex; + /** * Creates EventBus instances with custom parameters and also allows to install a custom default EventBus instance. * Create a new builder using {@link EventBus#builder()}. diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/de/greenrobot/event/SubscriberMethod.java index 4d77446a..f1c86820 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethod.java @@ -27,7 +27,7 @@ public class SubscriberMethod { /** Used for efficient comparison */ String methodString; - SubscriberMethod(Method method, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { + public SubscriberMethod(Method method, Class eventType, ThreadMode threadMode, int priority, boolean sticky) { this.method = method; this.threadMode = threadMode; this.eventType = eventType; diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java index 8df6ae0b..bf3e8c7b 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java @@ -23,6 +23,9 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import de.greenrobot.event.meta.SubscriberInfo; +import de.greenrobot.event.meta.SubscriberInfoIndex; + class SubscriberMethodFinder { /* * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. diff --git a/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java b/EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java similarity index 94% rename from EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java rename to EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java index df36f136..22a9ea0f 100644 --- a/EventBus/src/de/greenrobot/event/AbstractSubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java @@ -13,10 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package de.greenrobot.event.meta; import java.lang.reflect.Method; +import de.greenrobot.event.EventBusException; +import de.greenrobot.event.SubscriberMethod; +import de.greenrobot.event.ThreadMode; + /** Base class for generated subscriber meta info classes created by annotation processing. */ public abstract class AbstractSubscriberInfo implements SubscriberInfo { private final Class subscriberClass; diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfo.java b/EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java similarity index 92% rename from EventBus/src/de/greenrobot/event/SubscriberInfo.java rename to EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java index 635a4a0a..51dda356 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfo.java +++ b/EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package de.greenrobot.event.meta; + +import de.greenrobot.event.SubscriberMethod; /** Base class for generated index classes created by annotation processing. */ public interface SubscriberInfo { diff --git a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java b/EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java similarity index 95% rename from EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java rename to EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java index f5772fb1..f372c593 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberInfoIndex.java +++ b/EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package de.greenrobot.event.meta; /** * Interface for generated indexes. diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index b722a57b..35300062 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -212,7 +212,7 @@ private void createInfoFiles() { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); - writer.write("import de.greenrobot.event.AbstractSubscriberInfo;\n"); + writer.write("import de.greenrobot.event.meta.AbstractSubscriberInfo;\n"); writer.write("import de.greenrobot.event.SubscriberMethod;\n"); writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); @@ -357,8 +357,8 @@ private void createInfoIndexFile(String index) { if (myPackage != null) { writer.write("package " + myPackage + ";\n\n"); } - writer.write("import de.greenrobot.event.SubscriberInfo;\n"); - writer.write("import de.greenrobot.event.SubscriberInfoIndex;\n\n"); + writer.write("import de.greenrobot.event.meta.SubscriberInfo;\n"); + writer.write("import de.greenrobot.event.meta.SubscriberInfoIndex;\n\n"); writer.write("import java.util.HashMap;\n"); writer.write("import java.util.Map;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); From 880c0aea35bea562b6f99c1191e8a15149c89cfd Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 4 Dec 2015 22:03:06 +0100 Subject: [PATCH 084/112] formatting improvements --- .../EventBusAnnotationProcessor.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 35300062..3c3d87a8 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -407,7 +407,7 @@ private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOE } String subscriberClass = getClassString(subscriberTypeElement, myPackage); if (isVisible(myPackage, subscriberTypeElement)) { - writeLine(writer, 2, "SUBSCRIBER_INDEX.put(", subscriberClass + ".class,", infoClass + ".class);\n"); + writeLine(writer, 2, "SUBSCRIBER_INDEX.put(" + subscriberClass + ".class,", infoClass + ".class);"); } else { writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); } @@ -438,15 +438,17 @@ private void writeLine(BufferedWriter writer, int indentLevel, String... parts) int len = indentLevel * 4; for (int i = 0; i < parts.length; i++) { String part = parts[i]; - if (len + part.length() > 118) { - writer.write("\n"); - if (indentLevel < 12) { - indentLevel += 2; + if (i != 0) { + if (len + part.length() > 118) { + writer.write("\n"); + if (indentLevel < 12) { + indentLevel += 2; + } + writeIndent(writer, indentLevel); + len = indentLevel * 4; + } else { + writer.write(" "); } - writeIndent(writer, indentLevel); - len = indentLevel * 4; - } else if (i != 0) { - writer.write(" "); } writer.write(part); len += part.length(); From e2b179b92f109703a1bdc9fa8d15af87f06bb15c Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 8 Dec 2015 21:36:49 +0100 Subject: [PATCH 085/112] index with SimpleSubscriberInfo objects --- .../event/meta/SimpleSubscriberInfo.java | 43 ++++++++++++++ .../event/meta/SubscriberMethodInfo.java | 44 ++++++++++++++ .../EventBusAnnotationProcessor.java | 59 +++++++++---------- 3 files changed, 116 insertions(+), 30 deletions(-) create mode 100644 EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java create mode 100644 EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java diff --git a/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java b/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java new file mode 100644 index 00000000..39366a00 --- /dev/null +++ b/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.greenrobot.event.meta; + +import de.greenrobot.event.SubscriberMethod; + +/** + * Uses {@link SubscriberMethodInfo} objects to create {@link SubscriberMethod} objects on demand. + */ +public class SimpleSubscriberInfo extends AbstractSubscriberInfo { + + private final SubscriberMethodInfo[] methodInfos; + + public SimpleSubscriberInfo(Class subscriberClass, boolean shouldCheckSuperclass, SubscriberMethodInfo[] methodInfos) { + super(subscriberClass, null, shouldCheckSuperclass); + this.methodInfos = methodInfos; + } + + @Override + public synchronized SubscriberMethod[] getSubscriberMethods() { + int length = methodInfos.length; + SubscriberMethod[] methods = new SubscriberMethod[length]; + for (int i = 0; i < length; i++) { + SubscriberMethodInfo info = methodInfos[i]; + methods[i] = createSubscriberMethod(info.methodName, info.eventType, info.threadMode, + info.priority, info.sticky); + } + return methods; + } +} \ No newline at end of file diff --git a/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java b/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java new file mode 100644 index 00000000..ed822f35 --- /dev/null +++ b/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package de.greenrobot.event.meta; + +import de.greenrobot.event.ThreadMode; + +public class SubscriberMethodInfo { + final String methodName; + final ThreadMode threadMode; + final Class eventType; + final int priority; + final boolean sticky; + + public SubscriberMethodInfo(String methodName, Class eventType, ThreadMode threadMode, + int priority, boolean sticky) { + this.methodName = methodName; + this.threadMode = threadMode; + this.eventType = eventType; + this.priority = priority; + this.sticky = sticky; + } + + public SubscriberMethodInfo(String methodName, Class eventType) { + this(methodName, eventType, ThreadMode.POSTING, 0, false); + } + + public SubscriberMethodInfo(String methodName, Class eventType, ThreadMode threadMode) { + this(methodName, eventType, threadMode, 0, false); + } + +} \ No newline at end of file diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 3c3d87a8..0210c370 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -99,7 +99,7 @@ private void collectSubscribers(Set annotations, RoundEnv Element classElement = method.getEnclosingElement(); List methods = methodsByClass.get(classElement); if (methods == null) { - methods = new ArrayList(); + methods = new ArrayList<>(); methodsByClass.put((TypeElement) classElement, methods); } methods.add(method); @@ -223,8 +223,7 @@ private void createInfoFiles() { writer.write(" }\n\n"); writer.write(" public SubscriberMethod[] getSubscriberMethods() {\n"); writer.write(" return new SubscriberMethod[] {\n"); - Set methodSignatures = new HashSet<>(); - writeCreateSubscriberMethods(writer, entry.getValue(), methodSignatures, myPackage); + writeCreateSubscriberMethods(writer, entry.getValue(), "createSubscriberMethod", myPackage); writer.write(" };\n"); writer.write(" }\n}\n"); } catch (IOException e) { @@ -305,24 +304,18 @@ private PackageElement getPackageElement(TypeElement subscriberClass) { return (PackageElement) candidate; } - private void writeCreateSubscriberMethods(BufferedWriter writer, List methods, Set methodSignatures, - String myPackage) throws IOException { + private void writeCreateSubscriberMethods(BufferedWriter writer, List methods, + String callPrefix, String myPackage) throws IOException { for (ExecutableElement method : methods) { List parameters = method.getParameters(); TypeMirror paramType = parameters.get(0).asType(); TypeElement paramElement = (TypeElement) processingEnv.getTypeUtils().asElement(paramType); - String eventClass = getClassString(paramElement, myPackage) + ".class"; - - String methodSignature = method + ">" + paramElement.getQualifiedName(); - if (!methodSignatures.add(methodSignature)) { - continue; - } - String methodName = method.getSimpleName().toString(); + String eventClass = getClassString(paramElement, myPackage) + ".class"; Subscribe subscribe = method.getAnnotation(Subscribe.class); List parts = new ArrayList<>(); - parts.add("createSubscriberMethod(\"" + methodName + "\","); + parts.add(callPrefix + "(\"" + methodName + "\","); String lineEnd = "),"; if (subscribe.priority() == 0 && !subscribe.sticky()) { if (subscribe.threadMode() == ThreadMode.POSTING) { @@ -357,26 +350,28 @@ private void createInfoIndexFile(String index) { if (myPackage != null) { writer.write("package " + myPackage + ";\n\n"); } + writer.write("import de.greenrobot.event.meta.SimpleSubscriberInfo;\n"); + writer.write("import de.greenrobot.event.meta.SubscriberMethodInfo;\n"); writer.write("import de.greenrobot.event.meta.SubscriberInfo;\n"); writer.write("import de.greenrobot.event.meta.SubscriberInfoIndex;\n\n"); + writer.write("import de.greenrobot.event.ThreadMode;\n\n"); writer.write("import java.util.HashMap;\n"); writer.write("import java.util.Map;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + clazz + " implements SubscriberInfoIndex {\n"); - writer.write(" private static final Map, Class> SUBSCRIBER_INDEX;\n\n"); + writer.write(" private static final Map, SubscriberInfo> SUBSCRIBER_INDEX;\n\n"); writer.write(" static {\n"); - writer.write(" SUBSCRIBER_INDEX = new HashMap, Class>();\n"); + writer.write(" SUBSCRIBER_INDEX = new HashMap, SubscriberInfo>();\n\n"); writeIndexLines(writer, myPackage); writer.write(" }\n\n"); + writer.write(" private static void putIndex(SubscriberInfo info) {\n"); + writer.write(" SUBSCRIBER_INDEX.put(info.getSubscriberClass(), info);\n"); + writer.write(" }\n\n"); writer.write(" @Override\n"); writer.write(" public SubscriberInfo getSubscriberInfo(Class subscriberClass) {\n"); - writer.write(" Class infoClass = SUBSCRIBER_INDEX.get(subscriberClass);\n"); - writer.write(" if (infoClass != null) {\n"); - writer.write(" try {\n"); - writer.write(" return infoClass.newInstance();\n"); - writer.write(" } catch (Exception ex) {\n"); - writer.write(" throw new RuntimeException(ex);\n"); - writer.write(" }\n"); + writer.write(" SubscriberInfo info = SUBSCRIBER_INDEX.get(subscriberClass);\n"); + writer.write(" if (info != null) {\n"); + writer.write(" return info;\n"); writer.write(" } else {\n"); writer.write(" return null;\n"); writer.write(" }\n"); @@ -398,16 +393,15 @@ private void createInfoIndexFile(String index) { private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException { for (Map.Entry entry : infoByClass.entrySet()) { TypeElement subscriberTypeElement = entry.getKey(); - String infoClass = entry.getValue(); if (!classesToSkip.contains(subscriberTypeElement)) { - int infoPeriod = infoClass.lastIndexOf('.'); - String infoPackage = infoPeriod > 0 ? infoClass.substring(0, infoPeriod) : null; - if (infoPackage.equals(myPackage)) { - infoClass = infoClass.substring(infoPeriod + 1); - } String subscriberClass = getClassString(subscriberTypeElement, myPackage); if (isVisible(myPackage, subscriberTypeElement)) { - writeLine(writer, 2, "SUBSCRIBER_INDEX.put(" + subscriberClass + ".class,", infoClass + ".class);"); + writeLine(writer, 2, + "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,", + "true,", "new SubscriberMethodInfo[] {"); + List methods = methodsByClass.get(subscriberTypeElement); + writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage); + writer.write(" }));\n\n"); } else { writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); } @@ -434,6 +428,11 @@ private boolean isVisible(String myPackage, TypeElement typeElement) { } private void writeLine(BufferedWriter writer, int indentLevel, String... parts) throws IOException { + writeLine(writer, indentLevel, 2, parts); + } + + private void writeLine(BufferedWriter writer, int indentLevel, int indentLevelIncrease, String... parts) + throws IOException { writeIndent(writer, indentLevel); int len = indentLevel * 4; for (int i = 0; i < parts.length; i++) { @@ -442,7 +441,7 @@ private void writeLine(BufferedWriter writer, int indentLevel, String... parts) if (len + part.length() > 118) { writer.write("\n"); if (indentLevel < 12) { - indentLevel += 2; + indentLevel += indentLevelIncrease; } writeIndent(writer, indentLevel); len = indentLevel * 4; From 030a852dd3a558f398af9b87ff745503c90751c9 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 16 Dec 2015 09:17:18 +0100 Subject: [PATCH 086/112] prepare CHANGELOG.md for version 3 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index afe615df..413e86cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +### V3.0.0 (201?-??-??) Annotations +* Breaking change: switch subscriber methods to annotations +* Using annotations, each subscriber method can set sticky behavior and priority individually +* Annotation processor indexes annotation information for efficient subscriber registration on Android +* TODO: Renamed package and artifact id to allow co-existence with libs using EventBus 2 internally + +**Note:** This is a breaking change release: there is no inter-op between EventBus versions 2 and 3; they can run in parallel though. + ### V2.4.1 (2015-11-12) Bug fix release * Registering for sticky events now considers sticky events of subclasses, not just the exact same event type. This makes the semantic consistent to posting events. Note, that this may lead to subscribers being called more than once if matching sticky events of event type subclasses are available. * Workaround for an Android bug causing NoClassDefFoundError on some devices From 93e8ba6362f7757750a9ccd90d0fda2a91185d51 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 17 Dec 2015 22:26:12 +0100 Subject: [PATCH 087/112] convert Android instrumentation tests to JUnit 4 --- EventBusTest/AndroidManifest.xml | 2 +- EventBusTest/build.gradle | 14 ++++++-- .../event/test/AbstractEventBusTest.java | 25 +++++++++----- .../event/test/ClassMapPerfTest.java | 2 -- .../test/EventBusBackgroundThreadTest.java | 10 +++++- .../event/test/EventBusBasicTest.java | 33 ++++++++++++++++--- .../event/test/EventBusBuilderTest.java | 11 ++++++- .../test/EventBusCancelEventDeliveryTest.java | 14 ++++++-- .../EventBusFallbackToReflectionTest.java | 8 +++++ .../event/test/EventBusGenericsTest.java | 3 +- .../test/EventBusInheritanceDisabledTest.java | 20 ++++++++--- .../event/test/EventBusInheritanceTest.java | 12 ++++--- .../test/EventBusMainThreadRacingTest.java | 10 +++--- .../event/test/EventBusMainThreadTest.java | 22 ++++++++----- .../test/EventBusMethodModifiersTest.java | 9 +++-- .../event/test/EventBusMultithreadedTest.java | 20 ++++++++--- .../test/EventBusNoSubscriberEventTest.java | 9 ++++- .../EventBusOrderedSubscriptionsTest.java | 9 +++++ .../test/EventBusRegistrationRacingTest.java | 4 +++ .../event/test/EventBusStickyEventTest.java | 16 +++++++++ .../test/EventBusSubscriberExceptionTest.java | 8 ++++- .../test/EventBusSubscriberInJarTest.java | 2 ++ .../test/EventBusSubscriberLegalTest.java | 5 ++- 23 files changed, 212 insertions(+), 56 deletions(-) diff --git a/EventBusTest/AndroidManifest.xml b/EventBusTest/AndroidManifest.xml index 9695813a..22aedee0 100644 --- a/EventBusTest/AndroidManifest.xml +++ b/EventBusTest/AndroidManifest.xml @@ -4,7 +4,7 @@ android:versionCode="1" android:versionName="1.0" > - + { @@ -15,6 +15,7 @@ public void onGenericEvent(GenericEvent event) { } } + @Test public void testGenericEventAndSubscriber() { GenericSubscriber genericSubscriber = new GenericSubscriber(); eventBus.register(genericSubscriber); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 70eb9bde..45376aea 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -15,14 +15,20 @@ */ package de.greenrobot.event.test; +import android.support.test.runner.AndroidJUnit4; import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static junit.framework.Assert.assertEquals; /** * @author Markus Junginger, greenrobot */ -public class EventBusInheritanceDisabledTest extends TestCase { +@RunWith(AndroidJUnit4.class) +public class EventBusInheritanceDisabledTest { private EventBus eventBus; @@ -32,11 +38,12 @@ public class EventBusInheritanceDisabledTest extends TestCase { private int countMyEventInterface; private int countMyEventInterfaceExtended; - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { eventBus = EventBus.builder().eventInheritance(false).build(); } + @Test public void testEventClassHierarchy() { eventBus.register(this); @@ -53,6 +60,7 @@ public void testEventClassHierarchy() { assertEquals(1, countMyEventExtended); } + @Test public void testEventClassHierarchySticky() { eventBus.postSticky("Hello"); eventBus.postSticky(new MyEvent()); @@ -63,6 +71,7 @@ public void testEventClassHierarchySticky() { assertEquals(0, countObjectEvent); } + @Test public void testEventInterfaceHierarchy() { eventBus.register(this); @@ -74,6 +83,7 @@ public void testEventInterfaceHierarchy() { assertEquals(0, countMyEventInterfaceExtended); } + @Test public void testEventSuperInterfaceHierarchy() { eventBus.register(this); @@ -83,6 +93,7 @@ public void testEventSuperInterfaceHierarchy() { assertEquals(0, countMyEventInterfaceExtended); } + @Test public void testSubscriberClassHierarchy() { SubscriberExtended subscriber = new SubscriberExtended(); eventBus.register(subscriber); @@ -102,6 +113,7 @@ public void testSubscriberClassHierarchy() { assertEquals(1, subscriber.countMyEventOverwritten); } + @Test public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); eventBus.register(subscriber); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 183fe89d..fe594c54 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -15,12 +15,10 @@ */ package de.greenrobot.event.test; +import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; import junit.framework.TestCase; -import de.greenrobot.event.EventBus; - -import java.util.ArrayList; -import java.util.List; +import org.junit.Test; /** * @author Markus Junginger, greenrobot @@ -40,6 +38,7 @@ protected void setUp() throws Exception { eventBus = new EventBus(); } + @Test public void testEventClassHierarchy() { eventBus.register(this); @@ -56,6 +55,7 @@ public void testEventClassHierarchy() { assertEquals(1, countMyEventExtended); } + @Test public void testEventClassHierarchySticky() { eventBus.postSticky("Hello"); eventBus.postSticky(new MyEvent()); @@ -66,6 +66,7 @@ public void testEventClassHierarchySticky() { assertEquals(3, countObjectEvent); } + @Test public void testEventInterfaceHierarchy() { eventBus.register(this); @@ -77,6 +78,7 @@ public void testEventInterfaceHierarchy() { assertEquals(1, countMyEventInterfaceExtended); } + @Test public void testEventSuperInterfaceHierarchy() { eventBus.register(this); @@ -86,6 +88,7 @@ public void testEventSuperInterfaceHierarchy() { assertEquals(1, countMyEventInterfaceExtended); } + @Test public void testSubscriberClassHierarchy() { SubscriberExtended subscriber = new SubscriberExtended(); eventBus.register(subscriber); @@ -105,6 +108,7 @@ public void testSubscriberClassHierarchy() { assertEquals(2, subscriber.countMyEventOverwritten); } + @Test public void testSubscriberClassHierarchyWithoutNewSubscriberMethod() { SubscriberExtendedWithoutNewSubscriberMethod subscriber = new SubscriberExtendedWithoutNewSubscriberMethod(); eventBus.register(subscriber); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index b7127db5..e9e6cdf3 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -15,13 +15,14 @@ */ package de.greenrobot.event.test; -import java.util.Random; -import java.util.concurrent.CountDownLatch; - import android.os.Handler; import android.os.Looper; -import de.greenrobot.event.ThreadMode; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; +import org.junit.Test; + +import java.util.Random; +import java.util.concurrent.CountDownLatch; /** * @author Markus Junginger, greenrobot @@ -34,6 +35,7 @@ public class EventBusMainThreadRacingTest extends AbstractEventBusTest { private CountDownLatch startLatch; private volatile RuntimeException failed; + @Test public void testRacingThreads() throws InterruptedException { Runnable register = new Runnable() { @Override diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 944dba21..3415467f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -15,12 +15,17 @@ */ package de.greenrobot.event.test; +import android.os.Looper; +import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + import java.util.ArrayList; import java.util.List; -import android.os.Looper; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.Subscribe; +import static org.junit.Assert.assertEquals; /** * @author Markus Junginger, greenrobot @@ -29,19 +34,19 @@ public class EventBusMainThreadTest extends AbstractEventBusTest { private BackgroundPoster backgroundPoster; - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() throws Exception { backgroundPoster = new BackgroundPoster(); backgroundPoster.start(); } - @Override - protected void tearDown() throws Exception { + @After + public void tearDown() throws Exception { backgroundPoster.shutdown(); backgroundPoster.join(); - super.tearDown(); } + @Test public void testPost() throws InterruptedException { eventBus.register(this); eventBus.post("Hello"); @@ -51,6 +56,7 @@ public void testPost() throws InterruptedException { assertEquals(Looper.getMainLooper().getThread(), lastThread); } + @Test public void testPostInBackgroundThread() throws InterruptedException { eventBus.register(this); backgroundPoster.post("Hello"); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index e3f6c9c5..094492e0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -16,16 +16,19 @@ package de.greenrobot.event.test; import android.os.Looper; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.EventBusException; -import de.greenrobot.event.ThreadMode; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; +import org.junit.Test; + +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; /** * @author Markus Junginger, greenrobot */ public class EventBusMethodModifiersTest extends AbstractEventBusTest { + @Test public void testRegisterForEventTypeAndPost() throws InterruptedException { eventBus.register(this); String event = "Hello"; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index 1efbcd92..c3c544da 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -15,16 +15,19 @@ */ package de.greenrobot.event.test; +import android.os.Looper; +import android.util.Log; +import de.greenrobot.event.EventBus; +import de.greenrobot.event.Subscribe; +import de.greenrobot.event.ThreadMode; +import org.junit.Test; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; -import android.os.Looper; -import android.util.Log; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.Subscribe; +import static org.junit.Assert.*; /** * @author Markus Junginger, greenrobot @@ -43,30 +46,37 @@ public class EventBusMultithreadedTest extends AbstractEventBusTest { private IntTestEvent lastIntTestEvent; + @Test public void testPost01Thread() throws InterruptedException { runThreadsSingleEventType(1); } + @Test public void testPost04Threads() throws InterruptedException { runThreadsSingleEventType(4); } + @Test public void testPost40Threads() throws InterruptedException { runThreadsSingleEventType(40); } + @Test public void testPostMixedEventType01Thread() throws InterruptedException { runThreadsMixedEventType(1); } + @Test public void testPostMixedEventType04Threads() throws InterruptedException { runThreadsMixedEventType(4); } + @Test public void testPostMixedEventType40Threads() throws InterruptedException { runThreadsMixedEventType(40); } + @Test public void testSubscribeUnSubscribeAndPostMixedEventType() throws InterruptedException { List threads = new ArrayList(); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index f6d7516b..de638f22 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -17,14 +17,19 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.NoSubscriberEvent; -import de.greenrobot.event.SubscriberExceptionEvent; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.SubscriberExceptionEvent; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; /** * @author Markus Junginger, greenrobot */ public class EventBusNoSubscriberEventTest extends AbstractEventBusTest { + @Test public void testNoSubscriberEvent() { eventBus.register(this); eventBus.post("Foo"); @@ -35,6 +40,7 @@ public void testNoSubscriberEvent() { assertSame(eventBus, noSub.eventBus); } + @Test public void testNoSubscriberEventAfterUnregister() { Object subscriber = new DummySubscriber(); eventBus.register(subscriber); @@ -42,6 +48,7 @@ public void testNoSubscriberEventAfterUnregister() { testNoSubscriberEvent(); } + @Test public void testBadNoSubscriberSubscriber() { eventBus = EventBus.builder().logNoSubscriberMessages(false).build(); eventBus.register(this); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 7630ea64..36a40890 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -19,10 +19,13 @@ import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; import de.greenrobot.event.ThreadMode; +import org.junit.Test; import java.util.ArrayList; import java.util.List; +import static org.junit.Assert.assertEquals; + /** * @author Markus Junginger, greenrobot */ @@ -32,26 +35,32 @@ public class EventBusOrderedSubscriptionsTest extends AbstractEventBusTest { final List registered = new ArrayList(); private String fail; + @Test public void testOrdered() { runTestOrdered("42", false, 5); } + @Test public void testOrderedMainThread() { runTestOrdered(new IntTestEvent(42), false, 3); } + @Test public void testOrderedBackgroundThread() { runTestOrdered(Integer.valueOf(42), false, 3); } + @Test public void testOrderedSticky() { runTestOrdered("42", true, 5); } + @Test public void testOrderedMainThreadSticky() { runTestOrdered(new IntTestEvent(42), true, 3); } + @Test public void testOrderedBackgroundThreadSticky() { runTestOrdered(Integer.valueOf(42), true, 3); } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index 7c4dbf9d..853cc5dd 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -16,6 +16,7 @@ package de.greenrobot.event.test; import de.greenrobot.event.Subscribe; +import org.junit.Test; import java.util.ArrayList; import java.util.List; @@ -23,6 +24,8 @@ import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import static org.junit.Assert.fail; + /** * @author Markus Junginger, greenrobot */ @@ -40,6 +43,7 @@ public class EventBusRegistrationRacingTest extends AbstractEventBusTest { final Executor threadPool = Executors.newCachedThreadPool(); + @Test public void testRacingRegistrations() throws InterruptedException { for (int i = 0; i < ITERATIONS; i++) { startLatch = new CountDownLatch(THREAD_COUNT); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 6be32085..7694b185 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -16,12 +16,16 @@ package de.greenrobot.event.test; import de.greenrobot.event.Subscribe; +import org.junit.Test; + +import static org.junit.Assert.*; /** * @author Markus Junginger, greenrobot */ public class EventBusStickyEventTest extends AbstractEventBusTest { + @Test public void testPostSticky() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.register(this); @@ -29,6 +33,7 @@ public void testPostSticky() throws InterruptedException { assertEquals(Thread.currentThread(), lastThread); } + @Test public void testPostStickyTwoEvents() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky(new IntTestEvent(7)); @@ -36,6 +41,7 @@ public void testPostStickyTwoEvents() throws InterruptedException { assertEquals(2, eventCount.intValue()); } + @Test public void testPostStickyTwoSubscribers() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky(new IntTestEvent(7)); @@ -51,6 +57,7 @@ public void testPostStickyTwoSubscribers() throws InterruptedException { assertEquals(6, eventCount.intValue()); } + @Test public void testPostStickyRegisterNonSticky() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.register(new NonStickySubscriber()); @@ -58,6 +65,7 @@ public void testPostStickyRegisterNonSticky() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testPostNonStickyRegisterSticky() throws InterruptedException { eventBus.post("NonSticky"); eventBus.register(this); @@ -65,6 +73,7 @@ public void testPostNonStickyRegisterSticky() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testPostStickyTwice() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky("NewSticky"); @@ -72,6 +81,7 @@ public void testPostStickyTwice() throws InterruptedException { assertEquals("NewSticky", lastEvent); } + @Test public void testPostStickyThenPostNormal() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.post("NonSticky"); @@ -79,6 +89,7 @@ public void testPostStickyThenPostNormal() throws InterruptedException { assertEquals("Sticky", lastEvent); } + @Test public void testPostStickyWithRegisterAndUnregister() throws InterruptedException { eventBus.register(this); eventBus.postSticky("Sticky"); @@ -99,11 +110,13 @@ public void testPostStickyWithRegisterAndUnregister() throws InterruptedExceptio assertEquals("NewSticky", lastEvent); } + @Test public void testPostStickyAndGet() throws InterruptedException { eventBus.postSticky("Sticky"); assertEquals("Sticky", eventBus.getStickyEvent(String.class)); } + @Test public void testPostStickyRemoveClass() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.removeStickyEvent(String.class); @@ -113,6 +126,7 @@ public void testPostStickyRemoveClass() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testPostStickyRemoveEvent() throws InterruptedException { eventBus.postSticky("Sticky"); assertTrue(eventBus.removeStickyEvent("Sticky")); @@ -122,6 +136,7 @@ public void testPostStickyRemoveEvent() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testPostStickyRemoveAll() throws InterruptedException { eventBus.postSticky("Sticky"); eventBus.postSticky(new IntTestEvent(77)); @@ -133,6 +148,7 @@ public void testPostStickyRemoveAll() throws InterruptedException { assertEquals(0, eventCount.intValue()); } + @Test public void testRemoveStickyEventInSubscriber() throws InterruptedException { eventBus.register(new RemoveStickySubscriber()); eventBus.postSticky("Sticky"); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index 21c79f95..2651b4b5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -16,14 +16,19 @@ package de.greenrobot.event.test; import de.greenrobot.event.EventBus; -import de.greenrobot.event.SubscriberExceptionEvent; import de.greenrobot.event.Subscribe; +import de.greenrobot.event.SubscriberExceptionEvent; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; /** * @author Markus Junginger, greenrobot */ public class EventBusSubscriberExceptionTest extends AbstractEventBusTest { + @Test public void testSubscriberExceptionEvent() { eventBus = EventBus.builder().logSubscriberExceptions(false).build(); eventBus.register(this); @@ -36,6 +41,7 @@ public void testSubscriberExceptionEvent() { assertEquals("Bar", exEvent.throwable.getMessage()); } + @Test public void testBadExceptionSubscriber() { eventBus = EventBus.builder().logSubscriberExceptions(false).build(); eventBus.register(this); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java index 60882fc7..8eb5d281 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java @@ -3,8 +3,10 @@ import de.greenrobot.event.EventBus; import junit.framework.Assert; import junit.framework.TestCase; +import org.junit.Test; public class EventBusSubscriberInJarTest extends TestCase { + @Test public void testSubscriberInJar() { SubscriberInJar subscriber = new SubscriberInJar(); EventBus eventBus = EventBus.builder().build(); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index 1c84dda6..c1c504a9 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -15,14 +15,17 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBusException; import de.greenrobot.event.Subscribe; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; /** * @author Markus Junginger, greenrobot */ public class EventBusSubscriberLegalTest extends AbstractEventBusTest { + @Test public void testSubscriberLegal() { eventBus.register(this); eventBus.post("42"); From ddf19d24255c39a6f8d5a8fe7e79ab73b95fe6cd Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 17 Dec 2015 22:50:53 +0100 Subject: [PATCH 088/112] fixing @UiThreadTest --- EventBusTest/build.gradle | 1 + .../src/de/greenrobot/event/test/EventBusBasicTest.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index 38d4583a..c3d66113 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -21,6 +21,7 @@ dependencies { androidTestCompile project(':EventBus') compile fileTree(dir: 'libs', include: '*.jar') androidTestCompile 'com.android.support.test:runner:0.4.1' + androidTestCompile 'com.android.support.test:rules:0.4.1' } android { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 0d495112..784bf903 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -16,12 +16,14 @@ package de.greenrobot.event.test; import android.app.Activity; +import android.support.test.rule.UiThreadTestRule; import android.support.test.runner.AndroidJUnit4; -import android.test.UiThreadTest; +import android.support.test.annotation.UiThreadTest; import android.util.Log; import de.greenrobot.event.EventBus; import de.greenrobot.event.Subscribe; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,6 +34,8 @@ */ @RunWith(AndroidJUnit4.class) public class EventBusBasicTest { + @Rule + public final UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); private EventBus eventBus; private String lastStringEvent; From 479e83140d214b444a67e9e36a56b5759c5e114a Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 19 Jan 2016 17:44:20 +0100 Subject: [PATCH 089/112] test: Java 1.7, made test base class abstract, added EventBus.toString --- EventBus/src/de/greenrobot/event/EventBus.java | 7 +++++++ EventBusTest/build.gradle | 7 +++++++ .../src/de/greenrobot/event/test/AbstractEventBusTest.java | 3 +-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/de/greenrobot/event/EventBus.java index cbdd10ef..7a966865 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/de/greenrobot/event/EventBus.java @@ -72,6 +72,8 @@ protected PostingThreadState initialValue() { private final boolean sendNoSubscriberEvent; private final boolean eventInheritance; + private final int indexCount; + /** Convenience singleton for apps using a process-wide EventBus instance. */ public static EventBus getDefault() { if (defaultInstance == null) { @@ -109,6 +111,7 @@ public EventBus() { mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10); backgroundPoster = new BackgroundPoster(this); asyncPoster = new AsyncPoster(this); + indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0; subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes, builder.strictMethodVerification, builder.ignoreGeneratedIndex); logSubscriberExceptions = builder.logSubscriberExceptions; @@ -532,4 +535,8 @@ ExecutorService getExecutorService() { void onPostCompleted(List exceptionEvents); } + @Override + public String toString() { + return "EventBus[indexCount=" + indexCount + ", eventInheritance=" + eventInheritance + "]"; + } } diff --git a/EventBusTest/build.gradle b/EventBusTest/build.gradle index c3d66113..8e1d3abd 100644 --- a/EventBusTest/build.gradle +++ b/EventBusTest/build.gradle @@ -12,6 +12,8 @@ buildscript { apply plugin: 'com.android.application' apply plugin: 'com.neenbedankt.android-apt' +sourceCompatibility = 1.7 + repositories { jcenter() } @@ -28,6 +30,11 @@ android { buildToolsVersion '23.0.2' compileSdkVersion 19 + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 + } + sourceSets { main { manifest.srcFile 'AndroidManifest.xml' diff --git a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java index 766a54ea..641f586d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java @@ -37,8 +37,7 @@ * @author Markus Junginger, greenrobot */ @RunWith(AndroidJUnit4.class) -@Ignore("Base class") -public class AbstractEventBusTest { +public abstract class AbstractEventBusTest { /** Activates long(er) running tests e.g. testing multi-threading more thoroughly. */ protected static final boolean LONG_TESTS = false; From 591c618e71f12ff4accfa399dacb30e80973aff6 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 19 Jan 2016 21:18:34 +0100 Subject: [PATCH 090/112] first bunch of test subclasses with EventBus using an index --- .../event/test/EventBusBasicTest.java | 9 +++++++- .../EventBusFallbackToReflectionTest.java | 1 - .../test/EventBusInheritanceDisabledTest.java | 2 +- .../event/test/EventBusInheritanceTest.java | 2 +- ...EventBusBackgroundThreadTestWithIndex.java | 21 +++++++++++++++++++ .../indexed/EventBusBasicTestWithIndex.java | 19 +++++++++++++++++ ...ntBusCancelEventDeliveryTestWithIndex.java | 11 ++++++++++ ...tBusFallbackToReflectionTestWithIndex.java | 12 +++++++++++ .../EventBusGenericsTestWithIndex.java | 11 ++++++++++ ...ntBusInheritanceDisabledTestWithIndex.java | 13 ++++++++++++ .../EventBusInheritanceTestWithIndex.java | 11 ++++++++++ ...EventBusMainThreadRacingTestWithIndex.java | 11 ++++++++++ .../EventBusMainThreadTestWithIndex.java | 11 ++++++++++ .../EventBusMethodModifiersTestWithIndex.java | 11 ++++++++++ .../EventBusMultithreadedTestWithIndex.java | 11 ++++++++++ .../event/test/indexed/Indexed.java | 10 +++++++++ 16 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 784bf903..10458512 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -34,10 +34,17 @@ */ @RunWith(AndroidJUnit4.class) public class EventBusBasicTest { + + public static class WithIndex extends EventBusBasicTest { + @Test + public void dummy() {} + + } + @Rule public final UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); - private EventBus eventBus; + protected EventBus eventBus; private String lastStringEvent; private int countStringEvent; private int countIntEvent; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java index d228995d..91969393 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -5,7 +5,6 @@ import static org.junit.Assert.assertEquals; -/** TODO */ public class EventBusFallbackToReflectionTest extends AbstractEventBusTest { private class PrivateEvent { } diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 45376aea..74256dc1 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -30,7 +30,7 @@ @RunWith(AndroidJUnit4.class) public class EventBusInheritanceDisabledTest { - private EventBus eventBus; + protected EventBus eventBus; protected int countMyEventExtended; protected int countMyEvent; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index fe594c54..04f2c3fc 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -25,7 +25,7 @@ */ public class EventBusInheritanceTest extends TestCase { - private EventBus eventBus; + protected EventBus eventBus; protected int countMyEventExtended; protected int countMyEvent; diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java new file mode 100644 index 00000000..07f61cc4 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java @@ -0,0 +1,21 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.EventBus; +import de.greenrobot.event.test.EventBusBackgroundThreadTest; +import org.greenrobot.eventbus.EventBusTestsIndex; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class EventBusBackgroundThreadTestWithIndex extends EventBusBackgroundThreadTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } + + @Test + public void testIndex() { + assertTrue(eventBus.toString().contains("indexCount=1")); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java new file mode 100644 index 00000000..3d2f83e9 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java @@ -0,0 +1,19 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusBasicTest; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class EventBusBasicTestWithIndex extends EventBusBasicTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } + + @Test + public void testIndex() { + assertTrue(eventBus.toString().contains("indexCount=1")); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java new file mode 100644 index 00000000..1456f760 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusCancelEventDeliveryTest; +import org.junit.Before; + +public class EventBusCancelEventDeliveryTestWithIndex extends EventBusCancelEventDeliveryTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java new file mode 100644 index 00000000..7804b8b2 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusFallbackToReflectionTest; +import org.junit.Before; + +public class EventBusFallbackToReflectionTestWithIndex extends EventBusFallbackToReflectionTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } + +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java new file mode 100644 index 00000000..dd00aa02 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusGenericsTest; +import org.junit.Before; + +public class EventBusGenericsTestWithIndex extends EventBusGenericsTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java new file mode 100644 index 00000000..56613525 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java @@ -0,0 +1,13 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.EventBus; +import de.greenrobot.event.test.EventBusInheritanceDisabledTest; +import org.greenrobot.eventbus.EventBusTestsIndex; +import org.junit.Before; + +public class EventBusInheritanceDisabledTestWithIndex extends EventBusInheritanceDisabledTest { + @Before + public void setUp() throws Exception { + eventBus = EventBus.builder().eventInheritance(false).addIndex(new EventBusTestsIndex()).build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java new file mode 100644 index 00000000..54f2749b --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusInheritanceTest; +import org.junit.Before; + +public class EventBusInheritanceTestWithIndex extends EventBusInheritanceTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java new file mode 100644 index 00000000..52bdb6e1 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusMainThreadRacingTest; +import org.junit.Before; + +public class EventBusMainThreadRacingTestWithIndex extends EventBusMainThreadRacingTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java new file mode 100644 index 00000000..69fb22bc --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusMainThreadTest; +import org.junit.Before; + +public class EventBusMainThreadTestWithIndex extends EventBusMainThreadTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java new file mode 100644 index 00000000..c66f0baf --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusMethodModifiersTest; +import org.junit.Before; + +public class EventBusMethodModifiersTestWithIndex extends EventBusMethodModifiersTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java new file mode 100644 index 00000000..71329fe1 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java @@ -0,0 +1,11 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusMultithreadedTest; +import org.junit.Before; + +public class EventBusMultithreadedTestWithIndex extends EventBusMultithreadedTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java b/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java new file mode 100644 index 00000000..64417e95 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java @@ -0,0 +1,10 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.EventBus; +import org.greenrobot.eventbus.EventBusTestsIndex; + +public class Indexed { + static EventBus build() { + return EventBus.builder().addIndex(new EventBusTestsIndex()).build(); + } +} From 8a319664c6d7b29c60508130e8fc7406b63e93ab Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 19 Jan 2016 21:34:04 +0100 Subject: [PATCH 091/112] remaining test subclasses with EventBus using an index --- .../event/test/EventBusSubscriberInJarTest.java | 3 ++- .../EventBusNoSubscriberEventTestWithIndex.java | 12 ++++++++++++ .../EventBusOrderedSubscriptionsTestWithIndex.java | 12 ++++++++++++ .../EventBusRegistrationRacingTestWithIndex.java | 12 ++++++++++++ .../indexed/EventBusStickyEventTestWithIndex.java | 12 ++++++++++++ .../EventBusSubscriberExceptionTestWithIndex.java | 12 ++++++++++++ .../EventBusSubscriberInJarTestWithIndex.java | 12 ++++++++++++ 7 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java create mode 100644 EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java index 8eb5d281..eaef374d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java @@ -6,10 +6,11 @@ import org.junit.Test; public class EventBusSubscriberInJarTest extends TestCase { + protected EventBus eventBus = EventBus.builder().build(); + @Test public void testSubscriberInJar() { SubscriberInJar subscriber = new SubscriberInJar(); - EventBus eventBus = EventBus.builder().build(); eventBus.register(subscriber); eventBus.post("Hi Jar"); eventBus.post(42); diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java new file mode 100644 index 00000000..26c48eb6 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusNoSubscriberEventTest; +import org.junit.Before; + +/** TODO */ +public class EventBusNoSubscriberEventTestWithIndex extends EventBusNoSubscriberEventTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java new file mode 100644 index 00000000..21424186 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusOrderedSubscriptionsTest; +import org.junit.Before; + +/** TODO */ +public class EventBusOrderedSubscriptionsTestWithIndex extends EventBusOrderedSubscriptionsTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java new file mode 100644 index 00000000..35840f72 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusRegistrationRacingTest; +import org.junit.Before; + +/** TODO */ +public class EventBusRegistrationRacingTestWithIndex extends EventBusRegistrationRacingTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java new file mode 100644 index 00000000..c7b6413b --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusStickyEventTest; +import org.junit.Before; + +/** TODO */ +public class EventBusStickyEventTestWithIndex extends EventBusStickyEventTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java new file mode 100644 index 00000000..31253cb5 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusSubscriberExceptionTest; +import org.junit.Before; + +/** TODO */ +public class EventBusSubscriberExceptionTestWithIndex extends EventBusSubscriberExceptionTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java new file mode 100644 index 00000000..8899a546 --- /dev/null +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -0,0 +1,12 @@ +package de.greenrobot.event.test.indexed; + +import de.greenrobot.event.test.EventBusSubscriberInJarTest; +import org.junit.Before; + +/** TODO */ +public class EventBusSubscriberInJarTestWithIndex extends EventBusSubscriberInJarTest { + @Before + public void overwriteEventBus() throws Exception { + eventBus = Indexed.build(); + } +} From 80a9204f1cd352d122703469e73652067c3f6185 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 12:03:43 +0100 Subject: [PATCH 092/112] main package is now org.greenrobot.eventbus --- .../greenrobot/eventbus}/AsyncPoster.java | 2 +- .../eventbus}/BackgroundPoster.java | 2 +- .../greenrobot/eventbus}/EventBus.java | 10 ++++---- .../greenrobot/eventbus}/EventBusBuilder.java | 6 ++--- .../eventbus}/EventBusException.java | 2 +- .../greenrobot/eventbus}/HandlerPoster.java | 2 +- .../eventbus}/NoSubscriberEvent.java | 2 +- .../greenrobot/eventbus}/PendingPost.java | 2 +- .../eventbus}/PendingPostQueue.java | 2 +- .../greenrobot/eventbus}/Subscribe.java | 4 ++-- .../eventbus}/SubscriberExceptionEvent.java | 2 +- .../eventbus}/SubscriberMethod.java | 2 +- .../eventbus}/SubscriberMethodFinder.java | 8 +++---- .../greenrobot/eventbus}/Subscription.java | 2 +- .../greenrobot/eventbus}/ThreadMode.java | 2 +- .../meta/AbstractSubscriberInfo.java | 10 ++++---- .../eventbus}/meta/SimpleSubscriberInfo.java | 6 ++--- .../eventbus}/meta/SubscriberInfo.java | 4 ++-- .../eventbus}/meta/SubscriberInfoIndex.java | 2 +- .../eventbus}/meta/SubscriberMethodInfo.java | 4 ++-- .../eventbus}/util/AsyncExecutor.java | 11 +++++---- .../eventbus}/util/ErrorDialogConfig.java | 5 ++-- .../util/ErrorDialogFragmentFactory.java | 2 +- .../eventbus}/util/ErrorDialogFragments.java | 5 ++-- .../eventbus}/util/ErrorDialogManager.java | 5 ++-- .../util/ExceptionToResourceMapping.java | 9 +++---- .../eventbus}/util/HasExecutionScope.java | 2 +- .../eventbus}/util/ThrowableFailureEvent.java | 2 +- .../EventBusAnnotationProcessor.java | 24 +++++++++---------- .../src/de/greenrobot/eventperf/Test.java | 4 ++-- .../de/greenrobot/eventperf/TestParams.java | 4 ++-- .../de/greenrobot/eventperf/TestRunner.java | 7 +++--- .../eventperf/TestRunnerActivity.java | 8 +++---- .../eventperf/TestSetupActivity.java | 8 ++++--- .../testsubject/PerfTestEventBus.java | 12 ++++++---- .../eventperf/testsubject/PerfTestOtto.java | 11 ++++----- .../SubscribeClassEventBusDefault.java | 3 ++- .../event/test/AbstractEventBusTest.java | 4 ++-- .../test/EventBusBackgroundThreadTest.java | 7 +++--- .../event/test/EventBusBasicTest.java | 7 +++--- .../event/test/EventBusBuilderTest.java | 12 +++++----- .../test/EventBusCancelEventDeliveryTest.java | 7 +++--- .../EventBusFallbackToReflectionTest.java | 2 +- .../event/test/EventBusGenericsTest.java | 2 +- .../test/EventBusInheritanceDisabledTest.java | 5 ++-- .../event/test/EventBusInheritanceTest.java | 5 ++-- .../test/EventBusMainThreadRacingTest.java | 5 ++-- .../event/test/EventBusMainThreadTest.java | 5 ++-- .../test/EventBusMethodModifiersTest.java | 5 ++-- .../event/test/EventBusMultithreadedTest.java | 7 +++--- .../test/EventBusNoSubscriberEventTest.java | 8 +++---- .../EventBusOrderedSubscriptionsTest.java | 7 +++--- .../test/EventBusRegistrationRacingTest.java | 2 +- .../event/test/EventBusStickyEventTest.java | 2 +- .../test/EventBusSubscriberExceptionTest.java | 6 ++--- .../test/EventBusSubscriberInJarTest.java | 3 ++- .../test/EventBusSubscriberLegalTest.java | 2 +- ...EventBusBackgroundThreadTestWithIndex.java | 5 ++-- .../indexed/EventBusBasicTestWithIndex.java | 3 ++- ...ntBusCancelEventDeliveryTestWithIndex.java | 3 ++- ...tBusFallbackToReflectionTestWithIndex.java | 3 ++- .../EventBusGenericsTestWithIndex.java | 3 ++- ...ntBusInheritanceDisabledTestWithIndex.java | 5 ++-- .../EventBusInheritanceTestWithIndex.java | 3 ++- ...EventBusMainThreadRacingTestWithIndex.java | 3 ++- .../EventBusMainThreadTestWithIndex.java | 3 ++- .../EventBusMethodModifiersTestWithIndex.java | 3 ++- .../EventBusMultithreadedTestWithIndex.java | 3 ++- ...ventBusNoSubscriberEventTestWithIndex.java | 3 ++- ...tBusOrderedSubscriptionsTestWithIndex.java | 3 ++- ...entBusRegistrationRacingTestWithIndex.java | 3 ++- .../EventBusStickyEventTestWithIndex.java | 3 ++- ...ntBusSubscriberExceptionTestWithIndex.java | 3 ++- .../EventBusSubscriberInJarTestWithIndex.java | 3 ++- .../event/test/indexed/Indexed.java | 2 +- .../event/test/SubscriberInJar.java | 2 +- 76 files changed, 197 insertions(+), 163 deletions(-) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/AsyncPoster.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/BackgroundPoster.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/EventBus.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/EventBusBuilder.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/EventBusException.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/HandlerPoster.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/NoSubscriberEvent.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/PendingPost.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/PendingPostQueue.java (96%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/Subscribe.java (86%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/SubscriberExceptionEvent.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/SubscriberMethod.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/SubscriberMethodFinder.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/Subscription.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/ThreadMode.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/AbstractSubscriberInfo.java (93%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/SimpleSubscriberInfo.java (87%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/SubscriberInfo.java (91%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/SubscriberInfoIndex.java (95%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/meta/SubscriberMethodInfo.java (94%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/AsyncExecutor.java (98%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ErrorDialogConfig.java (96%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ErrorDialogFragmentFactory.java (99%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ErrorDialogFragments.java (97%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ErrorDialogManager.java (99%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ExceptionToResourceMapping.java (96%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/HasExecutionScope.java (76%) rename EventBus/src/{de/greenrobot/event => org/greenrobot/eventbus}/util/ThrowableFailureEvent.java (97%) diff --git a/EventBus/src/de/greenrobot/event/AsyncPoster.java b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java similarity index 97% rename from EventBus/src/de/greenrobot/event/AsyncPoster.java rename to EventBus/src/org/greenrobot/eventbus/AsyncPoster.java index 936527b7..e3129dee 100644 --- a/EventBus/src/de/greenrobot/event/AsyncPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** diff --git a/EventBus/src/de/greenrobot/event/BackgroundPoster.java b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java similarity index 98% rename from EventBus/src/de/greenrobot/event/BackgroundPoster.java rename to EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java index 00e9ee54..c23e1575 100644 --- a/EventBus/src/de/greenrobot/event/BackgroundPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import android.util.Log; diff --git a/EventBus/src/de/greenrobot/event/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java similarity index 98% rename from EventBus/src/de/greenrobot/event/EventBus.java rename to EventBus/src/org/greenrobot/eventbus/EventBus.java index 7a966865..3dd210b5 100644 --- a/EventBus/src/de/greenrobot/event/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import android.os.Looper; import android.util.Log; @@ -33,7 +33,7 @@ * bus, which delivers it to subscribers that have a matching handler method for the event type. To receive events, * subscribers must register themselves to the bus using {@link #register(Object)}. Once registered, subscribers * receive events until {@link #unregister(Object)} is called. Event handling methods must be annotated by - * {@link de.greenrobot.event.Subscribe}, must be public, return nothing (void), and have exactly one parameter + * {@link Subscribe}, must be public, return nothing (void), and have exactly one parameter * (the event). * * @author Markus Junginger, greenrobot @@ -127,9 +127,9 @@ public EventBus() { * Registers the given subscriber to receive events. Subscribers must call {@link #unregister(Object)} once they * are no longer interested in receiving events. *

- * Subscribers have event handling methods that must be annotated by {@link de.greenrobot.event.Subscribe}. - * The {@link de.greenrobot.event.Subscribe} annotation also allows configuration like {@link - * de.greenrobot.event.ThreadMode} and priority. + * Subscribers have event handling methods that must be annotated by {@link Subscribe}. + * The {@link Subscribe} annotation also allows configuration like {@link + * ThreadMode} and priority. */ public void register(Object subscriber) { Class subscriberClass = subscriber.getClass(); diff --git a/EventBus/src/de/greenrobot/event/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java similarity index 98% rename from EventBus/src/de/greenrobot/event/EventBusBuilder.java rename to EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 4ee59fc2..9d003108 100644 --- a/EventBus/src/de/greenrobot/event/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -13,15 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.meta.SubscriberInfoIndex; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import de.greenrobot.event.meta.SubscriberInfoIndex; - /** * Creates EventBus instances with custom parameters and also allows to install a custom default EventBus instance. * Create a new builder using {@link EventBus#builder()}. diff --git a/EventBus/src/de/greenrobot/event/EventBusException.java b/EventBus/src/org/greenrobot/eventbus/EventBusException.java similarity index 97% rename from EventBus/src/de/greenrobot/event/EventBusException.java rename to EventBus/src/org/greenrobot/eventbus/EventBusException.java index 80c51f86..9bbacf55 100644 --- a/EventBus/src/de/greenrobot/event/EventBusException.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusException.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** * An {@link RuntimeException} thrown in cases something went wrong inside EventBus. diff --git a/EventBus/src/de/greenrobot/event/HandlerPoster.java b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java similarity index 98% rename from EventBus/src/de/greenrobot/event/HandlerPoster.java rename to EventBus/src/org/greenrobot/eventbus/HandlerPoster.java index c1c44608..0571e1b2 100644 --- a/EventBus/src/de/greenrobot/event/HandlerPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import android.os.Handler; import android.os.Looper; diff --git a/EventBus/src/de/greenrobot/event/NoSubscriberEvent.java b/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java similarity index 97% rename from EventBus/src/de/greenrobot/event/NoSubscriberEvent.java rename to EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java index a7378ae8..8a6d0c50 100644 --- a/EventBus/src/de/greenrobot/event/NoSubscriberEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** * This Event is posted by EventBus when no subscriber is found for a posted event. diff --git a/EventBus/src/de/greenrobot/event/PendingPost.java b/EventBus/src/org/greenrobot/eventbus/PendingPost.java similarity index 98% rename from EventBus/src/de/greenrobot/event/PendingPost.java rename to EventBus/src/org/greenrobot/eventbus/PendingPost.java index 0bd5a2ec..e6c3bf4f 100644 --- a/EventBus/src/de/greenrobot/event/PendingPost.java +++ b/EventBus/src/org/greenrobot/eventbus/PendingPost.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import java.util.ArrayList; import java.util.List; diff --git a/EventBus/src/de/greenrobot/event/PendingPostQueue.java b/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java similarity index 96% rename from EventBus/src/de/greenrobot/event/PendingPostQueue.java rename to EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java index 5440559b..048a841f 100644 --- a/EventBus/src/de/greenrobot/event/PendingPostQueue.java +++ b/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java @@ -1,4 +1,4 @@ -package de.greenrobot.event; +package org.greenrobot.eventbus; final class PendingPostQueue { private PendingPost head; diff --git a/EventBus/src/de/greenrobot/event/Subscribe.java b/EventBus/src/org/greenrobot/eventbus/Subscribe.java similarity index 86% rename from EventBus/src/de/greenrobot/event/Subscribe.java rename to EventBus/src/org/greenrobot/eventbus/Subscribe.java index 6532c6cd..b36496db 100644 --- a/EventBus/src/de/greenrobot/event/Subscribe.java +++ b/EventBus/src/org/greenrobot/eventbus/Subscribe.java @@ -1,4 +1,4 @@ -package de.greenrobot.event; +package org.greenrobot.eventbus; import java.lang.annotation.Documented; @@ -15,7 +15,7 @@ /** * If true, delivers the most recent sticky event (posted with - * {@link de.greenrobot.event.EventBus#postSticky(Object)}) to this subscriber (if event available). + * {@link EventBus#postSticky(Object)}) to this subscriber (if event available). */ boolean sticky() default false; diff --git a/EventBus/src/de/greenrobot/event/SubscriberExceptionEvent.java b/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java similarity index 97% rename from EventBus/src/de/greenrobot/event/SubscriberExceptionEvent.java rename to EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java index 5d3b9b55..1302f777 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberExceptionEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** * This Event is posted by EventBus when an exception occurs inside a subscriber's event handling method. diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethod.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java similarity index 98% rename from EventBus/src/de/greenrobot/event/SubscriberMethod.java rename to EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java index f1c86820..5bd751c4 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethod.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; import java.lang.reflect.Method; diff --git a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java similarity index 98% rename from EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java rename to EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index bf3e8c7b..03974004 100644 --- a/EventBus/src/de/greenrobot/event/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.meta.SubscriberInfo; +import org.greenrobot.eventbus.meta.SubscriberInfoIndex; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -23,9 +26,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import de.greenrobot.event.meta.SubscriberInfo; -import de.greenrobot.event.meta.SubscriberInfoIndex; - class SubscriberMethodFinder { /* * In newer class files, compilers may add methods. Those are called bridge or synthetic methods. diff --git a/EventBus/src/de/greenrobot/event/Subscription.java b/EventBus/src/org/greenrobot/eventbus/Subscription.java similarity index 98% rename from EventBus/src/de/greenrobot/event/Subscription.java rename to EventBus/src/org/greenrobot/eventbus/Subscription.java index 868cbebe..1f529c92 100644 --- a/EventBus/src/de/greenrobot/event/Subscription.java +++ b/EventBus/src/org/greenrobot/eventbus/Subscription.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; final class Subscription { final Object subscriber; diff --git a/EventBus/src/de/greenrobot/event/ThreadMode.java b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java similarity index 98% rename from EventBus/src/de/greenrobot/event/ThreadMode.java rename to EventBus/src/org/greenrobot/eventbus/ThreadMode.java index bbe060cd..9292d4e9 100644 --- a/EventBus/src/de/greenrobot/event/ThreadMode.java +++ b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event; +package org.greenrobot.eventbus; /** * Each event handler method has a thread mode, which determines in which thread the method is to be called by EventBus. diff --git a/EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java similarity index 93% rename from EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java rename to EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java index 22a9ea0f..9156ea25 100644 --- a/EventBus/src/de/greenrobot/event/meta/AbstractSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; -import java.lang.reflect.Method; +import org.greenrobot.eventbus.EventBusException; +import org.greenrobot.eventbus.SubscriberMethod; +import org.greenrobot.eventbus.ThreadMode; -import de.greenrobot.event.EventBusException; -import de.greenrobot.event.SubscriberMethod; -import de.greenrobot.event.ThreadMode; +import java.lang.reflect.Method; /** Base class for generated subscriber meta info classes created by annotation processing. */ public abstract class AbstractSubscriberInfo implements SubscriberInfo { diff --git a/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java similarity index 87% rename from EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java rename to EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java index 39366a00..957d058d 100644 --- a/EventBus/src/de/greenrobot/event/meta/SimpleSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; -import de.greenrobot.event.SubscriberMethod; +import org.greenrobot.eventbus.SubscriberMethod; /** - * Uses {@link SubscriberMethodInfo} objects to create {@link SubscriberMethod} objects on demand. + * Uses {@link SubscriberMethodInfo} objects to create {@link org.greenrobot.eventbus.SubscriberMethod} objects on demand. */ public class SimpleSubscriberInfo extends AbstractSubscriberInfo { diff --git a/EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java similarity index 91% rename from EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java rename to EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java index 51dda356..7cd445a8 100644 --- a/EventBus/src/de/greenrobot/event/meta/SubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; -import de.greenrobot.event.SubscriberMethod; +import org.greenrobot.eventbus.SubscriberMethod; /** Base class for generated index classes created by annotation processing. */ public interface SubscriberInfo { diff --git a/EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java similarity index 95% rename from EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java rename to EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java index f372c593..5e27d4e8 100644 --- a/EventBus/src/de/greenrobot/event/meta/SubscriberInfoIndex.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; /** * Interface for generated indexes. diff --git a/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java similarity index 94% rename from EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java rename to EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java index ed822f35..9d0782ed 100644 --- a/EventBus/src/de/greenrobot/event/meta/SubscriberMethodInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.meta; +package org.greenrobot.eventbus.meta; -import de.greenrobot.event.ThreadMode; +import org.greenrobot.eventbus.ThreadMode; public class SubscriberMethodInfo { final String methodName; diff --git a/EventBus/src/de/greenrobot/event/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java similarity index 98% rename from EventBus/src/de/greenrobot/event/util/AsyncExecutor.java rename to EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index 71048a43..c1b49c1b 100644 --- a/EventBus/src/de/greenrobot/event/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -13,16 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; + +import android.app.Activity; +import android.util.Log; + +import org.greenrobot.eventbus.EventBus; import java.lang.reflect.Constructor; import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import android.app.Activity; -import android.util.Log; -import de.greenrobot.event.EventBus; - /** * Executes an {@link RunnableEx} using a thread pool. Thrown exceptions are propagated by posting failure events of any * given type (default is {@link ThrowableFailureEvent}). diff --git a/EventBus/src/de/greenrobot/event/util/ErrorDialogConfig.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java similarity index 96% rename from EventBus/src/de/greenrobot/event/util/ErrorDialogConfig.java rename to EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java index 25432631..3378ba4d 100644 --- a/EventBus/src/de/greenrobot/event/util/ErrorDialogConfig.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java @@ -1,8 +1,9 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; import android.content.res.Resources; import android.util.Log; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; public class ErrorDialogConfig { final Resources resources; diff --git a/EventBus/src/de/greenrobot/event/util/ErrorDialogFragmentFactory.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java similarity index 99% rename from EventBus/src/de/greenrobot/event/util/ErrorDialogFragmentFactory.java rename to EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java index 47b693b6..ca6a8b4d 100644 --- a/EventBus/src/de/greenrobot/event/util/ErrorDialogFragmentFactory.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; import android.annotation.TargetApi; import android.os.Build; diff --git a/EventBus/src/de/greenrobot/event/util/ErrorDialogFragments.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java similarity index 97% rename from EventBus/src/de/greenrobot/event/util/ErrorDialogFragments.java rename to EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java index 04002df2..79833b42 100644 --- a/EventBus/src/de/greenrobot/event/util/ErrorDialogFragments.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; import android.annotation.TargetApi; import android.app.Activity; @@ -10,7 +10,8 @@ import android.os.Build; import android.os.Bundle; import android.support.v4.app.DialogFragment; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; public class ErrorDialogFragments { /** TODO Use config: Icon res ID to use for all error dialogs. May be configured by each app (optional). */ diff --git a/EventBus/src/de/greenrobot/event/util/ErrorDialogManager.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java similarity index 99% rename from EventBus/src/de/greenrobot/event/util/ErrorDialogManager.java rename to EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java index cee7c6a5..34cb82da 100644 --- a/EventBus/src/de/greenrobot/event/util/ErrorDialogManager.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; import android.annotation.TargetApi; import android.app.Activity; @@ -10,7 +10,8 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.util.Log; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; /** * Central class for app that want to use event based error dialogs.
diff --git a/EventBus/src/de/greenrobot/event/util/ExceptionToResourceMapping.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java similarity index 96% rename from EventBus/src/de/greenrobot/event/util/ExceptionToResourceMapping.java rename to EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java index d3286175..d45159b1 100644 --- a/EventBus/src/de/greenrobot/event/util/ExceptionToResourceMapping.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java @@ -1,13 +1,14 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; + +import android.util.Log; + +import org.greenrobot.eventbus.EventBus; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import android.util.Log; -import de.greenrobot.event.EventBus; - /** * Maps throwables to texts for error dialogs. Use Config to configure the mapping. diff --git a/EventBus/src/de/greenrobot/event/util/HasExecutionScope.java b/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java similarity index 76% rename from EventBus/src/de/greenrobot/event/util/HasExecutionScope.java rename to EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java index d759d2c2..67613b4d 100644 --- a/EventBus/src/de/greenrobot/event/util/HasExecutionScope.java +++ b/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; public interface HasExecutionScope { Object getExecutionScope(); diff --git a/EventBus/src/de/greenrobot/event/util/ThrowableFailureEvent.java b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java similarity index 97% rename from EventBus/src/de/greenrobot/event/util/ThrowableFailureEvent.java rename to EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java index 7c6c07fa..abc37db9 100644 --- a/EventBus/src/de/greenrobot/event/util/ThrowableFailureEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.util; +package org.greenrobot.eventbus.util; /** * A generic failure event, which can be used by apps to propagate thrown exceptions. Also used in conjunction with diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java index 0210c370..69731f5b 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java @@ -1,5 +1,8 @@ package de.greenrobot.event.annotationprocessor; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + import java.io.BufferedWriter; import java.io.IOException; import java.util.ArrayList; @@ -26,10 +29,7 @@ import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; - -@SupportedAnnotationTypes("de.greenrobot.event.Subscribe") +@SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; @@ -212,9 +212,9 @@ private void createInfoFiles() { JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); - writer.write("import de.greenrobot.event.meta.AbstractSubscriberInfo;\n"); - writer.write("import de.greenrobot.event.SubscriberMethod;\n"); - writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("import org.greenrobot.eventbus.meta.AbstractSubscriberInfo;\n"); + writer.write("import org.greenrobot.eventbus.SubscriberMethod;\n"); + writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); writer.write("public class " + infoClassName + " extends AbstractSubscriberInfo {\n"); writer.write(" public " + infoClassName + "() {\n"); @@ -350,11 +350,11 @@ private void createInfoIndexFile(String index) { if (myPackage != null) { writer.write("package " + myPackage + ";\n\n"); } - writer.write("import de.greenrobot.event.meta.SimpleSubscriberInfo;\n"); - writer.write("import de.greenrobot.event.meta.SubscriberMethodInfo;\n"); - writer.write("import de.greenrobot.event.meta.SubscriberInfo;\n"); - writer.write("import de.greenrobot.event.meta.SubscriberInfoIndex;\n\n"); - writer.write("import de.greenrobot.event.ThreadMode;\n\n"); + writer.write("import org.greenrobot.eventbus.meta.SimpleSubscriberInfo;\n"); + writer.write("import org.greenrobot.eventbus.meta.SubscriberMethodInfo;\n"); + writer.write("import org.greenrobot.eventbus.meta.SubscriberInfo;\n"); + writer.write("import org.greenrobot.eventbus.meta.SubscriberInfoIndex;\n\n"); + writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n"); writer.write("import java.util.HashMap;\n"); writer.write("import java.util.Map;\n\n"); writer.write("/** This class is generated by EventBus, do not edit. */\n"); diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java b/EventBusPerformance/src/de/greenrobot/eventperf/Test.java index 0c510d86..8177f9cd 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/Test.java @@ -1,9 +1,9 @@ package de.greenrobot.eventperf; -import java.util.concurrent.atomic.AtomicLong; - import android.content.Context; +import java.util.concurrent.atomic.AtomicLong; + public abstract class Test { protected final Context context; protected final TestParams params; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java index 0776bd53..7d567191 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java @@ -1,10 +1,10 @@ package de.greenrobot.eventperf; +import org.greenrobot.eventbus.ThreadMode; + import java.io.Serializable; import java.util.ArrayList; -import de.greenrobot.event.ThreadMode; - public class TestParams implements Serializable { private static final long serialVersionUID = -2739435088947740809L; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java index e593c8e3..a04f77ca 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java @@ -1,12 +1,13 @@ package de.greenrobot.eventperf; +import android.content.Context; + +import org.greenrobot.eventbus.EventBus; + import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; -import android.content.Context; -import de.greenrobot.event.EventBus; - /** * This thread initialize all selected tests and runs them through. Also the thread skips the tests, when it is canceled */ diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java index 8ff7ff9f..91048797 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java @@ -1,15 +1,15 @@ package de.greenrobot.eventperf; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.Subscribe; - import android.app.Activity; import android.os.Bundle; import android.os.Process; import android.text.Html; import android.view.View; import android.widget.TextView; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** * This activity gets the information from the activity before, sets up the test and starts the test. After it watchs diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java b/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java index 6b760baf..51917286 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java @@ -8,12 +8,14 @@ import android.widget.CheckBox; import android.widget.EditText; import android.widget.Spinner; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.eventperf.testsubject.PerfTestEventBus; -import de.greenrobot.eventperf.testsubject.PerfTestOtto; + +import org.greenrobot.eventbus.ThreadMode; import java.util.ArrayList; +import de.greenrobot.eventperf.testsubject.PerfTestEventBus; +import de.greenrobot.eventperf.testsubject.PerfTestOtto; + public class TestSetupActivity extends Activity { @SuppressWarnings("rawtypes") diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java index cd0ae167..54fe6f71 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java @@ -1,13 +1,15 @@ package de.greenrobot.eventperf.testsubject; +import android.content.Context; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; + import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; -import android.content.Context; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.ThreadMode; -import de.greenrobot.event.Subscribe; import de.greenrobot.eventperf.MyEventBusIndex; import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; @@ -172,7 +174,7 @@ public static class RegisterFirstTime extends RegisterOneByOne { public RegisterFirstTime(Context context, TestParams params) { super(context, params); try { - Class clazz = Class.forName("de.greenrobot.event.SubscriberMethodFinder"); + Class clazz = Class.forName("org.greenrobot.eventbus.SubscriberMethodFinder"); clearCachesMethod = clazz.getDeclaredMethod("clearCaches"); clearCachesMethod.setAccessible(true); } catch (Exception e) { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java index 0d191aeb..f46988af 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java @@ -1,11 +1,5 @@ package de.greenrobot.eventperf.testsubject; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.concurrent.ConcurrentHashMap; - import android.app.Activity; import android.content.Context; import android.os.Looper; @@ -14,6 +8,11 @@ import com.squareup.otto.Subscribe; import com.squareup.otto.ThreadEnforcer; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.concurrent.ConcurrentHashMap; + import de.greenrobot.eventperf.Test; import de.greenrobot.eventperf.TestEvent; import de.greenrobot.eventperf.TestParams; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java index 2deabf7d..c64b54b1 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java +++ b/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java @@ -1,6 +1,7 @@ package de.greenrobot.eventperf.testsubject; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; + import de.greenrobot.eventperf.TestEvent; public class SubscribeClassEventBusDefault { diff --git a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java index 641f586d..822d6a20 100644 --- a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java @@ -20,9 +20,9 @@ import android.os.Looper; import android.os.Message; import android.support.test.runner.AndroidJUnit4; -import de.greenrobot.event.EventBus; + +import org.greenrobot.eventbus.EventBus; import org.junit.Before; -import org.junit.Ignore; import org.junit.runner.RunWith; import java.util.List; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java index fc090302..7ac54ec0 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java @@ -16,11 +16,10 @@ package de.greenrobot.event.test; import android.os.Looper; -import android.support.test.runner.AndroidJUnit4; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; -import org.junit.runner.RunWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java index 10458512..f89e778b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java @@ -16,12 +16,13 @@ package de.greenrobot.event.test; import android.app.Activity; +import android.support.test.annotation.UiThreadTest; import android.support.test.rule.UiThreadTestRule; import android.support.test.runner.AndroidJUnit4; -import android.support.test.annotation.UiThreadTest; import android.util.Log; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java index c85c2b06..14ae6dd7 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java @@ -15,12 +15,12 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.EventBusBuilder; -import de.greenrobot.event.EventBusException; -import de.greenrobot.event.NoSubscriberEvent; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.SubscriberExceptionEvent; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.EventBusBuilder; +import org.greenrobot.eventbus.EventBusException; +import org.greenrobot.eventbus.NoSubscriberEvent; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java index dd28e614..1139d012 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java @@ -16,9 +16,10 @@ package de.greenrobot.event.test; import android.test.UiThreadTest; -import de.greenrobot.event.EventBusException; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.EventBusException; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.concurrent.CountDownLatch; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java index 91969393..cc4c5952 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java @@ -1,6 +1,6 @@ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java index ee3b78a1..84f3d460 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java @@ -1,6 +1,6 @@ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; public class EventBusGenericsTest extends AbstractEventBusTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java index 74256dc1..cf6609ff 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java @@ -16,8 +16,9 @@ package de.greenrobot.event.test; import android.support.test.runner.AndroidJUnit4; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java index 04f2c3fc..e5b072b3 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java @@ -15,9 +15,10 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; import junit.framework.TestCase; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; /** diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java index e9e6cdf3..0bd64f27 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java @@ -17,8 +17,9 @@ import android.os.Handler; import android.os.Looper; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.Random; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java index 3415467f..5fe3e14f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java @@ -16,8 +16,9 @@ package de.greenrobot.event.test; import android.os.Looper; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java index 094492e0..485fdf5b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java @@ -16,8 +16,9 @@ package de.greenrobot.event.test; import android.os.Looper; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import static org.junit.Assert.assertNotSame; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java index c3c544da..4e4767cf 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java @@ -17,9 +17,10 @@ import android.os.Looper; import android.util.Log; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java index de638f22..9fe94a59 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java @@ -15,10 +15,10 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.NoSubscriberEvent; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.SubscriberExceptionEvent; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.NoSubscriberEvent; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java index 36a40890..e09b2c2f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java @@ -16,9 +16,10 @@ package de.greenrobot.event.test; import android.util.Log; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.ThreadMode; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java index 853cc5dd..d143d08d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java index 7694b185..ba902f89 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.*; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java index 2651b4b5..a2b660dc 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java @@ -15,9 +15,9 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.Subscribe; -import de.greenrobot.event.SubscriberExceptionEvent; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java index eaef374d..39eb12ce 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test; -import de.greenrobot.event.EventBus; import junit.framework.Assert; import junit.framework.TestCase; + +import org.greenrobot.eventbus.EventBus; import org.junit.Test; public class EventBusSubscriberInJarTest extends TestCase { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java index c1c504a9..61f543b8 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java @@ -15,7 +15,7 @@ */ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java index 07f61cc4..946f1bc1 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java @@ -1,11 +1,10 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.test.EventBusBackgroundThreadTest; -import org.greenrobot.eventbus.EventBusTestsIndex; import org.junit.Before; import org.junit.Test; +import de.greenrobot.event.test.EventBusBackgroundThreadTest; + import static org.junit.Assert.assertTrue; public class EventBusBackgroundThreadTestWithIndex extends EventBusBackgroundThreadTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java index 3d2f83e9..a386fd99 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java @@ -1,9 +1,10 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusBasicTest; import org.junit.Before; import org.junit.Test; +import de.greenrobot.event.test.EventBusBasicTest; + import static org.junit.Assert.assertTrue; public class EventBusBasicTestWithIndex extends EventBusBasicTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java index 1456f760..f0eecd92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusCancelEventDeliveryTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusCancelEventDeliveryTest; + public class EventBusCancelEventDeliveryTestWithIndex extends EventBusCancelEventDeliveryTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java index 7804b8b2..c51ef5ad 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusFallbackToReflectionTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusFallbackToReflectionTest; + public class EventBusFallbackToReflectionTestWithIndex extends EventBusFallbackToReflectionTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java index dd00aa02..86fd4d2e 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusGenericsTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusGenericsTest; + public class EventBusGenericsTestWithIndex extends EventBusGenericsTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java index 56613525..1c33a00d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java @@ -1,10 +1,11 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.EventBus; -import de.greenrobot.event.test.EventBusInheritanceDisabledTest; +import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBusTestsIndex; import org.junit.Before; +import de.greenrobot.event.test.EventBusInheritanceDisabledTest; + public class EventBusInheritanceDisabledTestWithIndex extends EventBusInheritanceDisabledTest { @Before public void setUp() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java index 54f2749b..0d770661 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusInheritanceTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusInheritanceTest; + public class EventBusInheritanceTestWithIndex extends EventBusInheritanceTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java index 52bdb6e1..24e9cc4d 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusMainThreadRacingTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusMainThreadRacingTest; + public class EventBusMainThreadRacingTestWithIndex extends EventBusMainThreadRacingTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java index 69fb22bc..e462d03f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusMainThreadTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusMainThreadTest; + public class EventBusMainThreadTestWithIndex extends EventBusMainThreadTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java index c66f0baf..3f237739 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusMethodModifiersTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusMethodModifiersTest; + public class EventBusMethodModifiersTestWithIndex extends EventBusMethodModifiersTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java index 71329fe1..2a0705b4 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusMultithreadedTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusMultithreadedTest; + public class EventBusMultithreadedTestWithIndex extends EventBusMultithreadedTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java index 26c48eb6..b3961da5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusNoSubscriberEventTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusNoSubscriberEventTest; + /** TODO */ public class EventBusNoSubscriberEventTestWithIndex extends EventBusNoSubscriberEventTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java index 21424186..54369cdd 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusOrderedSubscriptionsTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusOrderedSubscriptionsTest; + /** TODO */ public class EventBusOrderedSubscriptionsTestWithIndex extends EventBusOrderedSubscriptionsTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java index 35840f72..a06efd92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusRegistrationRacingTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusRegistrationRacingTest; + /** TODO */ public class EventBusRegistrationRacingTestWithIndex extends EventBusRegistrationRacingTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java index c7b6413b..0d947f05 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusStickyEventTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusStickyEventTest; + /** TODO */ public class EventBusStickyEventTestWithIndex extends EventBusStickyEventTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java index 31253cb5..18a0f76a 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusSubscriberExceptionTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusSubscriberExceptionTest; + /** TODO */ public class EventBusSubscriberExceptionTestWithIndex extends EventBusSubscriberExceptionTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java index 8899a546..1cb842e8 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -1,8 +1,9 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.test.EventBusSubscriberInJarTest; import org.junit.Before; +import de.greenrobot.event.test.EventBusSubscriberInJarTest; + /** TODO */ public class EventBusSubscriberInJarTestWithIndex extends EventBusSubscriberInJarTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java b/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java index 64417e95..a202ea5a 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java +++ b/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java @@ -1,6 +1,6 @@ package de.greenrobot.event.test.indexed; -import de.greenrobot.event.EventBus; +import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBusTestsIndex; public class Indexed { diff --git a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java b/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java index ea3bba4e..d79d0d80 100644 --- a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java +++ b/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java @@ -1,6 +1,6 @@ package de.greenrobot.event.test; -import de.greenrobot.event.Subscribe; +import org.greenrobot.eventbus.Subscribe; import java.util.ArrayList; import java.util.List; From 97de666bac477bda74f64f220de09632bda8f4c7 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 12:11:27 +0100 Subject: [PATCH 093/112] moved tests to org.greenrobot.eventbus --- .../greenrobot/eventbus}/AbstractEventBusTest.java | 2 +- .../greenrobot/eventbus}/ClassMapPerfTest.java | 2 +- .../eventbus}/EventBusBackgroundThreadTest.java | 4 +--- .../greenrobot/eventbus}/EventBusBasicTest.java | 4 +--- .../greenrobot/eventbus}/EventBusBuilderTest.java | 8 +------- .../eventbus}/EventBusCancelEventDeliveryTest.java | 5 +---- .../eventbus}/EventBusFallbackToReflectionTest.java | 3 +-- .../greenrobot/eventbus}/EventBusGenericsTest.java | 3 +-- .../eventbus}/EventBusInheritanceDisabledTest.java | 4 +--- .../greenrobot/eventbus}/EventBusInheritanceTest.java | 4 +--- .../eventbus}/EventBusMainThreadRacingTest.java | 4 +--- .../greenrobot/eventbus}/EventBusMainThreadTest.java | 4 +--- .../greenrobot/eventbus}/EventBusMethodModifiersTest.java | 4 +--- .../greenrobot/eventbus}/EventBusMultithreadedTest.java | 5 +---- .../eventbus}/EventBusNoSubscriberEventTest.java | 6 +----- .../eventbus}/EventBusOrderedSubscriptionsTest.java | 5 +---- .../eventbus}/EventBusRegistrationRacingTest.java | 3 +-- .../greenrobot/eventbus}/EventBusStickyEventTest.java | 3 +-- .../eventbus}/EventBusSubscriberExceptionTest.java | 5 +---- .../greenrobot/eventbus}/EventBusSubscriberInJarTest.java | 4 +++- .../greenrobot/eventbus}/EventBusSubscriberLegalTest.java | 3 +-- .../test => org/greenrobot/eventbus}/IntTestEvent.java | 2 +- .../indexed/EventBusBackgroundThreadTestWithIndex.java | 5 ++--- .../eventbus}/indexed/EventBusBasicTestWithIndex.java | 5 ++--- .../indexed/EventBusCancelEventDeliveryTestWithIndex.java | 5 ++--- .../EventBusFallbackToReflectionTestWithIndex.java | 4 ++-- .../eventbus}/indexed/EventBusGenericsTestWithIndex.java | 4 ++-- .../indexed/EventBusInheritanceDisabledTestWithIndex.java | 4 ++-- .../indexed/EventBusInheritanceTestWithIndex.java | 5 ++--- .../indexed/EventBusMainThreadRacingTestWithIndex.java | 4 ++-- .../indexed/EventBusMainThreadTestWithIndex.java | 4 ++-- .../indexed/EventBusMethodModifiersTestWithIndex.java | 5 ++--- .../indexed/EventBusMultithreadedTestWithIndex.java | 5 ++--- .../indexed/EventBusNoSubscriberEventTestWithIndex.java | 5 ++--- .../EventBusOrderedSubscriptionsTestWithIndex.java | 5 ++--- .../indexed/EventBusRegistrationRacingTestWithIndex.java | 4 ++-- .../indexed/EventBusStickyEventTestWithIndex.java | 5 ++--- .../indexed/EventBusSubscriberExceptionTestWithIndex.java | 4 ++-- .../indexed/EventBusSubscriberInJarTestWithIndex.java | 5 ++--- .../test => org/greenrobot/eventbus}/indexed/Indexed.java | 2 +- 40 files changed, 59 insertions(+), 108 deletions(-) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/AbstractEventBusTest.java (99%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/ClassMapPerfTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusBackgroundThreadTest.java (93%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusBasicTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusBuilderTest.java (90%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusCancelEventDeliveryTest.java (96%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusFallbackToReflectionTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusGenericsTest.java (89%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusInheritanceDisabledTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusInheritanceTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusMainThreadRacingTest.java (96%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusMainThreadTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusMethodModifiersTest.java (94%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusMultithreadedTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusNoSubscriberEventTest.java (92%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusOrderedSubscriptionsTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusRegistrationRacingTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusStickyEventTest.java (98%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusSubscriberExceptionTest.java (92%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusSubscriberInJarTest.java (88%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/EventBusSubscriberLegalTest.java (97%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/IntTestEvent.java (96%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusBackgroundThreadTestWithIndex.java (79%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusBasicTestWithIndex.java (80%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusCancelEventDeliveryTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusFallbackToReflectionTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusGenericsTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusInheritanceDisabledTestWithIndex.java (78%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusInheritanceTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusMainThreadRacingTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusMainThreadTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusMethodModifiersTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusMultithreadedTestWithIndex.java (68%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusNoSubscriberEventTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusOrderedSubscriptionsTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusRegistrationRacingTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusStickyEventTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusSubscriberExceptionTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/EventBusSubscriberInJarTestWithIndex.java (69%) rename EventBusTest/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/indexed/Indexed.java (84%) diff --git a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java b/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java similarity index 99% rename from EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java rename to EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java index 822d6a20..f313071a 100644 --- a/EventBusTest/src/de/greenrobot/event/test/AbstractEventBusTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.annotation.SuppressLint; import android.os.Handler; diff --git a/EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java b/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java rename to EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java index ac6d9ada..60f7a66c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/ClassMapPerfTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import java.util.HashMap; import java.util.IdentityHashMap; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java similarity index 93% rename from EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java index 7ac54ec0..32ce3b3f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Looper; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java index f89e778b..f50c4108 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBasicTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.app.Activity; import android.support.test.annotation.UiThreadTest; @@ -21,8 +21,6 @@ import android.support.test.runner.AndroidJUnit4; import android.util.Log; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java similarity index 90% rename from EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java index 14ae6dd7..354d78e2 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusBuilderTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java @@ -13,14 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.EventBusBuilder; -import org.greenrobot.eventbus.EventBusException; -import org.greenrobot.eventbus.NoSubscriberEvent; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java similarity index 96% rename from EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java index 1139d012..5c9966d6 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.test.UiThreadTest; -import org.greenrobot.eventbus.EventBusException; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.concurrent.CountDownLatch; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java index cc4c5952..ce102566 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java @@ -1,6 +1,5 @@ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java similarity index 89% rename from EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java index 84f3d460..06db3002 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusGenericsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java @@ -1,6 +1,5 @@ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; public class EventBusGenericsTest extends AbstractEventBusTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java index cf6609ff..4a767204 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.support.test.runner.AndroidJUnit4; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java index e5b072b3..d4a4d0f7 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusInheritanceTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import junit.framework.TestCase; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; /** diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java similarity index 96% rename from EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java index 0bd64f27..79fdfc92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java @@ -13,13 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Handler; import android.os.Looper; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.Random; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java index 5fe3e14f..55c6fc57 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMainThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Looper; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.After; import org.junit.Before; import org.junit.Test; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java similarity index 94% rename from EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java index 485fdf5b..8eb00cf2 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java @@ -13,12 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Looper; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import static org.junit.Assert.assertNotSame; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java index 4e4767cf..eec9103b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusMultithreadedTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java @@ -13,14 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.os.Looper; import android.util.Log; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java similarity index 92% rename from EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java index 9fe94a59..ad12d64f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java @@ -13,12 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.NoSubscriberEvent; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java index e09b2c2f..463f11bf 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import android.util.Log; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.ThreadMode; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java index d143d08d..c4f405ee 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import java.util.ArrayList; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java similarity index 98% rename from EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java index ba902f89..be23b4ab 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusStickyEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.*; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java similarity index 92% rename from EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java index a2b660dc..2d227c94 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java @@ -13,11 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.EventBus; -import org.greenrobot.eventbus.Subscribe; -import org.greenrobot.eventbus.SubscriberExceptionEvent; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java similarity index 88% rename from EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java index 39eb12ce..9f815583 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; import junit.framework.Assert; import junit.framework.TestCase; @@ -6,6 +6,8 @@ import org.greenrobot.eventbus.EventBus; import org.junit.Test; +import de.greenrobot.event.test.SubscriberInJar; + public class EventBusSubscriberInJarTest extends TestCase { protected EventBus eventBus = EventBus.builder().build(); diff --git a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java similarity index 97% rename from EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java rename to EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java index 61f543b8..c70a1e6b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java @@ -13,9 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; -import org.greenrobot.eventbus.Subscribe; import org.junit.Test; import static org.junit.Assert.assertEquals; diff --git a/EventBusTest/src/de/greenrobot/event/test/IntTestEvent.java b/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java similarity index 96% rename from EventBusTest/src/de/greenrobot/event/test/IntTestEvent.java rename to EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java index dc829b89..5874ae17 100644 --- a/EventBusTest/src/de/greenrobot/event/test/IntTestEvent.java +++ b/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java @@ -17,7 +17,7 @@ /** * Simple event storing an int value. More efficient than Integer because of the its flat hierarchy. */ -package de.greenrobot.event.test; +package org.greenrobot.eventbus; public class IntTestEvent { public final int value; diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java similarity index 79% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java index 946f1bc1..8771358a 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBackgroundThreadTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java @@ -1,10 +1,9 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusBackgroundThreadTest; import org.junit.Before; import org.junit.Test; -import de.greenrobot.event.test.EventBusBackgroundThreadTest; - import static org.junit.Assert.assertTrue; public class EventBusBackgroundThreadTestWithIndex extends EventBusBackgroundThreadTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java similarity index 80% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java index a386fd99..d5e6d1fd 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusBasicTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java @@ -1,10 +1,9 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusBasicTest; import org.junit.Before; import org.junit.Test; -import de.greenrobot.event.test.EventBusBasicTest; - import static org.junit.Assert.assertTrue; public class EventBusBasicTestWithIndex extends EventBusBasicTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java index f0eecd92..7c3d670c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusCancelEventDeliveryTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusCancelEventDeliveryTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusCancelEventDeliveryTest; - public class EventBusCancelEventDeliveryTestWithIndex extends EventBusCancelEventDeliveryTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java index c51ef5ad..74c2b44e 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusFallbackToReflectionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusFallbackToReflectionTest; +import org.greenrobot.eventbus.EventBusFallbackToReflectionTest; public class EventBusFallbackToReflectionTestWithIndex extends EventBusFallbackToReflectionTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java index 86fd4d2e..eeca3a92 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusGenericsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusGenericsTest; +import org.greenrobot.eventbus.EventBusGenericsTest; public class EventBusGenericsTestWithIndex extends EventBusGenericsTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java similarity index 78% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java index 1c33a00d..b0c85a0b 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceDisabledTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java @@ -1,10 +1,10 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBusTestsIndex; import org.junit.Before; -import de.greenrobot.event.test.EventBusInheritanceDisabledTest; +import org.greenrobot.eventbus.EventBusInheritanceDisabledTest; public class EventBusInheritanceDisabledTestWithIndex extends EventBusInheritanceDisabledTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java index 0d770661..6d8963b6 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusInheritanceTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusInheritanceTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusInheritanceTest; - public class EventBusInheritanceTestWithIndex extends EventBusInheritanceTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java index 24e9cc4d..f6a90873 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusMainThreadRacingTest; +import org.greenrobot.eventbus.EventBusMainThreadRacingTest; public class EventBusMainThreadRacingTestWithIndex extends EventBusMainThreadRacingTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java index e462d03f..99248950 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMainThreadTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusMainThreadTest; +import org.greenrobot.eventbus.EventBusMainThreadTest; public class EventBusMainThreadTestWithIndex extends EventBusMainThreadTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java index 3f237739..0a9d34ae 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMethodModifiersTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusMethodModifiersTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusMethodModifiersTest; - public class EventBusMethodModifiersTestWithIndex extends EventBusMethodModifiersTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java similarity index 68% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java index 2a0705b4..b0c06a67 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusMultithreadedTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusMultithreadedTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusMultithreadedTest; - public class EventBusMultithreadedTestWithIndex extends EventBusMultithreadedTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java index b3961da5..937af651 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusNoSubscriberEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusNoSubscriberEventTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusNoSubscriberEventTest; - /** TODO */ public class EventBusNoSubscriberEventTestWithIndex extends EventBusNoSubscriberEventTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java index 54369cdd..71389239 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusOrderedSubscriptionsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusOrderedSubscriptionsTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusOrderedSubscriptionsTest; - /** TODO */ public class EventBusOrderedSubscriptionsTestWithIndex extends EventBusOrderedSubscriptionsTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java index a06efd92..bbd40a9c 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusRegistrationRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusRegistrationRacingTest; +import org.greenrobot.eventbus.EventBusRegistrationRacingTest; /** TODO */ public class EventBusRegistrationRacingTestWithIndex extends EventBusRegistrationRacingTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java index 0d947f05..6fab88f5 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusStickyEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusStickyEventTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusStickyEventTest; - /** TODO */ public class EventBusStickyEventTestWithIndex extends EventBusStickyEventTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java index 18a0f76a..42bcce98 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberExceptionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -1,8 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.junit.Before; -import de.greenrobot.event.test.EventBusSubscriberExceptionTest; +import org.greenrobot.eventbus.EventBusSubscriberExceptionTest; /** TODO */ public class EventBusSubscriberExceptionTestWithIndex extends EventBusSubscriberExceptionTest { diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java similarity index 69% rename from EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java index 1cb842e8..4f721e2f 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/EventBusSubscriberInJarTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -1,9 +1,8 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; +import org.greenrobot.eventbus.EventBusSubscriberInJarTest; import org.junit.Before; -import de.greenrobot.event.test.EventBusSubscriberInJarTest; - /** TODO */ public class EventBusSubscriberInJarTestWithIndex extends EventBusSubscriberInJarTest { @Before diff --git a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java similarity index 84% rename from EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java rename to EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java index a202ea5a..f86e7872 100644 --- a/EventBusTest/src/de/greenrobot/event/test/indexed/Indexed.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.test.indexed; +package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBusTestsIndex; From 3f6f45019b3196da0405902b45d0c2d0da733694 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 12:34:27 +0100 Subject: [PATCH 094/112] moved perf to org.greenrobot.eventbusperf package --- EventBusPerformance/AndroidManifest.xml | 11 ++++----- EventBusPerformance/build.gradle | 2 +- EventBusPerformance/res/values/strings.xml | 2 +- .../greenrobot/eventbusperf}/Test.java | 2 +- .../greenrobot/eventbusperf}/TestEvent.java | 2 +- .../eventbusperf}/TestFinishedEvent.java | 24 +++++++++---------- .../greenrobot/eventbusperf}/TestParams.java | 2 +- .../greenrobot/eventbusperf}/TestRunner.java | 2 +- .../eventbusperf}/TestRunnerActivity.java | 2 +- .../eventbusperf}/TestSetupActivity.java | 6 ++--- .../testsubject/PerfTestEventBus.java | 10 ++++---- .../testsubject/PerfTestOtto.java | 8 +++---- .../SubscribeClassEventBusDefault.java | 4 ++-- 13 files changed, 38 insertions(+), 39 deletions(-) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/Test.java (97%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestEvent.java (62%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestFinishedEvent.java (84%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestParams.java (98%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestRunner.java (98%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestRunnerActivity.java (98%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/TestSetupActivity.java (96%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/testsubject/PerfTestEventBus.java (97%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/testsubject/PerfTestOtto.java (97%) rename EventBusPerformance/src/{de/greenrobot/eventperf => org/greenrobot/eventbusperf}/testsubject/SubscribeClassEventBusDefault.java (85%) diff --git a/EventBusPerformance/AndroidManifest.xml b/EventBusPerformance/AndroidManifest.xml index 4967dc56..af353b5d 100644 --- a/EventBusPerformance/AndroidManifest.xml +++ b/EventBusPerformance/AndroidManifest.xml @@ -1,8 +1,8 @@ + package="org.greenrobot.eventbusperf" + android:versionCode="1" + android:versionName="2.0.0" > - diff --git a/EventBusPerformance/build.gradle b/EventBusPerformance/build.gradle index 12f19fb6..401b9afb 100644 --- a/EventBusPerformance/build.gradle +++ b/EventBusPerformance/build.gradle @@ -24,7 +24,7 @@ dependencies { apt { arguments { - eventBusIndex "de.greenrobot.eventperf.MyEventBusIndex" + eventBusIndex "org.greenrobot.eventbusperf.MyEventBusIndex" } } diff --git a/EventBusPerformance/res/values/strings.xml b/EventBusPerformance/res/values/strings.xml index c7af6a88..feed5953 100644 --- a/EventBusPerformance/res/values/strings.xml +++ b/EventBusPerformance/res/values/strings.xml @@ -1,7 +1,7 @@ - Event Performance + EventBus Performance EventBus Event Inheritance Ignore generated index diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java similarity index 97% rename from EventBusPerformance/src/de/greenrobot/eventperf/Test.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java index 8177f9cd..35d20471 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/Test.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import android.content.Context; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestEvent.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java similarity index 62% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestEvent.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java index b90be773..d0edba31 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestEvent.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; /** Used by otto and EventBus */ public class TestEvent { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestFinishedEvent.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java similarity index 84% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestFinishedEvent.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java index 1e301c9b..7bc72ed8 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestFinishedEvent.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java @@ -1,12 +1,12 @@ -package de.greenrobot.eventperf; - -public class TestFinishedEvent { - - public final Test test; - public final boolean isLastEvent; - - public TestFinishedEvent(Test test, boolean isLastEvent) { - this.test = test; - this.isLastEvent = isLastEvent; - } -} +package org.greenrobot.eventbusperf; + +public class TestFinishedEvent { + + public final Test test; + public final boolean isLastEvent; + + public TestFinishedEvent(Test test, boolean isLastEvent) { + this.test = test; + this.isLastEvent = isLastEvent; + } +} diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java similarity index 98% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java index 7d567191..79af650a 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestParams.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import org.greenrobot.eventbus.ThreadMode; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java similarity index 98% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java index a04f77ca..3107289a 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunner.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import android.content.Context; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java similarity index 98% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java index 91048797..9c718597 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import android.app.Activity; import android.os.Bundle; diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java similarity index 96% rename from EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java index 51917286..0837bd4a 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/TestSetupActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf; +package org.greenrobot.eventbusperf; import android.app.Activity; import android.content.Intent; @@ -13,8 +13,8 @@ import java.util.ArrayList; -import de.greenrobot.eventperf.testsubject.PerfTestEventBus; -import de.greenrobot.eventperf.testsubject.PerfTestOtto; +import org.greenrobot.eventbusperf.testsubject.PerfTestEventBus; +import org.greenrobot.eventbusperf.testsubject.PerfTestOtto; public class TestSetupActivity extends Activity { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java similarity index 97% rename from EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java index 54fe6f71..5f43601a 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf.testsubject; +package org.greenrobot.eventbusperf.testsubject; import android.content.Context; @@ -10,10 +10,10 @@ import java.lang.reflect.Method; import java.util.ArrayList; -import de.greenrobot.eventperf.MyEventBusIndex; -import de.greenrobot.eventperf.Test; -import de.greenrobot.eventperf.TestEvent; -import de.greenrobot.eventperf.TestParams; +import org.greenrobot.eventbusperf.MyEventBusIndex; +import org.greenrobot.eventbusperf.Test; +import org.greenrobot.eventbusperf.TestEvent; +import org.greenrobot.eventbusperf.TestParams; public abstract class PerfTestEventBus extends Test { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java similarity index 97% rename from EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java index f46988af..1a9fb24c 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java @@ -1,4 +1,4 @@ -package de.greenrobot.eventperf.testsubject; +package org.greenrobot.eventbusperf.testsubject; import android.app.Activity; import android.content.Context; @@ -13,9 +13,9 @@ import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; -import de.greenrobot.eventperf.Test; -import de.greenrobot.eventperf.TestEvent; -import de.greenrobot.eventperf.TestParams; +import org.greenrobot.eventbusperf.Test; +import org.greenrobot.eventbusperf.TestEvent; +import org.greenrobot.eventbusperf.TestParams; public abstract class PerfTestOtto extends Test { diff --git a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java similarity index 85% rename from EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java rename to EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java index c64b54b1..2244a0a3 100644 --- a/EventBusPerformance/src/de/greenrobot/eventperf/testsubject/SubscribeClassEventBusDefault.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java @@ -1,8 +1,8 @@ -package de.greenrobot.eventperf.testsubject; +package org.greenrobot.eventbusperf.testsubject; import org.greenrobot.eventbus.Subscribe; -import de.greenrobot.eventperf.TestEvent; +import org.greenrobot.eventbusperf.TestEvent; public class SubscribeClassEventBusDefault { private PerfTestEventBus perfTestEventBus; From 633073e819e5563ce10e2364801260b7c25fc118 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 13:06:50 +0100 Subject: [PATCH 095/112] moved processor and inJar to org.greenrobot.eventbus --- .../META-INF/services/javax.annotation.processing.Processor | 2 +- .../annotationprocessor/EventBusAnnotationProcessor.java | 2 +- .../test => org/greenrobot/eventbus}/SubscriberInJar.java | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) rename EventBusAnnotationProcessor/src/{de/greenrobot/event => org/greenrobot/eventbus}/annotationprocessor/EventBusAnnotationProcessor.java (99%) rename EventBusTestSubscriberInJar/src/{de/greenrobot/event/test => org/greenrobot/eventbus}/SubscriberInJar.java (83%) diff --git a/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor b/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor index ec7e34b6..e6e7aa55 100644 --- a/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor +++ b/EventBusAnnotationProcessor/res/META-INF/services/javax.annotation.processing.Processor @@ -1 +1 @@ -de.greenrobot.event.annotationprocessor.EventBusAnnotationProcessor +org.greenrobot.eventbus.annotationprocessor.EventBusAnnotationProcessor diff --git a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java similarity index 99% rename from EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java rename to EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 69731f5b..6455233e 100644 --- a/EventBusAnnotationProcessor/src/de/greenrobot/event/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -1,4 +1,4 @@ -package de.greenrobot.event.annotationprocessor; +package org.greenrobot.eventbus.annotationprocessor; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; diff --git a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java b/EventBusTestSubscriberInJar/src/org/greenrobot/eventbus/SubscriberInJar.java similarity index 83% rename from EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java rename to EventBusTestSubscriberInJar/src/org/greenrobot/eventbus/SubscriberInJar.java index d79d0d80..9d185207 100644 --- a/EventBusTestSubscriberInJar/src/de/greenrobot/event/test/SubscriberInJar.java +++ b/EventBusTestSubscriberInJar/src/org/greenrobot/eventbus/SubscriberInJar.java @@ -1,6 +1,4 @@ -package de.greenrobot.event.test; - -import org.greenrobot.eventbus.Subscribe; +package org.greenrobot.eventbus; import java.util.ArrayList; import java.util.List; From ce943759dfbbde0361b53e26657ebec44004bac7 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 22 Jan 2016 14:49:35 +0100 Subject: [PATCH 096/112] updating subscriber-in-jar and using an index for it --- .../EventBusAnnotationProcessor.java | 2 ++ .../EventBusTestSubscriberInJar-3.0.0-beta1.jar | Bin 1351 -> 0 bytes .../EventBusTestSubscriberInJar-3.0.0-beta2.jar | Bin 0 -> 3800 bytes .../eventbus/EventBusSubscriberInJarTest.java | 2 +- .../EventBusSubscriberInJarTestWithIndex.java | 4 +++- EventBusTestSubscriberInJar/build.gradle | 5 +++++ 6 files changed, 11 insertions(+), 2 deletions(-) delete mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar create mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 6455233e..51ffc232 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -16,6 +16,7 @@ import javax.annotation.processing.Messager; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedOptions; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -30,6 +31,7 @@ import javax.tools.JavaFileObject; @SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") +@SupportedOptions("eventBusIndex") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; diff --git a/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar b/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta1.jar deleted file mode 100644 index bdfeab2124918adea44f041f85c5d9586c515c7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1351 zcmWIWW@h1HVBp|jxNd#ajR6RlKm-tQ0iYh?4Z8)YQD9{G|L6ysAO20~&~=I<+h{55FFeudwMUNiD|IXn8&3)H6l~hUq}3 z>*3QFT$)szT$GuVTI8AMl~|;goRe5w+#8geeZ@hb?pvJD`&swqUJqNVzxGo0CwT2S};(iG;UL5F*NL{HxQw|Wk@>Xf}= z+{HUgF8oW_VRLD(>IeDe9RJHP?T=<|X^xD4@q451#|Md1yW%g&W}Lkr?Z+Q}q3Gj* z!*X&)Jpan)ZDF0B6nEBtg<{*e`Bg8kf6|DOD3P?5+qYP?IO8jWn|$Yj-M(SG+AAje zcD;NfV5C{Iz}$*my4LyaTgzATFaC&dDSx?THFr|RgsaM@wI3IX{%xw~eJzr>bKa%g zWwP2_4FH@7WzoyVv7Ld@p+sT*C#qoi95W7Kai{OxvdU*~Mm-Tw2|-r4d-UN2)V z)0_WlYa;`v@!nT@Q_B)Ls5=cDi~uk+ Bqmuvt diff --git a/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar b/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar new file mode 100644 index 0000000000000000000000000000000000000000..abecd8bea32d336a7f861e95ba13e073f154d1fa GIT binary patch literal 3800 zcmbVP2{e>_7awcG*t3lxQq0(fghE-eWQOrt(~PBTNtVG-Lbht`5(&eIEG299h+a*$ zFeD*S$VeozSLmBLeQ(RWU!Bf(pYuG=f6lqT-#v5x_kZv2F*9ajW(NR(KtQ9vnh}6% zjI;;U*r+$kz)DvEVQQ$z1Tg!_u`-PDJ%s82rr!KNI-+z<5rzhqR&bQzGOD}F#8?6T zgwt3-mfYQ2WuY{%f1EN&VWcCY;=e^@rmnGmZvP7SqYw9gecb$9UA_IVPFVlnx(ol? z-Sw=ix4%;W?q4{Up5*+UOaOrT4gdi58yvzL>F9^>c5w}aJ9|3faH-Z_mVD;?p>PQh zC^~#3t|>iZ>3VS!hKF!FCb!23Js5SWg>z`o{uDav)4+-TPdd{BD@EK}g@te59g&Cx zcl-2CjN)$K-s8ykHaE8@kZ?#~_a0zN0zmq(kJDql+RSOcIFc9Fxj-MDgQFCso{4PG zy87P0z@({(Hl}QH!NG2ybjo5k0FCG>}yZPkTpgK+Tj}<(7%ynK%V3{2qi7u6pox2Io zd@yGibyq44Z1`6^!92|%wnnBY&#cU%wZb3Y>0=Xv$>_}AXSXmbp_c;#mm1=qFZ#~% zU4=VtQShydIXYhH92ZOTn-sUC${twG3x}xd$=@#+!FUf?alEayLk)R94UhsMo5&%i z#WO7K=4#7}2S6&0_z#ovtgFQW+06 zG{vq7rb9n^J-n5@5ZR=GtSC4?mmtV~RHK?uPVvg|Ep&8F*BUuoqt7>g-Ka4J08=9! z-w~epULjF+ns46H5SQgH-kesxT}RAJ-6L<8E2Ii^y43upr%+1WNU?^~ZCrvF^n8SY zIXT|tuWI&M>^+Vrv(@oU^*Y6M)8TRT`pE}8?6nUuHP#4i0Bu(QXIU{~XAfZ+KkU`T zi0i7hFkYJgBJjn+QrtV=F(EWN85rZla@z3=K4p)>a-hxaYo|$$46KMqsj`20@x4wvyp;_IhB`$`4*0tcwn zHAYP6GJaJ%{TdKlu zcHJ_-3FqwR?&M1Csno{$wWlT|dwJ~CQuotP7s5;tum^*ma8aQZK1@UM!x^>`m(PaFQ2^sA-y525)mz4KA9)!4{Es2iJP_XRxetu))pRY3^D_47o-v033K-X zCB3k<$IgVEF5g&uQqZ1O?_ByZxNF6i&5L{eg6MeC#G5?3*>B&kslBs}=#nz448 zqM%$89M?{&Q#l3a6#si>4`=ncjx#4YQI!a#(mDPNeyu);eRx81?uTi{o?ag#cKt-lLpysRG0Ra8In6x4_a;Tc;LX{qR)x`I+= z73vr$S2}hP`q24v1lfJNe80{6878UY@04F1`lN(1d#ffC$#5lV_p*y#ti%!o)~?2@TW4z7^bEpltXOxqfr7FL+4lzrZhzLIh?<#e z1vv4rsNTWkZJ>&Fzp#@N!FFW1T}K*%n|eFccG*@8C=Ij9*6I`#7H_ir+zdvuMb$yn z?RB9lO!fbFduc=Aa#EKmNr%H={UdvE@!nWz@gxDDpoF!3pV*PpyQE_XWc^*-+_{^Y zDQX2gEVHSuW6rPU9A=3nyrR!;O6wb&staz!UbkMfPOkp^lJ|=gPq2$j*)_Lhf_UT- z0dv{k?Sx%G%;Bz~j)eU}5ng(*o)K_-+v7t~UQdJih%39CEb|PK<5>rGj3)L4EV2mi z7~GfRj@EIIzF=lw41ITt5{&4DdU60Z$fpycC?Sg(IwkI7VR8MQ{fQL4E7!|S`u?lYz@5}3 z9r&Btr)Qy8`~UFdM=((9^j9qO+Mk}4Ug~^j#ZWWz2duOjrzfSKq~A%+Sbt6WKj$hv zHGSLtP8|yTW9t9Wgz4kZpa1W1?5PF(tGv+tg`eYm%@hkY0{{R!^ Date: Mon, 25 Jan 2016 18:05:18 +0100 Subject: [PATCH 097/112] annotation processor only generates a single index class (at least for now) --- .../EventBusAnnotationProcessor.java | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 51ffc232..36d006ca 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -34,10 +34,10 @@ @SupportedOptions("eventBusIndex") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; + public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex"; /** Found subscriber methods for a class (without superclasses). */ private final Map> methodsByClass = new HashMap<>(); - private final Map infoByClass = new HashMap<>(); private final Set classesToSkip = new HashSet<>(); private boolean writerRoundDone; @@ -74,10 +74,14 @@ public boolean process(Set annotations, RoundEnvironment checkForSubscribersToSkip(messager); if (!methodsByClass.isEmpty()) { - createInfoFiles(); - String index = processingEnv.getOptions().get("eventBusIndex"); + // Nor now, we just use a single index and skip individual files: createInfoFiles(); + + String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX); if (index != null) { createInfoIndexFile(index); + } else { + messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX + + " passed to annotation processor."); } } else { messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); @@ -193,10 +197,9 @@ private TypeElement getSuperclass(TypeElement type) { } } + // Currently unused in favor of single index files private void createInfoFiles() { - List>> entries = new ArrayList<>(methodsByClass.entrySet()); - for (int i = 0; i < entries.size(); i++) { - Map.Entry> entry = entries.get(i); + for (Map.Entry> entry : methodsByClass.entrySet()) { TypeElement subscriberClass = entry.getKey(); if (classesToSkip.contains(subscriberClass)) { continue; @@ -209,8 +212,6 @@ private void createInfoFiles() { String subscriberClassName = getClassString(subscriberClass, myPackage); String infoClassName = getInfoClass(subscriberClass, myPackage); - infoByClass.put(subscriberClass, myPackage + "." + infoClassName); - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); writer = new BufferedWriter(sourceFile.openWriter()); writer.write("package " + myPackage + ";\n\n"); @@ -393,20 +394,22 @@ private void createInfoIndexFile(String index) { } private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException { - for (Map.Entry entry : infoByClass.entrySet()) { + for (Map.Entry> entry : methodsByClass.entrySet()) { TypeElement subscriberTypeElement = entry.getKey(); - if (!classesToSkip.contains(subscriberTypeElement)) { - String subscriberClass = getClassString(subscriberTypeElement, myPackage); - if (isVisible(myPackage, subscriberTypeElement)) { - writeLine(writer, 2, - "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,", - "true,", "new SubscriberMethodInfo[] {"); - List methods = methodsByClass.get(subscriberTypeElement); - writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage); - writer.write(" }));\n\n"); - } else { - writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); - } + if (classesToSkip.contains(subscriberTypeElement)) { + continue; + } + + String subscriberClass = getClassString(subscriberTypeElement, myPackage); + if (isVisible(myPackage, subscriberTypeElement)) { + writeLine(writer, 2, + "putIndex(new SimpleSubscriberInfo(" + subscriberClass + ".class,", + "true,", "new SubscriberMethodInfo[] {"); + List methods = methodsByClass.get(subscriberTypeElement); + writeCreateSubscriberMethods(writer, methods, "new SubscriberMethodInfo", myPackage); + writer.write(" }));\n\n"); + } else { + writer.write(" // Subscriber not visible to index: " + subscriberClass + "\n"); } } } From e96bb42a93edcd8ac2cf45c35015b0d540d8afa1 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 25 Jan 2016 18:08:18 +0100 Subject: [PATCH 098/112] annotation processor: removed now unused methods getNextValue and createInfoFiles --- .../EventBusAnnotationProcessor.java | 78 ------------------- 1 file changed, 78 deletions(-) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 36d006ca..9985228d 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -197,84 +197,6 @@ private TypeElement getSuperclass(TypeElement type) { } } - // Currently unused in favor of single index files - private void createInfoFiles() { - for (Map.Entry> entry : methodsByClass.entrySet()) { - TypeElement subscriberClass = entry.getKey(); - if (classesToSkip.contains(subscriberClass)) { - continue; - } - - BufferedWriter writer = null; - try { - PackageElement packageElement = getPackageElement(subscriberClass); - String myPackage = packageElement.getQualifiedName().toString(); - String subscriberClassName = getClassString(subscriberClass, myPackage); - String infoClassName = getInfoClass(subscriberClass, myPackage); - - JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile(myPackage + '.' + infoClassName); - writer = new BufferedWriter(sourceFile.openWriter()); - writer.write("package " + myPackage + ";\n\n"); - writer.write("import org.greenrobot.eventbus.meta.AbstractSubscriberInfo;\n"); - writer.write("import org.greenrobot.eventbus.SubscriberMethod;\n"); - writer.write("import org.greenrobot.eventbus.ThreadMode;\n\n"); - writer.write("/** This class is generated by EventBus, do not edit. */\n"); - writer.write("public class " + infoClassName + " extends AbstractSubscriberInfo {\n"); - writer.write(" public " + infoClassName + "() {\n"); - String infoSuperClass = getSuperclassInfoClass(subscriberClass, myPackage); - writeLine(writer, 2, "super(" + subscriberClassName + ".class,", infoSuperClass + ",", "/* TODO */ true);"); - writer.write(" }\n\n"); - writer.write(" public SubscriberMethod[] getSubscriberMethods() {\n"); - writer.write(" return new SubscriberMethod[] {\n"); - writeCreateSubscriberMethods(writer, entry.getValue(), "createSubscriberMethod", myPackage); - writer.write(" };\n"); - writer.write(" }\n}\n"); - } catch (IOException e) { - throw new RuntimeException("Could not write source for " + subscriberClass.getQualifiedName(), e); - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - //Silent - } - } - } - } - } - - private String getSuperclassInfoClass(TypeElement subscriberClass, String myPackage) { - DeclaredType superclassType = (DeclaredType) subscriberClass.getSuperclass(); - if (superclassType != null) { - TypeElement superclass = (TypeElement) superclassType.asElement(); - if (methodsByClass.containsKey(superclass) && !classesToSkip.contains(superclass)) { - return getInfoClass(superclass, myPackage) + ".class"; - } - } - return "null"; - } - - private String getInfoClass(TypeElement subscriberClass, String myPackage) { - String subscriberClassName = getClassString(subscriberClass, myPackage); - return subscriberClassName.replace('.', '_') + INFO_CLASS_POSTFIX; - } - - private String getNextValue(String myPackage, TypeElement nextEntry) throws IOException { - String nextValue; - if (nextEntry != null) { - PackageElement nextPackageElement = getPackageElement(nextEntry); - String nextPackage = nextPackageElement.getQualifiedName().toString(); - String nextInfoClassName = getInfoClass(nextEntry, nextPackage); - if (!myPackage.equals(nextPackage)) { - nextInfoClassName = nextPackage + "." + nextInfoClassName; - } - nextValue = nextInfoClassName + ".class"; - } else { - nextValue = "null"; - } - return nextValue; - } - private String getClassString(TypeElement typeElement, String myPackage) { PackageElement packageElement = getPackageElement(typeElement); String packageString = packageElement.getQualifiedName().toString(); From 6372ee9bdf133fa50a92985b055170bc9e02ff21 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 27 Jan 2016 08:20:28 +0100 Subject: [PATCH 099/112] allow package protected classes along with index --- .../EventBusAnnotationProcessor.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 9985228d..018bffca 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -33,7 +33,6 @@ @SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") @SupportedOptions("eventBusIndex") public class EventBusAnnotationProcessor extends AbstractProcessor { - public static final String INFO_CLASS_POSTFIX = "_EventBusInfo"; public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex"; /** Found subscriber methods for a class (without superclasses). */ @@ -52,6 +51,15 @@ public SourceVersion getSupportedSourceVersion() { public boolean process(Set annotations, RoundEnvironment env) { Messager messager = processingEnv.getMessager(); try { + String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX); + if (index == null) { + messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX + + " passed to annotation processor"); + return false; + } + int lastPeriod = index.lastIndexOf('.'); + String indexPackage = lastPeriod != -1 ? index.substring(0, lastPeriod) : null; + round++; messager.printMessage(Diagnostic.Kind.NOTE, "Processing round " + round + ", new annotations: " + !annotations.isEmpty() + ", processingOver: " + env.processingOver()); @@ -71,18 +79,10 @@ public boolean process(Set annotations, RoundEnvironment "Unexpected processing state: annotations still available after writing."); } collectSubscribers(annotations, env, messager); - checkForSubscribersToSkip(messager); + checkForSubscribersToSkip(messager, indexPackage); if (!methodsByClass.isEmpty()) { - // Nor now, we just use a single index and skip individual files: createInfoFiles(); - - String index = processingEnv.getOptions().get(OPTION_EVENT_BUS_INDEX); - if (index != null) { - createInfoIndexFile(index); - } else { - messager.printMessage(Diagnostic.Kind.ERROR, "No option " + OPTION_EVENT_BUS_INDEX + - " passed to annotation processor."); - } + createInfoIndexFile(index); } else { messager.printMessage(Diagnostic.Kind.WARNING, "No @Subscribe annotations found"); } @@ -136,12 +136,12 @@ private boolean checkHasNoErrors(ExecutableElement element, Messager messager) { return true; } - private void checkForSubscribersToSkip(Messager messager) { + private void checkForSubscribersToSkip(Messager messager, String myPackage) { for (Map.Entry> entry : methodsByClass.entrySet()) { TypeElement skipCandidate = entry.getKey(); TypeElement subscriberClass = skipCandidate; while (subscriberClass != null) { - if (!subscriberClass.getModifiers().contains(Modifier.PUBLIC)) { + if (!isVisible(myPackage, subscriberClass)) { boolean added = classesToSkip.add(skipCandidate); if (added) { String msg; @@ -159,9 +159,8 @@ private void checkForSubscribersToSkip(Messager messager) { if (methods != null) { for (ExecutableElement method : methods) { VariableElement param = method.getParameters().get(0); - DeclaredType paramType = (DeclaredType) param.asType(); - Set eventClassModifiers = paramType.asElement().getModifiers(); - if (!eventClassModifiers.contains(Modifier.PUBLIC)) { + TypeElement eventTypeElement = (TypeElement) ((DeclaredType) param.asType()).asElement(); + if (!isVisible(myPackage, eventTypeElement)) { boolean added = classesToSkip.add(skipCandidate); if (added) { String msg; From e880e35e7f5a6ab2a4ec1074fed2c846342bf76b Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 27 Jan 2016 08:20:58 +0100 Subject: [PATCH 100/112] removed empty TODO comments from tests --- .../eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java | 1 - .../indexed/EventBusOrderedSubscriptionsTestWithIndex.java | 1 - .../indexed/EventBusRegistrationRacingTestWithIndex.java | 1 - .../eventbus/indexed/EventBusStickyEventTestWithIndex.java | 1 - .../indexed/EventBusSubscriberExceptionTestWithIndex.java | 1 - .../eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java | 1 - 6 files changed, 6 deletions(-) diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java index 937af651..3365157e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -3,7 +3,6 @@ import org.greenrobot.eventbus.EventBusNoSubscriberEventTest; import org.junit.Before; -/** TODO */ public class EventBusNoSubscriberEventTestWithIndex extends EventBusNoSubscriberEventTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java index 71389239..68fdd9db 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -3,7 +3,6 @@ import org.greenrobot.eventbus.EventBusOrderedSubscriptionsTest; import org.junit.Before; -/** TODO */ public class EventBusOrderedSubscriptionsTestWithIndex extends EventBusOrderedSubscriptionsTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java index bbd40a9c..ecfb2cba 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -4,7 +4,6 @@ import org.greenrobot.eventbus.EventBusRegistrationRacingTest; -/** TODO */ public class EventBusRegistrationRacingTestWithIndex extends EventBusRegistrationRacingTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java index 6fab88f5..8a3f8b4b 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java @@ -3,7 +3,6 @@ import org.greenrobot.eventbus.EventBusStickyEventTest; import org.junit.Before; -/** TODO */ public class EventBusStickyEventTestWithIndex extends EventBusStickyEventTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java index 42bcce98..a1e91b07 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -4,7 +4,6 @@ import org.greenrobot.eventbus.EventBusSubscriberExceptionTest; -/** TODO */ public class EventBusSubscriberExceptionTestWithIndex extends EventBusSubscriberExceptionTest { @Before public void overwriteEventBus() throws Exception { diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java index 27938dce..8a3d5967 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -5,7 +5,6 @@ import org.greenrobot.eventbus.InJarIndex; import org.junit.Before; -/** TODO */ public class EventBusSubscriberInJarTestWithIndex extends EventBusSubscriberInJarTest { @Before public void overwriteEventBus() throws Exception { From 8f9629eed5420dbea063cf54d2d7c9667518d9c7 Mon Sep 17 00:00:00 2001 From: Markus Date: Fri, 29 Jan 2016 22:02:39 +0100 Subject: [PATCH 101/112] using ListMap, org.greenrobot:eventbus-annotation-processor:3.0.0-rc --- EventBusAnnotationProcessor/build.gradle | 5 +-- .../EventBusAnnotationProcessor.java | 36 +++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index f8bf0b07..ddb9d53d 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -3,8 +3,8 @@ apply plugin: 'maven' apply plugin: 'signing' archivesBaseName = 'eventbus-annotation-processor' -group = 'de.greenrobot' -version = '3.0.0-beta2' +group = 'org.greenrobot' +version = '3.0.0-rc' sourceCompatibility = 1.7 @@ -29,6 +29,7 @@ configurations { dependencies { compile project(':EventBus') + compile 'de.greenrobot:java-common:2.3.1' deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' } diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 018bffca..8fc5888e 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.greenrobot.eventbus.annotationprocessor; import org.greenrobot.eventbus.Subscribe; @@ -6,10 +21,8 @@ import java.io.BufferedWriter; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import javax.annotation.processing.AbstractProcessor; @@ -30,13 +43,15 @@ import javax.tools.Diagnostic; import javax.tools.JavaFileObject; +import de.greenrobot.common.ListMap; + @SupportedAnnotationTypes("org.greenrobot.eventbus.Subscribe") @SupportedOptions("eventBusIndex") public class EventBusAnnotationProcessor extends AbstractProcessor { public static final String OPTION_EVENT_BUS_INDEX = "eventBusIndex"; /** Found subscriber methods for a class (without superclasses). */ - private final Map> methodsByClass = new HashMap<>(); + private final ListMap methodsByClass = new ListMap<>(); private final Set classesToSkip = new HashSet<>(); private boolean writerRoundDone; @@ -102,13 +117,8 @@ private void collectSubscribers(Set annotations, RoundEnv if (element instanceof ExecutableElement) { ExecutableElement method = (ExecutableElement) element; if (checkHasNoErrors(method, messager)) { - Element classElement = method.getEnclosingElement(); - List methods = methodsByClass.get(classElement); - if (methods == null) { - methods = new ArrayList<>(); - methodsByClass.put((TypeElement) classElement, methods); - } - methods.add(method); + TypeElement classElement = (TypeElement) method.getEnclosingElement(); + methodsByClass.putElement(classElement, method); } } else { messager.printMessage(Diagnostic.Kind.ERROR, "@Subscribe is only valid for methods", element); @@ -137,8 +147,7 @@ private boolean checkHasNoErrors(ExecutableElement element, Messager messager) { } private void checkForSubscribersToSkip(Messager messager, String myPackage) { - for (Map.Entry> entry : methodsByClass.entrySet()) { - TypeElement skipCandidate = entry.getKey(); + for (TypeElement skipCandidate : methodsByClass.keySet()) { TypeElement subscriberClass = skipCandidate; while (subscriberClass != null) { if (!isVisible(myPackage, subscriberClass)) { @@ -315,8 +324,7 @@ private void createInfoIndexFile(String index) { } private void writeIndexLines(BufferedWriter writer, String myPackage) throws IOException { - for (Map.Entry> entry : methodsByClass.entrySet()) { - TypeElement subscriberTypeElement = entry.getKey(); + for (TypeElement subscriberTypeElement : methodsByClass.keySet()) { if (classesToSkip.contains(subscriberTypeElement)) { continue; } From d3398723b3089cac311ac2145d5b3242f19f05a4 Mon Sep 17 00:00:00 2001 From: Markus Date: Sat, 30 Jan 2016 09:34:06 +0100 Subject: [PATCH 102/112] updated copyright headers --- .../src/org/greenrobot/eventbus/AsyncPoster.java | 2 +- .../greenrobot/eventbus/BackgroundPoster.java | 2 +- .../src/org/greenrobot/eventbus/EventBus.java | 2 +- .../org/greenrobot/eventbus/EventBusBuilder.java | 2 +- .../greenrobot/eventbus/EventBusException.java | 2 +- .../org/greenrobot/eventbus/HandlerPoster.java | 2 +- .../greenrobot/eventbus/NoSubscriberEvent.java | 2 +- .../src/org/greenrobot/eventbus/PendingPost.java | 2 +- .../greenrobot/eventbus/PendingPostQueue.java | 16 ++++++++++++++++ .../src/org/greenrobot/eventbus/Subscribe.java | 16 ++++++++++++++++ .../eventbus/SubscriberExceptionEvent.java | 2 +- .../greenrobot/eventbus/SubscriberMethod.java | 2 +- .../eventbus/SubscriberMethodFinder.java | 2 +- .../org/greenrobot/eventbus/Subscription.java | 2 +- .../src/org/greenrobot/eventbus/ThreadMode.java | 2 +- .../eventbus/meta/AbstractSubscriberInfo.java | 2 +- .../eventbus/meta/SimpleSubscriberInfo.java | 2 +- .../greenrobot/eventbus/meta/SubscriberInfo.java | 2 +- .../eventbus/meta/SubscriberInfoIndex.java | 2 +- .../eventbus/meta/SubscriberMethodInfo.java | 2 +- .../greenrobot/eventbus/util/AsyncExecutor.java | 2 +- .../eventbus/util/ErrorDialogConfig.java | 16 ++++++++++++++++ .../util/ErrorDialogFragmentFactory.java | 16 ++++++++++++++++ .../eventbus/util/ErrorDialogFragments.java | 16 ++++++++++++++++ .../eventbus/util/ErrorDialogManager.java | 16 ++++++++++++++++ .../util/ExceptionToResourceMapping.java | 16 ++++++++++++++++ .../eventbus/util/HasExecutionScope.java | 16 ++++++++++++++++ .../eventbus/util/ThrowableFailureEvent.java | 2 +- .../src/org/greenrobot/eventbusperf/Test.java | 16 ++++++++++++++++ .../org/greenrobot/eventbusperf/TestEvent.java | 16 ++++++++++++++++ .../eventbusperf/TestFinishedEvent.java | 16 ++++++++++++++++ .../org/greenrobot/eventbusperf/TestParams.java | 16 ++++++++++++++++ .../org/greenrobot/eventbusperf/TestRunner.java | 16 ++++++++++++++++ .../eventbusperf/TestRunnerActivity.java | 16 ++++++++++++++++ .../eventbusperf/TestSetupActivity.java | 16 ++++++++++++++++ .../testsubject/PerfTestEventBus.java | 16 ++++++++++++++++ .../eventbusperf/testsubject/PerfTestOtto.java | 16 ++++++++++++++++ .../SubscribeClassEventBusDefault.java | 16 ++++++++++++++++ .../eventbus/AbstractEventBusTest.java | 2 +- .../greenrobot/eventbus/ClassMapPerfTest.java | 16 ++++++++++++++++ .../eventbus/EventBusBackgroundThreadTest.java | 2 +- .../greenrobot/eventbus/EventBusBasicTest.java | 2 +- .../greenrobot/eventbus/EventBusBuilderTest.java | 2 +- .../EventBusCancelEventDeliveryTest.java | 2 +- .../EventBusFallbackToReflectionTest.java | 16 ++++++++++++++++ .../eventbus/EventBusGenericsTest.java | 16 ++++++++++++++++ .../EventBusInheritanceDisabledTest.java | 2 +- .../eventbus/EventBusInheritanceTest.java | 2 +- .../eventbus/EventBusMainThreadRacingTest.java | 2 +- .../eventbus/EventBusMainThreadTest.java | 2 +- .../eventbus/EventBusMethodModifiersTest.java | 2 +- .../eventbus/EventBusMultithreadedTest.java | 2 +- .../eventbus/EventBusNoSubscriberEventTest.java | 2 +- .../EventBusOrderedSubscriptionsTest.java | 2 +- .../eventbus/EventBusRegistrationRacingTest.java | 2 +- .../eventbus/EventBusStickyEventTest.java | 2 +- .../EventBusSubscriberExceptionTest.java | 2 +- .../eventbus/EventBusSubscriberInJarTest.java | 16 ++++++++++++++++ .../eventbus/EventBusSubscriberLegalTest.java | 2 +- .../org/greenrobot/eventbus/IntTestEvent.java | 2 +- .../EventBusBackgroundThreadTestWithIndex.java | 16 ++++++++++++++++ .../indexed/EventBusBasicTestWithIndex.java | 16 ++++++++++++++++ ...EventBusCancelEventDeliveryTestWithIndex.java | 16 ++++++++++++++++ ...ventBusFallbackToReflectionTestWithIndex.java | 16 ++++++++++++++++ .../indexed/EventBusGenericsTestWithIndex.java | 16 ++++++++++++++++ ...EventBusInheritanceDisabledTestWithIndex.java | 16 ++++++++++++++++ .../EventBusInheritanceTestWithIndex.java | 16 ++++++++++++++++ .../EventBusMainThreadRacingTestWithIndex.java | 16 ++++++++++++++++ .../indexed/EventBusMainThreadTestWithIndex.java | 16 ++++++++++++++++ .../EventBusMethodModifiersTestWithIndex.java | 16 ++++++++++++++++ .../EventBusMultithreadedTestWithIndex.java | 16 ++++++++++++++++ .../EventBusNoSubscriberEventTestWithIndex.java | 16 ++++++++++++++++ ...ventBusOrderedSubscriptionsTestWithIndex.java | 16 ++++++++++++++++ .../EventBusRegistrationRacingTestWithIndex.java | 16 ++++++++++++++++ .../EventBusStickyEventTestWithIndex.java | 16 ++++++++++++++++ ...EventBusSubscriberExceptionTestWithIndex.java | 16 ++++++++++++++++ .../EventBusSubscriberInJarTestWithIndex.java | 16 ++++++++++++++++ .../org/greenrobot/eventbus/indexed/Indexed.java | 16 ++++++++++++++++ 78 files changed, 678 insertions(+), 38 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java index e3129dee..a56f4ebf 100644 --- a/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/AsyncPoster.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java index c23e1575..2a5319d0 100644 --- a/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/BackgroundPoster.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/EventBus.java b/EventBus/src/org/greenrobot/eventbus/EventBus.java index 3dd210b5..1cd57e32 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBus.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBus.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java index 9d003108..e212750e 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/EventBusException.java b/EventBus/src/org/greenrobot/eventbus/EventBusException.java index 9bbacf55..20d50e6b 100644 --- a/EventBus/src/org/greenrobot/eventbus/EventBusException.java +++ b/EventBus/src/org/greenrobot/eventbus/EventBusException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java index 0571e1b2..3247be53 100644 --- a/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java +++ b/EventBus/src/org/greenrobot/eventbus/HandlerPoster.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java b/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java index 8a6d0c50..e4da4757 100644 --- a/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/NoSubscriberEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/PendingPost.java b/EventBus/src/org/greenrobot/eventbus/PendingPost.java index e6c3bf4f..01f474c2 100644 --- a/EventBus/src/org/greenrobot/eventbus/PendingPost.java +++ b/EventBus/src/org/greenrobot/eventbus/PendingPost.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java b/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java index 048a841f..55db529a 100644 --- a/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java +++ b/EventBus/src/org/greenrobot/eventbus/PendingPostQueue.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; final class PendingPostQueue { diff --git a/EventBus/src/org/greenrobot/eventbus/Subscribe.java b/EventBus/src/org/greenrobot/eventbus/Subscribe.java index b36496db..ed0b8c82 100644 --- a/EventBus/src/org/greenrobot/eventbus/Subscribe.java +++ b/EventBus/src/org/greenrobot/eventbus/Subscribe.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java b/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java index 1302f777..ff69f05a 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberExceptionEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java index 5bd751c4..1d78d479 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index 03974004..3cf28a42 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/Subscription.java b/EventBus/src/org/greenrobot/eventbus/Subscription.java index 1f529c92..cc0de1e3 100644 --- a/EventBus/src/org/greenrobot/eventbus/Subscription.java +++ b/EventBus/src/org/greenrobot/eventbus/Subscription.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java index 9292d4e9..79d5dc43 100644 --- a/EventBus/src/org/greenrobot/eventbus/ThreadMode.java +++ b/EventBus/src/org/greenrobot/eventbus/ThreadMode.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java index 9156ea25..75e309d2 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java index 957d058d..3ee4442d 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SimpleSubscriberInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java index 7cd445a8..bd7cd5c0 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java index 5e27d4e8..9fc65f6f 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfoIndex.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java index 9d0782ed..2152554c 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberMethodInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java index c1b49c1b..c44c1366 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java +++ b/EventBus/src/org/greenrobot/eventbus/util/AsyncExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java index 3378ba4d..95e84c72 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogConfig.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.content.res.Resources; diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java index ca6a8b4d..27ab963d 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragmentFactory.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.annotation.TargetApi; diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java index 79833b42..49174766 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogFragments.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.annotation.TargetApi; diff --git a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java index 34cb82da..9d5ccf2c 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ErrorDialogManager.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.annotation.TargetApi; diff --git a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java index d45159b1..9ab0d006 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ExceptionToResourceMapping.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; import android.util.Log; diff --git a/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java b/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java index 67613b4d..fd20a0dc 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java +++ b/EventBus/src/org/greenrobot/eventbus/util/HasExecutionScope.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.util; public interface HasExecutionScope { diff --git a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java index abc37db9..9b7b80b6 100644 --- a/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java +++ b/EventBus/src/org/greenrobot/eventbus/util/ThrowableFailureEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java index 35d20471..ee2d405d 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/Test.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import android.content.Context; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java index d0edba31..8db0db9f 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestEvent.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; /** Used by otto and EventBus */ diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java index 7bc72ed8..9e1a5594 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestFinishedEvent.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; public class TestFinishedEvent { diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java index 79af650a..85ee4f13 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestParams.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import org.greenrobot.eventbus.ThreadMode; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java index 3107289a..4c0f941f 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunner.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import android.content.Context; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java index 9c718597..e22631c1 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestRunnerActivity.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import android.app.Activity; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java index 0837bd4a..3488b8da 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/TestSetupActivity.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf; import android.app.Activity; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java index 5f43601a..7ceb8e6d 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestEventBus.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf.testsubject; import android.content.Context; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java index 1a9fb24c..646256ed 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/PerfTestOtto.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf.testsubject; import android.app.Activity; diff --git a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java index 2244a0a3..54a11423 100644 --- a/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java +++ b/EventBusPerformance/src/org/greenrobot/eventbusperf/testsubject/SubscribeClassEventBusDefault.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbusperf.testsubject; import org.greenrobot.eventbus.Subscribe; diff --git a/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java b/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java index f313071a..867cada1 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/AbstractEventBusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java b/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java index 60f7a66c..6c1e9b51 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/ClassMapPerfTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; import java.util.HashMap; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java index 32ce3b3f..5a57f744 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBackgroundThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java index f50c4108..d6af1eb4 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBasicTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java index 354d78e2..42d919de 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java index 5c9966d6..869da70e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusCancelEventDeliveryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java index ce102566..59e8d68c 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; import org.junit.Test; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java index 06db3002..2e218a37 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusGenericsTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; import org.junit.Test; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java index 4a767204..80638e8b 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceDisabledTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java index d4a4d0f7..f9619bed 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusInheritanceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java index 79fdfc92..a598220e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadRacingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java index 55c6fc57..2195d10f 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMainThreadTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2015 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java index 8eb00cf2..e974e73a 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMethodModifiersTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java index eec9103b..f3e7bd50 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusMultithreadedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java index ad12d64f..b358f8c3 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusNoSubscriberEventTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java index 463f11bf..f6f97201 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusOrderedSubscriptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java index c4f405ee..7d09d7ad 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusRegistrationRacingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java index be23b4ab..ec426745 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusStickyEventTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java index 2d227c94..f0dea680 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java index 45c21a42..5b013eb9 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberInJarTest.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus; import junit.framework.Assert; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java index c70a1e6b..c362e900 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusSubscriberLegalTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java b/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java index 5874ae17..db6fa83f 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java +++ b/EventBusTest/src/org/greenrobot/eventbus/IntTestEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Markus Junginger, greenrobot (http://greenrobot.de) + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java index 8771358a..00e38203 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBackgroundThreadTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusBackgroundThreadTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java index d5e6d1fd..4237ce8e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusBasicTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusBasicTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java index 7c3d670c..76418689 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusCancelEventDeliveryTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusCancelEventDeliveryTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java index 74c2b44e..d6a2df27 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusFallbackToReflectionTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java index eeca3a92..ca74fdfa 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusGenericsTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java index b0c85a0b..2443e9e1 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceDisabledTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java index 6d8963b6..151195a0 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusInheritanceTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusInheritanceTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java index f6a90873..b73c2d85 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadRacingTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java index 99248950..630d1d72 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMainThreadTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java index 0a9d34ae..6034354f 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMethodModifiersTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusMethodModifiersTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java index b0c06a67..e56a8020 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusMultithreadedTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusMultithreadedTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java index 3365157e..20b0d08e 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusNoSubscriberEventTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusNoSubscriberEventTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java index 68fdd9db..840e8bad 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusOrderedSubscriptionsTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusOrderedSubscriptionsTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java index ecfb2cba..55c43bfa 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusRegistrationRacingTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java index 8a3f8b4b..4e5c63d5 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusStickyEventTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBusStickyEventTest; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java index a1e91b07..2b9e3a17 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberExceptionTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.junit.Before; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java index 8a3d5967..9df9c7dd 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/EventBusSubscriberInJarTestWithIndex.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; diff --git a/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java index f86e7872..1fcda4e3 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java +++ b/EventBusTest/src/org/greenrobot/eventbus/indexed/Indexed.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.greenrobot.eventbus.indexed; import org.greenrobot.eventbus.EventBus; From 0c224c4660f771100137cb5251caed1f68094dd2 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 08:56:02 +0100 Subject: [PATCH 103/112] removed individual subscriberInfo look-ups via reflection --- .../eventbus/SubscriberMethodFinder.java | 41 +++---------------- .../eventbus/meta/AbstractSubscriberInfo.java | 11 ++++- .../eventbus/meta/SubscriberInfo.java | 2 +- 3 files changed, 15 insertions(+), 39 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index 3cf28a42..79c6addd 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -120,14 +120,10 @@ private FindState prepareFindState() { } private SubscriberInfo getSubscriberInfo(FindState findState) { - if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfoClass() != null) { - try { - SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfoClass().newInstance(); - if (findState.clazz == superclassInfo.getSubscriberClass()) { - return superclassInfo; - } - } catch (IllegalAccessException | InstantiationException e) { - throw new EventBusException(e); + if (findState.subscriberInfo != null && findState.subscriberInfo.getSuperSubscriberInfo() != null) { + SubscriberInfo superclassInfo = findState.subscriberInfo.getSuperSubscriberInfo(); + if (findState.clazz == superclassInfo.getSubscriberClass()) { + return superclassInfo; } } if (subscriberInfoIndexes != null) { @@ -138,36 +134,9 @@ private SubscriberInfo getSubscriberInfo(FindState findState) { } } } - String infoClass = getInfoClassName(findState); - try { - Class aClass = Class.forName(infoClass); - Object object = aClass.newInstance(); - if (object instanceof SubscriberInfo) { - return (SubscriberInfo) object; - } - } catch (ClassNotFoundException e) { - // TODO don't try again - } catch (Exception e) { - throw new EventBusException("Could not get infos for " + findState.clazz, e); - } return null; } - // A simple replace(char, char) is surprisingly slow, so we try to avoid it - private String getInfoClassName(FindState findState) { - String className = findState.clazz.getName(); - for (int i = className.length() - 1; i >= 0; i--) { - char c = className.charAt(i); - if (c == '.') { - break; - } else if (c == '$') { - className = className.replace('$', '_'); - break; - } - } - return className.concat("_EventBusInfo"); - } - private List findUsingReflection(Class subscriberClass) { FindState findState = prepareFindState(); findState.initForSubscriber(subscriberClass); @@ -277,7 +246,7 @@ private boolean checkAddWithMethodSignature(Method method, Class eventType) { String methodKey = methodKeyBuilder.toString(); Class methodClass = method.getDeclaringClass(); - Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); + Class methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass); if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) { // Only add if not already found in a sub class return true; diff --git a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java index 75e309d2..b68de63a 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/AbstractSubscriberInfo.java @@ -40,8 +40,15 @@ public Class getSubscriberClass() { } @Override - public Class getSuperSubscriberInfoClass() { - return superSubscriberInfoClass; + public SubscriberInfo getSuperSubscriberInfo() { + if(superSubscriberInfoClass == null) { + return null; + } + try { + return superSubscriberInfoClass.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } } @Override diff --git a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java index bd7cd5c0..83c1e741 100644 --- a/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java +++ b/EventBus/src/org/greenrobot/eventbus/meta/SubscriberInfo.java @@ -23,7 +23,7 @@ public interface SubscriberInfo { SubscriberMethod[] getSubscriberMethods(); - Class getSuperSubscriberInfoClass(); + SubscriberInfo getSuperSubscriberInfo(); boolean shouldCheckSuperclass(); } From 5871bd9c05e81e01ba6752cc3feaa9b2042cda4b Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 09:10:31 +0100 Subject: [PATCH 104/112] added testManualIndexWithoutAnnotation --- .../eventbus/EventBusIndexTest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java new file mode 100644 index 00000000..d5acc814 --- /dev/null +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusIndexTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.greenrobot.eventbus; + +import org.greenrobot.eventbus.meta.SimpleSubscriberInfo; +import org.greenrobot.eventbus.meta.SubscriberInfo; +import org.greenrobot.eventbus.meta.SubscriberInfoIndex; +import org.greenrobot.eventbus.meta.SubscriberMethodInfo; +import org.junit.Assert; +import org.junit.Test; + +public class EventBusIndexTest { + private String value; + + @Test + /** Ensures the index is actually used and no reflection fall-back kicks in. */ + public void testManualIndexWithoutAnnotation() { + SubscriberInfoIndex index = new SubscriberInfoIndex() { + + @Override + public SubscriberInfo getSubscriberInfo(Class subscriberClass) { + Assert.assertEquals(EventBusIndexTest.class, subscriberClass); + SubscriberMethodInfo[] methodInfos = { + new SubscriberMethodInfo("someMethodWithoutAnnotation", String.class) + }; + return new SimpleSubscriberInfo(EventBusIndexTest.class, false, methodInfos); + } + }; + + EventBus eventBus = EventBus.builder().addIndex(index).build(); + eventBus.register(this); + eventBus.post("Yepp"); + eventBus.unregister(this); + Assert.assertEquals("Yepp", value); + } + + public void someMethodWithoutAnnotation(String value) { + this.value = value; + } +} From 245990474bf10b15850124fe856f81b20d5be946 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 22:04:39 +0100 Subject: [PATCH 105/112] prepping v3.0.0 --- CHANGELOG.md | 6 ++--- COMPARISON.md | 2 ++ EventBus/build.gradle | 10 ++++---- EventBusAnnotationProcessor/build.gradle | 8 +++--- ...ventBusTestSubscriberInJar-3.0.0-beta2.jar | Bin 3800 -> 0 bytes .../EventBusTestSubscriberInJar-3.0.0.jar | Bin 0 -> 2761 bytes EventBusTestSubscriberInJar/build.gradle | 15 +++++++++--- README.md | 23 +++++++++--------- 8 files changed, 37 insertions(+), 27 deletions(-) delete mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar create mode 100644 EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0.jar diff --git a/CHANGELOG.md b/CHANGELOG.md index 413e86cf..7ddb539f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ -### V3.0.0 (201?-??-??) Annotations -* Breaking change: switch subscriber methods to annotations +### V3.0.0 (2016-02-??) Annotations +* Breaking change: switch subscriber method name conventions to annotations * Using annotations, each subscriber method can set sticky behavior and priority individually * Annotation processor indexes annotation information for efficient subscriber registration on Android -* TODO: Renamed package and artifact id to allow co-existence with libs using EventBus 2 internally +* Renamed package and artifact id to allow co-existence with libs using EventBus 2 internally **Note:** This is a breaking change release: there is no inter-op between EventBus versions 2 and 3; they can run in parallel though. diff --git a/COMPARISON.md b/COMPARISON.md index 31fadc03..2e0493cc 100644 --- a/COMPARISON.md +++ b/COMPARISON.md @@ -61,6 +61,8 @@ _**Note:** the following information is outdated, preprocessed annotations are m Besides features, performance is another differentiator. To compare performance, we created an Android application, which is also part of this repository (EventBusPerformance). You can also run the app on your phone to benchmark different scenarios. +TODO: Update for EventBus 3 with and without index. + Benchmark results indicate that EventBus is significantly faster in almost every scenario: diff --git a/EventBus/build.gradle b/EventBus/build.gradle index b1e8224f..a953f022 100644 --- a/EventBus/build.gradle +++ b/EventBus/build.gradle @@ -3,8 +3,8 @@ apply plugin: 'maven' apply plugin: 'signing' archivesBaseName = 'eventbus' -group = 'de.greenrobot' -version = '3.0.0-beta2' +group = 'org.greenrobot' +version = '3.0.0' sourceCompatibility = 1.7 def isSnapshot = version.endsWith('-SNAPSHOT') @@ -49,7 +49,7 @@ javadoc { failOnError = false classpath += configurations.provided title = "EventBus ${version} API" - options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2015 greenrobot.de. All Rights Reserved.' + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2012-2016 greenrobot.org. All Rights Reserved.' } task javadocJar(type: Jar, dependsOn: javadoc) { @@ -98,7 +98,7 @@ uploadArchives { name 'EventBus' packaging 'jar' description 'EventBus is a publish/subscribe event bus optimized for Android .' - url 'https://github.com/greenrobot/EventBus' + url 'http://greenrobot.org/eventbus/' scm { url 'https://github.com/greenrobot/EventBus' @@ -128,7 +128,7 @@ uploadArchives { organization { name 'greenrobot' - url 'http://greenrobot.de' + url 'http://greenrobot.org' } } } diff --git a/EventBusAnnotationProcessor/build.gradle b/EventBusAnnotationProcessor/build.gradle index ddb9d53d..d3434bb2 100644 --- a/EventBusAnnotationProcessor/build.gradle +++ b/EventBusAnnotationProcessor/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' archivesBaseName = 'eventbus-annotation-processor' group = 'org.greenrobot' -version = '3.0.0-rc' +version = '3.0.0' sourceCompatibility = 1.7 @@ -48,7 +48,7 @@ sourceSets { javadoc { classpath += configurations.provided title = "EventBus Annotation Processor ${version} API" - options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015 greenrobot.de. All Rights Reserved.' + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2015-2016 greenrobot.org. All Rights Reserved.' } task javadocJar(type: Jar, dependsOn: javadoc) { @@ -98,7 +98,7 @@ uploadArchives { name 'EventBus Annotation Processor' packaging 'jar' description 'Precompiler for EventBus Annotations.' - url 'https://github.com/greenrobot/EventBus' + url 'http://greenrobot.org/eventbus/' scm { url 'https://github.com/greenrobot/EventBus' @@ -128,7 +128,7 @@ uploadArchives { organization { name 'greenrobot' - url 'http://greenrobot.de' + url 'http://greenrobot.org' } } } diff --git a/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar b/EventBusTest/libs/EventBusTestSubscriberInJar-3.0.0-beta2.jar deleted file mode 100644 index abecd8bea32d336a7f861e95ba13e073f154d1fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3800 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 csPmd1i~e6*a6*d#6d @@ -19,13 +17,13 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) -Limitations of the SNAPSHOT version ------------------------------------ -The "subscriber index" is an optional optimization to speed up initial subscriber registration. The subscriber index is created during build time using an annotation processor. There are a couple of limitations of the current implementation: +Index and its Limitations +------------------------- +The "subscriber index" is a new feature of EventBus 3. It is an optional optimization to speed up initial subscriber registration. The subscriber index can be created during build time using EventBus' annotation processor. It is not required to use the index, but it's recommended on Android because of its poor reflection speed regarding annotations. + +Note that only those @Subscribers methods can be indexed for which the subscriber AND event class are public. Non-indexed methods have to be looked-up at runtime using reflection. - * Subscriber classes must be public - * Event classes must be public - * @Subscribe seems to be not recognized when inside of anonymous classes +Also, @Subscribe annotations are not recognized when inside of anonymous classes EventBus in 4 steps ------------------- @@ -47,16 +45,15 @@ Note: This SNAPSHOT version is only available on Sonatype's snapshot repository Gradle: ``` - compile 'de.greenrobot:eventbus:3.0.0-SNAPSHOT' - provided 'de.greenrobot:eventbus-annotation-processor:3.0.0-SNAPSHOT' + compile 'org.greenrobot:eventbus:3.0.0' ``` Maven: ``` - de.greenrobot + org.greenrobot eventbus - 3.0.0-SNAPSHOT + 3.0.0 ``` @@ -88,6 +85,8 @@ Release History, License ------------------------ [CHANGELOG](CHANGELOG.md) +Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) + EventBus binaries and source code can be used according to the [Apache License, Version 2.0](LICENSE). More Open Source by greenrobot From 0ec23c3cd912efc7470e247fadc77a575d480c28 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 22:12:32 +0100 Subject: [PATCH 106/112] pruning some old files --- EventBus/.classpath | 9 ----- EventBus/.project | 33 ----------------- EventBus/AndroidManifest.xml | 12 ------- EventBus/libs/android-support-v4.jar | Bin 385685 -> 0 bytes EventBus/mybuild.xml | 13 ------- EventBus/project.properties | 15 -------- EventBus/res/values/strings.xml | 2 -- EventBusPerformance/.classpath | 9 ----- EventBusPerformance/.project | 33 ----------------- .../.settings/org.eclipse.jdt.core.prefs | 4 --- EventBusTest/.classpath | 10 ------ EventBusTest/.project | 34 ------------------ EventBusTest/project.properties | 15 -------- 13 files changed, 189 deletions(-) delete mode 100644 EventBus/.classpath delete mode 100644 EventBus/.project delete mode 100644 EventBus/AndroidManifest.xml delete mode 100644 EventBus/libs/android-support-v4.jar delete mode 100644 EventBus/mybuild.xml delete mode 100644 EventBus/project.properties delete mode 100644 EventBus/res/values/strings.xml delete mode 100644 EventBusPerformance/.classpath delete mode 100644 EventBusPerformance/.project delete mode 100644 EventBusPerformance/.settings/org.eclipse.jdt.core.prefs delete mode 100644 EventBusTest/.classpath delete mode 100644 EventBusTest/.project delete mode 100644 EventBusTest/project.properties diff --git a/EventBus/.classpath b/EventBus/.classpath deleted file mode 100644 index 7bc01d9a..00000000 --- a/EventBus/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/EventBus/.project b/EventBus/.project deleted file mode 100644 index 3321bf38..00000000 --- a/EventBus/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - EventBus - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/EventBus/AndroidManifest.xml b/EventBus/AndroidManifest.xml deleted file mode 100644 index 2ad17bbd..00000000 --- a/EventBus/AndroidManifest.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - diff --git a/EventBus/libs/android-support-v4.jar b/EventBus/libs/android-support-v4.jar deleted file mode 100644 index 6080877d4ade158f24ad7ccd9a10db2ac9060b47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 385685 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

6HPQhY&mkuc_8%Q=4KIb)@wP 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%0A03X%h@VcJLH+gJm3sMzG=X1S%0K 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 - - - - - - - - - - - - diff --git a/EventBus/project.properties b/EventBus/project.properties deleted file mode 100644 index 484dab07..00000000 --- a/EventBus/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-17 -android.library=true diff --git a/EventBus/res/values/strings.xml b/EventBus/res/values/strings.xml deleted file mode 100644 index 85420055..00000000 --- a/EventBus/res/values/strings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/EventBusPerformance/.classpath b/EventBusPerformance/.classpath deleted file mode 100644 index 7bc01d9a..00000000 --- a/EventBusPerformance/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/EventBusPerformance/.project b/EventBusPerformance/.project deleted file mode 100644 index b29334b1..00000000 --- a/EventBusPerformance/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - EventBusPerformance - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/EventBusPerformance/.settings/org.eclipse.jdt.core.prefs b/EventBusPerformance/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index f77b31c2..00000000 --- a/EventBusPerformance/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/EventBusTest/.classpath b/EventBusTest/.classpath deleted file mode 100644 index 2b16fe8e..00000000 --- a/EventBusTest/.classpath +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/EventBusTest/.project b/EventBusTest/.project deleted file mode 100644 index 49b077d3..00000000 --- a/EventBusTest/.project +++ /dev/null @@ -1,34 +0,0 @@ - - - EventBusTest - - - greenBus - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/EventBusTest/project.properties b/EventBusTest/project.properties deleted file mode 100644 index 4655e969..00000000 --- a/EventBusTest/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-17 -android.library.reference.1=../EventBus From b064e61d1c977981ed15f6e0728547454c38bf27 Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 1 Feb 2016 22:24:42 +0100 Subject: [PATCH 107/112] upgraded to gradle wrapper 2.10 --- build.gradle | 6 +++++- gradle/wrapper/gradle-wrapper.jar | Bin 53637 -> 53636 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 760a32ad..c8d56ea1 100644 --- a/build.gradle +++ b/build.gradle @@ -4,4 +4,8 @@ if (JavaVersion.current().isJava8Compatible()) { options.addStringOption('Xdoclint:none', '-quiet') } } -} \ No newline at end of file +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.10' +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 05ef575b0cd0173fc735f2857ce4bd594ce4f6bd..13372aef5e24af05341d49695ee84e5f9b594659 100644 GIT binary patch delta 1915 zcmZWp3rtg27(Tr%g+V)>*5Oroilt5{MV$^`3?}1IR^*{Ur+_d!WoV`YHzrWTU>FAF zh|y>=kq#EeEYQLRf+_MW6iQ`=88e3lP!}{pR5nNE&i${IRc~_h{pY*?_rK0L_h=Qj zsER98M00ue2-(>oNkhd+p`VaI#7M=N%^MIxi6=M4ySYjvcT4V{Avt#hJ^k+kR@vuIp}i zC|R>=Ufe#X;+Bx_{yD8wSMN?(*|`7PX5Mt|@_pj!@a#{Whj{_{{N(B7$)a`F&$~a; zncu6KOdArv@0G7EJfkW8yW{B7ocWr(C3P;-zg`;dRN>${^`YJIPkcD#U*+-lPCUuq z7^HKYU-Ynk?1Qt7F5;b|4^|I(%N!DVsA3knQRH zhHvh$4KU9Oo^!yMDZIftn@Y?qQ&svSn}t(;<+$Ldkm7_MpJ!Kcz%E*DB^ z($^h0Lm_mDZz-jqkB@1SNIR;z$cm0Oe8OfJ*M_oc|6hh!X0|zj^@(rATo+~@pWQx; zHj!C`lh*^`ShE*)*Sm$jdDLWzH;>x5)dAyBZroSb5NGLESl>ge(XV9AJHDq61axm- z1-Q9=Js@t61srSN2bgqC4p@C{D~BBA{zG8+TXtE?677V_v&#-aX+$W;k=#C#MYZ$psP>1)|hU9V^gw6^P^0PP))TuJDIfh9O$r zN-J3ro*H~Pe-lmRG{Cs(8XRBs7iJbs{7FXj4avCHN;;y2%12B~AuVT!=FoW2&_^(q z<@1z delta 1838 zcmZWpdrVVT7(cz`Q65DLqJ}XU z9KpfZA`x1%7A{oS z(vw_%l9X#^jS!EAZ2aYwd@-LuOo2}96^0O!S8hrXemI#wmCr$ohA;i(m1=h`14bW! zrxFIRFK3uR4WBBYfG9D$55z9>Mj$joo`VH2tL$#EjD#5z2XYRSsWwxsg-B#W41nePuJks=cDqn#U5?0gea zClmdXC4os2$%Vjxi-Ex@d0+DFIMyz8`HsSSnN8y3!rxWS-m1~Yaq)dczGL-RwPH+l z+obdf;`j5hl2v`guPgrg6ZidBayulpQM+g31j;?nE5oHNR8)=AcAHR_7^U~Js+@nG zJX~#cvB+SQ-VW}bZHtyhsq1-EjDSwW6b* z>q~d|s$b+z=0*yCbXgy=%JZn#wE3CV7KO)WiF9U4z&>$}(X3&gSo3T4w%ix#V{v&w zKTNAWh>+E3l*3D`4gcX&R+lRU)gTJ5PePzFj@X ztqYpT8#xzRQy=f`ck}s;#17f)|1OzSig%~I!zHLur5&M|1rAU=0AhK@91t2&)&q87 zlZ`oW)Q}_M!J?y3#D&GZ-632%rg0v7IzOs1N2r#MIVFxbufj$nD>`KkM$-pgu==OP zgOLOqa{q$VnBa>_IToFvT(xjd$6_4Rwnd z9DQ?|%jQyfc9K0hcz!z@Z&VY`+W1`RXPKE+IR$~ETX@exxd?SxAru0ED|*ba?SP}^ zr?wcbJ(HU*%y%@J%t93Ti4aa0aK|oMVfdTFwnqNuu$hh+hZ1rZ9wOeQU2Xaj@fmF} zGx2y#`!1kM`x?OH_Kkp5?J~fT_AdZauOiTz3a6&z|3pO zfLE?b0j;jHc8cpMu)lmg70_PCx=q)83VVYt{>aJlWP}ZF^<&cG^ zdVO(Hr-z7%_opZS?-&k3QZg$6X53U?0u5*c;`EQ*6nw7V(wo3+5fsv-1i%6nwSXN|< zTXn3oKIh{;HOWjxhH34*j$pI$FRV1ifYeB&4tuKvg)8eetM0>6A^ zDd?psotoTC=)$e+A=LiUBt8Fys#>(?3ce=|`Pt(2UY6p?-dDZsqp7dXLqpD+SuQznns#5lT*^dJ=T^z7xBKH){nX5}3mKM-iKQ_FDw0jC(TDgXcg diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index c1823e9a..47511d78 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Nov 04 17:33:28 SGT 2015 +#Mon Feb 01 22:19:59 CET 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip From 07d28bcef371430d15e891275bc2e1d8ad7914a1 Mon Sep 17 00:00:00 2001 From: Markus Date: Tue, 2 Feb 2016 14:25:16 +0100 Subject: [PATCH 108/112] minor --- .../eventbus/SubscriberMethodFinder.java | 18 +++++++----------- README.md | 6 ++---- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java index 79c6addd..db5e0ad3 100644 --- a/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java +++ b/EventBus/src/org/greenrobot/eventbus/SubscriberMethodFinder.java @@ -171,19 +171,15 @@ private void findUsingReflectionInSingleClass(FindState findState) { subscribeAnnotation.priority(), subscribeAnnotation.sticky())); } } - } else if (strictMethodVerification) { - if (method.isAnnotationPresent(Subscribe.class)) { - String methodName = method.getDeclaringClass().getName() + "." + method.getName(); - throw new EventBusException("@Subscribe method " + methodName + - "must have exactly 1 parameter but has " + parameterTypes.length); - } - } - } else if (strictMethodVerification) { - if (method.isAnnotationPresent(Subscribe.class)) { + } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { String methodName = method.getDeclaringClass().getName() + "." + method.getName(); - throw new EventBusException(methodName + - " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); + throw new EventBusException("@Subscribe method " + methodName + + "must have exactly 1 parameter but has " + parameterTypes.length); } + } else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) { + String methodName = method.getDeclaringClass().getName() + "." + method.getName(); + throw new EventBusException(methodName + + " is a illegal @Subscribe method: must be public, non-static, and non-abstract"); } } } diff --git a/README.md b/README.md index d5e6cca9..23fd66c1 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ EventBus... * avoids complex and error-prone dependencies and life cycle issues * makes your code simpler * is fast - * is tiny (<50k jar) + * is tiny (~50k jar) * is proven in practice by apps with 100,000,000+ installs * has advanced features like delivery threads, subscriber priorities, etc. @@ -41,8 +41,6 @@ Add EventBus to your project ---------------------------- EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22) -Note: This SNAPSHOT version is only available on Sonatype's snapshot repository (https://oss.sonatype.org/content/repositories/snapshots). - Gradle: ``` compile 'org.greenrobot:eventbus:3.0.0' @@ -79,7 +77,7 @@ FAQ **A:** Unlike Android's BroadcastReceiver/Intent system, EventBus uses standard Java classes as events and offers a more convenient API. EventBus is intended for a lot more uses cases where you wouldn't want to go through the hassle of setting up Intents, preparing Intent extras, implementing broadcast receivers, and extracting Intent extras again. Also, EventBus comes with a much lower overhead. **Q:** How to do pull requests?
-**A:** Ensure good code quality and consistent formatting. EventBus has a good test coverage: if you propose a new feature or fix a bug, please add a unit test. +**A:** Ensure good code quality and consistent formatting. EventBus has good test coverage: if you propose a new feature or fix a bug, please add a unit test. Release History, License ------------------------ From 89f8e970be607e646b756b6596de8424c2b0c96a Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Feb 2016 18:39:21 +0100 Subject: [PATCH 109/112] added a test for subscribers having methods for public and private event classes --- .../EventBusAnnotationProcessor.java | 3 +++ .../EventBusFallbackToReflectionTest.java | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java index 8fc5888e..78b2ab62 100644 --- a/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java +++ b/EventBusAnnotationProcessor/src/org/greenrobot/eventbus/annotationprocessor/EventBusAnnotationProcessor.java @@ -146,6 +146,9 @@ private boolean checkHasNoErrors(ExecutableElement element, Messager messager) { return true; } + /** + * Subscriber classes should be skipped if their class or any involved event class are not visible to the index. + */ private void checkForSubscribersToSkip(Messager messager, String myPackage) { for (TypeElement skipCandidate : methodsByClass.keySet()) { TypeElement subscriberClass = skipCandidate; diff --git a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java index 59e8d68c..4b884ef4 100644 --- a/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java +++ b/EventBusTest/src/org/greenrobot/eventbus/EventBusFallbackToReflectionTest.java @@ -52,6 +52,18 @@ public void onEvent(PrivateEvent any) { } } + public class PublicClassWithPublicAndPrivateEvent { + @Subscribe + public void onEvent(String any) { + trackEvent(any); + } + + @Subscribe + public void onEvent(PrivateEvent any) { + trackEvent(any); + } + } + public class PublicWithPrivateEventInSuperclass extends PublicClassWithPrivateEvent { @Subscribe public void onEvent(Object any) { @@ -110,6 +122,20 @@ public void testSubscriberClassWithPrivateEvent() { assertEquals(1, eventsReceived.size()); } + @Test + public void testSubscriberClassWithPublicAndPrivateEvent() { + eventBus.register(new PublicClassWithPublicAndPrivateEvent()); + + eventBus.post("Hello"); + assertEquals("Hello", lastEvent); + assertEquals(1, eventsReceived.size()); + + PrivateEvent privateEvent = new PrivateEvent(); + eventBus.post(privateEvent); + assertEquals(privateEvent, lastEvent); + assertEquals(2, eventsReceived.size()); + } + @Test public void testSubscriberExtendingClassWithPrivateEvent() { eventBus.register(new PublicWithPrivateEventInSuperclass()); From a3045b448275c4251f08cbcc8f52bd67f7fe7a82 Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Feb 2016 19:04:50 +0100 Subject: [PATCH 110/112] Updated readme, removed embedded changelog, FAQ, and other redundant docs --- CHANGELOG.md | 78 ---------------------------------------------------- README.md | 29 ++++++------------- 2 files changed, 9 insertions(+), 98 deletions(-) delete mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 7ddb539f..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,78 +0,0 @@ -### V3.0.0 (2016-02-??) Annotations -* Breaking change: switch subscriber method name conventions to annotations -* Using annotations, each subscriber method can set sticky behavior and priority individually -* Annotation processor indexes annotation information for efficient subscriber registration on Android -* Renamed package and artifact id to allow co-existence with libs using EventBus 2 internally - -**Note:** This is a breaking change release: there is no inter-op between EventBus versions 2 and 3; they can run in parallel though. - -### V2.4.1 (2015-11-12) Bug fix release -* Registering for sticky events now considers sticky events of subclasses, not just the exact same event type. This makes the semantic consistent to posting events. Note, that this may lead to subscribers being called more than once if matching sticky events of event type subclasses are available. -* Workaround for an Android bug causing NoClassDefFoundError on some devices - -### V2.4.0 (2014-11-11) Clean up release -* Removed deprecated APIs: A year ago in Version 2.2.0, a couple of EventBus methods were deprecated and flagged to be removed in a future release. Well, version 2.4.0 is that release. Clean ups like this one keep the API concise and simple. - -**Note:** No new feature were added since 2.3.0. Use this release if you do not rely on deprecated APIs. - -### V2.3.0 (2014-11-11) Feature release: EventBusBuilder and performance fix -* New EventBusBuilder to configure EventBus instances (including the getDefault() instance, #124) -* Added configuration to disable "No subscribers registered for event" logs (EventBusBuilder, #107, #117) -* Added configuration to disable sending SubscriberExceptionEvent and NoSubscriberEvent (EventBusBuilder) -* Added configuration to fail when subscribers throw exceptions (EventBusBuilder, #55) -* Added configuration to use an existing thread pool (EventBusBuilder, #115) -* Added configuration to disable event inheritance improving performance for apps with high event rates (EventBusBuilder) -* Fixed performance regression sneaked into V2.2.x affecting (first time) registration of subscribers -* Updated to Gradle 2.1, using wrapper -* EventBusTest and EventBusPerformance use Gradle to build -* Added hasSubscriberForEvent to check if currently subscribers exist registered to a given event type -* Improved README.md and extracted an extended HOWTO.md and CHANGELOG.md from it -* Ignore compiler generated methods (#76) -* Various small code improvements (#120 among many others) - -**Note:** This is your last chance to use APIs that were deprecated in V2.2.0. It's recommended to switch to Version 2.4.0 (or above) at your earliest convenience. - -### V2.2.1 (2014-05-21) Bug fix release -* Fixed an issue with AsyncExecutor and execution scope - -### V2.2.0 (2013-11-18) Feature release, subscriber priority -* Register subscribers with a priority to to influence the order of event delivery (per delivery thread) -* Event delivery can be canceled by subscribers so subsequent subscribers will not receive the event -* Added "isRegistered" and "removeAllStickyEvents" methods -* Deprecated registration methods with custom method names and event class filters -* Starting with EventBus 2.2 we enforced methods to be public -* Fixed a race conditions with subscriber registration -* Fixed NoSubscriberEvent delivery after unregister - -### V2.1.0 (2013-11-15) Bug fix release, experimental util package -* Experimental: AsyncExecutor executes RunnableEx and wraps exceptions into FailureEvents -* Experimental: exception to UI mapping (for now based on dialogs) -* Fixed race condition with queued events that were delivered after subscription was unregistered. This is important for main thread events tied to application life cycle. -* Fixed typos and improved readme (#17, #22, #37, #39) -* Make getStickyEvent and removeStickyEvent generic (#45) -* Fixed bug in SubscriberMethod.equals() (#38) - -### V2.0.2 (2013-03-02) Bug fix release -* Fixed build dependencies, are "provided" now - -### V2.0.1 (2013-02-25) Bug fix release, Gradle and Maven Central -* Fixed #15: removeStickyEvent(...) does not remove event the first time -* Introduced Gradle build scripts for main project -* Maven artifacts are pushed to Maven Central starting with this version -* Added Travis CI - -### V2.0.0 (2012-10-23) Major feature release -* Event methods define for themselves in which thread they get called. This is done by providing "modifiers" to the method name, e.g. onEventMainThread is called by the main thread without further configuration. Have a look at the JavaDoc of the enum ThreadMode for all available thread modes. -* The event method modifiers replace registerForMainThread methods. Moving this information to the method itself should make things clearer. -* Using event method modifiers, subscribers can receive the same event type in different threads if they choose to. -* New "BackgroundThread" modifier for onEvent handler methods ensures that event handler methods are called in a background thread. If an event is posted from a non-main thread, handler methods will be called directly. If posted from the main thread, EventBus will use a background thread to call the handler methods. -* New "Async" modifier for onEvent handler methods ensures that each event handler method is called completely asynchronously. -* Better performance: Delivery of multiple events in the main thread got significantly faster. -* Added sticky events, which are inspired by sticky broadcasts of the Android system. EventBus keeps the most recent sticky events in memory. Subscribers registering with the new method registerSticky, will receive sticky events right away. You can also query and remove sticky events (methods getStickyEvent and removeStickyEvent). -* By listening to SubscriberExceptionEvent, it is possible to react to Exceptions occuring in subscribers. -* Bug fixes, and internal refactorings - -### V1.0.1 (2012-07-31): Important bug fix release -Please update! Now, EventBus.unregister releases all internal references to the subscriber. - -### V1.0.0 (2012-07-16): First public release diff --git a/README.md b/README.md index 23fd66c1..d273dff6 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,6 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) -Index and its Limitations -------------------------- -The "subscriber index" is a new feature of EventBus 3. It is an optional optimization to speed up initial subscriber registration. The subscriber index can be created during build time using EventBus' annotation processor. It is not required to use the index, but it's recommended on Android because of its poor reflection speed regarding annotations. - -Note that only those @Subscribers methods can be indexed for which the subscriber AND event class are public. Non-indexed methods have to be looked-up at runtime using reflection. - -Also, @Subscribe annotations are not recognized when inside of anonymous classes - EventBus in 4 steps ------------------- 1. Define events:
@@ -39,7 +31,7 @@ EventBus in 4 steps Add EventBus to your project ---------------------------- -EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22) +EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) Gradle: ``` @@ -61,28 +53,25 @@ How-to, Developer Documentation ------------------------------- Details on EventBus and its API are available in the [HOWTO document](HOWTO.md). -How does EventBus compare to other solutions, like Otto from Square? Check this [comparison](COMPARISON.md). - Additional Features and Notes ----------------------------- +Link: [Features](http://greenrobot.org/eventbus/features/) * **Based on annotations:** Event handling methods can be named however you want, and only need to be annotated with **@Subscribe**. * **Performance optimized:** It's probably the fastest event bus for Android. * **Convenience singleton:** You can get a process wide event bus instance by calling EventBus.getDefault(). You can still call new EventBus() to create any number of local busses. * **Subscriber and event inheritance:** Event handler methods may be defined in super classes, and events are posted to handlers of the event's super classes including any implemented interfaces. For example, subscriber may register to events of the type Object to receive all events posted on the event bus. -FAQ ---- -**Q:** How is EventBus different to Android's BroadcastReceiver/Intent system?
-**A:** Unlike Android's BroadcastReceiver/Intent system, EventBus uses standard Java classes as events and offers a more convenient API. EventBus is intended for a lot more uses cases where you wouldn't want to go through the hassle of setting up Intents, preparing Intent extras, implementing broadcast receivers, and extracting Intent extras again. Also, EventBus comes with a much lower overhead. +Links +----- +[CHANGELOG](http://greenrobot.org/eventbus/changelog/) -**Q:** How to do pull requests?
-**A:** Ensure good code quality and consistent formatting. EventBus has good test coverage: if you propose a new feature or fix a bug, please add a unit test. +[FAQ](http://greenrobot.org/eventbus/documentation/faq/) -Release History, License ------------------------- -[CHANGELOG](CHANGELOG.md) +How does EventBus compare to other solutions, like Otto from Square? Check this [comparison](COMPARISON.md). +License +------- Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org) EventBus binaries and source code can be used according to the [Apache License, Version 2.0](LICENSE). From 8cba55264db6dd13d4aca72bb3cf360e3779eeea Mon Sep 17 00:00:00 2001 From: Markus Date: Wed, 3 Feb 2016 21:51:09 +0100 Subject: [PATCH 111/112] Updated readme --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d273dff6..e9688985 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ EventBus ======== -EventBus is publish/subscribe event bus optimized for Android.
+EventBus is a publish/subscribe event bus optimized for Android.
EventBus... @@ -17,21 +17,24 @@ EventBus... [![Build Status](https://travis-ci.org/greenrobot/EventBus.svg?branch=master)](https://travis-ci.org/greenrobot/EventBus) -EventBus in 4 steps +EventBus in 3 steps ------------------- 1. Define events:
public class MessageEvent { /* Additional fields if needed */ }

-2. Register your subscriber (in your onCreate or in a constructor):
+2. Prepare subscribers
+Register your subscriber (in your onCreate or in a constructor):
eventBus.register(this);

-3. Declare your subscribing method
+Declare your subscribing method:
@Subscribe
public void onEvent(AnyEventType event) {/* Do something */};

-4. Post events:
+3. Post events:
eventBus.post(event); +This [getting started guide](http://greenrobot.org/eventbus/documentation/how-to-get-started/) shows these 3 steps in more detail. + Add EventBus to your project ---------------------------- -EventBus is available on Maven Central. Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) +Please ensure that you are using the latest version by [checking here](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.greenrobot%22%20AND%20a%3A%22eventbus%22) Gradle: ``` From 875f4aa4b46a001e33d93d5d32e5ac9d9692f8e0 Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 4 Feb 2016 17:49:26 +0100 Subject: [PATCH 112/112] Updated readme, removed obsolete HOWTO.md --- HOWTO.md | 263 ------------------------------------------------------ README.md | 21 ++--- 2 files changed, 7 insertions(+), 277 deletions(-) delete mode 100644 HOWTO.md diff --git a/HOWTO.md b/HOWTO.md deleted file mode 100644 index d630f7a7..00000000 --- a/HOWTO.md +++ /dev/null @@ -1,263 +0,0 @@ -EventBus How-To -=============== -In the [README file](README.md), you got to know EventBus, and some of its basic principles. You also saw how to add EventBus to your project using Maven Central. Great, now let's dive deeper! - -General usage and API ---------------------- -Here we pick up on the 3 steps of the README and expand a bit on the code. -### 1: Define events ### -Events are POJO (plain old Java object) without any specific requirements. - -```java -public class MessageEvent { - public final String message; - - public MessageEvent(String message) { - this.message = message; - } -} -``` -### 2: Prepare subscribers ### - -Subscribers implement event handling methods that will be called when an event is received. These are defined with the ``@Subscribe`` annotation. They also need to register and unregister themselves to the bus. - -```java - @Override - public void onStart() { - super.onStart(); - EventBus.getDefault().register(this); - } - - @Override - public void onStop() { - EventBus.getDefault().unregister(this); - super.onStop(); - } - - // This method will be called when a MessageEvent is posted - @Subscribe - public void onMessageEvent(MessageEvent event){ - Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show(); - } - - // This method will be called when a SomeOtherEvent is posted - @Subscribe - public void onEvent(SomeOtherEvent event){ - doSomethingWith(event); - } - -``` -### 3: Post events ### -Post an event from any part of your code. All subscribers matching the event type will receive it. - -```java - EventBus.getDefault().post(new MessageEvent("Hello everyone!")); -``` - -Delivery threads and ThreadModes --------------------------------- -EventBus can handle threading for you: events can be posted in threads different from the posting thread. - -A common use case is dealing with UI changes. In Android, UI changes must be done in the UI (main) thread. On the other hand, networking, or any time consuming task, must not run on the main thread. EventBus helps you to deal with those tasks and synchronize with the UI thread (without having to delve into thread transitions, using AsyncTask, etc). - -In EventBus, you may define the thread that will call the event handling method `onEvent` by using a **ThreadMode**: -* **PostThread:** Subscriber will be called in the same thread, which is posting the event. This is the default. Event delivery implies the least overhead because it avoids thread switching completely. Thus this is the recommended mode for simple tasks that are known to complete is a very short time without requiring the main thread. Event handlers using this mode should return quickly to avoid blocking the posting thread, which may be the main thread. -Example: -```java - // Called in the same thread (default) - @Subscribe(threadMode = ThreadMode.PostThread) // ThreadMode is optional here - public void onEvent(MessageEvent event) { - log(event.message); - } -``` -* **MainThread:** Subscriber will be called in Android's main thread (sometimes referred to as UI thread). If the posting thread is the main thread, event handler methods will be called directly. Event handlers using this mode must return quickly to avoid blocking the main thread. -Example: -```java - // Called in Android UI's main thread - @Subscribe(threadMode = ThreadMode.MainThread) - public void onEventMainThread(MessageEvent event) { - textField.setText(event.message); - } -``` -* **BackgroundThread:** Subscriber will be called in a background thread. If posting thread is not the main thread, event handler methods will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single background thread that will deliver all its events sequentially. Event handlers using this mode should try to return quickly to avoid blocking the background thread. -```java - // Called in the background thread - @Subscribe(threadMode = ThreadMode.BackgroundThread) - public void onEventBackgroundThread(MessageEvent event){ - saveToDisk(event.message); - } -``` -* **Async:** Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications. -```java - // Called in a separate thread - @Subscribe(threadMode = ThreadMode.Async) - public void onEventAsync(MessageEvent event){ - backend.send(event.message); - } -``` - -*Note:* EventBus takes care of calling the `onEvent` method in the proper thread depending on its annotation. - -Subscriber priorities and ordered event delivery ------------------------------------------------- -You may change the order of event delivery by providing a priority to the subscriber during registration. - -```java - @Subscribe(priority = 1); - public void onEvent(MessageEvent event) { - ... - } -``` - -Within the same delivery thread (ThreadMode), higher priority subscribers will receive events before others with a lower priority. The default priority is 0. - -*Note*: the priority does *NOT* affect the order of delivery among subscribers with different [ThreadModes](#delivery-threads-and-threadmodes)! - -Configure EventBus using EventBusBuilder ----------------------------------------- -EventBus 2.3 added EventBusBuilder to configure various aspects of EventBus. For example, here's how to build an EventBus that keeps quiet in case a posted event has no subscribers: - -```java - EventBus eventBus = EventBus.builder().logNoSubscriberMessages(false).sendNoSubscriberEvent(false).build(); -``` - -Another example is to fail when a subscriber throws an exception. Note: by default, EventBus catches exceptions thrown from onEvent methods and sends a SubscriberExceptionEvent that may but do not have to be handled. - -```java - EventBus eventBus = EventBus.builder().throwSubscriberException(true).build(); -``` - -Check the EventBusBuilder class and its JavaDoc for all possible configuration possibilities. - -### Configure the default EventBus instance ### -Using EventBus.getDefault() is a simple way to get a shared EventBus instance. EventBusBuilder also allows to configure this default instance using the method installDefaultEventBus(). - -For example, it's possible to configure the default EventBus instance to rethrow exceptions, which occurred in onEvent methods. But let's to this only for DEBUG builds, because this will likely crash the app on exceptions: - -```java -EventBus.builder().throwSubscriberException(BuildConfig.DEBUG).installDefaultEventBus(); -``` - -Note: this can be done only once before the default EventBus instance is used the first time. This ensures consistent behavior in your app. Your Application class is a good place to configure the default EventBus instance before its used. - -Cancelling event delivery -------------------------- -You may cancel the event delivery process by calling `cancelEventDelivery(Object event)` from a subscriber's event handling method. -Any further event delivery will be cancelled: subsequent subscribers won't receive the event. -```java - // Called in the same thread (default) - @Subscribe - public void onEvent(MessageEvent event){ - // Process the event - ... - - EventBus.getDefault().cancelEventDelivery(event) ; - } -``` - -Events are usually cancelled by higher priority subscribers. Cancelling is restricted to event handling methods running in posting thread [ThreadMode.PostThread](#delivery-threads-and-threadmodes). - -Sticky Events -------------- -Some events carry information that is of interest after the event is posted. For example, this could be an event signalizing that some initialization is complete. Or if you have some sensor or location data and you want to hold on the most recent values. Instead of implementing your own caching, you can use sticky events. EventBus keeps the last sticky event of a certain type in memory. The sticky event can be delivered to subscribers or queried explicitly. Thus, you don't need any special logic to consider already available data. - -Let's say, a sticky event was posted some time ago: -```java - EventBus.getDefault().postSticky(new MessageEvent("Hello everyone!")); -``` - -After that, a new Activity gets started. During registration, and sticky Subscriber methods will immediately get the previously posted sticky event: -```java - @Override - public void onStart() { - super.onStart(); - EventBus.getDefault().register(this); - } - - @Subscribe(sticky = true, threadMode = ThreadMode.MainThread) - public void onEvent(MessageEvent event) { - // UI updates must run on MainThread - textField.setText(event.message); - } - - @Override - public void onStop() { - EventBus.getDefault().unregister(this); - super.onStop(); - } -``` - -You may also get the last sticky event of a certain type with: -```java - EventBus.getDefault().getStickyEvent(Class eventType) -``` - -ProGuard configuration ----------------------- -ProGuard obfuscates method names and may remove "unused" methods, including Subscriber methods. Use the following snip in your ProGuard configuration file (proguard.cfg) to prevent Subscribers from being removed: - -``` --keepattributes *Annotation* --keepclassmembers class ** { - @de.greenrobot.event.Subscribe public *; -} - -# EventBus 3.0 annotation --keepclassmembers class * { - @de.greenrobot.event.Subscribe ; -} --keep enum de.greenrobot.event.ThreadMode { *; } - -# Only required if you use AsyncExecutor --keepclassmembers class * extends de.greenrobot.event.util.ThrowableFailureEvent { - (java.lang.Throwable); -} -``` - - -AsyncExecutor -------------- -_Disclaimer:_ AsyncExecutor is a non-core utility class. It might save you some code with error handling in background threads, but it's not a core EventBus class. - -AsyncExecutor is like a thread pool, but with failure handling. Failures are thrown exceptions, which get are wrapped inside an event, which is posted automatically by AsyncExecutor. - -Usually, you call AsyncExecutor.create() to create an instance and keep it in Application scope. To execute something, implement the RunnableEx interface and pass it to the execute method of the AsyncExecutor. Unlike Runnable, RunnableEx may throw an Exception. - -If the RunnableEx implementation throws an exception, it will be catched and wrapped into a ThrowableFailureEvent, which will be posted. - -Code example for execution: - -```java -AsyncExecutor.create().execute( - new RunnableEx { - public void run throws LoginException { - remote.login(); - EventBus.getDefault().postSticky(new LoggedInEvent()); - // No need to catch Exception - } - } -} -``` - -Code example for the receiving part: - -```java -public void onEventMainThread(LoggedInEvent event) { - // Change some UI -} - -public void onEventMainThread(ThrowableFailureEvent event) { - // Show error in UI -} -``` - -AsyncExecutor Builder ---------------------- -If you want to customize your AsyncExecutor instance, call the static method AsyncExecutor.builder(). It will return a builder which lets you customize the EventBus instance, the thread pool, and the class of the failure event. - -Another customization options is the execution scope, which gives failure events context information. For example, a failure event may be relevant only to a specific Activity instance or class. If your custom failure event class implements the HasExecutionScope interface, AsyncExecutor will set the execution scope automatically. Like this, your subscriber can query the failure event for its execution scope and react depending on it. - - -Comparison with Square's Otto ------------------------------ -Check the [COMPARISON.md](COMPARISON.md) \ No newline at end of file diff --git a/README.md b/README.md index e9688985..bcc0f4be 100644 --- a/README.md +++ b/README.md @@ -52,22 +52,15 @@ Maven: [Or download EventBus from Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22de.greenrobot%22%20AND%20a%3A%22eventbus%22) -How-to, Developer Documentation -------------------------------- -Details on EventBus and its API are available in the [HOWTO document](HOWTO.md). +Homepage, Documentation, Links +------------------------------ +For more details on EventBus please check [EventBus' website](http://greenrobot.org/eventbus). Here are some direct links you may find useful: -Additional Features and Notes ------------------------------ -Link: [Features](http://greenrobot.org/eventbus/features/) +[Features](http://greenrobot.org/eventbus/features/) -* **Based on annotations:** Event handling methods can be named however you want, and only need to be annotated with **@Subscribe**. -* **Performance optimized:** It's probably the fastest event bus for Android. -* **Convenience singleton:** You can get a process wide event bus instance by calling EventBus.getDefault(). You can still call new EventBus() to create any number of local busses. -* **Subscriber and event inheritance:** Event handler methods may be defined in super classes, and events are posted to handlers of the event's super classes including any implemented interfaces. For example, subscriber may register to events of the type Object to receive all events posted on the event bus. +[Documentation](http://greenrobot.org/eventbus/documentation/) -Links ------ -[CHANGELOG](http://greenrobot.org/eventbus/changelog/) +[Changelog](http://greenrobot.org/eventbus/changelog/) [FAQ](http://greenrobot.org/eventbus/documentation/faq/) @@ -85,4 +78,4 @@ More Open Source by greenrobot [__greenDAO__](https://github.com/greenrobot/greenDAO) is an ORM optimized for Android: it maps database tables to Java objects and uses code generation for optimal speed. -[Follow us on Google+](https://plus.google.com/b/114381455741141514652/+GreenrobotDe/posts) to stay up to date. \ No newline at end of file +[Follow us on Google+](https://plus.google.com/b/114381455741141514652/+GreenrobotDe/posts) or check our [homepage](http://greenrobot.org/) to stay up to date. \ No newline at end of file