From e81a430e6174a67d453cb9c1871e01193f96867a Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 3 Sep 2015 14:53:43 +0200 Subject: [PATCH] Fix @RequestBody(required=false) support Prior to this commit, requests with an empty body and no Content-Type header set would fail with a HttpMediaTypeNotSupportedException when mapped to a Controller method argument annotated with @RequestBody(required=false). In those cases, the server implementation considers with an "application/octet-stream" content type and polls messageconverters for conversion. If no messageconverter is able to process this request, a HttpMediaTypeNotSupportedException is thrown. This change makes sure that such exceptions are not thrown if the incoming request has: * no body * no content-type header In this case, a null value is returned. Issue: SPR-13147 --- ...bstractMessageConverterMethodArgumentResolver.java | 5 ++++- .../HttpEntityMethodProcessorMockTests.java | 1 + .../RequestResponseBodyMethodProcessorMockTests.java | 11 ++++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java index 11894c7d1f..469a6812f1 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java @@ -158,6 +158,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { MediaType contentType; + boolean noContentType = false; try { contentType = inputMessage.getHeaders().getContentType(); } @@ -165,6 +166,7 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } if (contentType == null) { + noContentType = true; contentType = MediaType.APPLICATION_OCTET_STREAM; } @@ -220,7 +222,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements } if (body == NO_VALUE) { - if (!SUPPORTED_METHODS.contains(httpMethod)) { + if (!SUPPORTED_METHODS.contains(httpMethod) + || (noContentType && inputMessage.getBody() == null)) { return null; } throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorMockTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorMockTests.java index 44d3e400a9..f27bb0d5b3 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorMockTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorMockTests.java @@ -194,6 +194,7 @@ public class HttpEntityMethodProcessorMockTests { @Test(expected = HttpMediaTypeNotSupportedException.class) public void resolveArgumentNoContentType() throws Exception { + servletRequest.setContent("some content".getBytes(Charset.forName("UTF-8"))); processor.resolveArgument(paramHttpEntity, mavContainer, webRequest, null); fail("Expected exception"); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorMockTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorMockTests.java index bffcdfa28e..8a4cef7a14 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorMockTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessorMockTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * 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. @@ -212,6 +212,15 @@ public class RequestResponseBodyMethodProcessorMockTests { assertNull(processor.resolveArgument(paramStringNotRequired, mavContainer, webRequest, new ValidatingBinderFactory())); } + // SPR-13417 + @Test + public void resolveArgumentNotRequiredNoContentNoContentType() throws Exception { + servletRequest.setContent(new byte[0]); + given(messageConverter.canRead(String.class, MediaType.TEXT_PLAIN)).willReturn(true); + given(messageConverter.canRead(String.class, MediaType.APPLICATION_OCTET_STREAM)).willReturn(false); + assertNull(processor.resolveArgument(paramStringNotRequired, mavContainer, webRequest, new ValidatingBinderFactory())); + } + @Test public void resolveArgumentNotGetRequests() throws Exception { servletRequest.setMethod("GET");