diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java b/spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java index 3b98e2edb5..4b29bafd08 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -26,9 +26,7 @@ import javax.servlet.jsp.tagext.BodyContent; /** * Mock implementation of the {@link javax.servlet.jsp.tagext.BodyContent} class. - * - *

Used for testing the web framework; only necessary for testing - * applications when testing custom JSP tags. + * Only necessary for testing applications when testing custom JSP tags. * * @author Juergen Hoeller * @since 2.5 diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockExpressionEvaluator.java b/spring-test/src/main/java/org/springframework/mock/web/MockExpressionEvaluator.java index 3672b52ed9..00334454f4 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockExpressionEvaluator.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockExpressionEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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,14 +20,13 @@ import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager; + import org.springframework.util.Assert; /** * Mock implementation of the JSP 2.0 {@link javax.servlet.jsp.el.ExpressionEvaluator} * interface, delegating to the Apache JSTL ExpressionEvaluatorManager. - * - *

Used for testing the web framework; only necessary for testing applications - * when testing custom JSP tags. + * Only necessary for testing applications when testing custom JSP tags. * *

Note that the Apache JSTL implementation (jstl.jar, standard.jar) has to be * available on the class path to use this expression evaluator. diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java b/spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java index 05db4a5bdd..1f2f775254 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -33,9 +33,7 @@ import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** - *

Mock implementation of the {@link javax.servlet.FilterChain} interface. Used - * for testing the web framework; also useful for testing custom - * {@link javax.servlet.Filter} implementations. + * Mock implementation of the {@link javax.servlet.FilterChain} interface. * *

A {@link MockFilterChain} can be configured with one or more filters and a * Servlet to invoke. The first time the chain is called, it invokes all filters diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java b/spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java index 123214b66f..d9067f7d5c 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java index 5f73abe401..b1593cf637 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java @@ -70,7 +70,7 @@ import org.springframework.util.StringUtils; * is {@link Locale#ENGLISH}. This value can be changed via {@link #addPreferredLocale} * or {@link #setPreferredLocales}. * - *

As of Spring Framework 5.0, this set of mocks is designed on a Servlet 3.1 baseline. + *

As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * * @author Juergen Hoeller * @author Rod Johnson diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java index 8b0967c5e6..1c278d1a10 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java @@ -45,7 +45,7 @@ import org.springframework.web.util.WebUtils; /** * Mock implementation of the {@link javax.servlet.http.HttpServletResponse} interface. * - *

As of Spring Framework 5.0, this set of mocks is designed on a Servlet 3.1 baseline. + *

As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * * @author Juergen Hoeller * @author Rod Johnson diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java b/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java index 70d55da985..81f43bb150 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -34,10 +34,7 @@ import org.springframework.util.Assert; /** * Mock implementation of the {@link javax.servlet.http.HttpSession} interface. * - *

As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline. - * - *

Used for testing the web framework; also useful for testing application - * controllers. + *

As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * * @author Juergen Hoeller * @author Rod Johnson @@ -72,7 +69,6 @@ public class MockHttpSession implements HttpSession { /** * Create a new MockHttpSession with a default {@link MockServletContext}. - * * @see MockServletContext */ public MockHttpSession() { @@ -81,7 +77,6 @@ public class MockHttpSession implements HttpSession { /** * Create a new MockHttpSession. - * * @param servletContext the ServletContext that the session runs in */ public MockHttpSession(ServletContext servletContext) { @@ -90,7 +85,6 @@ public class MockHttpSession implements HttpSession { /** * Create a new MockHttpSession. - * * @param servletContext the ServletContext that the session runs in * @param id a unique identifier for this session */ @@ -99,6 +93,7 @@ public class MockHttpSession implements HttpSession { this.id = (id != null ? id : Integer.toString(nextId++)); } + @Override public long getCreationTime() { assertIsValid(); @@ -111,8 +106,8 @@ public class MockHttpSession implements HttpSession { } /** - * As of Servlet 3.1 the id of a session can be changed. - * @return the new session id. + * As of Servlet 3.1, the id of a session can be changed. + * @return the new session id * @since 4.0.3 */ public String changeSessionId() { @@ -227,7 +222,6 @@ public class MockHttpSession implements HttpSession { /** * Invalidates this session then unbinds any objects bound to it. - * * @throws IllegalStateException if this method is called on an already invalidated session */ @Override @@ -244,7 +238,6 @@ public class MockHttpSession implements HttpSession { /** * Convenience method for asserting that this session has not been * {@linkplain #invalidate() invalidated}. - * * @throws IllegalStateException if this session has been invalidated */ private void assertIsValid() { @@ -264,7 +257,6 @@ public class MockHttpSession implements HttpSession { /** * Serialize the attributes of this session into an object that can be * turned into a byte array with standard Java serialization. - * * @return a representation of this session's serialized state */ public Serializable serializeState() { @@ -291,7 +283,6 @@ public class MockHttpSession implements HttpSession { /** * Deserialize the attributes of this session from a state object created by * {@link #serializeState()}. - * * @param state a representation of this session's serialized state */ @SuppressWarnings("unchecked") diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java b/spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java index 9fc585e59a..1245dbb5a8 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -24,9 +24,7 @@ import javax.servlet.jsp.JspWriter; /** * Mock implementation of the {@link javax.servlet.jsp.JspWriter} class. - * - *

Used for testing the web framework; only necessary for testing - * applications when testing custom JSP tags. + * Only necessary for testing applications when testing custom JSP tags. * * @author Juergen Hoeller * @since 2.5 diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java b/spring-test/src/main/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java index f1a0307836..bb47c6112d 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -35,11 +35,10 @@ import org.springframework.web.multipart.MultipartHttpServletRequest; * Mock implementation of the * {@link org.springframework.web.multipart.MultipartHttpServletRequest} interface. * - *

As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline. + *

As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * *

Useful for testing application controllers that access multipart uploads. - * The {@link MockMultipartFile} can be used to populate these mock requests - * with files. + * {@link MockMultipartFile} can be used to populate these mock requests with files. * * @author Juergen Hoeller * @author Eric Crampton @@ -49,8 +48,7 @@ import org.springframework.web.multipart.MultipartHttpServletRequest; */ public class MockMultipartHttpServletRequest extends MockHttpServletRequest implements MultipartHttpServletRequest { - private final MultiValueMap multipartFiles = - new LinkedMultiValueMap<>(); + private final MultiValueMap multipartFiles = new LinkedMultiValueMap<>(); /** diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java b/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java index 667741742c..7b31226583 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java @@ -40,9 +40,7 @@ import org.springframework.util.Assert; /** * Mock implementation of the {@link javax.servlet.jsp.PageContext} interface. - * - *

Used for testing the web framework; only necessary for testing - * applications when testing custom JSP tags. + * Only necessary for testing applications when testing custom JSP tags. * *

Note: Expects initialization via the constructor rather than via the * {@code PageContext.initialize} method. Does not support writing to a diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java b/spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java index 39a1e17f50..7fbae6f2ad 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -29,9 +29,6 @@ import org.springframework.util.Assert; /** * Mock implementation of the {@link javax.servlet.RequestDispatcher} interface. * - *

Used for testing the web framework; typically not necessary for - * testing application controllers. - * * @author Rod Johnson * @author Juergen Hoeller * @author Sam Brannen @@ -50,7 +47,7 @@ public class MockRequestDispatcher implements RequestDispatcher { * particular path or given by a particular name */ public MockRequestDispatcher(String resource) { - Assert.notNull(resource, "resource must not be null"); + Assert.notNull(resource, "Resource must not be null"); this.resource = resource; } diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java b/spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java index d5bb9f33aa..805e7b4635 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -28,9 +28,6 @@ import org.springframework.util.Assert; /** * Mock implementation of the {@link javax.servlet.ServletConfig} interface. * - *

Used for testing the web framework; typically not necessary for - * testing application controllers. - * * @author Rod Johnson * @author Juergen Hoeller * @since 1.0.2 diff --git a/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java b/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java index e35ade005d..b0833b15a6 100644 --- a/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java +++ b/spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -55,37 +55,21 @@ import org.springframework.web.util.WebUtils; /** * Mock implementation of the {@link javax.servlet.ServletContext} interface. * - *

As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline. + *

As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * - *

Compatible with Servlet 3.0 but can be configured to expose a specific version - * through {@link #setMajorVersion}/{@link #setMinorVersion}; default is 3.0. - * Note that Servlet 3.0 support is limited: servlet, filter and listener + *

Compatible with Servlet 3.1 but can be configured to expose a specific version + * through {@link #setMajorVersion}/{@link #setMinorVersion}; default is 3.1. + * Note that Servlet 3.1 support is limited: servlet, filter and listener * registration methods are not supported; neither is JSP configuration. * We generally do not recommend to unit test your ServletContainerInitializers and * WebApplicationInitializers which is where those registration methods would be used. * - *

Used for testing the Spring web framework; only rarely necessary for testing - * application controllers. As long as application components don't explicitly - * access the {@code ServletContext}, {@code ClassPathXmlApplicationContext} or - * {@code FileSystemXmlApplicationContext} can be used to load the context files - * for testing, even for {@code DispatcherServlet} context definitions. - * - *

For setting up a full {@code WebApplicationContext} in a test environment, - * you can use {@code AnnotationConfigWebApplicationContext}, - * {@code XmlWebApplicationContext}, or {@code GenericWebApplicationContext}, - * passing in an appropriate {@code MockServletContext} instance. You might want - * to configure your {@code MockServletContext} with a {@code FileSystemResourceLoader} - * in that case to ensure that resource paths are interpreted as relative filesystem - * locations. - * - *

A common setup is to point your JVM working directory to the root of your - * web application directory, in combination with filesystem-based resource loading. - * This allows to load the context files as used in the web application, with - * relative paths getting interpreted correctly. Such a setup will work with both - * {@code FileSystemXmlApplicationContext} (which will load straight from the - * filesystem) and {@code XmlWebApplicationContext} with an underlying - * {@code MockServletContext} (as long as the {@code MockServletContext} has been - * configured with a {@code FileSystemResourceLoader}). + *

For setting up a full {@code WebApplicationContext} in a test environment, you can + * use {@code AnnotationConfigWebApplicationContext}, {@code XmlWebApplicationContext}, + * or {@code GenericWebApplicationContext}, passing in a corresponding + * {@code MockServletContext} instance. Consider configuring your + * {@code MockServletContext} with a {@code FileSystemResourceLoader} in order to + * interpret resource paths as relative filesystem locations. * * @author Rod Johnson * @author Juergen Hoeller @@ -95,18 +79,15 @@ import org.springframework.web.util.WebUtils; * @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext * @see org.springframework.web.context.support.XmlWebApplicationContext * @see org.springframework.web.context.support.GenericWebApplicationContext - * @see org.springframework.context.support.ClassPathXmlApplicationContext - * @see org.springframework.context.support.FileSystemXmlApplicationContext */ public class MockServletContext implements ServletContext { - /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value}. */ + /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value} */ private static final String COMMON_DEFAULT_SERVLET_NAME = "default"; private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; - private static final Set DEFAULT_SESSION_TRACKING_MODES = - new LinkedHashSet<>(3); + private static final Set DEFAULT_SESSION_TRACKING_MODES = new LinkedHashSet<>(4); static { DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.COOKIE); @@ -127,11 +108,11 @@ public class MockServletContext implements ServletContext { private int majorVersion = 3; - private int minorVersion = 0; + private int minorVersion = 1; private int effectiveMajorVersion = 3; - private int effectiveMinorVersion = 0; + private int effectiveMinorVersion = 1; private final Map namedRequestDispatchers = new HashMap<>(); @@ -149,6 +130,8 @@ public class MockServletContext implements ServletContext { private final SessionCookieConfig sessionCookieConfig = new MockSessionCookieConfig(); + private int sessionTimeout; + /** * Create a new {@code MockServletContext}, using no base path and a @@ -570,6 +553,16 @@ public class MockServletContext implements ServletContext { return this.sessionCookieConfig; } + // @Override - but only against Servlet 4.0 + public void setSessionTimeout(int sessionTimeout) { + this.sessionTimeout = sessionTimeout; + } + + // @Override - but only against Servlet 4.0 + public int getSessionTimeout() { + return this.sessionTimeout; + } + //--------------------------------------------------------------------- // Unsupported Servlet 3.0 registration methods @@ -580,6 +573,11 @@ public class MockServletContext implements ServletContext { throw new UnsupportedOperationException(); } + // @Override - but only against Servlet 4.0 + public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { + throw new UnsupportedOperationException(); + } + @Override public ServletRegistration.Dynamic addServlet(String servletName, String className) { throw new UnsupportedOperationException(); diff --git a/spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java b/spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java index 5985a722ae..9e7dff48cf 100644 --- a/spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java +++ b/spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 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. @@ -97,16 +97,24 @@ public class MockServletContextTests { @Test public void servletVersion() { assertEquals(3, sc.getMajorVersion()); - assertEquals(0, sc.getMinorVersion()); - sc.setMinorVersion(1); assertEquals(1, sc.getMinorVersion()); + assertEquals(3, sc.getEffectiveMajorVersion()); + assertEquals(1, sc.getEffectiveMinorVersion()); + + sc.setMajorVersion(4); + sc.setMinorVersion(0); + sc.setEffectiveMajorVersion(4); + sc.setEffectiveMinorVersion(0); + assertEquals(4, sc.getMajorVersion()); + assertEquals(0, sc.getMinorVersion()); + assertEquals(4, sc.getEffectiveMajorVersion()); + assertEquals(0, sc.getEffectiveMinorVersion()); } @Test public void registerAndUnregisterNamedDispatcher() throws Exception { final String name = "test-servlet"; final String url = "/test"; - assertNull(sc.getNamedDispatcher(name)); sc.registerNamedDispatcher(name, new MockRequestDispatcher(url)); diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockBodyContent.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockBodyContent.java index eb3ebe8e8b..09a63a48ce 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockBodyContent.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockBodyContent.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -26,9 +26,7 @@ import javax.servlet.jsp.tagext.BodyContent; /** * Mock implementation of the {@link javax.servlet.jsp.tagext.BodyContent} class. - * - *

Used for testing the web framework; only necessary for testing - * applications when testing custom JSP tags. + * Only necessary for testing applications when testing custom JSP tags. * * @author Juergen Hoeller * @since 2.5 diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockExpressionEvaluator.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockExpressionEvaluator.java index 80b3365f47..ace4928ce2 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockExpressionEvaluator.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockExpressionEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2017 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. @@ -21,12 +21,12 @@ import javax.servlet.jsp.PageContext; import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager; +import org.springframework.util.Assert; + /** * Mock implementation of the JSP 2.0 {@link javax.servlet.jsp.el.ExpressionEvaluator} * interface, delegating to the Apache JSTL ExpressionEvaluatorManager. - * - *

Used for testing the web framework; only necessary for testing applications - * when testing custom JSP tags. + * Only necessary for testing applications when testing custom JSP tags. * *

Note that the Apache JSTL implementation (jstl.jar, standard.jar) has to be * available on the class path to use this expression evaluator. @@ -68,9 +68,7 @@ public class MockExpressionEvaluator extends javax.servlet.jsp.el.ExpressionEval public Object evaluate(String expression, Class expectedType, javax.servlet.jsp.el.VariableResolver variableResolver, javax.servlet.jsp.el.FunctionMapper functionMapper) throws javax.servlet.jsp.el.ELException { - if (variableResolver != null) { - throw new IllegalArgumentException("Custom VariableResolver not supported"); - } + Assert.isNull(variableResolver, "Custom VariableResolver not supported"); return doEvaluate(expression, expectedType, functionMapper); } @@ -78,9 +76,7 @@ public class MockExpressionEvaluator extends javax.servlet.jsp.el.ExpressionEval protected Object doEvaluate(String expression, Class expectedType, javax.servlet.jsp.el.FunctionMapper functionMapper) throws javax.servlet.jsp.el.ELException { - if (functionMapper != null) { - throw new IllegalArgumentException("Custom FunctionMapper not supported"); - } + Assert.isNull(functionMapper, "Custom FunctionMapper not supported"); try { return ExpressionEvaluatorManager.evaluate("JSP EL expression", expression, expectedType, this.pageContext); } diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockFilterChain.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockFilterChain.java index ac10e6e756..da4a909310 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockFilterChain.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockFilterChain.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -33,9 +33,7 @@ import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** - *

Mock implementation of the {@link javax.servlet.FilterChain} interface. Used - * for testing the web framework; also useful for testing custom - * {@link javax.servlet.Filter} implementations. + * Mock implementation of the {@link javax.servlet.FilterChain} interface. * *

A {@link MockFilterChain} can be configured with one or more filters and a * Servlet to invoke. The first time the chain is called, it invokes all filters @@ -120,10 +118,7 @@ public class MockFilterChain implements FilterChain { public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { Assert.notNull(request, "Request must not be null"); Assert.notNull(response, "Response must not be null"); - - if (this.request != null) { - throw new IllegalStateException("This FilterChain has already been called!"); - } + Assert.state(this.request == null, "This FilterChain has already been called!"); if (this.iterator == null) { this.iterator = this.filters.iterator(); diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockFilterConfig.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockFilterConfig.java index 276d8759d3..fbfc1a17f3 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockFilterConfig.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockFilterConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java index 182df3af88..896c174288 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java @@ -70,7 +70,7 @@ import org.springframework.util.StringUtils; * is {@link Locale#ENGLISH}. This value can be changed via {@link #addPreferredLocale} * or {@link #setPreferredLocales}. * - *

As of Spring Framework 5.0, this set of mocks is designed on a Servlet 3.1 baseline. + *

As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * * @author Juergen Hoeller * @author Rod Johnson diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletResponse.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletResponse.java index 5c1dd308df..bc667a8e60 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletResponse.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletResponse.java @@ -45,7 +45,7 @@ import org.springframework.web.util.WebUtils; /** * Mock implementation of the {@link javax.servlet.http.HttpServletResponse} interface. * - *

As of Spring Framework 5.0, this set of mocks is designed on a Servlet 3.1 baseline. + *

As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * * @author Juergen Hoeller * @author Rod Johnson diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpSession.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpSession.java index 2c8a411d40..a854fe9f43 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpSession.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockHttpSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -34,10 +34,7 @@ import org.springframework.util.Assert; /** * Mock implementation of the {@link javax.servlet.http.HttpSession} interface. * - *

As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline. - * - *

Used for testing the web framework; also useful for testing application - * controllers. + *

As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * * @author Juergen Hoeller * @author Rod Johnson @@ -72,7 +69,6 @@ public class MockHttpSession implements HttpSession { /** * Create a new MockHttpSession with a default {@link MockServletContext}. - * * @see MockServletContext */ public MockHttpSession() { @@ -81,7 +77,6 @@ public class MockHttpSession implements HttpSession { /** * Create a new MockHttpSession. - * * @param servletContext the ServletContext that the session runs in */ public MockHttpSession(ServletContext servletContext) { @@ -90,7 +85,6 @@ public class MockHttpSession implements HttpSession { /** * Create a new MockHttpSession. - * * @param servletContext the ServletContext that the session runs in * @param id a unique identifier for this session */ @@ -99,6 +93,7 @@ public class MockHttpSession implements HttpSession { this.id = (id != null ? id : Integer.toString(nextId++)); } + @Override public long getCreationTime() { assertIsValid(); @@ -111,8 +106,8 @@ public class MockHttpSession implements HttpSession { } /** - * As of Servlet 3.1 the id of a session can be changed. - * @return the new session id. + * As of Servlet 3.1, the id of a session can be changed. + * @return the new session id * @since 4.0.3 */ public String changeSessionId() { @@ -227,7 +222,6 @@ public class MockHttpSession implements HttpSession { /** * Invalidates this session then unbinds any objects bound to it. - * * @throws IllegalStateException if this method is called on an already invalidated session */ @Override @@ -244,13 +238,10 @@ public class MockHttpSession implements HttpSession { /** * Convenience method for asserting that this session has not been * {@linkplain #invalidate() invalidated}. - * * @throws IllegalStateException if this session has been invalidated */ private void assertIsValid() { - if (isInvalid()) { - throw new IllegalStateException("The session has already been invalidated"); - } + Assert.state(!isInvalid(), "The session has already been invalidated"); } public void setNew(boolean value) { @@ -266,7 +257,6 @@ public class MockHttpSession implements HttpSession { /** * Serialize the attributes of this session into an object that can be * turned into a byte array with standard Java serialization. - * * @return a representation of this session's serialized state */ public Serializable serializeState() { @@ -293,7 +283,6 @@ public class MockHttpSession implements HttpSession { /** * Deserialize the attributes of this session from a state object created by * {@link #serializeState()}. - * * @param state a representation of this session's serialized state */ @SuppressWarnings("unchecked") diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockJspWriter.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockJspWriter.java index e83ff23521..012e0978e5 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockJspWriter.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockJspWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -24,9 +24,7 @@ import javax.servlet.jsp.JspWriter; /** * Mock implementation of the {@link javax.servlet.jsp.JspWriter} class. - * - *

Used for testing the web framework; only necessary for testing - * applications when testing custom JSP tags. + * Only necessary for testing applications when testing custom JSP tags. * * @author Juergen Hoeller * @since 2.5 diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockMultipartHttpServletRequest.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockMultipartHttpServletRequest.java index 8a92ffefe6..d74c24c077 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockMultipartHttpServletRequest.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockMultipartHttpServletRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -35,11 +35,10 @@ import org.springframework.web.multipart.MultipartHttpServletRequest; * Mock implementation of the * {@link org.springframework.web.multipart.MultipartHttpServletRequest} interface. * - *

As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline. + *

As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * *

Useful for testing application controllers that access multipart uploads. - * The {@link MockMultipartFile} can be used to populate these mock requests - * with files. + * {@link MockMultipartFile} can be used to populate these mock requests with files. * * @author Juergen Hoeller * @author Eric Crampton @@ -49,8 +48,7 @@ import org.springframework.web.multipart.MultipartHttpServletRequest; */ public class MockMultipartHttpServletRequest extends MockHttpServletRequest implements MultipartHttpServletRequest { - private final MultiValueMap multipartFiles = - new LinkedMultiValueMap<>(); + private final MultiValueMap multipartFiles = new LinkedMultiValueMap<>(); /** diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockPageContext.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockPageContext.java index b60acba5ef..fbb541a98b 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockPageContext.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockPageContext.java @@ -40,9 +40,7 @@ import org.springframework.util.Assert; /** * Mock implementation of the {@link javax.servlet.jsp.PageContext} interface. - * - *

Used for testing the web framework; only necessary for testing - * applications when testing custom JSP tags. + * Only necessary for testing applications when testing custom JSP tags. * *

Note: Expects initialization via the constructor rather than via the * {@code PageContext.initialize} method. Does not support writing to a diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockRequestDispatcher.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockRequestDispatcher.java index b8679b8020..091b47b12e 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockRequestDispatcher.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockRequestDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -29,9 +29,6 @@ import org.springframework.util.Assert; /** * Mock implementation of the {@link javax.servlet.RequestDispatcher} interface. * - *

Used for testing the web framework; typically not necessary for - * testing application controllers. - * * @author Rod Johnson * @author Juergen Hoeller * @author Sam Brannen @@ -50,7 +47,7 @@ public class MockRequestDispatcher implements RequestDispatcher { * particular path or given by a particular name */ public MockRequestDispatcher(String resource) { - Assert.notNull(resource, "resource must not be null"); + Assert.notNull(resource, "Resource must not be null"); this.resource = resource; } @@ -59,9 +56,7 @@ public class MockRequestDispatcher implements RequestDispatcher { public void forward(ServletRequest request, ServletResponse response) { Assert.notNull(request, "Request must not be null"); Assert.notNull(response, "Response must not be null"); - if (response.isCommitted()) { - throw new IllegalStateException("Cannot perform forward - response is already committed"); - } + Assert.state(!response.isCommitted(), "Cannot perform forward - response is already committed"); getMockHttpServletResponse(response).setForwardedUrl(this.resource); if (logger.isDebugEnabled()) { logger.debug("MockRequestDispatcher: forwarding to [" + this.resource + "]"); diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockServletConfig.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockServletConfig.java index 1da0f87349..c73d05d657 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockServletConfig.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockServletConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -28,9 +28,6 @@ import org.springframework.util.Assert; /** * Mock implementation of the {@link javax.servlet.ServletConfig} interface. * - *

Used for testing the web framework; typically not necessary for - * testing application controllers. - * * @author Rod Johnson * @author Juergen Hoeller * @since 1.0.2 diff --git a/spring-web/src/test/java/org/springframework/mock/web/test/MockServletContext.java b/spring-web/src/test/java/org/springframework/mock/web/test/MockServletContext.java index f6fff852b0..853f34a727 100644 --- a/spring-web/src/test/java/org/springframework/mock/web/test/MockServletContext.java +++ b/spring-web/src/test/java/org/springframework/mock/web/test/MockServletContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -55,37 +55,21 @@ import org.springframework.web.util.WebUtils; /** * Mock implementation of the {@link javax.servlet.ServletContext} interface. * - *

As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline. + *

As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline. * - *

Compatible with Servlet 3.0 but can be configured to expose a specific version - * through {@link #setMajorVersion}/{@link #setMinorVersion}; default is 3.0. - * Note that Servlet 3.0 support is limited: servlet, filter and listener + *

Compatible with Servlet 3.1 but can be configured to expose a specific version + * through {@link #setMajorVersion}/{@link #setMinorVersion}; default is 3.1. + * Note that Servlet 3.1 support is limited: servlet, filter and listener * registration methods are not supported; neither is JSP configuration. * We generally do not recommend to unit test your ServletContainerInitializers and * WebApplicationInitializers which is where those registration methods would be used. * - *

Used for testing the Spring web framework; only rarely necessary for testing - * application controllers. As long as application components don't explicitly - * access the {@code ServletContext}, {@code ClassPathXmlApplicationContext} or - * {@code FileSystemXmlApplicationContext} can be used to load the context files - * for testing, even for {@code DispatcherServlet} context definitions. - * - *

For setting up a full {@code WebApplicationContext} in a test environment, - * you can use {@code AnnotationConfigWebApplicationContext}, - * {@code XmlWebApplicationContext}, or {@code GenericWebApplicationContext}, - * passing in an appropriate {@code MockServletContext} instance. You might want - * to configure your {@code MockServletContext} with a {@code FileSystemResourceLoader} - * in that case to ensure that resource paths are interpreted as relative filesystem - * locations. - * - *

A common setup is to point your JVM working directory to the root of your - * web application directory, in combination with filesystem-based resource loading. - * This allows to load the context files as used in the web application, with - * relative paths getting interpreted correctly. Such a setup will work with both - * {@code FileSystemXmlApplicationContext} (which will load straight from the - * filesystem) and {@code XmlWebApplicationContext} with an underlying - * {@code MockServletContext} (as long as the {@code MockServletContext} has been - * configured with a {@code FileSystemResourceLoader}). + *

For setting up a full {@code WebApplicationContext} in a test environment, you can + * use {@code AnnotationConfigWebApplicationContext}, {@code XmlWebApplicationContext}, + * or {@code GenericWebApplicationContext}, passing in a corresponding + * {@code MockServletContext} instance. Consider configuring your + * {@code MockServletContext} with a {@code FileSystemResourceLoader} in order to + * interpret resource paths as relative filesystem locations. * * @author Rod Johnson * @author Juergen Hoeller @@ -95,18 +79,15 @@ import org.springframework.web.util.WebUtils; * @see org.springframework.web.context.support.AnnotationConfigWebApplicationContext * @see org.springframework.web.context.support.XmlWebApplicationContext * @see org.springframework.web.context.support.GenericWebApplicationContext - * @see org.springframework.context.support.ClassPathXmlApplicationContext - * @see org.springframework.context.support.FileSystemXmlApplicationContext */ public class MockServletContext implements ServletContext { - /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value}. */ + /** Default Servlet name used by Tomcat, Jetty, JBoss, and GlassFish: {@value} */ private static final String COMMON_DEFAULT_SERVLET_NAME = "default"; private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir"; - private static final Set DEFAULT_SESSION_TRACKING_MODES = - new LinkedHashSet<>(3); + private static final Set DEFAULT_SESSION_TRACKING_MODES = new LinkedHashSet<>(4); static { DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.COOKIE); @@ -127,11 +108,11 @@ public class MockServletContext implements ServletContext { private int majorVersion = 3; - private int minorVersion = 0; + private int minorVersion = 1; private int effectiveMajorVersion = 3; - private int effectiveMinorVersion = 0; + private int effectiveMinorVersion = 1; private final Map namedRequestDispatchers = new HashMap<>(); @@ -149,6 +130,8 @@ public class MockServletContext implements ServletContext { private final SessionCookieConfig sessionCookieConfig = new MockSessionCookieConfig(); + private int sessionTimeout; + /** * Create a new {@code MockServletContext}, using no base path and a @@ -425,13 +408,13 @@ public class MockServletContext implements ServletContext { @Override @Deprecated public Enumeration getServlets() { - return Collections.enumeration(Collections.emptySet()); + return Collections.enumeration(Collections.emptySet()); } @Override @Deprecated public Enumeration getServletNames() { - return Collections.enumeration(Collections.emptySet()); + return Collections.enumeration(Collections.emptySet()); } @Override @@ -570,6 +553,16 @@ public class MockServletContext implements ServletContext { return this.sessionCookieConfig; } + // @Override - but only against Servlet 4.0 + public void setSessionTimeout(int sessionTimeout) { + this.sessionTimeout = sessionTimeout; + } + + // @Override - but only against Servlet 4.0 + public int getSessionTimeout() { + return this.sessionTimeout; + } + //--------------------------------------------------------------------- // Unsupported Servlet 3.0 registration methods @@ -580,6 +573,11 @@ public class MockServletContext implements ServletContext { throw new UnsupportedOperationException(); } + // @Override - but only against Servlet 4.0 + public ServletRegistration.Dynamic addJspFile(String servletName, String jspFile) { + throw new UnsupportedOperationException(); + } + @Override public ServletRegistration.Dynamic addServlet(String servletName, String className) { throw new UnsupportedOperationException(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java index 7c9f0465ff..17230276b3 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java @@ -16,8 +16,10 @@ package org.springframework.web.servlet.mvc.method.annotation; +import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.lang.reflect.Method; import java.security.Principal; import java.time.ZoneId; import java.util.Locale; @@ -28,6 +30,8 @@ import javax.servlet.http.HttpSession; import org.springframework.core.MethodParameter; import org.springframework.http.HttpMethod; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; @@ -43,13 +47,14 @@ import org.springframework.web.servlet.support.RequestContextUtils; *

  • {@link ServletRequest} *
  • {@link MultipartRequest} *
  • {@link HttpSession} + *
  • {@link PushBuilder} (as of Spring 5.0 on Servlet 4.0) *
  • {@link Principal} *
  • {@link InputStream} *
  • {@link Reader} - *
  • {@link HttpMethod} (as of Spring 4.0)
  • + *
  • {@link HttpMethod} (as of Spring 4.0) *
  • {@link Locale} *
  • {@link TimeZone} (as of Spring 4.0) - *
  • {@link java.time.ZoneId} (as of Spring 4.0 and Java 8)
  • + *
  • {@link java.time.ZoneId} (as of Spring 4.0 and Java 8) * * * @author Arjen Poutsma @@ -59,6 +64,10 @@ import org.springframework.web.servlet.support.RequestContextUtils; */ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgumentResolver { + private static final Method getPushBuilderMethod = + ClassUtils.getMethodIfAvailable(HttpServletRequest.class, "getPushBuilder"); + + @Override public boolean supportsParameter(MethodParameter parameter) { Class paramType = parameter.getParameterType(); @@ -66,6 +75,7 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType) || HttpSession.class.isAssignableFrom(paramType) || + (getPushBuilderMethod != null && getPushBuilderMethod.getReturnType().isAssignableFrom(paramType)) || Principal.class.isAssignableFrom(paramType) || InputStream.class.isAssignableFrom(paramType) || Reader.class.isAssignableFrom(paramType) || @@ -80,6 +90,8 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Class paramType = parameter.getParameterType(); + + // WebRequest / NativeWebRequest / ServletWebRequest if (WebRequest.class.isAssignableFrom(paramType)) { if (!paramType.isInstance(webRequest)) { throw new IllegalStateException( @@ -88,16 +100,26 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume return webRequest; } - HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); + // ServletRequest / HttpServletRequest / MultipartRequest / MultipartHttpServletRequest if (ServletRequest.class.isAssignableFrom(paramType) || MultipartRequest.class.isAssignableFrom(paramType)) { - Object nativeRequest = webRequest.getNativeRequest(paramType); - if (nativeRequest == null) { - throw new IllegalStateException( - "Current request is not of type [" + paramType.getName() + "]: " + request); - } - return nativeRequest; + return resolveNativeRequest(webRequest, paramType); + } + + // HttpServletRequest required for all further argument types + return resolveArgument(paramType, resolveNativeRequest(webRequest, HttpServletRequest.class)); + } + + private T resolveNativeRequest(NativeWebRequest webRequest, Class requiredType) { + T nativeRequest = webRequest.getNativeRequest(requiredType); + if (nativeRequest == null) { + throw new IllegalStateException( + "Current request is not of type [" + requiredType.getName() + "]: " + webRequest); } - else if (HttpSession.class.isAssignableFrom(paramType)) { + return nativeRequest; + } + + private Object resolveArgument(Class paramType, HttpServletRequest request) throws IOException { + if (HttpSession.class.isAssignableFrom(paramType)) { HttpSession session = request.getSession(); if (!paramType.isInstance(session)) { throw new IllegalStateException( @@ -105,6 +127,14 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume } return session; } + else if (getPushBuilderMethod != null && getPushBuilderMethod.getReturnType().isAssignableFrom(paramType)) { + Object pushBuilder = ReflectionUtils.invokeMethod(getPushBuilderMethod, request); + if (!paramType.isInstance(pushBuilder)) { + throw new IllegalStateException( + "Current push builder is not of type [" + paramType.getName() + "]: " + pushBuilder); + } + return pushBuilder; + } else if (InputStream.class.isAssignableFrom(paramType)) { InputStream inputStream = request.getInputStream(); if (!paramType.isInstance(inputStream)) { @@ -143,11 +173,9 @@ public class ServletRequestMethodArgumentResolver implements HandlerMethodArgume TimeZone timeZone = RequestContextUtils.getTimeZone(request); return (timeZone != null ? timeZone.toZoneId() : ZoneId.systemDefault()); } - else { - // Should never happen... - throw new UnsupportedOperationException( - "Unknown parameter type [" + paramType.getName() + "] in " + parameter.getMethod()); - } + + // Should never happen... + throw new UnsupportedOperationException("Unknown parameter type: " + paramType.getName()); } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolver.java index 2818dc529b..603135d4c5 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2017 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. @@ -16,11 +16,10 @@ package org.springframework.web.servlet.mvc.method.annotation; +import java.io.IOException; import java.io.OutputStream; import java.io.Writer; -import java.lang.reflect.Method; import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; import org.springframework.core.MethodParameter; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -38,6 +37,7 @@ import org.springframework.web.method.support.ModelAndViewContainer; * * @author Arjen Poutsma * @author Rossen Stoyanchev + * @author Juergen Hoeller * @since 3.1 */ public class ServletResponseMethodArgumentResolver implements HandlerMethodArgumentResolver { @@ -64,28 +64,36 @@ public class ServletResponseMethodArgumentResolver implements HandlerMethodArgum mavContainer.setRequestHandled(true); } - HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); Class paramType = parameter.getParameterType(); + // ServletResponse, HttpServletResponse if (ServletResponse.class.isAssignableFrom(paramType)) { - Object nativeResponse = webRequest.getNativeResponse(paramType); - if (nativeResponse == null) { - throw new IllegalStateException( - "Current response is not of type [" + paramType.getName() + "]: " + response); - } - return nativeResponse; + return resolveNativeResponse(webRequest, paramType); } - else if (OutputStream.class.isAssignableFrom(paramType)) { + + // ServletResponse required for all further argument types + return resolveArgument(paramType, resolveNativeResponse(webRequest, ServletResponse.class)); + } + + private T resolveNativeResponse(NativeWebRequest webRequest, Class requiredType) { + T nativeResponse = webRequest.getNativeResponse(requiredType); + if (nativeResponse == null) { + throw new IllegalStateException( + "Current response is not of type [" + requiredType.getName() + "]: " + webRequest); + } + return nativeResponse; + } + + private Object resolveArgument(Class paramType, ServletResponse response) throws IOException { + if (OutputStream.class.isAssignableFrom(paramType)) { return response.getOutputStream(); } else if (Writer.class.isAssignableFrom(paramType)) { return response.getWriter(); } - else { - // should not happen - Method method = parameter.getMethod(); - throw new UnsupportedOperationException("Unknown parameter type: " + paramType + " in method: " + method); - } + + // Should never happen... + throw new UnsupportedOperationException("Unknown parameter type: " + paramType); } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java index b8210fa23f..479e957bb0 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java @@ -75,11 +75,9 @@ public class ServletRequestMethodArgumentResolverTests { @Test public void servletRequest() throws Exception { MethodParameter servletRequestParameter = new MethodParameter(method, 0); + assertTrue("ServletRequest not supported", resolver.supportsParameter(servletRequestParameter)); - boolean isSupported = resolver.supportsParameter(servletRequestParameter); Object result = resolver.resolveArgument(servletRequestParameter, mavContainer, webRequest, null); - - assertTrue("ServletRequest not supported", isSupported); assertSame("Invalid result", servletRequest, result); assertFalse("The requestHandled flag shouldn't change", mavContainer.isRequestHandled()); } @@ -88,12 +86,11 @@ public class ServletRequestMethodArgumentResolverTests { public void session() throws Exception { MockHttpSession session = new MockHttpSession(); servletRequest.setSession(session); + MethodParameter sessionParameter = new MethodParameter(method, 2); + assertTrue("Session not supported", resolver.supportsParameter(sessionParameter)); - boolean isSupported = resolver.supportsParameter(sessionParameter); Object result = resolver.resolveArgument(sessionParameter, mavContainer, webRequest, null); - - assertTrue("Session not supported", isSupported); assertSame("Invalid result", session, result); assertFalse("The requestHandled flag shouldn't change", mavContainer.isRequestHandled()); } @@ -107,8 +104,8 @@ public class ServletRequestMethodArgumentResolverTests { } }; servletRequest.setUserPrincipal(principal); - MethodParameter principalParameter = new MethodParameter(method, 3); + MethodParameter principalParameter = new MethodParameter(method, 3); assertTrue("Principal not supported", resolver.supportsParameter(principalParameter)); Object result = resolver.resolveArgument(principalParameter, null, webRequest, null); @@ -119,8 +116,8 @@ public class ServletRequestMethodArgumentResolverTests { public void locale() throws Exception { Locale locale = Locale.ENGLISH; servletRequest.addPreferredLocale(locale); - MethodParameter localeParameter = new MethodParameter(method, 4); + MethodParameter localeParameter = new MethodParameter(method, 4); assertTrue("Locale not supported", resolver.supportsParameter(localeParameter)); Object result = resolver.resolveArgument(localeParameter, null, webRequest, null); @@ -132,8 +129,8 @@ public class ServletRequestMethodArgumentResolverTests { Locale locale = Locale.ENGLISH; servletRequest.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new FixedLocaleResolver(locale)); - MethodParameter localeParameter = new MethodParameter(method, 4); + MethodParameter localeParameter = new MethodParameter(method, 4); assertTrue("Locale not supported", resolver.supportsParameter(localeParameter)); Object result = resolver.resolveArgument(localeParameter, null, webRequest, null); @@ -143,7 +140,6 @@ public class ServletRequestMethodArgumentResolverTests { @Test public void timeZone() throws Exception { MethodParameter timeZoneParameter = new MethodParameter(method, 8); - assertTrue("TimeZone not supported", resolver.supportsParameter(timeZoneParameter)); Object result = resolver.resolveArgument(timeZoneParameter, null, webRequest, null); @@ -155,8 +151,8 @@ public class ServletRequestMethodArgumentResolverTests { TimeZone timeZone = TimeZone.getTimeZone("America/Los_Angeles"); servletRequest.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, new FixedLocaleResolver(Locale.US, timeZone)); - MethodParameter timeZoneParameter = new MethodParameter(method, 8); + MethodParameter timeZoneParameter = new MethodParameter(method, 8); assertTrue("TimeZone not supported", resolver.supportsParameter(timeZoneParameter)); Object result = resolver.resolveArgument(timeZoneParameter, null, webRequest, null); @@ -166,7 +162,6 @@ public class ServletRequestMethodArgumentResolverTests { @Test public void zoneId() throws Exception { MethodParameter zoneIdParameter = new MethodParameter(method, 9); - assertTrue("ZoneId not supported", resolver.supportsParameter(zoneIdParameter)); Object result = resolver.resolveArgument(zoneIdParameter, null, webRequest, null); @@ -189,7 +184,6 @@ public class ServletRequestMethodArgumentResolverTests { @Test public void inputStream() throws Exception { MethodParameter inputStreamParameter = new MethodParameter(method, 5); - assertTrue("InputStream not supported", resolver.supportsParameter(inputStreamParameter)); Object result = resolver.resolveArgument(inputStreamParameter, null, webRequest, null); @@ -199,7 +193,6 @@ public class ServletRequestMethodArgumentResolverTests { @Test public void reader() throws Exception { MethodParameter readerParameter = new MethodParameter(method, 6); - assertTrue("Reader not supported", resolver.supportsParameter(readerParameter)); Object result = resolver.resolveArgument(readerParameter, null, webRequest, null); @@ -209,7 +202,6 @@ public class ServletRequestMethodArgumentResolverTests { @Test public void webRequest() throws Exception { MethodParameter webRequestParameter = new MethodParameter(method, 7); - assertTrue("WebRequest not supported", resolver.supportsParameter(webRequestParameter)); Object result = resolver.resolveArgument(webRequestParameter, null, webRequest, null); @@ -219,7 +211,6 @@ public class ServletRequestMethodArgumentResolverTests { @Test public void httpMethod() throws Exception { MethodParameter httpMethodParameter = new MethodParameter(method, 10); - assertTrue("HttpMethod not supported", resolver.supportsParameter(httpMethodParameter)); Object result = resolver.resolveArgument(httpMethodParameter, null, webRequest, null); @@ -241,4 +232,4 @@ public class ServletRequestMethodArgumentResolverTests { HttpMethod p10) { } -} \ No newline at end of file +} diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolverTests.java index 0b15b6ce7e..5fa371217f 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2017 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. @@ -33,7 +33,7 @@ import org.springframework.web.method.support.ModelAndViewContainer; import static org.junit.Assert.*; /** - * Test fixture with {@link org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver}. + * Test fixture with {@link ServletResponseMethodArgumentResolver}. * * @author Arjen Poutsma */ @@ -49,6 +49,7 @@ public class ServletResponseMethodArgumentResolverTests { private MockHttpServletResponse servletResponse; + @Before public void setUp() throws Exception { resolver = new ServletResponseMethodArgumentResolver(); @@ -58,10 +59,10 @@ public class ServletResponseMethodArgumentResolverTests { webRequest = new ServletWebRequest(new MockHttpServletRequest(), servletResponse); } + @Test public void servletResponse() throws Exception { MethodParameter servletResponseParameter = new MethodParameter(method, 0); - assertTrue("ServletResponse not supported", resolver.supportsParameter(servletResponseParameter)); Object result = resolver.resolveArgument(servletResponseParameter, mavContainer, webRequest, null); @@ -69,8 +70,7 @@ public class ServletResponseMethodArgumentResolverTests { assertTrue(mavContainer.isRequestHandled()); } - // SPR-8983 - + @Test // SPR-8983 public void servletResponseNoMavContainer() throws Exception { MethodParameter servletResponseParameter = new MethodParameter(method, 0); assertTrue("ServletResponse not supported", resolver.supportsParameter(servletResponseParameter)); @@ -82,7 +82,6 @@ public class ServletResponseMethodArgumentResolverTests { @Test public void outputStream() throws Exception { MethodParameter outputStreamParameter = new MethodParameter(method, 1); - assertTrue("OutputStream not supported", resolver.supportsParameter(outputStreamParameter)); Object result = resolver.resolveArgument(outputStreamParameter, mavContainer, webRequest, null); @@ -93,7 +92,6 @@ public class ServletResponseMethodArgumentResolverTests { @Test public void writer() throws Exception { MethodParameter writerParameter = new MethodParameter(method, 2); - assertTrue("Writer not supported", resolver.supportsParameter(writerParameter)); Object result = resolver.resolveArgument(writerParameter, mavContainer, webRequest, null); @@ -101,7 +99,9 @@ public class ServletResponseMethodArgumentResolverTests { assertTrue(mavContainer.isRequestHandled()); } - public void supportedParams(ServletResponse p0, OutputStream p1, Writer p2) { + @SuppressWarnings("unused") + public void supportedParams(ServletResponse p0, OutputStream p1, Writer p2) { } -} \ No newline at end of file + +} diff --git a/src/asciidoc/web-mvc.adoc b/src/asciidoc/web-mvc.adoc index 3b5d1f7442..915ef6726f 100644 --- a/src/asciidoc/web-mvc.adoc +++ b/src/asciidoc/web-mvc.adoc @@ -476,11 +476,9 @@ abstract way, which enables you to create a wide variety of controllers. Spring 2.5 introduced an annotation-based programming model for MVC controllers that uses annotations such as `@RequestMapping`, `@RequestParam`, `@ModelAttribute`, and so -on. This annotation support is available for both Servlet MVC and Portlet MVC. -Controllers implemented in this style do not have to extend specific base classes or +on. Controllers implemented in this style do not have to extend specific base classes or implement specific interfaces. Furthermore, they do not usually have direct dependencies -on Servlet or Portlet APIs, although you can easily configure access to Servlet or -Portlet facilities. +on Servlet APIs, although you can easily configure access to Servlet facilities if needed. [TIP] ==== @@ -1293,8 +1291,13 @@ neither. ==== Supported method argument types The following are the supported method arguments: +* `org.springframework.web.context.request.WebRequest` or + `org.springframework.web.context.request.NativeWebRequest`. Allows for generic + request parameter access as well as request/session attribute access, without ties + to the native Servlet API. * Request or response objects (Servlet API). Choose any specific request or response - type, for example `ServletRequest` or `HttpServletRequest`. + type, for example `ServletRequest` or `HttpServletRequest` or Spring's + `MultipartRequest`/`MultipartHttpServletRequest`. * Session object (Servlet API) of type `HttpSession`. An argument of this type enforces the presence of a corresponding session. As a consequence, such an argument is never `null`. @@ -1306,21 +1309,21 @@ setting the ``RequestMappingHandlerAdapter``'s "synchronizeOnSession" flag to "t multiple requests are allowed to access a session concurrently. ==== -* `org.springframework.web.context.request.WebRequest` or - `org.springframework.web.context.request.NativeWebRequest`. Allows for generic - request parameter access as well as request/session attribute access, without ties - to the native Servlet/Portlet API. +* `java.servlet.http.PushBuilder` for the associated Servlet 4.0 push builder API, + allowing for programmatic HTTP/2 resource pushes. +* `java.security.Principal` (or a specific `Principal` implementation class if known), + containing the currently authenticated user. +* `org.springframework.http.HttpMethod` for the HTTP request method, represented as + Spring's `HttpMethod` enum. * `java.util.Locale` for the current request locale, determined by the most specific locale resolver available, in effect, the configured `LocaleResolver` / `LocaleContextResolver` in an MVC environment. -* `java.util.TimeZone` (Java 6+) / `java.time.ZoneId` (on Java 8) for the time zone +* `java.util.TimeZone` (Java 6+) / `java.time.ZoneId` (Java 8+) for the time zone associated with the current request, as determined by a `LocaleContextResolver`. * `java.io.InputStream` / `java.io.Reader` for access to the request's content. This value is the raw InputStream/Reader as exposed by the Servlet API. * `java.io.OutputStream` / `java.io.Writer` for generating the response's content. This value is the raw OutputStream/Writer as exposed by the Servlet API. -* `org.springframework.http.HttpMethod` for the HTTP request method. -* `java.security.Principal` containing the currently authenticated user. * `@PathVariable` annotated parameters for access to URI template variables. See <>. * `@MatrixVariable` annotated parameters for access to name-value pairs located in @@ -2000,9 +2003,6 @@ The following code sample demonstrates how to get the value of the `JSESSIONID` Type conversion is applied automatically if the target method parameter type is not `String`. See <>. -This annotation is supported for annotated handler methods in Servlet and Portlet -environments. - [[mvc-ann-requestheader]] ==== Mapping request header attributes with the @RequestHeader annotation @@ -2050,9 +2050,6 @@ example a method parameter annotated with `@RequestHeader("Accept")` may be of t `String` but also `String[]` or `List`. ==== -This annotation is supported for annotated handler methods in Servlet and Portlet -environments. - [[mvc-ann-typeconversion]] ==== Method Parameters And Type Conversion @@ -3968,11 +3965,10 @@ the exception types listed as method arguments are used. Much like standard controller methods annotated with a `@RequestMapping` annotation, the method arguments and return values of `@ExceptionHandler` methods can be flexible. For -example, the `HttpServletRequest` can be accessed in Servlet environments and the -`PortletRequest` in Portlet environments. The return type can be a `String`, which is -interpreted as a view name, a `ModelAndView` object, a `ResponseEntity`, or you can also -add the `@ResponseBody` to have the method return value converted with message -converters and written to the response stream. +example, the `HttpServletRequest` can be accessed in Servlet environments. The return +type can be a `String`, which is interpreted as a view name, a `ModelAndView` object, +a `ResponseEntity`, or you can also add the `@ResponseBody` to have the method return +value converted with message converters and written to the response stream.