Browse Source
The DispatcherHandler now has an errorMapper property that is a function for transforming errors. By default this property is set to an instance of DispatcherHandlerExceptionMapper which wraps "standard" framework exceptions and @ResponseStatus-annotated exceptions as ResponseStatusException. This makes it easy to handle the exceptions downstream uniformly.pull/1111/head
4 changed files with 194 additions and 3 deletions
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
/* |
||||
* Copyright 2002-2015 the original author or authors. |
||||
* |
||||
* 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.springframework.web.reactive; |
||||
|
||||
import java.util.function.Function; |
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.web.ResponseStatusException; |
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException; |
||||
import org.springframework.web.bind.annotation.ResponseStatus; |
||||
|
||||
/** |
||||
* Map "standard" framework exceptions and |
||||
* {@link ResponseStatus @ResponseStatus}-annotated exceptions to a |
||||
* {@link ResponseStatusException}. |
||||
* |
||||
* @author Rossen Stoyanchev |
||||
*/ |
||||
public class DispatcherHandlerExceptionMapper implements Function<Throwable, Throwable> { |
||||
|
||||
|
||||
@Override |
||||
public Throwable apply(Throwable ex) { |
||||
if (ex instanceof HandlerNotFoundException) { |
||||
ex = new ResponseStatusException(HttpStatus.NOT_FOUND, ex); |
||||
} |
||||
else if (ex instanceof HttpMediaTypeNotAcceptableException) { |
||||
ex = new ResponseStatusException(HttpStatus.NOT_ACCEPTABLE, ex); |
||||
} |
||||
else { |
||||
ResponseStatus status = findStatus(ex); |
||||
if (status != null) { |
||||
ex = new ResponseStatusException(status.code(), ex); |
||||
} |
||||
} |
||||
return ex; |
||||
} |
||||
|
||||
private ResponseStatus findStatus(Throwable ex) { |
||||
Class<? extends Throwable> type = ex.getClass(); |
||||
ResponseStatus status = AnnotatedElementUtils.findMergedAnnotation(type, ResponseStatus.class); |
||||
if (status != null) { |
||||
return status; |
||||
} |
||||
else if (ex.getCause() != null) { |
||||
return findStatus(ex.getCause()); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
/* |
||||
* Copyright 2002-2015 the original author or authors. |
||||
* |
||||
* 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.springframework.web.reactive; |
||||
|
||||
import java.util.Collections; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.http.HttpHeaders; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpStatus; |
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException; |
||||
import org.springframework.web.ResponseStatusException; |
||||
import org.springframework.web.bind.annotation.ResponseStatus; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
|
||||
/** |
||||
* @author Rossen Stoyanchev |
||||
*/ |
||||
public class DispatcherHandlerExceptionMapperTests { |
||||
|
||||
private DispatcherHandlerExceptionMapper mapper; |
||||
|
||||
|
||||
@Before |
||||
public void setUp() throws Exception { |
||||
this.mapper = new DispatcherHandlerExceptionMapper(); |
||||
} |
||||
|
||||
|
||||
@Test |
||||
public void handlerNotFound() throws Exception { |
||||
Throwable ex = new HandlerNotFoundException(HttpMethod.GET, "/path", new HttpHeaders()); |
||||
ex = this.mapper.apply(ex); |
||||
|
||||
assertEquals(ResponseStatusException.class, ex.getClass()); |
||||
assertEquals(HttpStatus.NOT_FOUND, ((ResponseStatusException) ex).getHttpStatus()); |
||||
} |
||||
|
||||
|
||||
@Test |
||||
public void httpMediaTypeNotAcceptable() throws Exception { |
||||
Throwable ex = new HttpMediaTypeNotAcceptableException(Collections.emptyList()); |
||||
ex = this.mapper.apply(ex); |
||||
|
||||
assertEquals(ResponseStatusException.class, ex.getClass()); |
||||
assertEquals(HttpStatus.NOT_ACCEPTABLE, ((ResponseStatusException) ex).getHttpStatus()); |
||||
} |
||||
|
||||
@Test |
||||
public void responseStatusAnnotation() throws Exception { |
||||
Throwable ex = new ResponseStatusAnnotatedException(); |
||||
ex = this.mapper.apply(ex); |
||||
|
||||
assertEquals(ResponseStatusException.class, ex.getClass()); |
||||
assertEquals(HttpStatus.BAD_REQUEST, ((ResponseStatusException) ex).getHttpStatus()); |
||||
} |
||||
|
||||
@Test |
||||
public void responseStatusAnnotationOnRootCause() throws Exception { |
||||
Throwable ex = new Exception(new ResponseStatusAnnotatedException()); |
||||
ex = this.mapper.apply(ex); |
||||
|
||||
assertEquals(ResponseStatusException.class, ex.getClass()); |
||||
assertEquals(HttpStatus.BAD_REQUEST, ((ResponseStatusException) ex).getHttpStatus()); |
||||
} |
||||
|
||||
|
||||
@ResponseStatus(code = HttpStatus.BAD_REQUEST) |
||||
private static class ResponseStatusAnnotatedException extends Exception { |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue