Skip to content

Commit 53bb943

Browse files
committed
Merge pull request androidannotations#763 from JoanZapata/develop
Fixed androidannotations#646 sending background exception to the global UncaughtExceptionHandler
2 parents 4920ca6 + ed8e031 commit 53bb943

3 files changed

Lines changed: 58 additions & 1 deletion

File tree

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/BackgroundProcessor.java‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
import javax.lang.model.element.Element;
2222
import javax.lang.model.element.ExecutableElement;
2323

24+
import com.sun.codemodel.JCatchBlock;
25+
import com.sun.codemodel.JStatement;
26+
import com.sun.codemodel.JTryBlock;
27+
import com.sun.codemodel.JVar;
2428
import org.androidannotations.annotations.Background;
2529
import org.androidannotations.api.BackgroundExecutor;
2630
import org.androidannotations.api.BackgroundExecutor.Task;
@@ -60,7 +64,17 @@ public void process(Element element, JCodeModel codeModel, EBeanHolder holder) t
6064
JMethod executeMethod = anonymousTaskClass.method(JMod.PUBLIC, codeModel.VOID, "execute");
6165
executeMethod.annotate(Override.class);
6266

63-
executeMethod.body().add( previousMethodBody );
67+
// Catch exception in user code
68+
JTryBlock tryBlock = executeMethod.body()._try();
69+
tryBlock.body().add(previousMethodBody);
70+
JCatchBlock catchBlock = tryBlock._catch(holder.classes().THROWABLE);
71+
JVar caughtException = catchBlock.param("e");
72+
JStatement uncaughtExceptionCall = holder.classes().THREAD
73+
.staticInvoke("getDefaultUncaughtExceptionHandler")
74+
.invoke("uncaughtException")
75+
.arg(holder.classes().THREAD.staticInvoke("currentThread"))
76+
.arg(caughtException);
77+
catchBlock.body().add(uncaughtExceptionCall);
6478

6579
Background annotation = element.getAnnotation(Background.class);
6680
String id = annotation.id();

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/processing/EBeansHolder.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class Classes {
4343
*/
4444
public final JClass RUNTIME_EXCEPTION = refClass(RuntimeException.class);
4545
public final JClass EXCEPTION = refClass(Exception.class);
46+
public final JClass THROWABLE = refClass(Throwable.class);
4647
public final JClass CHAR_SEQUENCE = refClass(CharSequence.class);
4748
public final JClass CLASS_CAST_EXCEPTION = refClass(ClassCastException.class);
4849
public final JClass SERIALIZABLE = refClass(Serializable.class);

‎AndroidAnnotations/functional-test-1-5-tests/src/test/java/org/androidannotations/test15/ThreadActivityTest.java‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ public class ThreadActivityTest {
4646

4747
private ThreadActivity_ activity;
4848

49+
private volatile boolean propagatedExceptionToGlobalExceptionHandler;
50+
4951
@Before
5052
public void setup() {
5153
activity = new ThreadActivity_();
@@ -320,4 +322,44 @@ public void run() {
320322
Assert.assertTrue("Handler field not associated to the main thread", handler.getLooper() == Looper.getMainLooper());
321323
}
322324

325+
@Test
326+
public void propagateExceptionToGlobalExceptionHandler() {
327+
328+
// Prepare lock on which we'll wait for the
329+
// background exception handler to catch the exception
330+
final Object LOCK = new Object();
331+
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
332+
@Override
333+
public void uncaughtException(Thread thread, Throwable ex) {
334+
synchronized (LOCK) {
335+
propagatedExceptionToGlobalExceptionHandler = true;
336+
LOCK.notify();
337+
}
338+
}
339+
});
340+
341+
propagatedExceptionToGlobalExceptionHandler = false;
342+
activity.backgroundThrowException();
343+
344+
// If the default uncaught exception handler is not called
345+
// after 2 secs this method returns and the following assert will fail.
346+
waitOn(LOCK, 2000);
347+
Assert.assertTrue("Exception should have been caught in the DefaultUncaughtExceptionHandler during @Background call.",
348+
propagatedExceptionToGlobalExceptionHandler);
349+
}
350+
351+
/**
352+
* Call wait() on the given object with the specified timeout.
353+
* Avoid boilerplate code like synchronized or try..catch.
354+
*/
355+
private void waitOn(Object lock, long timeout) {
356+
synchronized (lock) {
357+
try {
358+
lock.wait(timeout);
359+
} catch (InterruptedException e) {
360+
e.printStackTrace();
361+
}
362+
}
363+
}
364+
323365
}

0 commit comments

Comments
 (0)