Browse Source

Support for Servlet 4.0 (PushBuilder argument, MockServletContext)

Issue: SPR-12674
pull/1323/merge
Juergen Hoeller 8 years ago
parent
commit
199aa776c9
  1. 6
      spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java
  2. 7
      spring-test/src/main/java/org/springframework/mock/web/MockExpressionEvaluator.java
  3. 6
      spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java
  4. 2
      spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java
  5. 2
      spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java
  6. 2
      spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java
  7. 19
      spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java
  8. 6
      spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java
  9. 10
      spring-test/src/main/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java
  10. 4
      spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java
  11. 7
      spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java
  12. 5
      spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java
  13. 66
      spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java
  14. 16
      spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java
  15. 6
      spring-web/src/test/java/org/springframework/mock/web/test/MockBodyContent.java
  16. 16
      spring-web/src/test/java/org/springframework/mock/web/test/MockExpressionEvaluator.java
  17. 11
      spring-web/src/test/java/org/springframework/mock/web/test/MockFilterChain.java
  18. 2
      spring-web/src/test/java/org/springframework/mock/web/test/MockFilterConfig.java
  19. 2
      spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java
  20. 2
      spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletResponse.java
  21. 23
      spring-web/src/test/java/org/springframework/mock/web/test/MockHttpSession.java
  22. 6
      spring-web/src/test/java/org/springframework/mock/web/test/MockJspWriter.java
  23. 10
      spring-web/src/test/java/org/springframework/mock/web/test/MockMultipartHttpServletRequest.java
  24. 4
      spring-web/src/test/java/org/springframework/mock/web/test/MockPageContext.java
  25. 11
      spring-web/src/test/java/org/springframework/mock/web/test/MockRequestDispatcher.java
  26. 5
      spring-web/src/test/java/org/springframework/mock/web/test/MockServletConfig.java
  27. 70
      spring-web/src/test/java/org/springframework/mock/web/test/MockServletContext.java
  28. 58
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java
  29. 40
      spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolver.java
  30. 25
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java
  31. 18
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolverTests.java
  32. 42
      src/asciidoc/web-mvc.adoc

6
spring-test/src/main/java/org/springframework/mock/web/MockBodyContent.java

@ -1,5 +1,5 @@ @@ -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; @@ -26,9 +26,7 @@ import javax.servlet.jsp.tagext.BodyContent;
/**
* Mock implementation of the {@link javax.servlet.jsp.tagext.BodyContent} class.
*
* <p>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

7
spring-test/src/main/java/org/springframework/mock/web/MockExpressionEvaluator.java

@ -1,5 +1,5 @@ @@ -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; @@ -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.
*
* <p>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.
*
* <p>Note that the Apache JSTL implementation (jstl.jar, standard.jar) has to be
* available on the class path to use this expression evaluator.

6
spring-test/src/main/java/org/springframework/mock/web/MockFilterChain.java

@ -1,5 +1,5 @@ @@ -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; @@ -33,9 +33,7 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* <p>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.
*
* <p>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

2
spring-test/src/main/java/org/springframework/mock/web/MockFilterConfig.java

@ -1,5 +1,5 @@ @@ -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.

2
spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java

@ -70,7 +70,7 @@ import org.springframework.util.StringUtils; @@ -70,7 +70,7 @@ import org.springframework.util.StringUtils;
* is {@link Locale#ENGLISH}. This value can be changed via {@link #addPreferredLocale}
* or {@link #setPreferredLocales}.
*
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 3.1 baseline.
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* @author Juergen Hoeller
* @author Rod Johnson

2
spring-test/src/main/java/org/springframework/mock/web/MockHttpServletResponse.java

@ -45,7 +45,7 @@ import org.springframework.web.util.WebUtils; @@ -45,7 +45,7 @@ import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link javax.servlet.http.HttpServletResponse} interface.
*
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 3.1 baseline.
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* @author Juergen Hoeller
* @author Rod Johnson

19
spring-test/src/main/java/org/springframework/mock/web/MockHttpSession.java

@ -1,5 +1,5 @@ @@ -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; @@ -34,10 +34,7 @@ import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.http.HttpSession} interface.
*
* <p>As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline.
*
* <p>Used for testing the web framework; also useful for testing application
* controllers.
* <p>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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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")

6
spring-test/src/main/java/org/springframework/mock/web/MockJspWriter.java

@ -1,5 +1,5 @@ @@ -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; @@ -24,9 +24,7 @@ import javax.servlet.jsp.JspWriter;
/**
* Mock implementation of the {@link javax.servlet.jsp.JspWriter} class.
*
* <p>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

10
spring-test/src/main/java/org/springframework/mock/web/MockMultipartHttpServletRequest.java

@ -1,5 +1,5 @@ @@ -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; @@ -35,11 +35,10 @@ import org.springframework.web.multipart.MultipartHttpServletRequest;
* Mock implementation of the
* {@link org.springframework.web.multipart.MultipartHttpServletRequest} interface.
*
* <p>As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline.
* <p>As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* <p>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; @@ -49,8 +48,7 @@ import org.springframework.web.multipart.MultipartHttpServletRequest;
*/
public class MockMultipartHttpServletRequest extends MockHttpServletRequest implements MultipartHttpServletRequest {
private final MultiValueMap<String, MultipartFile> multipartFiles =
new LinkedMultiValueMap<>();
private final MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<>();
/**

4
spring-test/src/main/java/org/springframework/mock/web/MockPageContext.java

@ -40,9 +40,7 @@ import org.springframework.util.Assert; @@ -40,9 +40,7 @@ import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.jsp.PageContext} interface.
*
* <p>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.
*
* <p>Note: Expects initialization via the constructor rather than via the
* {@code PageContext.initialize} method. Does not support writing to a

7
spring-test/src/main/java/org/springframework/mock/web/MockRequestDispatcher.java

@ -1,5 +1,5 @@ @@ -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; @@ -29,9 +29,6 @@ import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.RequestDispatcher} interface.
*
* <p>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 { @@ -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;
}

5
spring-test/src/main/java/org/springframework/mock/web/MockServletConfig.java

@ -1,5 +1,5 @@ @@ -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; @@ -28,9 +28,6 @@ import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.ServletConfig} interface.
*
* <p>Used for testing the web framework; typically not necessary for
* testing application controllers.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 1.0.2

66
spring-test/src/main/java/org/springframework/mock/web/MockServletContext.java

@ -1,5 +1,5 @@ @@ -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; @@ -55,37 +55,21 @@ import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link javax.servlet.ServletContext} interface.
*
* <p>As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline.
* <p>As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* <p>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
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>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}).
* <p>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; @@ -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<SessionTrackingMode> DEFAULT_SESSION_TRACKING_MODES =
new LinkedHashSet<>(3);
private static final Set<SessionTrackingMode> DEFAULT_SESSION_TRACKING_MODES = new LinkedHashSet<>(4);
static {
DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.COOKIE);
@ -127,11 +108,11 @@ public class MockServletContext implements ServletContext { @@ -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<String, RequestDispatcher> namedRequestDispatchers = new HashMap<>();
@ -149,6 +130,8 @@ public class MockServletContext implements ServletContext { @@ -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 { @@ -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 { @@ -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();

16
spring-test/src/test/java/org/springframework/mock/web/MockServletContextTests.java

@ -1,5 +1,5 @@ @@ -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 { @@ -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));

6
spring-web/src/test/java/org/springframework/mock/web/test/MockBodyContent.java

@ -1,5 +1,5 @@ @@ -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; @@ -26,9 +26,7 @@ import javax.servlet.jsp.tagext.BodyContent;
/**
* Mock implementation of the {@link javax.servlet.jsp.tagext.BodyContent} class.
*
* <p>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

16
spring-web/src/test/java/org/springframework/mock/web/test/MockExpressionEvaluator.java

@ -1,5 +1,5 @@ @@ -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; @@ -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.
*
* <p>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.
*
* <p>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 @@ -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 @@ -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);
}

11
spring-web/src/test/java/org/springframework/mock/web/test/MockFilterChain.java

@ -1,5 +1,5 @@ @@ -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; @@ -33,9 +33,7 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* <p>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.
*
* <p>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 { @@ -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();

2
spring-web/src/test/java/org/springframework/mock/web/test/MockFilterConfig.java

@ -1,5 +1,5 @@ @@ -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.

2
spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java

@ -70,7 +70,7 @@ import org.springframework.util.StringUtils; @@ -70,7 +70,7 @@ import org.springframework.util.StringUtils;
* is {@link Locale#ENGLISH}. This value can be changed via {@link #addPreferredLocale}
* or {@link #setPreferredLocales}.
*
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 3.1 baseline.
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* @author Juergen Hoeller
* @author Rod Johnson

2
spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletResponse.java

@ -45,7 +45,7 @@ import org.springframework.web.util.WebUtils; @@ -45,7 +45,7 @@ import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link javax.servlet.http.HttpServletResponse} interface.
*
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 3.1 baseline.
* <p>As of Spring Framework 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* @author Juergen Hoeller
* @author Rod Johnson

23
spring-web/src/test/java/org/springframework/mock/web/test/MockHttpSession.java

@ -1,5 +1,5 @@ @@ -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; @@ -34,10 +34,7 @@ import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.http.HttpSession} interface.
*
* <p>As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline.
*
* <p>Used for testing the web framework; also useful for testing application
* controllers.
* <p>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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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")

6
spring-web/src/test/java/org/springframework/mock/web/test/MockJspWriter.java

@ -1,5 +1,5 @@ @@ -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; @@ -24,9 +24,7 @@ import javax.servlet.jsp.JspWriter;
/**
* Mock implementation of the {@link javax.servlet.jsp.JspWriter} class.
*
* <p>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

10
spring-web/src/test/java/org/springframework/mock/web/test/MockMultipartHttpServletRequest.java

@ -1,5 +1,5 @@ @@ -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; @@ -35,11 +35,10 @@ import org.springframework.web.multipart.MultipartHttpServletRequest;
* Mock implementation of the
* {@link org.springframework.web.multipart.MultipartHttpServletRequest} interface.
*
* <p>As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline.
* <p>As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* <p>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; @@ -49,8 +48,7 @@ import org.springframework.web.multipart.MultipartHttpServletRequest;
*/
public class MockMultipartHttpServletRequest extends MockHttpServletRequest implements MultipartHttpServletRequest {
private final MultiValueMap<String, MultipartFile> multipartFiles =
new LinkedMultiValueMap<>();
private final MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<>();
/**

4
spring-web/src/test/java/org/springframework/mock/web/test/MockPageContext.java

@ -40,9 +40,7 @@ import org.springframework.util.Assert; @@ -40,9 +40,7 @@ import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.jsp.PageContext} interface.
*
* <p>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.
*
* <p>Note: Expects initialization via the constructor rather than via the
* {@code PageContext.initialize} method. Does not support writing to a

11
spring-web/src/test/java/org/springframework/mock/web/test/MockRequestDispatcher.java

@ -1,5 +1,5 @@ @@ -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; @@ -29,9 +29,6 @@ import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.RequestDispatcher} interface.
*
* <p>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 { @@ -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 { @@ -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 + "]");

5
spring-web/src/test/java/org/springframework/mock/web/test/MockServletConfig.java

@ -1,5 +1,5 @@ @@ -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; @@ -28,9 +28,6 @@ import org.springframework.util.Assert;
/**
* Mock implementation of the {@link javax.servlet.ServletConfig} interface.
*
* <p>Used for testing the web framework; typically not necessary for
* testing application controllers.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @since 1.0.2

70
spring-web/src/test/java/org/springframework/mock/web/test/MockServletContext.java

@ -1,5 +1,5 @@ @@ -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; @@ -55,37 +55,21 @@ import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link javax.servlet.ServletContext} interface.
*
* <p>As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline.
* <p>As of Spring 5.0, this set of mocks is designed on a Servlet 4.0 baseline.
*
* <p>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
* <p>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.
*
* <p>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.
*
* <p>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.
*
* <p>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}).
* <p>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; @@ -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<SessionTrackingMode> DEFAULT_SESSION_TRACKING_MODES =
new LinkedHashSet<>(3);
private static final Set<SessionTrackingMode> DEFAULT_SESSION_TRACKING_MODES = new LinkedHashSet<>(4);
static {
DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.COOKIE);
@ -127,11 +108,11 @@ public class MockServletContext implements ServletContext { @@ -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<String, RequestDispatcher> namedRequestDispatchers = new HashMap<>();
@ -149,6 +130,8 @@ public class MockServletContext implements ServletContext { @@ -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 { @@ -425,13 +408,13 @@ public class MockServletContext implements ServletContext {
@Override
@Deprecated
public Enumeration<Servlet> getServlets() {
return Collections.enumeration(Collections.<Servlet>emptySet());
return Collections.enumeration(Collections.emptySet());
}
@Override
@Deprecated
public Enumeration<String> getServletNames() {
return Collections.enumeration(Collections.<String>emptySet());
return Collections.enumeration(Collections.emptySet());
}
@Override
@ -570,6 +553,16 @@ public class MockServletContext implements ServletContext { @@ -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 { @@ -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();

58
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolver.java

@ -16,8 +16,10 @@ @@ -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; @@ -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; @@ -43,13 +47,14 @@ import org.springframework.web.servlet.support.RequestContextUtils;
* <li>{@link ServletRequest}
* <li>{@link MultipartRequest}
* <li>{@link HttpSession}
* <li>{@link PushBuilder} (as of Spring 5.0 on Servlet 4.0)
* <li>{@link Principal}
* <li>{@link InputStream}
* <li>{@link Reader}
* <li>{@link HttpMethod} (as of Spring 4.0)</li>
* <li>{@link HttpMethod} (as of Spring 4.0)
* <li>{@link Locale}
* <li>{@link TimeZone} (as of Spring 4.0)
* <li>{@link java.time.ZoneId} (as of Spring 4.0 and Java 8)</li>
* <li>{@link java.time.ZoneId} (as of Spring 4.0 and Java 8)
* </ul>
*
* @author Arjen Poutsma
@ -59,6 +64,10 @@ import org.springframework.web.servlet.support.RequestContextUtils; @@ -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 @@ -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 @@ -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 @@ -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> T resolveNativeRequest(NativeWebRequest webRequest, Class<T> 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 @@ -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 @@ -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());
}
}

40
spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolver.java

@ -1,5 +1,5 @@ @@ -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 @@ @@ -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; @@ -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 @@ -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> T resolveNativeResponse(NativeWebRequest webRequest, Class<T> 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);
}
}

25
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletRequestMethodArgumentResolverTests.java

@ -75,11 +75,9 @@ public class ServletRequestMethodArgumentResolverTests { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -241,4 +232,4 @@ public class ServletRequestMethodArgumentResolverTests {
HttpMethod p10) {
}
}
}

18
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletResponseMethodArgumentResolverTests.java

@ -1,5 +1,5 @@ @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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) {
}
}
}

42
src/asciidoc/web-mvc.adoc

@ -476,11 +476,9 @@ abstract way, which enables you to create a wide variety of controllers. @@ -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. @@ -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 @@ -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
<<mvc-ann-requestmapping-uri-templates>>.
* `@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` @@ -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 <<mvc-ann-typeconversion>>.
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 @@ -2050,9 +2050,6 @@ example a method parameter annotated with `@RequestHeader("Accept")` may be of t
`String` but also `String[]` or `List<String>`.
====
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. @@ -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.

Loading…
Cancel
Save