/* * Copyright 2008 biaoping.yin * * 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.frameworkset.web.servlet.handler.annotations; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.servlet.jsp.PageContext; import org.apache.log4j.Logger; import org.frameworkset.http.converter.HttpMessageConverter; import org.frameworkset.util.AntPathMatcher; import org.frameworkset.util.Assert; import org.frameworkset.util.ParameterNameDiscoverer; import org.frameworkset.util.PathMatcher; import org.frameworkset.util.annotations.SessionAttributes; import org.frameworkset.web.servlet.HandlerAdapter; import org.frameworkset.web.servlet.ModelAndView; import org.frameworkset.web.servlet.handler.HandlerMeta; import org.frameworkset.web.servlet.handler.HandlerUtils; import org.frameworkset.web.servlet.handler.HandlerUtils.ServletHandlerMethodResolver; import org.frameworkset.web.servlet.mvc.MethodNameResolver; import org.frameworkset.web.servlet.mvc.mutiaction.InternalPathMethodNameResolver; import org.frameworkset.web.servlet.support.WebArgumentResolver; import org.frameworkset.web.servlet.support.WebContentGenerator; import org.frameworkset.web.servlet.support.session.DefaultSessionAttributeStore; import org.frameworkset.web.servlet.support.session.SessionAttributeStore; import org.frameworkset.web.util.UrlPathHelper; import org.frameworkset.web.util.WebUtils; /** * <p>Title: AnnotationMethodHandlerAdapter.java</p> * <p>Description: </p> * <p>bboss workgroup</p> * <p>Copyright (c) 2008</p> * @Date 2010-10-23 * @author biaoping.yin * @version 1.0 */ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implements HandlerAdapter{ /** * Log category to use when no mapped handler is found for a request. * @see #pageNotFoundLogger */ public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.frameworkset.web.servlet.PageNotFound"; /** * Additional logger to use when no mapped handler is found for a request. * @see #PAGE_NOT_FOUND_LOG_CATEGORY */ protected final static Logger pageNotFoundLogger = Logger.getLogger(PAGE_NOT_FOUND_LOG_CATEGORY); // protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY); private UrlPathHelper urlPathHelper = new UrlPathHelper(); private PathMatcher pathMatcher = new AntPathMatcher(); protected HttpMessageConverter[] messageConverters; private MethodNameResolver methodNameResolver = new InternalPathMethodNameResolver(); // private WebBindingInitializer webBindingInitializer; private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore(); private int cacheSecondsForSessionAttributeHandlers = 0; private boolean synchronizeOnSession = false; // private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); private ParameterNameDiscoverer parameterNameDiscoverer = null; private WebArgumentResolver[] customArgumentResolvers; private Map<Class<?>, ServletHandlerMethodResolver> methodResolverCache = new ConcurrentHashMap<Class<?>, ServletHandlerMethodResolver>(); public AnnotationMethodHandlerAdapter() { // no restriction of HTTP methods by default super(false); setAlwaysUseFullPath(true) ; } /** * Set if URL lookup should always use the full path within the current servlet * context. Else, the path within the current servlet mapping is used if applicable * (that is, in the case of a ".../*" servlet mapping in web.xml). * <p>Default is "false". * @see org.frameworkset.web.util.UrlPathHelper#setAlwaysUseFullPath */ public void setAlwaysUseFullPath(boolean alwaysUseFullPath) { this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath); } /** * Set if context path and request URI should be URL-decoded. Both are returned * <i>undecoded</i> by the Servlet API, in contrast to the servlet path. * <p>Uses either the request encoding or the default encoding according * to the Servlet spec (ISO-8859-1). * @see org.frameworkset.web.util.UrlPathHelper#setUrlDecode */ public void setUrlDecode(boolean urlDecode) { this.urlPathHelper.setUrlDecode(urlDecode); } /** * Set the UrlPathHelper to use for resolution of lookup paths. * <p>Use this to override the default UrlPathHelper with a custom subclass, * or to share common UrlPathHelper settings across multiple HandlerMappings * and HandlerAdapters. */ public void setUrlPathHelper(UrlPathHelper urlPathHelper) { Assert.notNull(urlPathHelper, "UrlPathHelper must not be null"); this.urlPathHelper = urlPathHelper; } /** * Set the PathMatcher implementation to use for matching URL paths * against registered URL patterns. Default is AntPathMatcher. * @see org.frameworkset.web.util.AntPathMatcher */ public void setPathMatcher(PathMatcher pathMatcher) { Assert.notNull(pathMatcher, "PathMatcher must not be null"); this.pathMatcher = pathMatcher; } /** * Set the MethodNameResolver to use for resolving default handler methods * (carrying an empty <code>@HandlerMapping</code> annotation). * <p>Will only kick in when the handler method cannot be resolved uniquely * through the annotation metadata already. */ public void setMethodNameResolver(MethodNameResolver methodNameResolver) { this.methodNameResolver = methodNameResolver; } // /** // * Specify a WebBindingInitializer which will apply pre-configured // * configuration to every DataBinder that this controller uses. // */ // public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) { // this.webBindingInitializer = webBindingInitializer; // } /** * Specify the strategy to store session attributes with. * <p>Default is {@link org.frameworkset.web.servlet.support.session.DefaultSessionAttributeStore}, * storing session attributes in the HttpSession, using the same * attribute name as in the model. */ public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) { Assert.notNull(sessionAttributeStore, "SessionAttributeStore must not be null"); this.sessionAttributeStore = sessionAttributeStore; } /** * Cache content produced by <code>@SessionAttributes</code> annotated handlers * for the given number of seconds. Default is 0, preventing caching completely. * <p>In contrast to the "cacheSeconds" property which will apply to all general * handlers (but not to <code>@SessionAttributes</code> annotated handlers), this * setting will apply to <code>@SessionAttributes</code> annotated handlers only. * @see #setCacheSeconds */ public void setCacheSecondsForSessionAttributeHandlers(int cacheSecondsForSessionAttributeHandlers) { this.cacheSecondsForSessionAttributeHandlers = cacheSecondsForSessionAttributeHandlers; } /** * Set if controller execution should be synchronized on the session, * to serialize parallel invocations from the same client. * <p>More specifically, the execution of each handler method will get * synchronized if this flag is "true". The best available session mutex * will be used for the synchronization; ideally, this will be a mutex * exposed by HttpSessionMutexListener. * <p>The session mutex is guaranteed to be the same object during * the entire lifetime of the session, available under the key defined * by the <code>SESSION_MUTEX_ATTRIBUTE</code> constant. It serves as a * safe reference to synchronize on for locking on the current session. * <p>In many cases, the HttpSession reference itself is a safe mutex * as well, since it will always be the same object reference for the * same active logical session. However, this is not guaranteed across * different servlet containers; the only 100% safe way is a session mutex. */ public void setSynchronizeOnSession(boolean synchronizeOnSession) { this.synchronizeOnSession = synchronizeOnSession; } /** * Set the ParameterNameDiscoverer to use for resolving method parameter * names if needed (e.g. for default attribute names). * <p>Default is a {@link org.frameworkset.spi.support.LocalVariableTableParameterNameDiscoverer}. */ public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) { this.parameterNameDiscoverer = parameterNameDiscoverer; } /** * Set a custom ArgumentResolvers to use for special method parameter types. * Such a custom ArgumentResolver will kick in first, having a chance to * resolve an argument value before the standard argument handling kicks in. */ public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) { this.customArgumentResolvers = new WebArgumentResolver[] {argumentResolver}; } /** * Set one or more custom ArgumentResolvers to use for special method * parameter types. Any such custom ArgumentResolver will kick in first, * having a chance to resolve an argument value before the standard * argument handling kicks in. */ public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) { this.customArgumentResolvers = argumentResolvers; } public boolean supports(HandlerMeta handler) { return !handler.isWebsocket() && getMethodResolver(handler.getHandlerClass()).hasHandlerMethods(); } public boolean hasHandlerMethods(Class handler) { return getMethodResolver(handler).hasHandlerMethods(); } public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, PageContext pageContext,HandlerMeta handler) throws Exception { if (handler.getHandlerClass().getAnnotation(SessionAttributes.class) != null) { // Always prevent caching in case of session attribute management. checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); // Prepare cached set of session attributes names. } else { // Uses configured default cacheSeconds setting. checkAndPrepare(request, response, true); } // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { return invokeHandlerMethod(request, response, pageContext,handler); } } } return invokeHandlerMethod(request, response, pageContext,handler); } protected ModelAndView invokeHandlerMethod( HttpServletRequest request, HttpServletResponse response, PageContext pageContext,HandlerMeta handler) throws Exception { // try { // ServletHandlerMethodResolver methodResolver = getMethodResolver(handler.getClass()); // MethodData handlerMethod = methodResolver.resolveHandlerMethod(request); // ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver); // ServletWebRequest webRequest = new ServletWebRequest(request, response); // ModelMap implicitModel = new ModelMap(); // // Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, request, response, pageContext,implicitModel); // ModelAndView mav = // methodInvoker.getModelAndView(handlerMethod.getMethodInfo(), handler.getClass(), result, implicitModel, webRequest); //// methodInvoker.updateModelAttributes( //// handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); // return mav; // } // catch (NoSuchRequestHandlingMethodException ex) { // return handleNoSuchRequestHandlingMethod(ex, request, response); // } ServletHandlerMethodResolver methodResolver = getMethodResolver(handler.getHandlerClass()); return HandlerUtils.invokeHandlerMethod(request, response, pageContext, handler, methodResolver,messageConverters); } /** * Build a HandlerMethodResolver for the given handler type. */ public ServletHandlerMethodResolver getMethodResolver(Class handlerClass) { // Class handlerClass = ClassUtils.getUserClass(handler); ServletHandlerMethodResolver resolver = (org.frameworkset.web.servlet.handler.HandlerUtils.ServletHandlerMethodResolver) methodResolverCache.get(handlerClass); if (resolver == null) { resolver = new ServletHandlerMethodResolver(handlerClass, urlPathHelper, pathMatcher, methodNameResolver); methodResolverCache.put(handlerClass, resolver); } return resolver; } // protected ModelAndView invokeHandlerMethod( // HttpServletRequest request, HttpServletResponse response, PageContext pageContext,Object handler) throws Exception { // // try { // ServletHandlerMethodResolver methodResolver = getMethodResolver(handler.getClass()); // MethodData handlerMethod = methodResolver.resolveHandlerMethod(request); // ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver); // ServletWebRequest webRequest = new ServletWebRequest(request, response); // ModelMap implicitModel = new ModelMap(); // // Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, request, response, pageContext,implicitModel); // ModelAndView mav = // methodInvoker.getModelAndView(handlerMethod.getMethodInfo(), handler.getClass(), result, implicitModel, webRequest); //// methodInvoker.updateModelAttributes( //// handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); // return mav; // } // catch (NoSuchRequestHandlingMethodException ex) { // return handleNoSuchRequestHandlingMethod(ex, request, response); // } // } public long getLastModified(HttpServletRequest request, HandlerMeta handler) { return -1; } public void setMessageConverters(HttpMessageConverter[] messageConverters) { this.messageConverters = messageConverters; } public boolean containMessageConverters() { return this.messageConverters != null && this.messageConverters.length > 0; } @Override public void destroy() { if(methodNameResolver != null) { this.methodNameResolver.destroy(); methodNameResolver = null; } this.messageConverters = null; if(methodResolverCache != null) { Iterator<Entry<Class<?>, ServletHandlerMethodResolver>> it = this.methodResolverCache.entrySet().iterator(); while(it.hasNext()) { Entry<Class<?>, ServletHandlerMethodResolver> entry = it.next(); entry.getValue().destroy(); } this.methodResolverCache.clear(); methodResolverCache = null; } } // /** // * Handle the case where no request handler method was found. // * <p>The default implementation logs a warning and sends an HTTP 404 error. // * Alternatively, a fallback view could be chosen, or the // * NoSuchRequestHandlingMethodException could be rethrown as-is. // * @param ex the NoSuchRequestHandlingMethodException to be handled // * @param request current HTTP request // * @param response current HTTP response // * @return a ModelAndView to render, or <code>null</code> if handled directly // * @throws Exception an Exception that should be thrown as result of the servlet request // */ // protected ModelAndView handleNoSuchRequestHandlingMethod( // NoSuchRequestHandlingMethodException ex, HttpServletRequest request, HttpServletResponse response) // throws Exception { // // pageNotFoundLogger.warn(ex.getMessage()); // response.sendError(HttpServletResponse.SC_NOT_FOUND); // return null; // } // /** // * Template method for creating a new ServletRequestDataBinder instance. // * <p>The default implementation creates a standard ServletRequestDataBinder. // * This can be overridden for custom ServletRequestDataBinder subclasses. // * @param request current HTTP request // * @param target the target object to bind onto (or <code>null</code> // * if the binder is just used to convert a plain parameter value) // * @param objectName the objectName of the target object // * @return the ServletRequestDataBinder instance to use // * @throws Exception in case of invalid state or arguments // * @see ServletRequestDataBinder#bind(javax.servlet.ServletRequest) // * @see ServletRequestDataBinder#convertIfNecessary(Object, Class, MethodParameter) // */ // protected ServletRequestDataBinder createBinder( // HttpServletRequest request, Object target, String objectName) throws Exception { // // return new ServletRequestDataBinder(target, objectName); // } // // /** // * Build a HandlerMethodResolver for the given handler type. // */ // private ServletHandlerMethodResolver getMethodResolver(Class handlerClass) { //// Class handlerClass = ClassUtils.getUserClass(handler); // // ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass); // if (resolver == null) { // resolver = new ServletHandlerMethodResolver(handlerClass); // this.methodResolverCache.put(handlerClass, resolver); // } // return resolver; // } // // // private class ServletHandlerMethodResolver extends HandlerMethodResolver { // // public ServletHandlerMethodResolver(Class<?> handlerType) { // super(handlerType); // } // // // public MethodData resolveHandlerMethod(HttpServletRequest request) throws ServletException { // String lookupPath = urlPathHelper.getLookupPathForRequest(request); // Map<HandlerMappingInfo, MethodInfo> targetHandlerMethods = new LinkedHashMap<HandlerMappingInfo, MethodInfo>(); // Map<HandlerMappingInfo, String> targetPathMatches = new LinkedHashMap<HandlerMappingInfo, String>(); // // // // String resolvedMethodName = methodNameResolver.getHandlerMethodName(request); // // for (MethodInfo handlerMethod : getHandlerMethods()) { // HandlerMappingInfo mappingInfo = new HandlerMappingInfo(); // HandlerMapping mapping = handlerMethod.getMethodMapping(); // if(mapping == null) // { // if(resolvedMethodName.equals(handlerMethod.getMethod().getName())) // { // String path_ = (String)request.getAttribute(org.frameworkset.web.servlet.HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); // Map pathdatas = AnnotationUtils.resolvePathDatas(handlerMethod, path_); // // MethodData methodData = new MethodData(handlerMethod,pathdatas); // // return methodData; // } // continue; // } // mappingInfo.paths = handlerMethod.getPathPattern(); // if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) { // mappingInfo.methods = mapping.method(); // } // if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) { // mappingInfo.params = mapping.params(); // } // boolean match = false; // if (handlerMethod.getPathPattern() != null && handlerMethod.getPathPattern().length > 0) { // for (String mappedPath : handlerMethod.getPathPattern()) { // if (isPathMatch(mappedPath, lookupPath)) { // if (checkParameters(mappingInfo, request)) { // match = true; // targetPathMatches.put(mappingInfo, mappedPath); // } // else { // break; // } // } // } // } // else { // // No paths specified: parameter match sufficient. // match = checkParameters(mappingInfo, request); //// if (match && mappingInfo.methods.length == 0 && mappingInfo.params.length == 0 && //// resolvedMethodName != null && !resolvedMethodName.equals(handlerMethod.getMethod().getName())) { //// match = false; //// } // } // if (match) { // MethodInfo oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod); // if(oldMappedMethod != null) // throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + // lookupPath + "': {" + oldMappedMethod + ", " + handlerMethod + // "}. If you intend to handle the same path in multiple methods, then factor " + // "them out into a dedicated handler class with that path mapped at the type level!"); //// if (oldMappedMethod != null && oldMappedMethod != handlerMethod.getMethod()) { //// if (methodNameResolver != null && mappingInfo.paths.length == 0) { //// if (!oldMappedMethod.getName().equals(handlerMethod.getMethod().getName())) { //// if (resolvedMethodName == null) { //// resolvedMethodName = methodNameResolver.getHandlerMethodName(request); //// } //// if (!resolvedMethodName.equals(oldMappedMethod.getName())) { //// oldMappedMethod = null; //// } //// if (!resolvedMethodName.equals(handlerMethod.getMethod().getName())) { //// if (oldMappedMethod != null) { //// targetHandlerMethods.put(mappingInfo, oldMappedMethod); //// oldMappedMethod = null; //// } //// else { //// targetHandlerMethods.remove(mappingInfo); //// } //// } //// } //// } //// if (oldMappedMethod != null) { //// throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + //// lookupPath + "': {" + oldMappedMethod + ", " + handlerMethod + //// "}. If you intend to handle the same path in multiple methods, then factor " + //// "them out into a dedicated handler class with that path mapped at the type level!"); //// } //// } // } // } // if (targetHandlerMethods.size() == 1) { // MethodInfo handlerMethod = targetHandlerMethods.values().iterator().next(); // String path_ = (String)request.getAttribute(org.frameworkset.web.servlet.HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); // Map pathdatas = AnnotationUtils.resolvePathDatas(handlerMethod, path_); // // MethodData methodData = new MethodData(handlerMethod,pathdatas); // // return methodData; //// return targetHandlerMethods.values().iterator().next(); // } // else if (!targetHandlerMethods.isEmpty()) { // HandlerMappingInfo bestMappingMatch = null; // String bestPathMatch = null; // for (HandlerMappingInfo mapping : targetHandlerMethods.keySet()) { // String mappedPath = targetPathMatches.get(mapping); // if (bestMappingMatch == null) { // bestMappingMatch = mapping; // bestPathMatch = mappedPath; // } // else { // if (isBetterPathMatch(mappedPath, bestPathMatch, lookupPath) || // (!isBetterPathMatch(bestPathMatch, mappedPath, lookupPath) && // (isBetterMethodMatch(mapping, bestMappingMatch) || // (!isBetterMethodMatch(bestMappingMatch, mapping) && // isBetterParamMatch(mapping, bestMappingMatch))))) { // bestMappingMatch = mapping; // bestPathMatch = mappedPath; // } // } // } // MethodInfo handlerMethod = targetHandlerMethods.get(bestMappingMatch); // String path_ = (String)request.getAttribute(org.frameworkset.web.servlet.HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); // Map pathdatas = AnnotationUtils.resolvePathDatas(handlerMethod, path_); // // MethodData methodData = new MethodData(handlerMethod,pathdatas); // // return methodData; //// return targetHandlerMethods.get(bestMappingMatch); // } // else { // throw new NoSuchRequestHandlingMethodException(lookupPath, request.getMethod(), request.getParameterMap()); // } // } // // private boolean isPathMatch(String mappedPath, String lookupPath) { // if (mappedPath.equals(lookupPath) || pathMatcher.match(mappedPath, lookupPath)) { // return true; // } // boolean hasSuffix = (mappedPath.indexOf('.') != -1); // if (!hasSuffix && pathMatcher.match(mappedPath + ".*", lookupPath)) { // return true; // } // return (!mappedPath.startsWith("/") && // (lookupPath.endsWith(mappedPath) || pathMatcher.match("/**/" + mappedPath, lookupPath) || // (!hasSuffix && pathMatcher.match("/**/" + mappedPath + ".*", lookupPath)))); // } // // private boolean checkParameters(HandlerMappingInfo mapping, HttpServletRequest request) { // return ServletAnnotationMappingUtils.checkRequestMethod(mapping.methods, request) && // ServletAnnotationMappingUtils.checkParameters(mapping.params, request); // } // // private boolean isBetterPathMatch(String mappedPath, String mappedPathToCompare, String lookupPath) { // return (mappedPath != null && // (mappedPathToCompare == null || mappedPathToCompare.length() < mappedPath.length() || // (mappedPath.equals(lookupPath) && !mappedPathToCompare.equals(lookupPath)))); // } // // private boolean isBetterMethodMatch(HandlerMappingInfo mapping, HandlerMappingInfo mappingToCompare) { // return (mappingToCompare.methods.length == 0 && mapping.methods.length > 0); // } // // private boolean isBetterParamMatch(HandlerMappingInfo mapping, HandlerMappingInfo mappingToCompare) { // return (mappingToCompare.params.length < mapping.params.length); // } // } // // // private class ServletHandlerMethodInvoker extends HandlerMethodInvoker { // // private boolean responseArgumentUsed = false; // // public ServletHandlerMethodInvoker(HandlerMethodResolver resolver) { // super(resolver, webBindingInitializer, sessionAttributeStore, // parameterNameDiscoverer, customArgumentResolvers); // } // // @Override // protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { // throw new MissingServletRequestParameterException(paramName, paramType.getName()); // } // // @Override // protected void raiseSessionRequiredException(String message) throws Exception { // throw new HttpSessionRequiredException(message); // } // // @Override // protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) // throws Exception { // // return AnnotationMethodHandlerAdapter.this.createBinder( // (HttpServletRequest) webRequest.getNativeRequest(), target, objectName); // } // // @Override // protected void doBind(NativeWebRequest webRequest, WebDataBinder binder, boolean failOnErrors) // throws Exception { // // ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder; // servletBinder.bind((ServletRequest) webRequest.getNativeRequest()); // if (failOnErrors) { // servletBinder.closeNoCatch(); // } // } // // @Override // protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) // throws Exception { // // HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); // HttpServletResponse response = (HttpServletResponse) webRequest.getNativeResponse(); // // if (ServletRequest.class.isAssignableFrom(parameterType)) { // return request; // } // else if (ServletResponse.class.isAssignableFrom(parameterType)) { // this.responseArgumentUsed = true; // return response; // } // else if (HttpSession.class.isAssignableFrom(parameterType)) { // return request.getSession(); // } // else if (Principal.class.isAssignableFrom(parameterType)) { // return request.getUserPrincipal(); // } // else if (Locale.class.equals(parameterType)) { // return RequestContextUtils.getLocale(request); // } // else if (InputStream.class.isAssignableFrom(parameterType)) { // return request.getInputStream(); // } // else if (Reader.class.isAssignableFrom(parameterType)) { // return request.getReader(); // } // else if (OutputStream.class.isAssignableFrom(parameterType)) { // this.responseArgumentUsed = true; // return response.getOutputStream(); // } // else if (Writer.class.isAssignableFrom(parameterType)) { // this.responseArgumentUsed = true; // return response.getWriter(); // } // return super.resolveStandardArgument(parameterType, webRequest); // } // // @SuppressWarnings("unchecked") // public ModelAndView getModelAndView(MethodInfo handlerMethod, Class handlerType, Object returnValue, // ModelMap implicitModel, ServletWebRequest webRequest) { // // if (returnValue instanceof ModelAndView) { // ModelAndView mav = (ModelAndView) returnValue; // mav.getModelMap().mergeAttributes(implicitModel); // return mav; // } // else if (returnValue instanceof ModelMap) { // return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((ModelMap) returnValue)); // } // else if (returnValue instanceof Map) { // return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue); // } // else if (returnValue instanceof View) { // return new ModelAndView((View) returnValue).addAllObjects(implicitModel); // } // else if (returnValue instanceof String) { // return new ModelAndView((String) returnValue).addAllObjects(implicitModel); // } // else if (returnValue == null) { // // Either returned null or was 'void' return. // if (this.responseArgumentUsed || webRequest.isNotModified()) { // return null; // } // else { // // Assuming view name translation... // return new ModelAndView().addAllObjects(implicitModel); // } // } // else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) { // // Assume a single model attribute... // ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), ModelAttribute.class); // String attrName = (attr != null ? attr.name() : ""); // ModelAndView mav = new ModelAndView().addAllObjects(implicitModel); // if ("".equals(attrName)) { // Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod.getMethod(), handlerType); // attrName = Conventions.getVariableNameForReturnType(handlerMethod.getMethod(), resolvedType, returnValue); // } // return mav.addObject(attrName, returnValue); // } // else { // throw new IllegalArgumentException("Invalid handler method return value: " + returnValue); // } // } // } // // // private static class HandlerMappingInfo { // // public String[] paths = new String[0]; // // public RequestMethod[] methods = new RequestMethod[0]; // // public String[] params = new String[0]; // // public boolean equals(Object obj) { // HandlerMappingInfo other = (HandlerMappingInfo) obj; // return (Arrays.equals(this.paths, other.paths) && Arrays.equals(this.methods, other.methods) && // Arrays.equals(this.params, other.params)); // } // // public int hashCode() { // return (Arrays.hashCode(this.paths) * 29 + Arrays.hashCode(this.methods) * 31 + // Arrays.hashCode(this.params)); // } // } // // // public Set<MethodInfo> getHandlerMethods(Class<?> handlerType) { // // return this.getMethodResolver(handlerType).getHandlerMethods(); // } }