Add WebFlux equivalent of ResponseEntityExceptionHandler
Closes gh-28665
This commit is contained in:
@@ -16,11 +16,9 @@
|
||||
|
||||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.servlet.ServletException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -36,7 +34,6 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.MapBindingResult;
|
||||
@@ -56,6 +53,7 @@ import org.springframework.web.context.request.async.AsyncRequestTimeoutExceptio
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
import org.springframework.web.multipart.support.MissingServletRequestPartException;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.NoHandlerFoundException;
|
||||
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
|
||||
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
|
||||
@@ -65,19 +63,19 @@ import org.springframework.web.testfixture.servlet.MockServletConfig;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test fixture for {@link ResponseEntityExceptionHandler}.
|
||||
* Unit tests for {@link ResponseEntityExceptionHandler}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ResponseEntityExceptionHandlerTests {
|
||||
|
||||
private ResponseEntityExceptionHandler exceptionHandlerSupport = new ApplicationExceptionHandler();
|
||||
private final ResponseEntityExceptionHandler exceptionHandler = new ApplicationExceptionHandler();
|
||||
|
||||
private DefaultHandlerExceptionResolver defaultExceptionResolver = new DefaultHandlerExceptionResolver();
|
||||
private final DefaultHandlerExceptionResolver exceptionResolver = new DefaultHandlerExceptionResolver();
|
||||
|
||||
private MockHttpServletRequest servletRequest = new MockHttpServletRequest("GET", "/");
|
||||
|
||||
private MockHttpServletResponse servletResponse = new MockHttpServletResponse();
|
||||
private final MockHttpServletResponse servletResponse = new MockHttpServletResponse();
|
||||
|
||||
private WebRequest request = new ServletWebRequest(this.servletRequest, this.servletResponse);
|
||||
|
||||
@@ -101,21 +99,19 @@ public class ResponseEntityExceptionHandlerTests {
|
||||
|
||||
@Test
|
||||
public void httpRequestMethodNotSupported() {
|
||||
List<String> supported = Arrays.asList("POST", "DELETE");
|
||||
Exception ex = new HttpRequestMethodNotSupportedException("GET", supported);
|
||||
ResponseEntity<Object> entity =
|
||||
testException(new HttpRequestMethodNotSupportedException("GET", List.of("POST", "DELETE")));
|
||||
|
||||
ResponseEntity<Object> responseEntity = testException(ex);
|
||||
assertThat(responseEntity.getHeaders().getAllow()).isEqualTo(Set.of(HttpMethod.POST, HttpMethod.DELETE));
|
||||
assertThat(entity.getHeaders().getFirst(HttpHeaders.ALLOW)).isEqualTo("POST, DELETE");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleHttpMediaTypeNotSupported() {
|
||||
List<MediaType> acceptable = Arrays.asList(MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_XML);
|
||||
Exception ex = new HttpMediaTypeNotSupportedException(MediaType.APPLICATION_JSON, acceptable);
|
||||
ResponseEntity<Object> entity = testException(new HttpMediaTypeNotSupportedException(
|
||||
MediaType.APPLICATION_JSON, List.of(MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_XML)));
|
||||
|
||||
ResponseEntity<Object> responseEntity = testException(ex);
|
||||
assertThat(responseEntity.getHeaders().getAccept()).isEqualTo(acceptable);
|
||||
assertThat(responseEntity.getHeaders().getAcceptPatch()).isEmpty();
|
||||
assertThat(entity.getHeaders().getFirst(HttpHeaders.ACCEPT)).isEqualTo("application/atom+xml, application/xml");
|
||||
assertThat(entity.getHeaders().getAcceptPatch()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -123,92 +119,80 @@ public class ResponseEntityExceptionHandlerTests {
|
||||
this.servletRequest = new MockHttpServletRequest("PATCH", "/");
|
||||
this.request = new ServletWebRequest(this.servletRequest, this.servletResponse);
|
||||
|
||||
List<MediaType> acceptable = Arrays.asList(MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_XML);
|
||||
Exception ex = new HttpMediaTypeNotSupportedException(MediaType.APPLICATION_JSON, acceptable, HttpMethod.PATCH);
|
||||
ResponseEntity<Object> entity = testException(
|
||||
new HttpMediaTypeNotSupportedException(
|
||||
MediaType.APPLICATION_JSON,
|
||||
List.of(MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_XML),
|
||||
HttpMethod.PATCH));
|
||||
|
||||
ResponseEntity<Object> responseEntity = testException(ex);
|
||||
assertThat(responseEntity.getHeaders().getAccept()).isEqualTo(acceptable);
|
||||
assertThat(responseEntity.getHeaders().getAcceptPatch()).isEqualTo(acceptable);
|
||||
HttpHeaders headers = entity.getHeaders();
|
||||
assertThat(headers.getFirst(HttpHeaders.ACCEPT)).isEqualTo("application/atom+xml, application/xml");
|
||||
assertThat(headers.getFirst(HttpHeaders.ACCEPT)).isEqualTo("application/atom+xml, application/xml");
|
||||
assertThat(headers.getFirst(HttpHeaders.ACCEPT_PATCH)).isEqualTo("application/atom+xml, application/xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpMediaTypeNotAcceptable() {
|
||||
Exception ex = new HttpMediaTypeNotAcceptableException("");
|
||||
testException(ex);
|
||||
testException(new HttpMediaTypeNotAcceptableException(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingPathVariable() throws NoSuchMethodException {
|
||||
Method method = getClass().getDeclaredMethod("handle", String.class);
|
||||
MethodParameter parameter = new MethodParameter(method, 0);
|
||||
Exception ex = new MissingPathVariableException("param", parameter);
|
||||
testException(ex);
|
||||
testException(new MissingPathVariableException("param",
|
||||
new MethodParameter(getClass().getDeclaredMethod("handle", String.class), 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingServletRequestParameter() {
|
||||
Exception ex = new MissingServletRequestParameterException("param", "type");
|
||||
testException(ex);
|
||||
testException(new MissingServletRequestParameterException("param", "type"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void servletRequestBindingException() {
|
||||
Exception ex = new ServletRequestBindingException("message");
|
||||
testException(ex);
|
||||
testException(new ServletRequestBindingException("message"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void conversionNotSupported() {
|
||||
Exception ex = new ConversionNotSupportedException(new Object(), Object.class, null);
|
||||
testException(ex);
|
||||
testException(new ConversionNotSupportedException(new Object(), Object.class, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void typeMismatch() {
|
||||
Exception ex = new TypeMismatchException("foo", String.class);
|
||||
testException(ex);
|
||||
testException(new TypeMismatchException("foo", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
public void httpMessageNotReadable() {
|
||||
Exception ex = new HttpMessageNotReadableException("message");
|
||||
testException(ex);
|
||||
testException(new HttpMessageNotReadableException("message"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpMessageNotWritable() {
|
||||
Exception ex = new HttpMessageNotWritableException("");
|
||||
testException(ex);
|
||||
testException(new HttpMessageNotWritableException(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodArgumentNotValid() throws Exception {
|
||||
Exception ex = new MethodArgumentNotValidException(
|
||||
testException(new MethodArgumentNotValidException(
|
||||
new MethodParameter(getClass().getDeclaredMethod("handle", String.class), 0),
|
||||
new MapBindingResult(Collections.emptyMap(), "name"));
|
||||
testException(ex);
|
||||
new MapBindingResult(Collections.emptyMap(), "name")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingServletRequestPart() {
|
||||
Exception ex = new MissingServletRequestPartException("partName");
|
||||
testException(ex);
|
||||
testException(new MissingServletRequestPartException("partName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindException() {
|
||||
Exception ex = new BindException(new Object(), "name");
|
||||
testException(ex);
|
||||
testException(new BindException(new Object(), "name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noHandlerFoundException() {
|
||||
ServletServerHttpRequest req = new ServletServerHttpRequest(
|
||||
new MockHttpServletRequest("GET","/resource"));
|
||||
Exception ex = new NoHandlerFoundException(req.getMethod().toString(),
|
||||
req.getServletRequest().getRequestURI(),req.getHeaders());
|
||||
testException(ex);
|
||||
testException(new NoHandlerFoundException("GET", "/resource", HttpHeaders.EMPTY));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -244,8 +228,11 @@ public class ResponseEntityExceptionHandlerTests {
|
||||
resolver.setApplicationContext(ctx);
|
||||
resolver.afterPropertiesSet();
|
||||
|
||||
IllegalStateException ex = new IllegalStateException(new ServletRequestBindingException("message"));
|
||||
assertThat(resolver.resolveException(this.servletRequest, this.servletResponse, null, ex)).isNull();
|
||||
ModelAndView mav = resolver.resolveException(
|
||||
this.servletRequest, this.servletResponse, null,
|
||||
new IllegalStateException(new ServletRequestBindingException("message")));
|
||||
|
||||
assertThat(mav).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -287,18 +274,18 @@ public class ResponseEntityExceptionHandlerTests {
|
||||
|
||||
private ResponseEntity<Object> testException(Exception ex) {
|
||||
try {
|
||||
ResponseEntity<Object> responseEntity = this.exceptionHandlerSupport.handleException(ex, this.request);
|
||||
ResponseEntity<Object> entity = this.exceptionHandler.handleException(ex, this.request);
|
||||
|
||||
// SPR-9653
|
||||
if (HttpStatus.INTERNAL_SERVER_ERROR.equals(responseEntity.getStatusCode())) {
|
||||
if (HttpStatus.INTERNAL_SERVER_ERROR.equals(entity.getStatusCode())) {
|
||||
assertThat(this.servletRequest.getAttribute("jakarta.servlet.error.exception")).isSameAs(ex);
|
||||
}
|
||||
|
||||
this.defaultExceptionResolver.resolveException(this.servletRequest, this.servletResponse, null, ex);
|
||||
// Verify DefaultHandlerExceptionResolver would set the same status
|
||||
this.exceptionResolver.resolveException(this.servletRequest, this.servletResponse, null, ex);
|
||||
assertThat(entity.getStatusCode().value()).isEqualTo(this.servletResponse.getStatus());
|
||||
|
||||
assertThat(responseEntity.getStatusCode().value()).isEqualTo(this.servletResponse.getStatus());
|
||||
|
||||
return responseEntity;
|
||||
return entity;
|
||||
}
|
||||
catch (Exception ex2) {
|
||||
throw new IllegalStateException("handleException threw exception", ex2);
|
||||
|
||||
Reference in New Issue
Block a user