Skip to content

Commit 3a774f6

Browse files
committed
Merge merged PR 763 : Send background exception to UncaughtExceptionHandler"
2 parents 534a825 + 53bb943 commit 3a774f6

3 files changed

Lines changed: 58 additions & 1 deletion

File tree

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/handler/BackgroundHandler.java‎

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

25+
import com.sun.codemodel.JCatchBlock;
26+
import com.sun.codemodel.JStatement;
27+
import com.sun.codemodel.JTryBlock;
28+
import com.sun.codemodel.JVar;
2529
import org.androidannotations.annotations.Background;
2630
import org.androidannotations.api.BackgroundExecutor;
2731
import org.androidannotations.api.BackgroundExecutor.Task;
@@ -58,7 +62,17 @@ public void process(Element element, EComponentHolder holder) throws Exception {
5862
JMethod executeMethod = anonymousTaskClass.method(JMod.PUBLIC, codeModel().VOID, "execute");
5963
executeMethod.annotate(Override.class);
6064

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

6377
Background annotation = element.getAnnotation(Background.class);
6478
String id = annotation.id();

‎AndroidAnnotations/androidannotations/src/main/java/org/androidannotations/process/ProcessHolder.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class Classes {
3636
*/
3737
public final JClass RUNTIME_EXCEPTION = refClass(RuntimeException.class);
3838
public final JClass EXCEPTION = refClass(Exception.class);
39+
public final JClass THROWABLE = refClass(Throwable.class);
3940
public final JClass CHAR_SEQUENCE = refClass(CharSequence.class);
4041
public final JClass CLASS_CAST_EXCEPTION = refClass(ClassCastException.class);
4142
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_();
@@ -351,4 +353,44 @@ public void run() {
351353
Assert.assertTrue("Handler field not associated to the main thread", handler.getLooper() == Looper.getMainLooper());
352354
}
353355

356+
@Test
357+
public void propagateExceptionToGlobalExceptionHandler() {
358+
359+
// Prepare lock on which we'll wait for the
360+
// background exception handler to catch the exception
361+
final Object LOCK = new Object();
362+
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
363+
@Override
364+
public void uncaughtException(Thread thread, Throwable ex) {
365+
synchronized (LOCK) {
366+
propagatedExceptionToGlobalExceptionHandler = true;
367+
LOCK.notify();
368+
}
369+
}
370+
});
371+
372+
propagatedExceptionToGlobalExceptionHandler = false;
373+
activity.backgroundThrowException();
374+
375+
// If the default uncaught exception handler is not called
376+
// after 2 secs this method returns and the following assert will fail.
377+
waitOn(LOCK, 2000);
378+
Assert.assertTrue("Exception should have been caught in the DefaultUncaughtExceptionHandler during @Background call.",
379+
propagatedExceptionToGlobalExceptionHandler);
380+
}
381+
382+
/**
383+
* Call wait() on the given object with the specified timeout.
384+
* Avoid boilerplate code like synchronized or try..catch.
385+
*/
386+
private void waitOn(Object lock, long timeout) {
387+
synchronized (lock) {
388+
try {
389+
lock.wait(timeout);
390+
} catch (InterruptedException e) {
391+
e.printStackTrace();
392+
}
393+
}
394+
}
395+
354396
}

0 commit comments

Comments
 (0)