FutureAdapter should wrap RuntimeExceptions

RuntimeExceptions thrown from FutureAdapter.adapt() should be wrapped in
an ExecutionException, not thrown as is.

Issue: SPR-12887
This commit is contained in:
Arjen Poutsma 2015-04-10 12:52:15 +02:00
parent e5b505224b
commit b119a9c82c
2 changed files with 50 additions and 9 deletions

View File

@ -107,6 +107,12 @@ public abstract class FutureAdapter<T, S> implements Future<T> {
this.state = State.FAILURE; this.state = State.FAILURE;
throw ex; throw ex;
} }
catch (RuntimeException ex) {
ExecutionException execEx = new ExecutionException(ex);
this.result = execEx;
this.state = State.FAILURE;
throw execEx;
}
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
} }

View File

@ -20,6 +20,7 @@ import java.net.URI;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import org.junit.Before; import org.junit.Before;
@ -317,16 +318,47 @@ public class AsyncRestTemplateIntegrationTests extends AbstractJettyServerTestCa
} }
@Test @Test
public void notFound() throws Exception { public void identicalExceptionThroughGetAndCallback() throws Exception {
final HttpClientErrorException[] callbackException = new HttpClientErrorException[1];
ListenableFuture<?> future = template.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null);
future.addCallback(new ListenableFutureCallback<Object>() {
@Override
public void onSuccess(Object result) {
fail("onSuccess not expected");
}
@Override
public void onFailure(Throwable t) {
assertTrue(t instanceof HttpClientErrorException);
callbackException[0] = (HttpClientErrorException) t;
}
});
try {
future.get();
fail("Exception expected");
}
catch (ExecutionException ex) {
Throwable cause = ex.getCause();
assertTrue(cause instanceof HttpClientErrorException);
assertSame(callbackException[0], cause);
}
}
@Test
public void notFoundGet() throws Exception {
try { try {
Future<?> future = template.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null); Future<?> future = template.execute(baseUrl + "/status/notfound", HttpMethod.GET, null, null);
future.get(); future.get();
fail("HttpClientErrorException expected"); fail("HttpClientErrorException expected");
} }
catch (HttpClientErrorException ex) { catch (ExecutionException ex) {
assertEquals(HttpStatus.NOT_FOUND, ex.getStatusCode()); assertTrue(ex.getCause() instanceof HttpClientErrorException);
assertNotNull(ex.getStatusText()); HttpClientErrorException cause = (HttpClientErrorException)ex.getCause();
assertNotNull(ex.getResponseBodyAsString());
assertEquals(HttpStatus.NOT_FOUND, cause.getStatusCode());
assertNotNull(cause.getStatusText());
assertNotNull(cause.getResponseBodyAsString());
} }
} }
@ -372,10 +404,13 @@ public class AsyncRestTemplateIntegrationTests extends AbstractJettyServerTestCa
future.get(); future.get();
fail("HttpServerErrorException expected"); fail("HttpServerErrorException expected");
} }
catch (HttpServerErrorException ex) { catch (ExecutionException ex) {
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, ex.getStatusCode()); assertTrue(ex.getCause() instanceof HttpServerErrorException);
assertNotNull(ex.getStatusText()); HttpServerErrorException cause = (HttpServerErrorException)ex.getCause();
assertNotNull(ex.getResponseBodyAsString());
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, cause.getStatusCode());
assertNotNull(cause.getStatusText());
assertNotNull(cause.getResponseBodyAsString());
} }
} }