SPR-5409 - Support for PUTting and POSTing non-form data
This commit is contained in:
parent
93c56f19df
commit
035eea01e8
|
|
@ -60,6 +60,7 @@ import org.springframework.core.MethodParameter;
|
|||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.style.StylerUtils;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
@ -547,7 +548,7 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator impl
|
|||
|
||||
public PortletHandlerMethodInvoker(HandlerMethodResolver resolver) {
|
||||
super(resolver, webBindingInitializer, sessionAttributeStore,
|
||||
parameterNameDiscoverer, customArgumentResolvers);
|
||||
parameterNameDiscoverer, customArgumentResolvers, new HttpMessageConverter[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
package org.springframework.web.bind.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation which indicates that a method parameter should be bound to the web request body. Supported for annotated
|
||||
* handler methods in Servlet environments.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @see RequestHeader
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
* @since 3.0
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RequestBody {
|
||||
|
||||
}
|
||||
|
|
@ -19,9 +19,11 @@ package org.springframework.web.bind.annotation.support;
|
|||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -35,6 +37,9 @@ import org.springframework.core.GenericTypeResolver;
|
|||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
|
@ -42,11 +47,13 @@ import org.springframework.util.ReflectionUtils;
|
|||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.support.DefaultSessionAttributeStore;
|
||||
|
|
@ -89,24 +96,28 @@ public class HandlerMethodInvoker {
|
|||
|
||||
private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus();
|
||||
|
||||
private final HttpMessageConverter[] messageConverters;
|
||||
|
||||
|
||||
public HandlerMethodInvoker(HandlerMethodResolver methodResolver) {
|
||||
this(methodResolver, null);
|
||||
}
|
||||
|
||||
public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer) {
|
||||
this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null);
|
||||
this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null, new WebArgumentResolver[0],
|
||||
new HttpMessageConverter[0]);
|
||||
}
|
||||
|
||||
public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer,
|
||||
SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer,
|
||||
WebArgumentResolver... customArgumentResolvers) {
|
||||
WebArgumentResolver[] customArgumentResolvers, HttpMessageConverter[] messageConverters) {
|
||||
|
||||
this.methodResolver = methodResolver;
|
||||
this.bindingInitializer = bindingInitializer;
|
||||
this.sessionAttributeStore = sessionAttributeStore;
|
||||
this.parameterNameDiscoverer = parameterNameDiscoverer;
|
||||
this.customArgumentResolvers = customArgumentResolvers;
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -159,6 +170,7 @@ public class HandlerMethodInvoker {
|
|||
GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
|
||||
String paramName = null;
|
||||
String headerName = null;
|
||||
boolean requestBodyFound = false;
|
||||
String cookieName = null;
|
||||
String pathVarName = null;
|
||||
String attrName = null;
|
||||
|
|
@ -182,6 +194,10 @@ public class HandlerMethodInvoker {
|
|||
defaultValue = requestHeader.defaultValue();
|
||||
found++;
|
||||
}
|
||||
else if (RequestBody.class.isInstance(paramAnn)) {
|
||||
requestBodyFound = true;
|
||||
found++;
|
||||
}
|
||||
else if (CookieValue.class.isInstance(paramAnn)) {
|
||||
CookieValue cookieValue = (CookieValue) paramAnn;
|
||||
cookieName = cookieValue.value();
|
||||
|
|
@ -238,6 +254,9 @@ public class HandlerMethodInvoker {
|
|||
else if (headerName != null) {
|
||||
args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
|
||||
}
|
||||
else if (requestBodyFound) {
|
||||
args[i] = resolveRequestBody(methodParam, webRequest, handler);
|
||||
}
|
||||
else if (cookieName != null) {
|
||||
args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
|
||||
}
|
||||
|
|
@ -418,6 +437,45 @@ public class HandlerMethodInvoker {
|
|||
return binder.convertIfNecessary(headerValue, paramType, methodParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given {@link RequestBody @RequestBody} annotation.
|
||||
* Throws an UnsupportedOperationException by default.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Object resolveRequestBody(MethodParameter methodParam, NativeWebRequest webRequest, Object handler)
|
||||
throws Exception {
|
||||
|
||||
HttpInputMessage inputMessage = createHttpInputMessage(webRequest);
|
||||
|
||||
Class paramType = methodParam.getParameterType();
|
||||
MediaType contentType = inputMessage.getHeaders().getContentType();
|
||||
if (contentType == null) {
|
||||
throw new IllegalStateException("Cannot extract response: no Content-Type found");
|
||||
}
|
||||
List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
|
||||
for (HttpMessageConverter<?> messageConverter : messageConverters) {
|
||||
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
|
||||
if (messageConverter.supports(paramType)) {
|
||||
for (MediaType supportedMediaType : messageConverter.getSupportedMediaTypes()) {
|
||||
if (supportedMediaType.includes(contentType)) {
|
||||
return messageConverter.read(paramType, inputMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link HttpInputMessage} for the given {@link NativeWebRequest}.
|
||||
* Throws an UnsupportedOperationException by default.
|
||||
*/
|
||||
protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
throw new UnsupportedOperationException("@RequestBody not supported");
|
||||
}
|
||||
|
||||
private Object resolveCookieValue(String cookieName, boolean required, String defaultValue,
|
||||
MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall)
|
||||
throws Exception {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,14 @@ import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
|||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
||||
import org.springframework.http.converter.FormHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
|
@ -60,6 +68,7 @@ import org.springframework.util.CollectionUtils;
|
|||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.support.BindingAwareModelMap;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||
import org.springframework.web.HttpSessionRequiredException;
|
||||
import org.springframework.web.bind.MissingServletRequestParameterException;
|
||||
|
|
@ -149,6 +158,9 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
private final Map<Class<?>, ServletHandlerMethodResolver> methodResolverCache =
|
||||
new ConcurrentHashMap<Class<?>, ServletHandlerMethodResolver>();
|
||||
|
||||
private HttpMessageConverter<?>[] messageConverters =
|
||||
new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter(),
|
||||
new FormHttpMessageConverter(), new SourceHttpMessageConverter()};
|
||||
|
||||
public AnnotationMethodHandlerAdapter() {
|
||||
// no restriction of HTTP methods by default
|
||||
|
|
@ -291,6 +303,16 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
this.customArgumentResolvers = argumentResolvers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message body converters to use. These converters are used to convert
|
||||
* from and to HTTP requests and responses.
|
||||
*/
|
||||
public void setMessageConverters(HttpMessageConverter<?>[] messageConverters) {
|
||||
Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public boolean supports(Object handler) {
|
||||
return getMethodResolver(handler).hasHandlerMethods();
|
||||
|
|
@ -346,13 +368,15 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
catch (HttpRequestMethodNotSupportedException ex) {
|
||||
return handleHttpRequestMethodNotSupportedException(ex, request, response);
|
||||
}
|
||||
catch (HttpMediaTypeNotSupportedException ex) {
|
||||
return handleHttpMediaTypeNotSupportedException(ex, request, response);
|
||||
}
|
||||
}
|
||||
|
||||
public long getLastModified(HttpServletRequest request, Object handler) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle the case where no request handler method was found.
|
||||
* <p>The default implementation logs a warning and sends an HTTP 404 error.
|
||||
|
|
@ -394,6 +418,27 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the case where no {@linkplain HttpMessageConverter message converters} was found for the PUT or POSTed
|
||||
* content.
|
||||
* <p>The default implementation logs a warning, sends an HTTP 415 error and sets the "Allow" header.
|
||||
* Alternatively, a fallback view could be chosen, or the HttpMediaTypeNotSupportedException
|
||||
* could be rethrown as-is.
|
||||
* @param ex the HttpMediaTypeNotSupportedException to be handled
|
||||
* @param request current HTTP request
|
||||
* @param response current HTTP response
|
||||
* @return a ModelAndView to render, or <code>null</code> if handled directly
|
||||
* @throws Exception an Exception that should be thrown as result of the servlet request
|
||||
*/
|
||||
protected ModelAndView handleHttpMediaTypeNotSupportedException(
|
||||
HttpMediaTypeNotSupportedException ex, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE);
|
||||
response.addHeader("Accept", MediaType.toString(ex.getSupportedMediaTypes()));
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for creating a new ServletRequestDataBinder instance.
|
||||
* <p>The default implementation creates a standard ServletRequestDataBinder.
|
||||
|
|
@ -593,7 +638,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
|
||||
private ServletHandlerMethodInvoker(HandlerMethodResolver resolver) {
|
||||
super(resolver, webBindingInitializer, sessionAttributeStore,
|
||||
parameterNameDiscoverer, customArgumentResolvers);
|
||||
parameterNameDiscoverer, customArgumentResolvers, messageConverters);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -625,6 +670,12 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception {
|
||||
HttpServletRequest servletRequest = (HttpServletRequest) webRequest.getNativeRequest();
|
||||
return new ServletServerHttpRequest(servletRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import org.junit.Test;
|
|||
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
||||
import org.springframework.aop.interceptor.SimpleTraceInterceptor;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.DerivedTestBean;
|
||||
import org.springframework.beans.ITestBean;
|
||||
import org.springframework.beans.TestBean;
|
||||
|
|
@ -66,6 +67,7 @@ import org.springframework.web.bind.WebDataBinder;
|
|||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
|
@ -93,18 +95,11 @@ import org.springframework.web.util.NestedServletException;
|
|||
*/
|
||||
public class ServletAnnotationControllerTests {
|
||||
|
||||
private DispatcherServlet servlet;
|
||||
|
||||
@Test
|
||||
public void standardHandleMethod() throws Exception {
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(MyController.class));
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
initServlet(MyController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
|
@ -114,16 +109,7 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
@Test(expected = MissingServletRequestParameterException.class)
|
||||
public void requiredParamMissing() throws Exception {
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(RequiredParamController.class));
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
initServlet(RequiredParamController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
|
@ -132,16 +118,7 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
@Test
|
||||
public void optionalParamPresent() throws Exception {
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(OptionalParamController.class));
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
initServlet(OptionalParamController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
|
||||
request.addParameter("id", "val");
|
||||
|
|
@ -154,16 +131,7 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
@Test
|
||||
public void optionalParamMissing() throws Exception {
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(OptionalParamController.class));
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
initServlet(OptionalParamController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
|
@ -173,16 +141,7 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
@Test
|
||||
public void defaultParamMissing() throws Exception {
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(DefaultValueParamController.class));
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
initServlet(DefaultValueParamController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
|
@ -192,16 +151,7 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
@Test
|
||||
public void methodNotAllowed() throws Exception {
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(MethodNotAllowedController.class));
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
initServlet(MethodNotAllowedController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
|
@ -285,17 +235,23 @@ public class ServletAnnotationControllerTests {
|
|||
doTestAdaptedHandleMethods(MyAdaptedController3.class);
|
||||
}
|
||||
|
||||
private void doTestAdaptedHandleMethods(final Class<?> controllerClass) throws Exception {
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
private void initServlet(final Class<?> controllerclass) throws ServletException {
|
||||
servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)
|
||||
throws BeansException {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass));
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerclass));
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
}
|
||||
|
||||
|
||||
private void doTestAdaptedHandleMethods(final Class<?> controllerClass) throws Exception {
|
||||
initServlet(controllerClass);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath1.do");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
|
@ -886,16 +842,7 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
@Test
|
||||
public void pathOrdering() throws ServletException, IOException {
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(PathOrderingController.class));
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
initServlet(PathOrderingController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/dir/myPath1.do");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
|
@ -903,6 +850,34 @@ public class ServletAnnotationControllerTests {
|
|||
assertEquals("method1", response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestBody() throws ServletException, IOException {
|
||||
initServlet(RequestBodyController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
|
||||
String requestBody = "Hello World";
|
||||
request.setContent(requestBody.getBytes("UTF-8"));
|
||||
request.addHeader("Content-Type", "text/plain; charset=utf-8");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals(requestBody, response.getContentAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unsupportedRequestBody() throws ServletException, IOException {
|
||||
initServlet(RequestBodyController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
|
||||
String requestBody = "Hello World";
|
||||
request.setContent(requestBody.getBytes("UTF-8"));
|
||||
request.addHeader("Content-Type", "application/pdf");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("Invalid response status code", HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE,
|
||||
response.getStatus());
|
||||
assertNotNull("No Accept response header set", response.getHeader("Accept"));
|
||||
}
|
||||
|
||||
/*
|
||||
* Controllers
|
||||
*/
|
||||
|
|
@ -1482,4 +1457,13 @@ public class ServletAnnotationControllerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Controller
|
||||
public static class RequestBodyController {
|
||||
|
||||
@RequestMapping(value = "/something", method = RequestMethod.PUT)
|
||||
public void handle(@RequestBody String body, Writer writer) throws IOException {
|
||||
writer.write(body);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
package org.springframework.web;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
* Exception thrown when a client POSTs or PUTs content
|
||||
* not supported by request handler does not support a
|
||||
* specific request method.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 3.0
|
||||
*/
|
||||
public class HttpMediaTypeNotSupportedException extends ServletException {
|
||||
|
||||
private MediaType contentType;
|
||||
|
||||
private List<MediaType> supportedMediaTypes;
|
||||
|
||||
/**
|
||||
* Create a new HttpMediaTypeNotSupportedException.
|
||||
* @param contentType the unsupported content type
|
||||
* @param supportedMediaTypes the list of supported media types
|
||||
*/
|
||||
public HttpMediaTypeNotSupportedException(MediaType contentType, List<MediaType> supportedMediaTypes) {
|
||||
this(contentType, supportedMediaTypes, "Content type '" + contentType + "' not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new HttpMediaTypeNotSupportedException.
|
||||
* @param contentType the unsupported content type
|
||||
* @param supportedMediaTypes the list of supported media types
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public HttpMediaTypeNotSupportedException(MediaType contentType, List<MediaType> supportedMediaTypes, String msg) {
|
||||
super(msg);
|
||||
this.contentType = contentType;
|
||||
this.supportedMediaTypes = supportedMediaTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTTP request content type method that caused the failure.
|
||||
*/
|
||||
public MediaType getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of supported media types.
|
||||
*/
|
||||
public List<MediaType> getSupportedMediaTypes() {
|
||||
return supportedMediaTypes;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue