|
Spring Framework example source code file (HandlerMethodInvoker.java)
The Spring Framework HandlerMethodInvoker.java source code/* * Copyright 2002-2008 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.bind.annotation.support; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanUtils; import org.springframework.core.Conventions; import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.ui.ExtendedModelMap; import org.springframework.ui.Model; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.support.DefaultSessionAttributeStore; import org.springframework.web.bind.support.SessionAttributeStore; import org.springframework.web.bind.support.SessionStatus; import org.springframework.web.bind.support.SimpleSessionStatus; import org.springframework.web.bind.support.WebArgumentResolver; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.bind.support.WebRequestDataBinder; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.multipart.MultipartRequest; /** * Support class for invoking an annotated handler method. * Operates on the introspection results of a {@link HandlerMethodResolver} * for a specific handler type. * * <p>Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} * and {@link org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}. * * @author Juergen Hoeller * @since 2.5.2 * @see #invokeHandlerMethod */ public class HandlerMethodInvoker { /** * We'll create a lot of these objects, so we don't want a new logger every time. */ private static final Log logger = LogFactory.getLog(HandlerMethodInvoker.class); private final HandlerMethodResolver methodResolver; private final WebBindingInitializer bindingInitializer; private final SessionAttributeStore sessionAttributeStore; private final ParameterNameDiscoverer parameterNameDiscoverer; private final WebArgumentResolver[] customArgumentResolvers; private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus(); public HandlerMethodInvoker(HandlerMethodResolver methodResolver) { this(methodResolver, null); } public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer) { this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null); } public HandlerMethodInvoker( HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer, SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer, WebArgumentResolver... customArgumentResolvers) { this.methodResolver = methodResolver; this.bindingInitializer = bindingInitializer; this.sessionAttributeStore = sessionAttributeStore; this.parameterNameDiscoverer = parameterNameDiscoverer; this.customArgumentResolvers = customArgumentResolvers; } public final Object invokeHandlerMethod( Method handlerMethod, Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { boolean debug = logger.isDebugEnabled(); for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { Object[] args = resolveHandlerArguments(attributeMethod, handler, webRequest, implicitModel); if (debug) { logger.debug("Invoking model attribute method: " + attributeMethod); } Object attrValue = doInvokeMethod(attributeMethod, handler, args); String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); if ("".equals(attrName)) { Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethod, handler.getClass()); attrName = Conventions.getVariableNameForReturnType(attributeMethod, resolvedType, attrValue); } implicitModel.addAttribute(attrName, attrValue); } Object[] args = resolveHandlerArguments(handlerMethod, handler, webRequest, implicitModel); if (debug) { logger.debug("Invoking request handler method: " + handlerMethod); } return doInvokeMethod(handlerMethod, handler, args); } @SuppressWarnings("unchecked") private Object[] resolveHandlerArguments( Method handlerMethod, Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { Class[] paramTypes = handlerMethod.getParameterTypes(); Object[] args = new Object[paramTypes.length]; for (int i = 0; i < args.length; i++) { MethodParameter methodParam = new MethodParameter(handlerMethod, i); methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); String paramName = null; boolean paramRequired = false; String attrName = null; Object[] paramAnns = methodParam.getParameterAnnotations(); for (int j = 0; j < paramAnns.length; j++) { Object paramAnn = paramAnns[j]; if (RequestParam.class.isInstance(paramAnn)) { RequestParam requestParam = (RequestParam) paramAnn; paramName = requestParam.value(); paramRequired = requestParam.required(); break; } else if (ModelAttribute.class.isInstance(paramAnn)) { ModelAttribute attr = (ModelAttribute) paramAnn; attrName = attr.value(); } } if (paramName != null && attrName != null) { throw new IllegalStateException("@RequestParam and @ModelAttribute are an exclusive choice -" + "do not specify both on the same parameter: " + handlerMethod); } Class paramType = methodParam.getParameterType(); if (paramName == null && attrName == null) { Object argValue = resolveCommonArgument(methodParam, webRequest); if (argValue != WebArgumentResolver.UNRESOLVED) { args[i] = argValue; } else { if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) { args[i] = implicitModel; } else if (SessionStatus.class.isAssignableFrom(paramType)) { args[i] = this.sessionStatus; } else if (Errors.class.isAssignableFrom(paramType)) { throw new IllegalStateException("Errors/BindingResult argument declared " + "without preceding model attribute. Check your handler method signature!"); } else if (BeanUtils.isSimpleProperty(paramType)) { paramName = ""; } else { attrName = ""; } } } if (paramName != null) { args[i] = resolveRequestParam(paramName, paramRequired, methodParam, webRequest, handler); } else if (attrName != null) { WebDataBinder binder = resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); if (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1])) { doBind(webRequest, binder, false); args[i] = binder.getTarget(); args[i + 1] = binder.getBindingResult(); i++; } else { doBind(webRequest, binder, true); args[i] = binder.getTarget(); } implicitModel.putAll(binder.getBindingResult().getModel()); } } return args; } private void initBinder(Object handler, String attrName, WebDataBinder binder, NativeWebRequest webRequest) throws Exception { if (this.bindingInitializer != null) { this.bindingInitializer.initBinder(binder, webRequest); } if (handler != null) { Set<Method> initBinderMethods = this.methodResolver.getInitBinderMethods(); if (!initBinderMethods.isEmpty()) { boolean debug = logger.isDebugEnabled(); for (Method initBinderMethod : initBinderMethods) { String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value(); if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) { Object[] initBinderArgs = resolveInitBinderArguments(handler, initBinderMethod, binder, webRequest); if (debug) { logger.debug("Invoking init-binder method: " + initBinderMethod); } Object returnValue = doInvokeMethod(initBinderMethod, handler, initBinderArgs); if (returnValue != null) { throw new IllegalStateException( "InitBinder methods must not have a return value: " + initBinderMethod); } } } } } } private Object[] resolveInitBinderArguments(Object handler, Method initBinderMethod, WebDataBinder binder, NativeWebRequest webRequest) throws Exception { Class[] initBinderParams = initBinderMethod.getParameterTypes(); Object[] initBinderArgs = new Object[initBinderParams.length]; for (int i = 0; i < initBinderArgs.length; i++) { MethodParameter methodParam = new MethodParameter(initBinderMethod, i); methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); String paramName = null; boolean paramRequired = false; Object[] paramAnns = methodParam.getParameterAnnotations(); for (int j = 0; j < paramAnns.length; j++) { Object paramAnn = paramAnns[j]; if (RequestParam.class.isInstance(paramAnn)) { RequestParam requestParam = (RequestParam) paramAnn; paramName = requestParam.value(); paramRequired = requestParam.required(); break; } else if (ModelAttribute.class.isInstance(paramAnn)) { throw new IllegalStateException( "@ModelAttribute is not supported on @InitBinder methods: " + initBinderMethod); } } if (paramName == null) { Object argValue = resolveCommonArgument(methodParam, webRequest); if (argValue != WebArgumentResolver.UNRESOLVED) { initBinderArgs[i] = argValue; } else { Class paramType = initBinderParams[i]; if (paramType.isInstance(binder)) { initBinderArgs[i] = binder; } else if (BeanUtils.isSimpleProperty(paramType)) { paramName = ""; } else { throw new IllegalStateException("Unsupported argument [" + paramType.getName() + "] for @InitBinder method: " + initBinderMethod); } } } if (paramName != null) { initBinderArgs[i] = resolveRequestParam(paramName, paramRequired, methodParam, webRequest, null); } } return initBinderArgs; } private Object resolveRequestParam(String paramName, boolean paramRequired, MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { Class paramType = methodParam.getParameterType(); if ("".equals(paramName)) { paramName = methodParam.getParameterName(); if (paramName == null) { throw new IllegalStateException("No parameter specified for @RequestParam argument of type [" + paramType.getName() + "], and no parameter name information found in class file either."); } } Object paramValue = null; if (webRequest.getNativeRequest() instanceof MultipartRequest) { paramValue = ((MultipartRequest) webRequest.getNativeRequest()).getFile(paramName); } if (paramValue == null) { String[] paramValues = webRequest.getParameterValues(paramName); if (paramValues != null) { paramValue = (paramValues.length == 1 ? paramValues[0] : paramValues); } } if (paramValue == null) { if (paramRequired) { raiseMissingParameterException(paramName, paramType); } if (paramType.isPrimitive()) { throw new IllegalStateException("Optional " + paramType + " parameter '" + paramName + "' is not present but cannot be translated into a null value due to being declared as a " + "primitive type. Consider declaring it as object wrapper for the corresponding primitive type."); } } WebDataBinder binder = createBinder(webRequest, null, paramName); initBinder(handlerForInitBinderCall, paramName, binder, webRequest); return binder.convertIfNecessary(paramValue, paramType, methodParam); } private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { // Bind request parameter onto object... if ("".equals(attrName)) { attrName = Conventions.getVariableNameForParameter(methodParam); } Class paramType = methodParam.getParameterType(); if (!implicitModel.containsKey(attrName) && this.methodResolver.isSessionAttribute(attrName, paramType)) { Object sessionAttr = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); if (sessionAttr == null) { raiseSessionRequiredException("Session attribute '" + attrName + "' required - not found in session"); } implicitModel.addAttribute(attrName, sessionAttr); } Object bindObject = implicitModel.get(attrName); if (bindObject == null) { bindObject = BeanUtils.instantiateClass(paramType); } WebDataBinder binder = createBinder(webRequest, bindObject, attrName); initBinder(handler, attrName, binder, webRequest); return binder; } @SuppressWarnings("unchecked") public final void updateModelAttributes( Object handler, Map mavModel, ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception { if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) { for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { this.sessionAttributeStore.cleanupAttribute(webRequest, attrName); } } // Expose model attributes as session attributes, if required. // Expose BindingResults for all attributes, making custom editors available. Map<String, Object> model = (mavModel != null ? mavModel : implicitModel); for (Map.Entry<String, Object> entry : new HashSet Other Spring Framework examples (source code examples)Here is a short list of links related to this Spring Framework HandlerMethodInvoker.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.