@ -17,8 +17,12 @@
@@ -17,8 +17,12 @@
package org.springframework.web.bind.annotation.support ;
import java.lang.annotation.Annotation ;
import java.lang.reflect.Array ;
import java.lang.reflect.GenericArrayType ;
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.Method ;
import java.lang.reflect.ParameterizedType ;
import java.lang.reflect.Type ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Collection ;
@ -40,12 +44,14 @@ import org.springframework.core.GenericTypeResolver;
@@ -40,12 +44,14 @@ import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter ;
import org.springframework.core.ParameterNameDiscoverer ;
import org.springframework.core.annotation.AnnotationUtils ;
import org.springframework.http.HttpEntity ;
import org.springframework.http.HttpHeaders ;
import org.springframework.http.HttpInputMessage ;
import org.springframework.http.MediaType ;
import org.springframework.http.converter.HttpMessageConverter ;
import org.springframework.ui.ExtendedModelMap ;
import org.springframework.ui.Model ;
import org.springframework.util.Assert ;
import org.springframework.util.ClassUtils ;
import org.springframework.util.LinkedMultiValueMap ;
import org.springframework.util.MultiValueMap ;
@ -192,7 +198,7 @@ public class HandlerMethodInvoker {
@@ -192,7 +198,7 @@ public class HandlerMethodInvoker {
boolean required = false ;
String defaultValue = null ;
boolean validate = false ;
int f ound = 0 ;
int annotationsF ound = 0 ;
Annotation [ ] paramAnns = methodParam . getParameterAnnotations ( ) ;
for ( Annotation paramAnn : paramAnns ) {
@ -201,35 +207,35 @@ public class HandlerMethodInvoker {
@@ -201,35 +207,35 @@ public class HandlerMethodInvoker {
paramName = requestParam . value ( ) ;
required = requestParam . required ( ) ;
defaultValue = parseDefaultValueAttribute ( requestParam . defaultValue ( ) ) ;
f ound+ + ;
annotationsF ound+ + ;
}
else if ( RequestHeader . class . isInstance ( paramAnn ) ) {
RequestHeader requestHeader = ( RequestHeader ) paramAnn ;
headerName = requestHeader . value ( ) ;
required = requestHeader . required ( ) ;
defaultValue = parseDefaultValueAttribute ( requestHeader . defaultValue ( ) ) ;
f ound+ + ;
annotationsF ound+ + ;
}
else if ( RequestBody . class . isInstance ( paramAnn ) ) {
requestBodyFound = true ;
f ound+ + ;
annotationsF ound+ + ;
}
else if ( CookieValue . class . isInstance ( paramAnn ) ) {
CookieValue cookieValue = ( CookieValue ) paramAnn ;
cookieName = cookieValue . value ( ) ;
required = cookieValue . required ( ) ;
defaultValue = parseDefaultValueAttribute ( cookieValue . defaultValue ( ) ) ;
f ound+ + ;
annotationsF ound+ + ;
}
else if ( PathVariable . class . isInstance ( paramAnn ) ) {
PathVariable pathVar = ( PathVariable ) paramAnn ;
pathVarName = pathVar . value ( ) ;
f ound+ + ;
annotationsF ound+ + ;
}
else if ( ModelAttribute . class . isInstance ( paramAnn ) ) {
ModelAttribute attr = ( ModelAttribute ) paramAnn ;
attrName = attr . value ( ) ;
f ound+ + ;
annotationsF ound+ + ;
}
else if ( Value . class . isInstance ( paramAnn ) ) {
defaultValue = ( ( Value ) paramAnn ) . value ( ) ;
@ -239,12 +245,12 @@ public class HandlerMethodInvoker {
@@ -239,12 +245,12 @@ public class HandlerMethodInvoker {
}
}
if ( f ound > 1 ) {
if ( annotationsF ound > 1 ) {
throw new IllegalStateException ( "Handler parameter annotations are exclusive choices - " +
"do not specify more than one such annotation on the same parameter: " + handlerMethod ) ;
}
if ( f ound = = 0 ) {
if ( annotationsF ound = = 0 ) {
Object argValue = resolveCommonArgument ( methodParam , webRequest ) ;
if ( argValue ! = WebArgumentResolver . UNRESOLVED ) {
args [ i ] = argValue ;
@ -260,6 +266,9 @@ public class HandlerMethodInvoker {
@@ -260,6 +266,9 @@ public class HandlerMethodInvoker {
else if ( SessionStatus . class . isAssignableFrom ( paramType ) ) {
args [ i ] = this . sessionStatus ;
}
else if ( HttpEntity . class . isAssignableFrom ( paramType ) ) {
args [ i ] = resolveHttpEntityRequest ( methodParam , webRequest , handler ) ;
}
else if ( Errors . class . isAssignableFrom ( paramType ) ) {
throw new IllegalStateException ( "Errors/BindingResult argument declared " +
"without preceding model attribute. Check your handler method signature!" ) ;
@ -527,12 +536,22 @@ public class HandlerMethodInvoker {
@@ -527,12 +536,22 @@ public class HandlerMethodInvoker {
/ * *
* Resolves the given { @link RequestBody @RequestBody } annotation .
* /
@SuppressWarnings ( "unchecked" )
protected Object resolveRequestBody ( MethodParameter methodParam , NativeWebRequest webRequest , Object handler )
throws Exception {
return readWithMessageConverters ( methodParam , createHttpInputMessage ( webRequest ) , methodParam . getParameterType ( ) ) ;
}
@SuppressWarnings ( "unchecked" )
private HttpEntity resolveHttpEntityRequest ( MethodParameter methodParam , NativeWebRequest webRequest , Object handler )
throws Exception {
HttpInputMessage inputMessage = createHttpInputMessage ( webRequest ) ;
Class paramType = methodParam . getParameterType ( ) ;
Class < ? > paramType = getHttpEntityType ( methodParam ) ;
Object body = readWithMessageConverters ( methodParam , inputMessage , paramType ) ;
return new HttpEntity ( body , inputMessage . getHeaders ( ) ) ;
}
private Object readWithMessageConverters ( MethodParameter methodParam , HttpInputMessage inputMessage , Class paramType )
throws Exception {
MediaType contentType = inputMessage . getHeaders ( ) . getContentType ( ) ;
if ( contentType = = null ) {
StringBuilder builder = new StringBuilder ( ClassUtils . getShortName ( methodParam . getParameterType ( ) ) ) ;
@ -542,8 +561,9 @@ public class HandlerMethodInvoker {
@@ -542,8 +561,9 @@ public class HandlerMethodInvoker {
builder . append ( paramName ) ;
}
throw new HttpMediaTypeNotSupportedException (
"Cannot extract @RequestBody parameter (" + builder . toString ( ) + "): no Content-Type found" ) ;
"Cannot extract parameter (" + builder . toString ( ) + "): no Content-Type found" ) ;
}
List < MediaType > allSupportedMediaTypes = new ArrayList < MediaType > ( ) ;
if ( this . messageConverters ! = null ) {
for ( HttpMessageConverter < ? > messageConverter : this . messageConverters ) {
@ -560,6 +580,28 @@ public class HandlerMethodInvoker {
@@ -560,6 +580,28 @@ public class HandlerMethodInvoker {
throw new HttpMediaTypeNotSupportedException ( contentType , allSupportedMediaTypes ) ;
}
private Class < ? > getHttpEntityType ( MethodParameter methodParam ) {
Assert . isAssignable ( HttpEntity . class , methodParam . getParameterType ( ) ) ;
ParameterizedType type = ( ParameterizedType ) methodParam . getGenericParameterType ( ) ;
if ( type . getActualTypeArguments ( ) . length = = 1 ) {
Type typeArgument = type . getActualTypeArguments ( ) [ 0 ] ;
if ( typeArgument instanceof Class ) {
return ( Class < ? > ) typeArgument ;
}
else if ( typeArgument instanceof GenericArrayType ) {
Type componentType = ( ( GenericArrayType ) typeArgument ) . getGenericComponentType ( ) ;
if ( componentType instanceof Class ) {
// Surely, there should be a nicer way to do this
Object array = Array . newInstance ( ( Class < ? > ) componentType , 0 ) ;
return array . getClass ( ) ;
}
}
}
throw new IllegalArgumentException (
"HttpEntity parameter (" + methodParam . getParameterName ( ) + ") is not parameterized" ) ;
}
private Object resolveCookieValue ( String cookieName , boolean required , String defaultValue ,
MethodParameter methodParam , NativeWebRequest webRequest , Object handlerForInitBinderCall )
throws Exception {