19
19
import java .lang .annotation .Annotation ;
20
20
import java .lang .reflect .InvocationTargetException ;
21
21
import java .lang .reflect .Method ;
22
+ import java .util .ArrayList ;
22
23
import java .util .Arrays ;
23
24
import java .util .Collection ;
24
25
import java .util .HashSet ;
26
+ import java .util .List ;
25
27
import java .util .Map ;
26
28
import java .util .Set ;
27
29
35
37
import org .springframework .core .MethodParameter ;
36
38
import org .springframework .core .ParameterNameDiscoverer ;
37
39
import org .springframework .core .annotation .AnnotationUtils ;
40
+ import org .springframework .http .HttpInputMessage ;
41
+ import org .springframework .http .MediaType ;
42
+ import org .springframework .http .converter .HttpMessageConverter ;
38
43
import org .springframework .ui .ExtendedModelMap ;
39
44
import org .springframework .ui .Model ;
40
45
import org .springframework .util .ClassUtils ;
41
46
import org .springframework .util .ReflectionUtils ;
42
47
import org .springframework .util .StringUtils ;
43
48
import org .springframework .validation .BindingResult ;
44
49
import org .springframework .validation .Errors ;
50
+ import org .springframework .web .HttpMediaTypeNotSupportedException ;
45
51
import org .springframework .web .bind .WebDataBinder ;
46
52
import org .springframework .web .bind .annotation .CookieValue ;
47
53
import org .springframework .web .bind .annotation .InitBinder ;
48
54
import org .springframework .web .bind .annotation .ModelAttribute ;
49
55
import org .springframework .web .bind .annotation .PathVariable ;
56
+ import org .springframework .web .bind .annotation .RequestBody ;
50
57
import org .springframework .web .bind .annotation .RequestHeader ;
51
58
import org .springframework .web .bind .annotation .RequestParam ;
52
59
import org .springframework .web .bind .support .DefaultSessionAttributeStore ;
@@ -89,24 +96,28 @@ public class HandlerMethodInvoker {
89
96
90
97
private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus ();
91
98
99
+ private final HttpMessageConverter [] messageConverters ;
100
+
92
101
93
102
public HandlerMethodInvoker (HandlerMethodResolver methodResolver ) {
94
103
this (methodResolver , null );
95
104
}
96
105
97
106
public HandlerMethodInvoker (HandlerMethodResolver methodResolver , WebBindingInitializer bindingInitializer ) {
98
- this (methodResolver , bindingInitializer , new DefaultSessionAttributeStore (), null );
107
+ this (methodResolver , bindingInitializer , new DefaultSessionAttributeStore (), null , new WebArgumentResolver [0 ],
108
+ new HttpMessageConverter [0 ]);
99
109
}
100
110
101
111
public HandlerMethodInvoker (HandlerMethodResolver methodResolver , WebBindingInitializer bindingInitializer ,
102
112
SessionAttributeStore sessionAttributeStore , ParameterNameDiscoverer parameterNameDiscoverer ,
103
- WebArgumentResolver ... customArgumentResolvers ) {
113
+ WebArgumentResolver [] customArgumentResolvers , HttpMessageConverter [] messageConverters ) {
104
114
105
115
this .methodResolver = methodResolver ;
106
116
this .bindingInitializer = bindingInitializer ;
107
117
this .sessionAttributeStore = sessionAttributeStore ;
108
118
this .parameterNameDiscoverer = parameterNameDiscoverer ;
109
119
this .customArgumentResolvers = customArgumentResolvers ;
120
+ this .messageConverters = messageConverters ;
110
121
}
111
122
112
123
@@ -159,6 +170,7 @@ private Object[] resolveHandlerArguments(Method handlerMethod,
159
170
GenericTypeResolver .resolveParameterType (methodParam , handler .getClass ());
160
171
String paramName = null ;
161
172
String headerName = null ;
173
+ boolean requestBodyFound = false ;
162
174
String cookieName = null ;
163
175
String pathVarName = null ;
164
176
String attrName = null ;
@@ -182,6 +194,10 @@ else if (RequestHeader.class.isInstance(paramAnn)) {
182
194
defaultValue = requestHeader .defaultValue ();
183
195
found ++;
184
196
}
197
+ else if (RequestBody .class .isInstance (paramAnn )) {
198
+ requestBodyFound = true ;
199
+ found ++;
200
+ }
185
201
else if (CookieValue .class .isInstance (paramAnn )) {
186
202
CookieValue cookieValue = (CookieValue ) paramAnn ;
187
203
cookieName = cookieValue .value ();
@@ -238,6 +254,9 @@ else if (BeanUtils.isSimpleProperty(paramType)) {
238
254
else if (headerName != null ) {
239
255
args [i ] = resolveRequestHeader (headerName , required , defaultValue , methodParam , webRequest , handler );
240
256
}
257
+ else if (requestBodyFound ) {
258
+ args [i ] = resolveRequestBody (methodParam , webRequest , handler );
259
+ }
241
260
else if (cookieName != null ) {
242
261
args [i ] = resolveCookieValue (cookieName , required , defaultValue , methodParam , webRequest , handler );
243
262
}
@@ -418,6 +437,45 @@ else if (required) {
418
437
return binder .convertIfNecessary (headerValue , paramType , methodParam );
419
438
}
420
439
440
+ /**
441
+ * Resolves the given {@link RequestBody @RequestBody} annotation.
442
+ * Throws an UnsupportedOperationException by default.
443
+ */
444
+ @ SuppressWarnings ("unchecked" )
445
+ protected Object resolveRequestBody (MethodParameter methodParam , NativeWebRequest webRequest , Object handler )
446
+ throws Exception {
447
+
448
+ HttpInputMessage inputMessage = createHttpInputMessage (webRequest );
449
+
450
+ Class paramType = methodParam .getParameterType ();
451
+ MediaType contentType = inputMessage .getHeaders ().getContentType ();
452
+ if (contentType == null ) {
453
+ throw new IllegalStateException ("Cannot extract response: no Content-Type found" );
454
+ }
455
+ List <MediaType > allSupportedMediaTypes = new ArrayList <MediaType >();
456
+ for (HttpMessageConverter <?> messageConverter : messageConverters ) {
457
+ allSupportedMediaTypes .addAll (messageConverter .getSupportedMediaTypes ());
458
+ if (messageConverter .supports (paramType )) {
459
+ for (MediaType supportedMediaType : messageConverter .getSupportedMediaTypes ()) {
460
+ if (supportedMediaType .includes (contentType )) {
461
+ return messageConverter .read (paramType , inputMessage );
462
+ }
463
+ }
464
+ }
465
+ }
466
+
467
+ throw new HttpMediaTypeNotSupportedException (contentType , allSupportedMediaTypes );
468
+ }
469
+
470
+ /**
471
+ * Returns a {@link HttpInputMessage} for the given {@link NativeWebRequest}.
472
+ * Throws an UnsupportedOperationException by default.
473
+ */
474
+ protected HttpInputMessage createHttpInputMessage (NativeWebRequest webRequest ) throws Exception {
475
+
476
+ throw new UnsupportedOperationException ("@RequestBody not supported" );
477
+ }
478
+
421
479
private Object resolveCookieValue (String cookieName , boolean required , String defaultValue ,
422
480
MethodParameter methodParam , NativeWebRequest webRequest , Object handlerForInitBinderCall )
423
481
throws Exception {
0 commit comments