提交 9a894ab6 编写于 作者: R Rossen Stoyanchev

Use ResponseEntity Content-Type as producible media type

Issue: SPR-16172
上级 780993ce
......@@ -152,6 +152,10 @@ public abstract class HandlerResultHandlerSupport implements Ordered {
private List<MediaType> getProducibleTypes(ServerWebExchange exchange,
Supplier<List<MediaType>> producibleTypesSupplier) {
MediaType contentType = exchange.getResponse().getHeaders().getContentType();
if (contentType != null && contentType.isConcrete()) {
return Collections.singletonList(contentType);
}
Set<MediaType> mediaTypes = exchange.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
return (mediaTypes != null ? new ArrayList<>(mediaTypes) : producibleTypesSupplier.get());
}
......
......@@ -111,7 +111,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
MediaType bestMediaType = selectMediaType(exchange, () -> getProducibleMediaTypes(elementType));
MediaType bestMediaType = selectMediaType(exchange, () -> getMediaTypesFor(elementType));
if (bestMediaType != null) {
for (HttpMessageWriter<?> writer : getMessageWriters()) {
if (writer.canWrite(elementType, bestMediaType)) {
......@@ -121,12 +121,12 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
}
}
else {
if (getProducibleMediaTypes(elementType).isEmpty()) {
return Mono.error(new IllegalStateException("No converter for return value type: " + elementType));
if (getMediaTypesFor(elementType).isEmpty()) {
return Mono.error(new IllegalStateException("No writer for : " + elementType));
}
}
return Mono.error(new NotAcceptableStatusException(getProducibleMediaTypes(elementType)));
return Mono.error(new NotAcceptableStatusException(getMediaTypesFor(elementType)));
}
private ResolvableType getElementType(ReactiveAdapter adapter, ResolvableType genericType) {
......@@ -141,7 +141,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
}
}
private List<MediaType> getProducibleMediaTypes(ResolvableType elementType) {
private List<MediaType> getMediaTypesFor(ResolvableType elementType) {
return getMessageWriters().stream()
.filter(converter -> converter.canWrite(elementType, null))
.flatMap(converter -> converter.getWritableMediaTypes().stream())
......
......@@ -155,6 +155,16 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq
assertEquals(expected, performGet("/person-response/mono-response-entity", JSON, Person.class).getBody());
}
@Test // SPR-16172
public void personResponseBodyWithMonoResponseEntityXml() throws Exception {
String actual = performGet("/person-response/mono-response-entity-xml",
new HttpHeaders(), String.class).getBody();
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
"<person><name>Robert</name></person>", actual);
}
@Test
public void personResponseBodyWithList() throws Exception {
List<?> expected = asList(new Person("Robert"), new Person("Marie"));
......@@ -465,6 +475,12 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq
return ResponseEntity.ok(body);
}
@GetMapping("/mono-response-entity-xml")
public ResponseEntity<Mono<Person>> getMonoResponseEntityXml() {
Mono<Person> body = Mono.just(new Person("Robert"));
return ResponseEntity.ok().contentType(MediaType.APPLICATION_XML).body(body);
}
@GetMapping("/list")
public List<Person> getList() {
return asList(new Person("Robert"), new Person("Marie"));
......
......@@ -212,7 +212,10 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);
MediaType contentType = outputMessage.getHeaders().getContentType();
List<MediaType> producibleMediaTypes = (contentType != null && contentType.isConcrete() ?
Collections.singletonList(contentType) : getProducibleMediaTypes(request, valueType, declaredType));
if (outputValue != null && producibleMediaTypes.isEmpty()) {
throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);
......
......@@ -83,6 +83,8 @@ import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.mock.web.test.MockHttpServletRequest;
......@@ -934,6 +936,26 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertEquals(404, response.getStatus());
}
@Test // SPR-16172
public void httpEntityWithContentType() throws Exception {
initServlet(wac -> {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new MappingJackson2HttpMessageConverter());
messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
adapterDef.getPropertyValues().add("messageConverters", messageConverters);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, ResponseEntityController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test-entity");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals(200, response.getStatus());
assertEquals("application/xml", response.getHeader("Content-Type"));
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
"<testEntity><name>Foo Bar</name></testEntity>", response.getContentAsString());
}
@Test // SPR-6877
public void overlappingMessageConvertersRequestBody() throws Exception {
initServlet(wac -> {
......@@ -3210,7 +3232,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Controller
public static class ResponseEntityController {
@RequestMapping(path = "/foo", method = RequestMethod.POST)
@PostMapping("/foo")
public ResponseEntity<String> foo(HttpEntity<byte[]> requestEntity) throws Exception {
assertNotNull(requestEntity);
assertEquals("MyValue", requestEntity.getHeaders().getFirst("MyRequestHeader"));
......@@ -3222,12 +3244,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
return ResponseEntity.created(location).header("MyResponseHeader", "MyValue").body(body);
}
@RequestMapping(path = "/bar", method = RequestMethod.GET)
@GetMapping("/bar")
public ResponseEntity<Void> bar() {
return ResponseEntity.notFound().header("MyResponseHeader", "MyValue").build();
}
@RequestMapping(path = "/baz", method = RequestMethod.GET)
@GetMapping("/baz")
public ResponseEntity<String> baz() {
return ResponseEntity.ok().header("MyResponseHeader", "MyValue").body("body");
}
......@@ -3237,10 +3259,32 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
return ResponseEntity.ok().header("h1", "v1").build();
}
@RequestMapping(path = "/stores", method = RequestMethod.GET)
@GetMapping("/stores")
public ResponseEntity<String> getResource() {
return ResponseEntity.ok().body("body");
}
@GetMapping("/test-entity")
public ResponseEntity<TestEntity> testEntity() {
TestEntity entity = new TestEntity();
entity.setName("Foo Bar");
return ResponseEntity.ok().contentType(MediaType.APPLICATION_XML).body(entity);
}
}
@XmlRootElement
static class TestEntity {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Controller
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册