diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java index 79d56fe5c60..72e43cd1b62 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java @@ -109,15 +109,12 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol if (binder.getTarget() != null) { bindRequestParameters(binder, webRequest); validateIfApplicable(binder, parameter); - if (binder.getBindingResult().hasErrors()) { - if (isBindExceptionRequired(binder, parameter)) { - throw new BindException(binder.getBindingResult()); - } + if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { + throw new BindException(binder.getBindingResult()); } } // Add resolved attribute and BindingResult at the end of the model - Map bindingResultModel = binder.getBindingResult().getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); @@ -129,15 +126,15 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol * Extension point to create the model attribute if not found in the model. * The default implementation uses the default constructor. * @param attributeName the name of the attribute (never {@code null}) - * @param parameter the method parameter + * @param methodParam the method parameter * @param binderFactory for creating WebDataBinder instance * @param request the current request * @return the created model attribute (never {@code null}) */ - protected Object createAttribute(String attributeName, MethodParameter parameter, - WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { + protected Object createAttribute(String attributeName, MethodParameter methodParam, + WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { - return BeanUtils.instantiateClass(parameter.getParameterType()); + return BeanUtils.instantiateClass(methodParam.getParameterType()); } /** @@ -155,10 +152,10 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol * Spring's {@link org.springframework.validation.annotation.Validated}, * and custom annotations whose name starts with "Valid". * @param binder the DataBinder to be used - * @param parameter the method parameter + * @param methodParam the method parameter */ - protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { - Annotation[] annotations = parameter.getParameterAnnotations(); + protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) { + Annotation[] annotations = methodParam.getParameterAnnotations(); for (Annotation ann : annotations) { Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { @@ -171,16 +168,15 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol } /** - * Whether to raise a {@link BindException} on validation errors. + * Whether to raise a fatal bind exception on validation errors. * @param binder the data binder used to perform data binding - * @param parameter the method argument - * @return {@code true} if the next method argument is not of type {@link Errors}. + * @param methodParam the method argument + * @return {@code true} if the next method argument is not of type {@link Errors} */ - protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) { - int i = parameter.getParameterIndex(); - Class[] paramTypes = parameter.getMethod().getParameterTypes(); + protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) { + int i = methodParam.getParameterIndex(); + Class[] paramTypes = methodParam.getMethod().getParameterTypes(); boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1])); - return !hasBindingResult; } 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 335810df725..e5bd4f5972b 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 @@ -17,6 +17,7 @@ package org.springframework.web.servlet.mvc.method.annotation; import java.io.IOException; +import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; @@ -30,6 +31,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.http.HttpInputMessage; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; @@ -38,7 +40,9 @@ import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.util.Assert; import org.springframework.validation.Errors; +import org.springframework.validation.annotation.Validated; import org.springframework.web.HttpMediaTypeNotSupportedException; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; @@ -113,8 +117,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements * @throws HttpMediaTypeNotSupportedException if no suitable message converter is found */ @SuppressWarnings("unchecked") - protected Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter methodParam, - Type targetType) throws IOException, HttpMediaTypeNotSupportedException { + protected Object readWithMessageConverters(HttpInputMessage inputMessage, + MethodParameter methodParam, Type targetType) throws IOException, HttpMediaTypeNotSupportedException { MediaType contentType; try { @@ -171,14 +175,38 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements } /** - * Whether to raise a handler method invocation exception on validation errors. - * @param parameter the method argument + * Validate the request part if applicable. + *

The default implementation checks for {@code @javax.validation.Valid}, + * Spring's {@link org.springframework.validation.annotation.Validated}, + * and custom annotations whose name starts with "Valid". + * @param binder the DataBinder to be used + * @param methodParam the method parameter + * @see #isBindExceptionRequired + * @since 4.1.5 + */ + protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) { + Annotation[] annotations = methodParam.getParameterAnnotations(); + for (Annotation ann : annotations) { + Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); + if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { + Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann)); + Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); + binder.validate(validationHints); + break; + } + } + } + + /** + * Whether to raise a fatal bind exception on validation errors. + * @param binder the data binder used to perform data binding + * @param methodParam the method argument * @return {@code true} if the next method argument is not of type {@link Errors} * @since 4.1.5 */ - protected boolean isBindingErrorFatal(MethodParameter parameter) { - int i = parameter.getParameterIndex(); - Class[] paramTypes = parameter.getMethod().getParameterTypes(); + protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) { + int i = methodParam.getParameterIndex(); + Class[] paramTypes = methodParam.getMethod().getParameterTypes(); boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1])); return !hasBindingResult; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java index 9adf177dccc..69982f7c7b6 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java @@ -16,7 +16,6 @@ package org.springframework.web.servlet.mvc.method.annotation; -import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -26,14 +25,11 @@ import javax.servlet.http.Part; import org.springframework.core.GenericCollectionTypeResolver; 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.lang.UsesJava8; import org.springframework.util.Assert; import org.springframework.validation.BindingResult; -import org.springframework.validation.Errors; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.RequestBody; @@ -86,9 +82,9 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM /** * Supports the following: *

    - *
  • Annotated with {@code @RequestPart} - *
  • Of type {@link MultipartFile} unless annotated with {@code @RequestParam}. - *
  • Of type {@code javax.servlet.http.Part} unless annotated with {@code @RequestParam}. + *
  • annotated with {@code @RequestPart} + *
  • of type {@link MultipartFile} unless annotated with {@code @RequestParam} + *
  • of type {@code javax.servlet.http.Part} unless annotated with {@code @RequestParam} *
*/ @Override @@ -164,7 +160,10 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM arg = readWithMessageConverters(inputMessage, parameter, parameter.getNestedGenericParameterType()); WebDataBinder binder = binderFactory.createBinder(request, arg, partName); if (arg != null) { - validate(binder, parameter); + validateIfApplicable(binder, parameter); + if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { + throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); + } } mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + partName, binder.getBindingResult()); } @@ -174,8 +173,8 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM } } - RequestPart annot = parameter.getParameterAnnotation(RequestPart.class); - boolean isRequired = ((annot == null || annot.required()) && !optional); + RequestPart ann = parameter.getParameterAnnotation(RequestPart.class); + boolean isRequired = ((ann == null || ann.required()) && !optional); if (arg == null && isRequired) { throw new MissingServletRequestPartException(partName); @@ -194,44 +193,44 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM } } - private String getPartName(MethodParameter param) { - RequestPart annot = param.getParameterAnnotation(RequestPart.class); - String partName = (annot != null ? annot.value() : ""); + private String getPartName(MethodParameter methodParam) { + RequestPart ann = methodParam.getParameterAnnotation(RequestPart.class); + String partName = (ann != null ? ann.value() : ""); if (partName.length() == 0) { - partName = param.getParameterName(); + partName = methodParam.getParameterName(); if (partName == null) { throw new IllegalArgumentException("Request part name for argument type [" + - param.getNestedParameterType().getName() + + methodParam.getNestedParameterType().getName() + "] not specified, and parameter name information not found in class file either."); } } return partName; } - private boolean isMultipartFileCollection(MethodParameter param) { - Class collectionType = getCollectionParameterType(param); - return (collectionType != null && collectionType.equals(MultipartFile.class)); + private boolean isMultipartFileCollection(MethodParameter methodParam) { + Class collectionType = getCollectionParameterType(methodParam); + return MultipartFile.class.equals(collectionType); } - private boolean isMultipartFileArray(MethodParameter param) { - Class paramType = param.getNestedParameterType().getComponentType(); - return (paramType != null && MultipartFile.class.equals(paramType)); + private boolean isMultipartFileArray(MethodParameter methodParam) { + Class paramType = methodParam.getNestedParameterType().getComponentType(); + return MultipartFile.class.equals(paramType); } - private boolean isPartCollection(MethodParameter param) { - Class collectionType = getCollectionParameterType(param); + private boolean isPartCollection(MethodParameter methodParam) { + Class collectionType = getCollectionParameterType(methodParam); return (collectionType != null && "javax.servlet.http.Part".equals(collectionType.getName())); } - private boolean isPartArray(MethodParameter param) { - Class paramType = param.getNestedParameterType().getComponentType(); + private boolean isPartArray(MethodParameter methodParam) { + Class paramType = methodParam.getNestedParameterType().getComponentType(); return (paramType != null && "javax.servlet.http.Part".equals(paramType.getName())); } - private Class getCollectionParameterType(MethodParameter param) { - Class paramType = param.getNestedParameterType(); + private Class getCollectionParameterType(MethodParameter methodParam) { + Class paramType = methodParam.getNestedParameterType(); if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){ - Class valueType = GenericCollectionTypeResolver.getCollectionParameterType(param); + Class valueType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam); if (valueType != null) { return valueType; } @@ -239,35 +238,6 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM return null; } - /** - * Validate the request part if applicable. - *

The default implementation checks for {@code @javax.validation.Valid}, - * Spring's {@link org.springframework.validation.annotation.Validated}, - * and custom annotations whose name starts with "Valid". - * @param binder the DataBinder to be used - * @param param the method parameter - * @throws MethodArgumentNotValidException in case of a binding error which - * is meant to be fatal (i.e. without a declared {@link Errors} parameter) - * @see #isBindingErrorFatal - */ - protected void validate(WebDataBinder binder, MethodParameter param) throws MethodArgumentNotValidException { - Annotation[] annotations = param.getParameterAnnotations(); - for (Annotation ann : annotations) { - Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); - if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { - Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann)); - Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); - binder.validate(validationHints); - BindingResult bindingResult = binder.getBindingResult(); - if (bindingResult.hasErrors()) { - if (isBindingErrorFatal(param)) { - throw new MethodArgumentNotValidException(param, bindingResult); - } - } - } - } - } - /** * Inner class to avoid hard-coded dependency on Servlet 3.0 Part type... diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java index dd26ddc343e..a99dfcbf072 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java @@ -19,7 +19,6 @@ 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; @@ -32,8 +31,6 @@ 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.validation.annotation.Validated; import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.accept.ContentNegotiationManager; @@ -47,16 +44,14 @@ import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; /** - * Resolves method arguments annotated with {@code @RequestBody} and handles - * return values from methods annotated with {@code @ResponseBody} by reading - * and writing to the body of the request or response with an - * {@link HttpMessageConverter}. + * Resolves method arguments annotated with {@code @RequestBody} and handles return + * values from methods annotated with {@code @ResponseBody} by reading and writing + * to the body of the request or response with an {@link HttpMessageConverter}. * - *

An {@code @RequestBody} method argument is also validated if it is - * annotated with {@code @javax.validation.Valid}. In case of validation - * failure, {@link MethodArgumentNotValidException} is raised and results - * in a 400 response status code if {@link DefaultHandlerExceptionResolver} - * is configured. + *

An {@code @RequestBody} method argument is also validated if it is annotated + * with {@code @javax.validation.Valid}. In case of validation failure, + * {@link MethodArgumentNotValidException} is raised and results in a 400 response + * status code if {@link DefaultHandlerExceptionResolver} is configured. * * @author Arjen Poutsma * @author Rossen Stoyanchev @@ -102,44 +97,17 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { - Object argument = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType()); + Object arg = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType()); String name = Conventions.getVariableNameForParameter(parameter); - WebDataBinder binder = binderFactory.createBinder(webRequest, argument, name); - if (argument != null) { - validate(binder, parameter); - } - mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); - return argument; - } - - /** - * Validate the request part if applicable. - *

The default implementation checks for {@code @javax.validation.Valid}, - * Spring's {@link org.springframework.validation.annotation.Validated}, - * and custom annotations whose name starts with "Valid". - * @param binder the DataBinder to be used - * @param parameter the method parameter - * @throws MethodArgumentNotValidException in case of a binding error which - * is meant to be fatal (i.e. without a declared {@link Errors} parameter) - * @see #isBindingErrorFatal - */ - protected void validate(WebDataBinder binder, MethodParameter parameter) throws MethodArgumentNotValidException { - Annotation[] annotations = parameter.getParameterAnnotations(); - for (Annotation ann : annotations) { - Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); - if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { - Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann)); - Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); - binder.validate(validationHints); - BindingResult bindingResult = binder.getBindingResult(); - if (bindingResult.hasErrors()) { - if (isBindingErrorFatal(parameter)) { - throw new MethodArgumentNotValidException(parameter, bindingResult); - } - } - break; + WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); + if (arg != null) { + validateIfApplicable(binder, parameter); + if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { + throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } } + mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); + return arg; } @Override diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java index e17eec5cbfe..6fcea9d5489 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.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. @@ -50,7 +50,7 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr /** * @param annotationNotRequired if "true", non-simple method arguments and * return values are considered model attributes with or without a - * {@code @ModelAttribute} annotation. + * {@code @ModelAttribute} annotation */ public ServletModelAttributeMethodProcessor(boolean annotationNotRequired) { super(annotationNotRequired); @@ -62,21 +62,22 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr * request parameter if the name matches to the model attribute name and * if there is an appropriate type conversion strategy. If none of these * are true delegate back to the base class. - * @see #createAttributeFromRequestValue(String, String, MethodParameter, WebDataBinderFactory, NativeWebRequest) + * @see #createAttributeFromRequestValue */ @Override - protected final Object createAttribute(String attributeName, MethodParameter parameter, + protected final Object createAttribute(String attributeName, MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { String value = getRequestValueForAttribute(attributeName, request); if (value != null) { - Object attribute = createAttributeFromRequestValue(value, attributeName, parameter, binderFactory, request); + Object attribute = createAttributeFromRequestValue( + value, attributeName, methodParam, binderFactory, request); if (attribute != null) { return attribute; } } - return super.createAttribute(attributeName, parameter, binderFactory, request); + return super.createAttribute(attributeName, methodParam, binderFactory, request); } /** @@ -103,9 +104,8 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr @SuppressWarnings("unchecked") protected final Map getUriTemplateVariables(NativeWebRequest request) { - Map variables = - (Map) request.getAttribute( - HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); + Map variables = (Map) request.getAttribute( + HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); return (variables != null ? variables : Collections.emptyMap()); } @@ -116,23 +116,23 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr * {@link Converter} that can perform the conversion. * @param sourceValue the source value to create the model attribute from * @param attributeName the name of the attribute, never {@code null} - * @param parameter the method parameter + * @param methodParam the method parameter * @param binderFactory for creating WebDataBinder instance * @param request the current request * @return the created model attribute, or {@code null} * @throws Exception */ protected Object createAttributeFromRequestValue(String sourceValue, String attributeName, - MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request) + MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { DataBinder binder = binderFactory.createBinder(request, null, attributeName); ConversionService conversionService = binder.getConversionService(); if (conversionService != null) { TypeDescriptor source = TypeDescriptor.valueOf(String.class); - TypeDescriptor target = new TypeDescriptor(parameter); + TypeDescriptor target = new TypeDescriptor(methodParam); if (conversionService.canConvert(source, target)) { - return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter); + return binder.convertIfNecessary(sourceValue, methodParam.getParameterType(), methodParam); } } return null;