Browse Source

Peek into the content for @RequestBody(required=false)

For @RequestBody(required=false), it is not sufficient to check if the
InputStream is null. This change reads the first byte of the request
InputStream to determine if the request body is empty or not.

If the InputStream implementation supports mark(int) and reset(), then
we use those. Otherwise we use PushbackInputStream to read and unread
the first byte.

All of this is done only if the required flag of @RequestBody is set
to "false" (default is "true").

Issue: SPR-9942
pull/177/head
Rossen Stoyanchev 12 years ago
parent
commit
0e3aa0eec4
  1. 46
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java

46
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java

@ -17,16 +17,21 @@ @@ -17,16 +17,21 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.springframework.core.Conventions;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
@ -134,18 +139,45 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter @@ -134,18 +139,45 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
}
@Override
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage,
MethodParameter methodParam, Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest,
MethodParameter methodParam, Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
if (inputMessage.getBody() != null) {
return super.readWithMessageConverters(inputMessage, methodParam, paramType);
}
final HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
HttpInputMessage inputMessage = new ServletServerHttpRequest(servletRequest);
RequestBody annot = methodParam.getParameterAnnotation(RequestBody.class);
if (!annot.required()) {
return null;
InputStream inputStream = inputMessage.getBody();
if (inputStream == null) {
return null;
}
else if (inputStream.markSupported()) {
inputStream.mark(1);
if (inputStream.read() == -1) {
return null;
}
inputStream.reset();
}
else {
final PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
int b = pushbackInputStream.read();
if (b == -1) {
return null;
}
else {
pushbackInputStream.unread(b);
}
inputMessage = new ServletServerHttpRequest(servletRequest) {
@Override
public InputStream getBody() throws IOException {
// Form POST should not get here
return pushbackInputStream;
}
};
}
}
throw new HttpMessageNotReadableException("Required request body content is missing: " + methodParam.toString());
return super.readWithMessageConverters(inputMessage, methodParam, paramType);
}
public void handleReturnValue(Object returnValue, MethodParameter returnType,

Loading…
Cancel
Save