Fix Exception Handling result handler resolution

Prior to this commit, the wrong `HandlerResultHandler` could be
resolved when handling exceptions; this could happen only if the
original handler and exception handler had different signatures:

```
Publisher<String> originalHandler() { ... }

@ExceptionHandler(MyCustomException.class)
ResponseEntity<Mono<String>> handleException() { ... }
```

In that case, the `ResponseBodyResultHandler` would be used when
handling exceptions instead of the `ResponseEntityResultHandler`.

This commit ensures that the `HandlerResult` returned by the exception
handler is used to resolve the `HandlerResultHandler`. The latter will
process the result and use it to write to the HTTP response.

Issue: SPR-14876
This commit is contained in:
Brian Clozel 2016-11-03 17:00:18 +01:00
parent a90e4b230f
commit 95abd18fea
2 changed files with 12 additions and 6 deletions

View File

@ -142,7 +142,7 @@ public class DispatcherHandler implements WebHandler, ApplicationContextAware {
private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
return getResultHandler(result).handleResult(exchange, result)
.otherwise(ex -> result.applyExceptionHandler(ex).then(exceptionResult ->
getResultHandler(result).handleResult(exchange, exceptionResult)));
getResultHandler(exceptionResult).handleResult(exchange, exceptionResult)));
}
private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {

View File

@ -25,6 +25,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@ -52,13 +53,13 @@ public class RequestMappingExceptionHandlingIntegrationTests extends AbstractReq
@Test
public void controllerThrowingException() throws Exception {
String expected = "Recovered from error: Boo";
String expected = "Recovered from error: State";
assertEquals(expected, performGet("/thrown-exception", new HttpHeaders(), String.class).getBody());
}
@Test
public void controllerReturnsMonoError() throws Exception {
String expected = "Recovered from error: Boo";
String expected = "Recovered from error: Argument";
assertEquals(expected, performGet("/mono-error", new HttpHeaders(), String.class).getBody());
}
@ -78,19 +79,24 @@ public class RequestMappingExceptionHandlingIntegrationTests extends AbstractReq
@GetMapping("/thrown-exception")
public Publisher<String> handleAndThrowException() {
throw new IllegalStateException("Boo");
throw new IllegalStateException("State");
}
@GetMapping("/mono-error")
public Publisher<String> handleWithError() {
return Mono.error(new IllegalStateException("Boo"));
return Mono.error(new IllegalArgumentException("Argument"));
}
@ExceptionHandler
public Publisher<String> handleException(IllegalStateException ex) {
public Publisher<String> handleArgumentException(IllegalArgumentException ex) {
return Mono.just("Recovered from error: " + ex.getMessage());
}
@ExceptionHandler
public ResponseEntity<Publisher<String>> handleStateException(IllegalStateException ex) {
return ResponseEntity.ok(Mono.just("Recovered from error: " + ex.getMessage()));
}
}
}