Produces media types cleared prior to error handling
Issue: SPR-16318
This commit is contained in:
parent
b3b233b43a
commit
395792b302
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
|
|
@ -38,6 +38,7 @@ import org.springframework.web.bind.support.WebBindingInitializer;
|
|||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.reactive.HandlerAdapter;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.HandlerResult;
|
||||
import org.springframework.web.reactive.result.method.InvocableHandlerMethod;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
|
@ -206,6 +207,9 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
|
|||
|
||||
Assert.state(this.methodResolver != null, "Not initialized");
|
||||
|
||||
// Success and error responses may use different content types
|
||||
exchange.getAttributes().remove(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
|
||||
|
||||
InvocableHandlerMethod invocable = this.methodResolver.getExceptionHandlerMethod(exception, handlerMethod);
|
||||
if (invocable != null) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package org.springframework.web.reactive.result.method.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
|
@ -32,6 +34,7 @@ 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;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.reactive.config.EnableWebFlux;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
|
@ -74,7 +77,7 @@ public class RequestMappingExceptionHandlingIntegrationTests extends AbstractReq
|
|||
}
|
||||
|
||||
@Test // SPR-16051
|
||||
public void exceptionAfterSeveralItems() throws Exception {
|
||||
public void exceptionAfterSeveralItems() {
|
||||
try {
|
||||
performGet("/SPR-16051", new HttpHeaders(), String.class).getBody();
|
||||
fail();
|
||||
|
|
@ -86,6 +89,21 @@ public class RequestMappingExceptionHandlingIntegrationTests extends AbstractReq
|
|||
}
|
||||
}
|
||||
|
||||
@Test // SPR-16318
|
||||
public void exceptionFromMethodWithProducesCondition() throws Exception {
|
||||
try {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Accept", "text/csv, application/problem+json");
|
||||
performGet("/SPR-16318", headers, String.class).getBody();
|
||||
fail();
|
||||
}
|
||||
catch (HttpStatusCodeException ex) {
|
||||
assertEquals(500, ex.getRawStatusCode());
|
||||
assertEquals("application/problem+json;charset=UTF-8", ex.getResponseHeaders().getContentType().toString());
|
||||
assertEquals("{\"reason\":\"error\"}", ex.getResponseBodyAsString());
|
||||
}
|
||||
}
|
||||
|
||||
private void doTest(String url, String expected) throws Exception {
|
||||
assertEquals(expected, performGet(url, new HttpHeaders(), String.class).getBody());
|
||||
}
|
||||
|
|
@ -118,7 +136,7 @@ public class RequestMappingExceptionHandlingIntegrationTests extends AbstractReq
|
|||
throw new RuntimeException("State", new IOException("IO"));
|
||||
}
|
||||
|
||||
@GetMapping("/mono-error")
|
||||
@GetMapping(path = "/mono-error")
|
||||
public Publisher<String> handleWithError() {
|
||||
return Mono.error(new IllegalArgumentException("Argument"));
|
||||
}
|
||||
|
|
@ -134,6 +152,10 @@ public class RequestMappingExceptionHandlingIntegrationTests extends AbstractReq
|
|||
});
|
||||
}
|
||||
|
||||
@GetMapping(path = "/SPR-16318", produces = "text/csv")
|
||||
public String handleCsv() throws Exception {
|
||||
throw new Spr16318Exception();
|
||||
}
|
||||
|
||||
@ExceptionHandler
|
||||
public Publisher<String> handleArgumentException(IOException ex) {
|
||||
|
|
@ -149,6 +171,14 @@ public class RequestMappingExceptionHandlingIntegrationTests extends AbstractReq
|
|||
public ResponseEntity<Publisher<String>> handleStateException(IllegalStateException ex) {
|
||||
return ResponseEntity.ok(Mono.just("Recovered from error: " + ex.getMessage()));
|
||||
}
|
||||
|
||||
@ExceptionHandler
|
||||
public ResponseEntity<Map<String, String>> handle(Spr16318Exception ex) {
|
||||
return ResponseEntity.status(500).body(Collections.singletonMap("reason", "error"));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class Spr16318Exception extends Exception {}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1248,6 +1248,9 @@ public class DispatcherServlet extends FrameworkServlet {
|
|||
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
|
||||
@Nullable Object handler, Exception ex) throws Exception {
|
||||
|
||||
// Success and error responses may use different content types
|
||||
request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
|
||||
|
||||
// Check registered HandlerExceptionResolvers...
|
||||
ModelAndView exMv = null;
|
||||
if (this.handlerExceptionResolvers != null) {
|
||||
|
|
|
|||
|
|
@ -1121,7 +1121,22 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
|||
|
||||
@Test
|
||||
public void produces() throws Exception {
|
||||
initServletWithControllers(ProducesController.class);
|
||||
initServlet(wac -> {
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<>();
|
||||
converters.add(new MappingJackson2HttpMessageConverter());
|
||||
converters.add(new Jaxb2RootElementHttpMessageConverter());
|
||||
|
||||
RootBeanDefinition beanDef;
|
||||
|
||||
beanDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
|
||||
beanDef.getPropertyValues().add("messageConverters", converters);
|
||||
wac.registerBeanDefinition("handlerAdapter", beanDef);
|
||||
|
||||
beanDef = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
|
||||
beanDef.getPropertyValues().add("messageConverters", converters);
|
||||
wac.registerBeanDefinition("requestMappingResolver", beanDef);
|
||||
|
||||
}, ProducesController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something");
|
||||
request.addHeader("Accept", "text/html");
|
||||
|
|
@ -1152,6 +1167,15 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
|||
response = new MockHttpServletResponse();
|
||||
getServlet().service(request, response);
|
||||
assertEquals(406, response.getStatus());
|
||||
|
||||
// SPR-16318
|
||||
request = new MockHttpServletRequest("GET", "/something");
|
||||
request.addHeader("Accept", "text/csv,application/problem+json");
|
||||
response = new MockHttpServletResponse();
|
||||
getServlet().service(request, response);
|
||||
assertEquals(500, response.getStatus());
|
||||
assertEquals("application/problem+json;charset=UTF-8", response.getContentType());
|
||||
assertEquals("{\"reason\":\"error\"}", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -3000,15 +3024,25 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
|
|||
@Controller
|
||||
public static class ProducesController {
|
||||
|
||||
@RequestMapping(value = "/something", produces = "text/html")
|
||||
@GetMapping(path = "/something", produces = "text/html")
|
||||
public void handleHtml(Writer writer) throws IOException {
|
||||
writer.write("html");
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/something", produces = "application/xml")
|
||||
@GetMapping(path = "/something", produces = "application/xml")
|
||||
public void handleXml(Writer writer) throws IOException {
|
||||
writer.write("xml");
|
||||
}
|
||||
|
||||
@GetMapping(path = "/something", produces = "text/csv")
|
||||
public String handleCsv() {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@ExceptionHandler
|
||||
public ResponseEntity<Map<String, String>> handle(IllegalArgumentException ex) {
|
||||
return ResponseEntity.status(500).body(Collections.singletonMap("reason", "error"));
|
||||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
|
|
|
|||
Loading…
Reference in New Issue