diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java index 05dc086616..9be71736c4 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -23,6 +23,8 @@ import java.util.Map; import javax.portlet.PortletRequest; import javax.portlet.PortletResponse; import javax.portlet.PortletSession; +import javax.portlet.filter.PortletRequestWrapper; +import javax.portlet.filter.PortletResponseWrapper; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; @@ -75,6 +77,44 @@ public class PortletWebRequest extends PortletRequestAttributes implements Nativ return getResponse(); } + @SuppressWarnings("unchecked") + public T getNativeRequest(Class requiredType) { + if (requiredType != null) { + PortletRequest request = getRequest(); + while (request != null) { + if (requiredType.isInstance(request)) { + return (T) request; + } + else if (request instanceof PortletRequestWrapper) { + request = ((PortletRequestWrapper) request).getRequest(); + } + else { + request = null; + } + } + } + return null; + } + + @SuppressWarnings("unchecked") + public T getNativeResponse(Class requiredType) { + if (requiredType != null) { + PortletResponse response = getResponse(); + while (response != null) { + if (requiredType.isInstance(response)) { + return (T) response; + } + else if (response instanceof PortletResponseWrapper) { + response = ((PortletResponseWrapper) response).getResponse(); + } + else { + response = null; + } + } + } + return null; + } + public String getHeader(String headerName) { return getRequest().getProperty(headerName); diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java index 7057743d4b..b1af99a428 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -534,13 +534,13 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator throws Exception { return AnnotationMethodHandlerAdapter.this.createBinder( - (PortletRequest) webRequest.getNativeRequest(), target, objectName); + webRequest.getNativeRequest(PortletRequest.class), target, objectName); } @Override protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { PortletRequestDataBinder portletBinder = (PortletRequestDataBinder) binder; - portletBinder.bind((PortletRequest) webRequest.getNativeRequest()); + portletBinder.bind(webRequest.getNativeRequest(PortletRequest.class)); } @Override @@ -560,7 +560,7 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) throws Exception { - PortletRequest portletRequest = (PortletRequest) webRequest.getNativeRequest(); + PortletRequest portletRequest = webRequest.getNativeRequest(PortletRequest.class); Cookie cookieValue = PortletUtils.getCookie(portletRequest, cookieName); if (Cookie.class.isAssignableFrom(paramType)) { return cookieValue; @@ -577,8 +577,8 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { - PortletRequest request = (PortletRequest) webRequest.getNativeRequest(); - PortletResponse response = (PortletResponse) webRequest.getNativeResponse(); + PortletRequest request = webRequest.getNativeRequest(PortletRequest.class); + PortletResponse response = webRequest.getNativeResponse(PortletResponse.class); if (PortletRequest.class.isAssignableFrom(parameterType)) { return request; diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java index bcc5bedb0d..a4bf4277c4 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -61,6 +61,7 @@ import org.springframework.web.servlet.View; /** * Implementation of the {@link org.springframework.web.portlet.HandlerExceptionResolver} interface that handles * exceptions through the {@link ExceptionHandler} annotation. + * *

This exception resolver is enabled by default in the {@link org.springframework.web.portlet.DispatcherPortlet}. * * @author Arjen Poutsma @@ -70,6 +71,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc private WebArgumentResolver[] customArgumentResolvers; + /** * 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. @@ -86,11 +88,11 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc this.customArgumentResolvers = argumentResolvers; } + @Override - protected ModelAndView doResolveException(PortletRequest request, - MimeResponse response, - Object handler, - Exception ex) { + protected ModelAndView doResolveException(PortletRequest request, MimeResponse response, + Object handler, Exception ex) { + if (handler != null) { Method handlerMethod = findBestExceptionHandlerMethod(handler, ex); if (handlerMethod != null) { @@ -113,15 +115,13 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc /** * Finds the handler method that matches the thrown exception best. - * - * @param handler the handler object + * @param handler the handler object * @param thrownException the exception to be handled * @return the best matching method; or null if none is found */ private Method findBestExceptionHandlerMethod(Object handler, final Exception thrownException) { final Class handlerType = handler.getClass(); final Class thrownExceptionType = thrownException.getClass(); - final Map, Method> resolverMethods = new LinkedHashMap, Method>(); @@ -145,16 +145,15 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } } }); + return getBestMatchingMethod(thrownException, resolverMethods); } /** * Returns all the exception classes handled by the given method. - * - *

Default implementation looks for exceptions in the {@linkplain ExceptionHandler#value() annotation}, or - - * if that annotation element is empty - any exceptions listed in the method parameters if the method is annotated - * with {@code @ExceptionHandler}. - * + *

Default implementation looks for exceptions in the {@linkplain ExceptionHandler#value() annotation}, + * or - if that annotation element is empty - any exceptions listed in the method parameters if the + * method is annotated with {@code @ExceptionHandler}. * @param method the method * @return the handled exceptions */ @@ -182,6 +181,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc */ private Method getBestMatchingMethod(Exception thrownException, Map, Method> resolverMethods) { + if (!resolverMethods.isEmpty()) { List> handledExceptions = new ArrayList>(resolverMethods.keySet()); @@ -197,47 +197,40 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc /** * Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}. */ - private Object[] resolveHandlerArguments(Method handlerMethod, - Object handler, - NativeWebRequest webRequest, - Exception thrownException) throws Exception { + private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, + NativeWebRequest webRequest, Exception thrownException) throws Exception { Class[] paramTypes = handlerMethod.getParameterTypes(); Object[] args = new Object[paramTypes.length]; - Class handlerType = handler.getClass(); - for (int i = 0; i < args.length; i++) { MethodParameter methodParam = new MethodParameter(handlerMethod, i); GenericTypeResolver.resolveParameterType(methodParam, handlerType); - Class paramType = methodParam.getParameterType(); - Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException); if (argValue != WebArgumentResolver.UNRESOLVED) { args[i] = argValue; } else { - throw new IllegalStateException( - "Unsupported argument [" + paramType.getName() + "] for @ExceptionHandler method: " + - handlerMethod); + throw new IllegalStateException("Unsupported argument [" + paramType.getName() + + "] for @ExceptionHandler method: " + handlerMethod); } } return args; } /** - * Resolves common method arguments. Delegates to registered {@link #setCustomArgumentResolver(org.springframework.web.bind.support.WebArgumentResolver) argumentResolvers} first, + * Resolves common method arguments. Delegates to registered + * {@link #setCustomArgumentResolver argumentResolvers} first, * then checking {@link #resolveStandardArgument}. - * * @param methodParameter the method parameter - * @param webRequest the request + * @param webRequest the request * @param thrownException the exception thrown * @return the argument value, or {@link org.springframework.web.bind.support.WebArgumentResolver#UNRESOLVED} */ - protected Object resolveCommonArgument(MethodParameter methodParameter, - NativeWebRequest webRequest, + protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest, Exception thrownException) throws Exception { + // Invoke custom argument resolvers if present... if (this.customArgumentResolvers != null) { for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { @@ -261,25 +254,24 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } /** - * Resolves standard method arguments. Default implementation handles {@link org.springframework.web.context.request.NativeWebRequest}, - * {@link javax.servlet.ServletRequest}, {@link javax.servlet.ServletResponse}, {@link javax.servlet.http.HttpSession}, {@link java.security.Principal}, {@link java.util.Locale}, - * request {@link java.io.InputStream}, request {@link java.io.Reader}, response {@link java.io.OutputStream}, response {@link java.io.Writer}, - * and the given {@code thrownException}. - * - * @param parameterType the method parameter type - * @param webRequest the request + * Resolves standard method arguments. The default implementation handles {@link NativeWebRequest}, + * {@link ServletRequest}, {@link ServletResponse}, {@link HttpSession}, {@link Principal}, + * {@link Locale}, request {@link InputStream}, request {@link Reader}, response {@link OutputStream}, + * response {@link Writer}, and the given {@code thrownException}. + * @param parameterType the method parameter type + * @param webRequest the request * @param thrownException the exception thrown * @return the argument value, or {@link org.springframework.web.bind.support.WebArgumentResolver#UNRESOLVED} */ - protected Object resolveStandardArgument(Class parameterType, - NativeWebRequest webRequest, + protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest, Exception thrownException) throws Exception { + if (WebRequest.class.isAssignableFrom(parameterType)) { return webRequest; } - PortletRequest request = (PortletRequest) webRequest.getNativeRequest(); - PortletResponse response = (PortletResponse) webRequest.getNativeResponse(); + PortletRequest request = webRequest.getNativeRequest(PortletRequest.class); + PortletResponse response = webRequest.getNativeResponse(PortletResponse.class); if (PortletRequest.class.isAssignableFrom(parameterType)) { return request; @@ -382,6 +374,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } } + /** * Comparator capable of sorting exceptions based on their depth from the thrown exception type. */ @@ -413,4 +406,5 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } } -} \ No newline at end of file + +} diff --git a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/PortletWebRequestTests.java b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/PortletWebRequestTests.java index 193dde60be..f1a92dd170 100644 --- a/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/PortletWebRequestTests.java +++ b/org.springframework.web.portlet/src/test/java/org/springframework/web/portlet/context/PortletWebRequestTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 the original author or authors. + * Copyright 2002-2010 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. @@ -19,16 +19,29 @@ package org.springframework.web.portlet.context; import java.util.Locale; import java.util.Map; -import junit.framework.TestCase; +import javax.portlet.PortletRequest; +import javax.portlet.RenderRequest; +import javax.portlet.RenderResponse; +import javax.portlet.PortletResponse; +import javax.portlet.filter.PortletRequestWrapper; +import javax.portlet.filter.PortletResponseWrapper; + +import static org.junit.Assert.*; +import org.junit.Test; import org.springframework.mock.web.portlet.MockPortletRequest; +import org.springframework.mock.web.portlet.MockPortletResponse; +import org.springframework.mock.web.portlet.MockRenderRequest; +import org.springframework.mock.web.portlet.MockRenderResponse; +import org.springframework.web.multipart.MultipartRequest; /** * @author Juergen Hoeller * @since 26.07.2006 */ -public class PortletWebRequestTests extends TestCase { +public class PortletWebRequestTests { + @Test public void testParameters() { MockPortletRequest portletRequest = new MockPortletRequest(); portletRequest.addParameter("param1", "value1"); @@ -53,6 +66,7 @@ public class PortletWebRequestTests extends TestCase { assertEquals("value2a", ((String[]) paramMap.get("param2"))[1]); } + @Test public void testLocale() { MockPortletRequest portletRequest = new MockPortletRequest(); portletRequest.addPreferredLocale(Locale.UK); @@ -61,4 +75,40 @@ public class PortletWebRequestTests extends TestCase { assertEquals(Locale.UK, request.getLocale()); } + @Test + public void testNativeRequest() { + MockRenderRequest portletRequest = new MockRenderRequest(); + MockRenderResponse portletResponse = new MockRenderResponse(); + PortletWebRequest request = new PortletWebRequest(portletRequest, portletResponse); + assertSame(portletRequest, request.getNativeRequest()); + assertSame(portletRequest, request.getNativeRequest(PortletRequest.class)); + assertSame(portletRequest, request.getNativeRequest(RenderRequest.class)); + assertSame(portletRequest, request.getNativeRequest(MockRenderRequest.class)); + assertNull(request.getNativeRequest(MultipartRequest.class)); + assertSame(portletResponse, request.getNativeResponse()); + assertSame(portletResponse, request.getNativeResponse(PortletResponse.class)); + assertSame(portletResponse, request.getNativeResponse(RenderResponse.class)); + assertSame(portletResponse, request.getNativeResponse(MockRenderResponse.class)); + assertNull(request.getNativeResponse(MultipartRequest.class)); + } + + @Test + public void testDecoratedNativeRequest() { + MockRenderRequest portletRequest = new MockRenderRequest(); + MockRenderResponse portletResponse = new MockRenderResponse(); + PortletRequest decoratedRequest = new PortletRequestWrapper(portletRequest); + PortletResponse decoratedResponse = new PortletResponseWrapper(portletResponse); + PortletWebRequest request = new PortletWebRequest(decoratedRequest, decoratedResponse); + assertSame(decoratedRequest, request.getNativeRequest()); + assertSame(decoratedRequest, request.getNativeRequest(PortletRequest.class)); + assertSame(portletRequest, request.getNativeRequest(RenderRequest.class)); + assertSame(portletRequest, request.getNativeRequest(MockRenderRequest.class)); + assertNull(request.getNativeRequest(MultipartRequest.class)); + assertSame(decoratedResponse, request.getNativeResponse()); + assertSame(decoratedResponse, request.getNativeResponse(PortletResponse.class)); + assertSame(portletResponse, request.getNativeResponse(RenderResponse.class)); + assertSame(portletResponse, request.getNativeResponse(MockRenderResponse.class)); + assertNull(request.getNativeResponse(MultipartRequest.class)); + } + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java index 88f34b6a90..ac981c7312 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java @@ -701,18 +701,18 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator throws Exception { return AnnotationMethodHandlerAdapter.this.createBinder( - (HttpServletRequest) webRequest.getNativeRequest(), target, objectName); + webRequest.getNativeRequest(HttpServletRequest.class), target, objectName); } @Override protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder; - servletBinder.bind((ServletRequest) webRequest.getNativeRequest()); + servletBinder.bind(webRequest.getNativeRequest(ServletRequest.class)); } @Override protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { - HttpServletRequest servletRequest = (HttpServletRequest) webRequest.getNativeRequest(); + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); return AnnotationMethodHandlerAdapter.this.createHttpInputMessage(servletRequest); } @@ -739,7 +739,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) throws Exception { - HttpServletRequest servletRequest = (HttpServletRequest) webRequest.getNativeRequest(); + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName); if (Cookie.class.isAssignableFrom(paramType)) { return cookieValue; @@ -757,7 +757,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) throws Exception { - HttpServletRequest servletRequest = (HttpServletRequest) webRequest.getNativeRequest(); + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); Map uriTemplateVariables = (Map) servletRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); if (uriTemplateVariables == null || !uriTemplateVariables.containsKey(pathVarName)) { @@ -769,8 +769,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator @Override protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { - HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); - HttpServletResponse response = (HttpServletResponse) webRequest.getNativeResponse(); + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); if (ServletRequest.class.isAssignableFrom(parameterType)) { return request; diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java index f892fe90af..a91a6b72d3 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java @@ -110,11 +110,11 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc this.messageConverters = messageConverters; } + @Override - protected ModelAndView doResolveException(HttpServletRequest request, - HttpServletResponse response, - Object handler, - Exception ex) { + protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, + Object handler, Exception ex) { + if (handler != null) { Method handlerMethod = findBestExceptionHandlerMethod(handler, ex); if (handlerMethod != null) { @@ -137,7 +137,6 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc /** * Finds the handler method that matches the thrown exception best. - * * @param handler the handler object * @param thrownException the exception to be handled * @return the best matching method; or null if none is found @@ -145,7 +144,6 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc private Method findBestExceptionHandlerMethod(Object handler, final Exception thrownException) { final Class handlerType = handler.getClass(); final Class thrownExceptionType = thrownException.getClass(); - final Map, Method> resolverMethods = new LinkedHashMap, Method>(); @@ -165,7 +163,6 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc "Ambiguous exception handler mapped for " + handledException + "]: {" + oldMappedMethod + ", " + method + "}."); } - } } } @@ -176,10 +173,10 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } /** - * Returns all the exception classes handled by the given method.

Default implementation looks for exceptions in the - * {@linkplain ExceptionHandler#value() annotation}, or - if that annotation element is empty - any exceptions listed - * in the method parameters if the method is annotated with {@code @ExceptionHandler}. - * + * Returns all the exception classes handled by the given method. + *

The default implementation looks for exceptions in the {@linkplain ExceptionHandler#value() annotation}, + * or - if that annotation element is empty - any exceptions listed in the method parameters if the method + * is annotated with {@code @ExceptionHandler}. * @param method the method * @return the handled exceptions */ @@ -202,9 +199,12 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc return result; } - /** Returns the best matching method. Uses the {@link DepthComparator}. */ + /** + * Returns the best matching method. Uses the {@link DepthComparator}. + */ private Method getBestMatchingMethod(Exception thrownException, Map, Method> resolverMethods) { + if (!resolverMethods.isEmpty()) { List> handledExceptions = new ArrayList>(resolverMethods.keySet()); @@ -217,31 +217,26 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } } - /** Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}. */ - private Object[] resolveHandlerArguments(Method handlerMethod, - Object handler, - NativeWebRequest webRequest, - Exception thrownException) throws Exception { + /** + * Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}. + */ + private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, + NativeWebRequest webRequest, Exception thrownException) throws Exception { Class[] paramTypes = handlerMethod.getParameterTypes(); Object[] args = new Object[paramTypes.length]; - Class handlerType = handler.getClass(); - for (int i = 0; i < args.length; i++) { MethodParameter methodParam = new MethodParameter(handlerMethod, i); GenericTypeResolver.resolveParameterType(methodParam, handlerType); - Class paramType = methodParam.getParameterType(); - Object argValue = resolveCommonArgument(methodParam, webRequest, thrownException); if (argValue != WebArgumentResolver.UNRESOLVED) { args[i] = argValue; } else { - throw new IllegalStateException( - "Unsupported argument [" + paramType.getName() + "] for @ExceptionHandler method: " + - handlerMethod); + throw new IllegalStateException("Unsupported argument [" + paramType.getName() + + "] for @ExceptionHandler method: " + handlerMethod); } } return args; @@ -250,15 +245,14 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc /** * Resolves common method arguments. Delegates to registered {@link #setCustomArgumentResolver(WebArgumentResolver) * argumentResolvers} first, then checking {@link #resolveStandardArgument}. - * * @param methodParameter the method parameter * @param webRequest the request * @param thrownException the exception thrown * @return the argument value, or {@link WebArgumentResolver#UNRESOLVED} */ - protected Object resolveCommonArgument(MethodParameter methodParameter, - NativeWebRequest webRequest, + protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest, Exception thrownException) throws Exception { + // Invoke custom argument resolvers if present... if (this.customArgumentResolvers != null) { for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { @@ -282,25 +276,24 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } /** - * Resolves standard method arguments. Default implementation handles {@link NativeWebRequest}, {@link ServletRequest}, - * {@link ServletResponse}, {@link HttpSession}, {@link Principal}, {@link Locale}, request {@link InputStream}, - * request {@link Reader}, response {@link OutputStream}, response {@link Writer}, and the given {@code - * thrownException}. - * + * Resolves standard method arguments. The default implementation handles {@link NativeWebRequest}, + * {@link ServletRequest}, {@link ServletResponse}, {@link HttpSession}, {@link Principal}, + * {@link Locale}, request {@link InputStream}, request {@link Reader}, response {@link OutputStream}, + * response {@link Writer}, and the given {@code thrownException}. * @param parameterType the method parameter type * @param webRequest the request * @param thrownException the exception thrown * @return the argument value, or {@link WebArgumentResolver#UNRESOLVED} */ - protected Object resolveStandardArgument(Class parameterType, - NativeWebRequest webRequest, + protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest, Exception thrownException) throws Exception { + if (WebRequest.class.isAssignableFrom(parameterType)) { return webRequest; } - HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); - HttpServletResponse response = (HttpServletResponse) webRequest.getNativeResponse(); + HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); if (ServletRequest.class.isAssignableFrom(parameterType)) { return request; @@ -416,7 +409,9 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } - /** Comparator capable of sorting exceptions based on their depth from the thrown exception type. */ + /** + * Comparator capable of sorting exceptions based on their depth from the thrown exception type. + */ private static class DepthComparator implements Comparator> { private final Class handlerExceptionType; @@ -443,6 +438,6 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } return getDepth(exceptionType.getSuperclass(), depth + 1); } - } + } diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java index fc083fce18..f852df5ea8 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java @@ -427,8 +427,9 @@ public class HandlerMethodInvoker { paramName = getRequiredParameterName(methodParam); } Object paramValue = null; - if (webRequest.getNativeRequest() instanceof MultipartRequest) { - paramValue = ((MultipartRequest) webRequest.getNativeRequest()).getFile(paramName); + MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class); + if (multipartRequest != null) { + paramValue = multipartRequest.getFile(paramName); } if (paramValue == null) { String[] paramValues = webRequest.getParameterValues(paramName); diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java b/org.springframework.web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java index 9ccc349db2..062abd54e0 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/support/WebRequestDataBinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -101,9 +101,9 @@ public class WebRequestDataBinder extends WebDataBinder { public void bind(WebRequest request) { MutablePropertyValues mpvs = new MutablePropertyValues(request.getParameterMap()); if (request instanceof NativeWebRequest) { - Object nativeRequest = ((NativeWebRequest) request).getNativeRequest(); - if (nativeRequest instanceof MultipartRequest) { - bindMultipartFiles(((MultipartRequest) nativeRequest).getFileMap(), mpvs); + MultipartRequest multipartRequest = ((NativeWebRequest) request).getNativeRequest(MultipartRequest.class); + if (multipartRequest != null) { + bindMultipartFiles(multipartRequest.getFileMap(), mpvs); } } doBind(mpvs); diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java b/org.springframework.web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java index 49b68695d1..458d67a29f 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -51,6 +51,28 @@ public class FacesWebRequest extends FacesRequestAttributes implements NativeWeb return getExternalContext().getResponse(); } + @SuppressWarnings("unchecked") + public T getNativeRequest(Class requiredType) { + if (requiredType != null) { + Object request = getExternalContext().getRequest(); + if (requiredType.isInstance(request)) { + return (T) request; + } + } + return null; + } + + @SuppressWarnings("unchecked") + public T getNativeResponse(Class requiredType) { + if (requiredType != null) { + Object response = getExternalContext().getResponse(); + if (requiredType.isInstance(response)) { + return (T) response; + } + } + return null; + } + public String getHeader(String headerName) { return getExternalContext().getRequestHeaderMap().get(headerName); diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/request/NativeWebRequest.java b/org.springframework.web/src/main/java/org/springframework/web/context/request/NativeWebRequest.java index f4663e04af..d147fa9ad3 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/request/NativeWebRequest.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/request/NativeWebRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -44,4 +44,26 @@ public interface NativeWebRequest extends WebRequest { */ Object getNativeResponse(); + /** + * Return the underlying native request object, if available. + * @param requiredType the desired type of request object + * @return the matching request object, or null if none + * of that type is available + * @see javax.servlet.http.HttpServletRequest + * @see javax.portlet.ActionRequest + * @see javax.portlet.RenderRequest + */ + T getNativeRequest(Class requiredType); + + /** + * Return the underlying native request object, if available. + * @param requiredType the desired type of response object + * @return the matching response object, or null if none + * of that type is available + * @see javax.servlet.http.HttpServletRequest + * @see javax.portlet.ActionRequest + * @see javax.portlet.RenderRequest + */ + T getNativeResponse(Class requiredType); + } diff --git a/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java b/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java index 3fcae3f22c..7ccb5d7096 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java +++ b/org.springframework.web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2010 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. @@ -20,6 +20,10 @@ import java.security.Principal; import java.util.Iterator; import java.util.Locale; import java.util.Map; +import javax.servlet.ServletRequest; +import javax.servlet.ServletRequestWrapper; +import javax.servlet.ServletResponse; +import javax.servlet.ServletResponseWrapper; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -80,6 +84,44 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ return getResponse(); } + @SuppressWarnings("unchecked") + public T getNativeRequest(Class requiredType) { + if (requiredType != null) { + ServletRequest request = getRequest(); + while (request != null) { + if (requiredType.isInstance(request)) { + return (T) request; + } + else if (request instanceof ServletRequestWrapper) { + request = ((ServletRequestWrapper) request).getRequest(); + } + else { + request = null; + } + } + } + return null; + } + + @SuppressWarnings("unchecked") + public T getNativeResponse(Class requiredType) { + if (requiredType != null) { + ServletResponse response = getResponse(); + while (response != null) { + if (requiredType.isInstance(response)) { + return (T) response; + } + else if (response instanceof ServletResponseWrapper) { + response = ((ServletResponseWrapper) response).getResponse(); + } + else { + response = null; + } + } + } + return null; + } + public String getHeader(String headerName) { return getRequest().getHeader(headerName); diff --git a/org.springframework.web/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java b/org.springframework.web/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java index 3280b53314..f8ae9ff478 100644 --- a/org.springframework.web/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java +++ b/org.springframework.web/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006 the original author or authors. + * Copyright 2002-2010 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. @@ -18,17 +18,27 @@ package org.springframework.web.context.request; import java.util.Locale; import java.util.Map; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; -import junit.framework.TestCase; +import static org.junit.Assert.*; +import org.junit.Test; import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.web.multipart.MultipartRequest; /** * @author Juergen Hoeller * @since 26.07.2006 */ -public class ServletWebRequestTests extends TestCase { +public class ServletWebRequestTests { + @Test public void testParameters() { MockHttpServletRequest servletRequest = new MockHttpServletRequest(); servletRequest.addParameter("param1", "value1"); @@ -53,6 +63,7 @@ public class ServletWebRequestTests extends TestCase { assertEquals("value2a", ((String[]) paramMap.get("param2"))[1]); } + @Test public void testLocale() { MockHttpServletRequest servletRequest = new MockHttpServletRequest(); servletRequest.addPreferredLocale(Locale.UK); @@ -61,4 +72,40 @@ public class ServletWebRequestTests extends TestCase { assertEquals(Locale.UK, request.getLocale()); } + @Test + public void testNativeRequest() { + MockHttpServletRequest servletRequest = new MockHttpServletRequest(); + MockHttpServletResponse servletResponse = new MockHttpServletResponse(); + ServletWebRequest request = new ServletWebRequest(servletRequest, servletResponse); + assertSame(servletRequest, request.getNativeRequest()); + assertSame(servletRequest, request.getNativeRequest(ServletRequest.class)); + assertSame(servletRequest, request.getNativeRequest(HttpServletRequest.class)); + assertSame(servletRequest, request.getNativeRequest(MockHttpServletRequest.class)); + assertNull(request.getNativeRequest(MultipartRequest.class)); + assertSame(servletResponse, request.getNativeResponse()); + assertSame(servletResponse, request.getNativeResponse(ServletResponse.class)); + assertSame(servletResponse, request.getNativeResponse(HttpServletResponse.class)); + assertSame(servletResponse, request.getNativeResponse(MockHttpServletResponse.class)); + assertNull(request.getNativeResponse(MultipartRequest.class)); + } + + @Test + public void testDecoratedNativeRequest() { + MockHttpServletRequest servletRequest = new MockHttpServletRequest(); + MockHttpServletResponse servletResponse = new MockHttpServletResponse(); + HttpServletRequest decoratedRequest = new HttpServletRequestWrapper(servletRequest); + HttpServletResponse decoratedResponse = new HttpServletResponseWrapper(servletResponse); + ServletWebRequest request = new ServletWebRequest(decoratedRequest, decoratedResponse); + assertSame(decoratedRequest, request.getNativeRequest()); + assertSame(decoratedRequest, request.getNativeRequest(ServletRequest.class)); + assertSame(decoratedRequest, request.getNativeRequest(HttpServletRequest.class)); + assertSame(servletRequest, request.getNativeRequest(MockHttpServletRequest.class)); + assertNull(request.getNativeRequest(MultipartRequest.class)); + assertSame(decoratedResponse, request.getNativeResponse()); + assertSame(decoratedResponse, request.getNativeResponse(ServletResponse.class)); + assertSame(decoratedResponse, request.getNativeResponse(HttpServletResponse.class)); + assertSame(servletResponse, request.getNativeResponse(MockHttpServletResponse.class)); + assertNull(request.getNativeResponse(MultipartRequest.class)); + } + }