HttpMessageConverter.supports() is split into canRead/canWrite.
HttpMessageConverter.write() now allows for a specific content type.
This commit is contained in:
@@ -121,22 +121,24 @@ import org.springframework.web.util.WebUtils;
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Arjen Poutsma
|
||||
* @since 2.5
|
||||
* @see #setPathMatcher
|
||||
* @see #setMethodNameResolver
|
||||
* @see #setWebBindingInitializer
|
||||
* @see #setSessionAttributeStore
|
||||
* @since 2.5
|
||||
*/
|
||||
public class AnnotationMethodHandlerAdapter extends WebContentGenerator implements HandlerAdapter, BeanFactoryAware {
|
||||
|
||||
/**
|
||||
* Log category to use when no mapped handler is found for a request.
|
||||
*
|
||||
* @see #pageNotFoundLogger
|
||||
*/
|
||||
public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
|
||||
|
||||
/**
|
||||
* Additional logger to use when no mapped handler is found for a request.
|
||||
*
|
||||
* @see #PAGE_NOT_FOUND_LOG_CATEGORY
|
||||
*/
|
||||
protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
|
||||
@@ -162,7 +164,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
private ModelAndViewResolver[] customModelAndViewResolvers;
|
||||
|
||||
private HttpMessageConverter<?>[] messageConverters =
|
||||
new HttpMessageConverter[] {new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter(),
|
||||
new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), new StringHttpMessageConverter(),
|
||||
new FormHttpMessageConverter(), new SourceHttpMessageConverter()};
|
||||
|
||||
private ConfigurableBeanFactory beanFactory;
|
||||
@@ -172,17 +174,16 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
private final Map<Class<?>, ServletHandlerMethodResolver> methodResolverCache =
|
||||
new ConcurrentHashMap<Class<?>, ServletHandlerMethodResolver>();
|
||||
|
||||
|
||||
public AnnotationMethodHandlerAdapter() {
|
||||
// no restriction of HTTP methods by default
|
||||
super(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set if URL lookup should always use the full path within the current servlet context. Else, the path within the
|
||||
* current servlet mapping is used if applicable (that is, in the case of a ".../*" servlet mapping in web.xml).
|
||||
* <p>Default is "false".
|
||||
*
|
||||
* @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath
|
||||
*/
|
||||
public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
|
||||
@@ -193,6 +194,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
* Set if context path and request URI should be URL-decoded. Both are returned <i>undecoded</i> by the Servlet API, in
|
||||
* contrast to the servlet path. <p>Uses either the request encoding or the default encoding according to the Servlet
|
||||
* spec (ISO-8859-1).
|
||||
*
|
||||
* @see org.springframework.web.util.UrlPathHelper#setUrlDecode
|
||||
*/
|
||||
public void setUrlDecode(boolean urlDecode) {
|
||||
@@ -211,6 +213,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
/**
|
||||
* Set the PathMatcher implementation to use for matching URL paths against registered URL patterns. Default is
|
||||
* AntPathMatcher.
|
||||
*
|
||||
* @see org.springframework.util.AntPathMatcher
|
||||
*/
|
||||
public void setPathMatcher(PathMatcher pathMatcher) {
|
||||
@@ -220,8 +223,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
|
||||
/**
|
||||
* Set the MethodNameResolver to use for resolving default handler methods (carrying an empty
|
||||
* <code>@RequestMapping</code> annotation).
|
||||
* <p>Will only kick in when the handler method cannot be resolved uniquely
|
||||
* <code>@RequestMapping</code> annotation). <p>Will only kick in when the handler method cannot be resolved uniquely
|
||||
* through the annotation metadata already.
|
||||
*/
|
||||
public void setMethodNameResolver(MethodNameResolver methodNameResolver) {
|
||||
@@ -229,16 +231,15 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a WebBindingInitializer which will apply pre-configured configuration to every
|
||||
* DataBinder that this controller uses.
|
||||
* Specify a WebBindingInitializer which will apply pre-configured configuration to every DataBinder that this
|
||||
* controller uses.
|
||||
*/
|
||||
public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {
|
||||
this.webBindingInitializer = webBindingInitializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the strategy to store session attributes with.
|
||||
* <p>Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore},
|
||||
* Specify the strategy to store session attributes with. <p>Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore},
|
||||
* storing session attributes in the HttpSession, using the same attribute name as in the model.
|
||||
*/
|
||||
public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) {
|
||||
@@ -248,10 +249,10 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
|
||||
/**
|
||||
* Cache content produced by <code>@SessionAttributes</code> annotated handlers for the given number of seconds.
|
||||
* Default is 0, preventing caching completely.
|
||||
* <p>In contrast to the "cacheSeconds" property which will apply to all
|
||||
* Default is 0, preventing caching completely. <p>In contrast to the "cacheSeconds" property which will apply to all
|
||||
* general handlers (but not to <code>@SessionAttributes</code> annotated handlers), this setting will apply to
|
||||
* <code>@SessionAttributes</code> annotated handlers only.
|
||||
*
|
||||
* @see #setCacheSeconds
|
||||
* @see org.springframework.web.bind.annotation.SessionAttributes
|
||||
*/
|
||||
@@ -260,17 +261,15 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if controller execution should be synchronized on the session, to serialize
|
||||
* parallel invocations from the same client.
|
||||
* <p>More specifically, the execution of each handler method will get synchronized if this
|
||||
* flag is "true". The best available session mutex will be used for the synchronization;
|
||||
* ideally, this will be a mutex exposed by HttpSessionMutexListener.
|
||||
* <p>The session mutex is guaranteed to be the same object during the entire lifetime of the
|
||||
* session, available under the key defined by the <code>SESSION_MUTEX_ATTRIBUTE</code> constant.
|
||||
* It serves as a safe reference to synchronize on for locking on the current session.
|
||||
* <p>In many cases, the HttpSession reference itself a safe mutex as well, since it will
|
||||
* always be the same object reference for the same active logical session. However, this is
|
||||
* not guaranteed across different servlet containers; the only 100% safe way is a session mutex.
|
||||
* Set if controller execution should be synchronized on the session, to serialize parallel invocations from the same
|
||||
* client. <p>More specifically, the execution of each handler method will get synchronized if this flag is "true". The
|
||||
* best available session mutex will be used for the synchronization; ideally, this will be a mutex exposed by
|
||||
* HttpSessionMutexListener. <p>The session mutex is guaranteed to be the same object during the entire lifetime of the
|
||||
* session, available under the key defined by the <code>SESSION_MUTEX_ATTRIBUTE</code> constant. It serves as a safe
|
||||
* reference to synchronize on for locking on the current session. <p>In many cases, the HttpSession reference itself a
|
||||
* safe mutex as well, since it will always be the same object reference for the same active logical session. However,
|
||||
* this is not guaranteed across different servlet containers; the only 100% safe way is a session mutex.
|
||||
*
|
||||
* @see org.springframework.web.util.HttpSessionMutexListener
|
||||
* @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession)
|
||||
*/
|
||||
@@ -280,40 +279,41 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
|
||||
/**
|
||||
* Set the ParameterNameDiscoverer to use for resolving method parameter names if needed (e.g. for default attribute
|
||||
* names).
|
||||
* <p>Default is a {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}.
|
||||
* names). <p>Default is a {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}.
|
||||
*/
|
||||
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
|
||||
this.parameterNameDiscoverer = parameterNameDiscoverer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom WebArgumentResolvers to use for special method parameter types. Such a custom WebArgumentResolver will kick
|
||||
* in first, having a chance to resolve an argument value before the standard argument handling kicks in.
|
||||
* Set a custom WebArgumentResolvers to use for special method parameter types. Such a custom WebArgumentResolver will
|
||||
* kick in first, having a chance to resolve an argument value before the standard argument handling kicks in.
|
||||
*/
|
||||
public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) {
|
||||
this.customArgumentResolvers = new WebArgumentResolver[]{argumentResolver};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one or more custom WebArgumentResolvers to use for special method parameter types. Any such custom WebArgumentResolver
|
||||
* will kick in first, having a chance to resolve an argument value before the standard argument handling kicks in.
|
||||
* Set one or more custom WebArgumentResolvers to use for special method parameter types. Any such custom
|
||||
* WebArgumentResolver will kick in first, having a chance to resolve an argument value before the standard argument
|
||||
* handling kicks in.
|
||||
*/
|
||||
public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) {
|
||||
this.customArgumentResolvers = argumentResolvers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a custom ModelAndViewResolvers to use for special method return types. Such a custom ModelAndViewResolver will kick
|
||||
* in first, having a chance to resolve an return value before the standard ModelAndView handling kicks in.
|
||||
* Set a custom ModelAndViewResolvers to use for special method return types. Such a custom ModelAndViewResolver will
|
||||
* kick in first, having a chance to resolve an return value before the standard ModelAndView handling kicks in.
|
||||
*/
|
||||
public void setCustomModelAndViewResolver(ModelAndViewResolver customModelAndViewResolver) {
|
||||
this.customModelAndViewResolvers = new ModelAndViewResolver[]{customModelAndViewResolver};
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one or more custom ModelAndViewResolvers to use for special method return types. Any such custom ModelAndViewResolver
|
||||
* will kick in first, having a chance to resolve an return value before the standard ModelAndView handling kicks in.
|
||||
* Set one or more custom ModelAndViewResolvers to use for special method return types. Any such custom
|
||||
* ModelAndViewResolver will kick in first, having a chance to resolve an return value before the standard ModelAndView
|
||||
* handling kicks in.
|
||||
*/
|
||||
public void setCustomModelAndViewResolvers(ModelAndViewResolver[] customModelAndViewResolvers) {
|
||||
this.customModelAndViewResolvers = customModelAndViewResolvers;
|
||||
@@ -334,7 +334,6 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean supports(Object handler) {
|
||||
return getMethodResolver(handler).hasHandlerMethods();
|
||||
}
|
||||
@@ -386,9 +385,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a HandlerMethodResolver for the given handler type.
|
||||
*/
|
||||
/** Build a HandlerMethodResolver for the given handler type. */
|
||||
private ServletHandlerMethodResolver getMethodResolver(Object handler) {
|
||||
Class handlerClass = ClassUtils.getUserClass(handler);
|
||||
ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass);
|
||||
@@ -399,10 +396,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
return resolver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Servlet-specific subclass of {@link HandlerMethodResolver}.
|
||||
*/
|
||||
/** Servlet-specific subclass of {@link HandlerMethodResolver}. */
|
||||
private class ServletHandlerMethodResolver extends HandlerMethodResolver {
|
||||
|
||||
private ServletHandlerMethodResolver(Class<?> handlerType) {
|
||||
@@ -459,7 +453,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
else {
|
||||
for (RequestMethod requestMethod : mappingInfo.methods) {
|
||||
allowedMethods.add(requestMethod.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
@@ -521,17 +515,10 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
/**
|
||||
* Determines the matched pattern for the given methodLevelPattern and path.
|
||||
*
|
||||
* <p>Uses the following algorithm:
|
||||
* <ol>
|
||||
* <li>If there is a type-level mapping with path information, it is
|
||||
* {@linkplain PathMatcher#combine(String, String) combined} with the method-level pattern.
|
||||
* <li>If there is a {@linkplain HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern} in the
|
||||
* request, it is combined with the method-level pattern.
|
||||
* <li>Otherwise,
|
||||
* @param methodLevelPattern
|
||||
* @param lookupPath
|
||||
* @param request
|
||||
* @return
|
||||
* <p>Uses the following algorithm: <ol> <li>If there is a type-level mapping with path information, it is {@linkplain
|
||||
* PathMatcher#combine(String, String) combined} with the method-level pattern. <li>If there is a {@linkplain
|
||||
* HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern} in the request, it is combined with the
|
||||
* method-level pattern. <li>Otherwise,
|
||||
*/
|
||||
private String getMatchedPattern(String methodLevelPattern, String lookupPath, HttpServletRequest request) {
|
||||
if (hasTypeLevelMapping() && (!ObjectUtils.isEmpty(getTypeLevelMapping().value()))) {
|
||||
@@ -550,7 +537,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
String bestMatchingPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
|
||||
if (StringUtils.hasText(bestMatchingPattern)) {
|
||||
String combinedPattern = pathMatcher.combine(bestMatchingPattern, methodLevelPattern);
|
||||
if (!combinedPattern.equals(bestMatchingPattern) && (isPathMatchInternal(combinedPattern, lookupPath))) {
|
||||
if (!combinedPattern.equals(bestMatchingPattern) &&
|
||||
(isPathMatchInternal(combinedPattern, lookupPath))) {
|
||||
return combinedPattern;
|
||||
}
|
||||
}
|
||||
@@ -610,10 +598,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Servlet-specific subclass of {@link HandlerMethodInvoker}.
|
||||
*/
|
||||
/** Servlet-specific subclass of {@link HandlerMethodInvoker}. */
|
||||
private class ServletHandlerMethodInvoker extends HandlerMethodInvoker {
|
||||
|
||||
private boolean responseArgumentUsed = false;
|
||||
@@ -729,7 +714,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
Object returnValue,
|
||||
ExtendedModelMap implicitModel,
|
||||
ServletWebRequest webRequest) throws Exception {
|
||||
|
||||
|
||||
ResponseStatus responseStatusAnn = AnnotationUtils.findAnnotation(handlerMethod, ResponseStatus.class);
|
||||
if (responseStatusAnn != null) {
|
||||
HttpStatus responseStatus = responseStatusAnn.value();
|
||||
@@ -797,7 +782,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleResponseBody(Object returnValue, ServletWebRequest webRequest) throws ServletException, IOException {
|
||||
private void handleResponseBody(Object returnValue, ServletWebRequest webRequest)
|
||||
throws ServletException, IOException {
|
||||
HttpInputMessage inputMessage = new ServletServerHttpRequest(webRequest.getRequest());
|
||||
List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept();
|
||||
if (acceptedMediaTypes.isEmpty()) {
|
||||
@@ -809,16 +795,11 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
if (messageConverters != null) {
|
||||
for (HttpMessageConverter messageConverter : messageConverters) {
|
||||
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
|
||||
if (messageConverter.supports(returnValueType)) {
|
||||
for (Object o : messageConverter.getSupportedMediaTypes()) {
|
||||
MediaType supportedMediaType = (MediaType) o;
|
||||
for (MediaType acceptedMediaType : acceptedMediaTypes) {
|
||||
if (acceptedMediaType.includes(supportedMediaType)) {
|
||||
messageConverter.write(returnValue, outputMessage);
|
||||
this.responseArgumentUsed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (MediaType acceptedMediaType : acceptedMediaTypes) {
|
||||
if (messageConverter.canWrite(returnValueType, acceptedMediaType)) {
|
||||
messageConverter.write(returnValue, null, outputMessage);
|
||||
this.responseArgumentUsed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -827,7 +808,6 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class RequestMappingInfo {
|
||||
|
||||
String[] paths = new String[0];
|
||||
@@ -864,7 +844,6 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Comparator capable of sorting {@link RequestMappingInfo}s (RHIs) so that sorting a list with this comparator will
|
||||
* result in: <ul> <li>RHIs with {@linkplain RequestMappingInfo#matchedPaths better matched paths} take prescedence
|
||||
|
||||
@@ -30,12 +30,12 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Iterator;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
@@ -52,10 +52,10 @@ 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;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
||||
@@ -63,14 +63,16 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.propertyeditors.CustomDateEditor;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockServletConfig;
|
||||
@@ -79,9 +81,9 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.SerializationTestUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.FieldError;
|
||||
@@ -445,7 +447,8 @@ public class ServletAnnotationControllerTests {
|
||||
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
||||
autoProxyCreator.setBeanFactory(wac.getBeanFactory());
|
||||
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
|
||||
wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
|
||||
wac.getBeanFactory()
|
||||
.registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
@@ -639,8 +642,8 @@ public class ServletAnnotationControllerTests {
|
||||
servlet.service(request, response);
|
||||
assertEquals("mySurpriseView", response.getContentAsString());
|
||||
|
||||
MyParameterDispatchingController deserialized = (MyParameterDispatchingController)
|
||||
SerializationTestUtils.serializeAndDeserialize(servlet.getWebApplicationContext().getBean("controller"));
|
||||
MyParameterDispatchingController deserialized = (MyParameterDispatchingController) SerializationTestUtils
|
||||
.serializeAndDeserialize(servlet.getWebApplicationContext().getBean("controller"));
|
||||
assertNotNull(deserialized.request);
|
||||
assertNotNull(deserialized.session);
|
||||
}
|
||||
@@ -947,7 +950,23 @@ public class ServletAnnotationControllerTests {
|
||||
|
||||
@Test
|
||||
public void responseBodyNoAcceptableMediaType() throws ServletException, IOException {
|
||||
initServlet(RequestBodyController.class);
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(RequestBodyController.class));
|
||||
RootBeanDefinition converterDef = new RootBeanDefinition(StringHttpMessageConverter.class);
|
||||
converterDef.getPropertyValues().add("supportedMediaTypes", new MediaType("text", "plain"));
|
||||
RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
|
||||
StringHttpMessageConverter converter = new StringHttpMessageConverter();
|
||||
converter.setSupportedMediaTypes(Collections.singletonList(new MediaType("text", "plain")));
|
||||
adapterDef.getPropertyValues().add("messageConverters", converter);
|
||||
wac.registerBeanDefinition("handlerAdapter", adapterDef);
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
|
||||
String requestBody = "Hello World";
|
||||
@@ -975,7 +994,19 @@ public class ServletAnnotationControllerTests {
|
||||
|
||||
@Test
|
||||
public void unsupportedRequestBody() throws ServletException, IOException {
|
||||
initServlet(RequestBodyController.class);
|
||||
@SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(RequestBodyController.class));
|
||||
RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
|
||||
adapterDef.getPropertyValues().add("messageConverters", new ByteArrayHttpMessageConverter());
|
||||
wac.registerBeanDefinition("handlerAdapter", adapterDef);
|
||||
wac.refresh();
|
||||
return wac;
|
||||
}
|
||||
};
|
||||
servlet.init(new MockServletConfig());
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
|
||||
String requestBody = "Hello World";
|
||||
@@ -1061,11 +1092,9 @@ public class ServletAnnotationControllerTests {
|
||||
@Override
|
||||
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
|
||||
GenericWebApplicationContext wac = new GenericWebApplicationContext();
|
||||
wac.registerBeanDefinition("controller",
|
||||
new RootBeanDefinition(ModelAndViewResolverController.class));
|
||||
wac.registerBeanDefinition("controller", new RootBeanDefinition(ModelAndViewResolverController.class));
|
||||
RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class);
|
||||
adapterDef.getPropertyValues()
|
||||
.add("customModelAndViewResolver", new MyModelAndViewResolver());
|
||||
adapterDef.getPropertyValues().add("customModelAndViewResolver", new MyModelAndViewResolver());
|
||||
wac.registerBeanDefinition("handlerAdapter", adapterDef);
|
||||
wac.refresh();
|
||||
return wac;
|
||||
@@ -1086,7 +1115,7 @@ public class ServletAnnotationControllerTests {
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
|
||||
request.setCookies(new Cookie("date", "2008-11-18"));
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("test-108", response.getContentAsString());
|
||||
}
|
||||
@@ -1096,7 +1125,7 @@ public class ServletAnnotationControllerTests {
|
||||
initServlet(AmbiguousParamsController.class);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
servlet.service(request, response);
|
||||
assertEquals("noParams", response.getContentAsString());
|
||||
|
||||
@@ -1116,7 +1145,6 @@ public class ServletAnnotationControllerTests {
|
||||
servlet.service(request, response);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void requestParamMap() throws Exception {
|
||||
initServlet(RequestParamMapController.class);
|
||||
@@ -1229,11 +1257,9 @@ public class ServletAnnotationControllerTests {
|
||||
assertEquals("create", response.getContentAsString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Controllers
|
||||
*/
|
||||
* Controllers
|
||||
*/
|
||||
|
||||
@RequestMapping("/myPath.do")
|
||||
private static class MyController extends AbstractController {
|
||||
@@ -1470,7 +1496,8 @@ public class ServletAnnotationControllerTests {
|
||||
@SuppressWarnings("unused")
|
||||
@ModelAttribute("myCommand")
|
||||
private ValidTestBean createTestBean(@RequestParam T defaultName,
|
||||
Map<String, Object> model, @RequestParam Date date) {
|
||||
Map<String, Object> model,
|
||||
@RequestParam Date date) {
|
||||
model.put("myKey", "myOriginalValue");
|
||||
ValidTestBean tb = new ValidTestBean();
|
||||
tb.setName(defaultName.getClass().getSimpleName() + ":" + defaultName.toString());
|
||||
@@ -1740,9 +1767,10 @@ public class ServletAnnotationControllerTests {
|
||||
}
|
||||
List<TestBean> testBeans = (List<TestBean>) model.get("testBeanList");
|
||||
if (errors.hasFieldErrors("age")) {
|
||||
response.getWriter().write(viewName + "-" + tb.getName() + "-" +
|
||||
errors.getFieldError("age").getCode() + "-" + testBeans.get(0).getName() + "-" +
|
||||
model.get("myKey") + (model.containsKey("yourKey") ? "-" + model.get("yourKey") : ""));
|
||||
response.getWriter()
|
||||
.write(viewName + "-" + tb.getName() + "-" + errors.getFieldError("age").getCode() +
|
||||
"-" + testBeans.get(0).getName() + "-" + model.get("myKey") +
|
||||
(model.containsKey("yourKey") ? "-" + model.get("yourKey") : ""));
|
||||
}
|
||||
else {
|
||||
response.getWriter().write(viewName + "-" + tb.getName() + "-" + tb.getAge() + "-" +
|
||||
@@ -1760,6 +1788,7 @@ public class ServletAnnotationControllerTests {
|
||||
public String getContentType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) {
|
||||
request.getSession().setAttribute("model", model);
|
||||
}
|
||||
@@ -1787,6 +1816,7 @@ public class ServletAnnotationControllerTests {
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Controller
|
||||
public @interface MyControllerAnnotation {
|
||||
|
||||
}
|
||||
|
||||
@MyControllerAnnotation
|
||||
@@ -1835,8 +1865,8 @@ public class ServletAnnotationControllerTests {
|
||||
@RequestMapping("/myPath.do")
|
||||
public void myHandle(@RequestParam(value = "id", defaultValue = "${myKey}") String id,
|
||||
@RequestHeader(defaultValue = "#{systemProperties.myHeader}") String header,
|
||||
@Value("#{request.contextPath}") String contextPath, HttpServletResponse response)
|
||||
throws IOException {
|
||||
@Value("#{request.contextPath}") String contextPath,
|
||||
HttpServletResponse response) throws IOException {
|
||||
response.getWriter().write(String.valueOf(id) + "-" + String.valueOf(header) + "-" + contextPath);
|
||||
}
|
||||
}
|
||||
@@ -1873,7 +1903,6 @@ public class ServletAnnotationControllerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
public static class PathOrderingController {
|
||||
|
||||
@@ -1888,7 +1917,6 @@ public class ServletAnnotationControllerTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
public static class RequestBodyController {
|
||||
|
||||
@@ -1901,7 +1929,11 @@ public class ServletAnnotationControllerTests {
|
||||
|
||||
public static class MyMessageConverter implements HttpMessageConverter {
|
||||
|
||||
public boolean supports(Class clazz) {
|
||||
public boolean canRead(Class clazz, MediaType mediaType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canWrite(Class clazz, MediaType mediaType) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1914,7 +1946,7 @@ public class ServletAnnotationControllerTests {
|
||||
throw new HttpMessageNotReadableException("Could not read");
|
||||
}
|
||||
|
||||
public void write(Object o, HttpOutputMessage outputMessage)
|
||||
public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
throw new UnsupportedOperationException("Not implemented");
|
||||
}
|
||||
@@ -1955,8 +1987,11 @@ public class ServletAnnotationControllerTests {
|
||||
|
||||
public static class MyModelAndViewResolver implements ModelAndViewResolver {
|
||||
|
||||
public ModelAndView resolveModelAndView(Method handlerMethod, Class handlerType,
|
||||
Object returnValue, ExtendedModelMap implicitModel, NativeWebRequest webRequest) {
|
||||
public ModelAndView resolveModelAndView(Method handlerMethod,
|
||||
Class handlerType,
|
||||
Object returnValue,
|
||||
ExtendedModelMap implicitModel,
|
||||
NativeWebRequest webRequest) {
|
||||
if (returnValue instanceof MySpecialArg) {
|
||||
return new ModelAndView(new View() {
|
||||
public String getContentType() {
|
||||
@@ -2002,8 +2037,7 @@ public class ServletAnnotationControllerTests {
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
public void handle(@CookieValue("date") Date date, Writer writer)
|
||||
throws IOException {
|
||||
public void handle(@CookieValue("date") Date date, Writer writer) throws IOException {
|
||||
assertEquals("Invalid path variable value", new Date(108, 10, 18), date);
|
||||
writer.write("test-" + date.getYear());
|
||||
}
|
||||
@@ -2043,7 +2077,8 @@ public class ServletAnnotationControllerTests {
|
||||
}
|
||||
|
||||
@RequestMapping("/multiValueMap")
|
||||
public void multiValueMap(@RequestParam MultiValueMap<String, String> params, Writer writer) throws IOException {
|
||||
public void multiValueMap(@RequestParam MultiValueMap<String, String> params, Writer writer)
|
||||
throws IOException {
|
||||
for (Iterator<Map.Entry<String, List<String>>> it1 = params.entrySet().iterator(); it1.hasNext();) {
|
||||
Map.Entry<String, List<String>> entry = it1.next();
|
||||
writer.write(entry.getKey() + "=[");
|
||||
@@ -2078,7 +2113,8 @@ public class ServletAnnotationControllerTests {
|
||||
}
|
||||
|
||||
@RequestMapping("/multiValueMap")
|
||||
public void multiValueMap(@RequestHeader MultiValueMap<String, String> headers, Writer writer) throws IOException {
|
||||
public void multiValueMap(@RequestHeader MultiValueMap<String, String> headers, Writer writer)
|
||||
throws IOException {
|
||||
for (Iterator<Map.Entry<String, List<String>>> it1 = headers.entrySet().iterator(); it1.hasNext();) {
|
||||
Map.Entry<String, List<String>> entry = it1.next();
|
||||
writer.write(entry.getKey() + "=[");
|
||||
@@ -2104,5 +2140,5 @@ public class ServletAnnotationControllerTests {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user