BindingResult support for constructor argument mismatch on immutable data object

Issue: SPR-15542
This commit is contained in:
Juergen Hoeller 2017-08-17 11:02:40 +02:00
parent b8f5e97ae5
commit 61cdc842e0
4 changed files with 415 additions and 345 deletions

View File

@ -20,11 +20,13 @@ import java.beans.ConstructorProperties;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.TypeMismatchException;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
@ -32,7 +34,9 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
@ -110,9 +114,6 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
String name = ModelFactory.getNameForParameter(parameter);
Object attribute = (mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) :
createAttribute(name, parameter, binderFactory, webRequest));
if (!mavContainer.isBindingDisabled(name)) {
ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
if (ann != null && !ann.binding()) {
@ -120,51 +121,113 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
}
}
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
if (!mavContainer.isBindingDisabled(name)) {
bindRequestParameters(binder, webRequest);
Object attribute = null;
BindingResult bindingResult = null;
if (mavContainer.containsAttribute(name)) {
attribute = mavContainer.getModel().get(name);
}
else {
// Create attribute instance
try {
attribute = createAttribute(name, parameter, binderFactory, webRequest);
}
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
catch (BindException ex) {
if (isBindExceptionRequired(parameter)) {
// No BindingResult parameter -> fail with BindException
throw ex;
}
// Otherwise, expose null/empty value and associated BindingResult
if (parameter.getParameterType() == Optional.class) {
attribute = Optional.empty();
}
bindingResult = ex.getBindingResult();
}
}
if (bindingResult == null) {
// Bean property binding and validation;
// skipped in case of binding failure on construction.
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
if (!mavContainer.isBindingDisabled(name)) {
bindRequestParameters(binder, webRequest);
}
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());
}
}
// Value type adaptation, also covering java.util.Optional
if (!parameter.getParameterType().isInstance(attribute)) {
attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
}
bindingResult = binder.getBindingResult();
}
// Add resolved attribute and BindingResult at the end of the model
Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
Map<String, Object> bindingResultModel = bindingResult.getModel();
mavContainer.removeAttributes(bindingResultModel);
mavContainer.addAllAttributes(bindingResultModel);
return (parameter.getParameterType().isInstance(attribute) ? attribute :
binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter));
return attribute;
}
/**
* Extension point to create the model attribute if not found in the model,
* with subsequent parameter binding through bean properties (unless suppressed).
* <p>The default implementation uses the unique public no-arg constructor, if any,
* which may have arguments: It understands the JavaBeans {@link ConstructorProperties}
* annotation as well as runtime-retained parameter names in the bytecode,
* associating request parameters with constructor arguments by name. If no such
* constructor is found, the default constructor will be used (even if not public),
* assuming subsequent bean property bindings through setter methods.
* <p>The default implementation typically uses the unique public no-arg constructor
* if available but also handles a "primary constructor" approach for data classes:
* It understands the JavaBeans {@link ConstructorProperties} annotation as well as
* runtime-retained parameter names in the bytecode, associating request parameters
* with constructor arguments by name. If no such constructor is found, the default
* constructor will be used (even if not public), assuming subsequent bean property
* bindings through setter methods.
* @param attributeName the name of the attribute (never {@code null})
* @param parameter the method parameter declaration
* @param binderFactory for creating WebDataBinder instance
* @param webRequest the current request
* @return the created model attribute (never {@code null})
* @throws BindException in case of constructor argument binding failure
* @throws Exception in case of constructor invocation failure
* @see #constructAttribute(Constructor, String, WebDataBinderFactory, NativeWebRequest)
* @see BeanUtils#findPrimaryConstructor(Class)
*/
protected Object createAttribute(String attributeName, MethodParameter parameter,
WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception {
Class<?> type = parameter.getParameterType();
MethodParameter nestedParameter = parameter.nestedIfOptional();
Class<?> type = nestedParameter.getNestedParameterType();
Constructor<?> ctor = BeanUtils.findPrimaryConstructor(type);
if (ctor == null) {
throw new IllegalStateException("No primary constructor found for " + type.getName());
}
Object attribute = constructAttribute(ctor, attributeName, binderFactory, webRequest);
if (parameter != nestedParameter) {
attribute = Optional.of(attribute);
}
return attribute;
}
/**
* Construct a new attribute instance with the given constructor.
* <p>Called from
* {@link #createAttribute(String, MethodParameter, WebDataBinderFactory, NativeWebRequest)}
* after constructor resolution.
* @param ctor the constructor to use
* @param attributeName the name of the attribute (never {@code null})
* @param binderFactory for creating WebDataBinder instance
* @param webRequest the current request
* @return the created model attribute (never {@code null})
* @throws BindException in case of constructor argument binding failure
* @throws Exception in case of constructor invocation failure
* @since 5.0
*/
protected Object constructAttribute(Constructor<?> ctor, String attributeName,
WebDataBinderFactory binderFactory, NativeWebRequest webRequest) throws Exception {
if (ctor.getParameterCount() == 0) {
// A single default constructor -> clearly a standard JavaBeans arrangement.
return BeanUtils.instantiateClass(ctor);
@ -179,10 +242,22 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
() -> "Invalid number of parameter names: " + paramNames.length + " for constructor " + ctor);
Object[] args = new Object[paramTypes.length];
WebDataBinder binder = binderFactory.createBinder(webRequest, null, attributeName);
boolean bindingFailure = false;
for (int i = 0; i < paramNames.length; i++) {
String[] parameterValues = webRequest.getParameterValues(paramNames[i]);
args[i] = (parameterValues != null ? binder.convertIfNecessary(parameterValues, paramTypes[i],
new MethodParameter(ctor, i)) : null);
String[] paramValues = webRequest.getParameterValues(paramNames[i]);
try {
args[i] = (paramValues != null ?
binder.convertIfNecessary(paramValues, paramTypes[i], new MethodParameter(ctor, i)) : null);
}
catch (TypeMismatchException ex) {
bindingFailure = true;
binder.getBindingResult().addError(new FieldError(
binder.getObjectName(), paramNames[i], ex.getValue(), true,
new String[] {ex.getErrorCode()}, null, ex.getLocalizedMessage()));
}
}
if (bindingFailure) {
throw new BindException(binder.getBindingResult());
}
return BeanUtils.instantiateClass(ctor, args);
}
@ -219,11 +294,23 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
/**
* Whether to raise a fatal bind exception on validation errors.
* <p>The default implementation delegates to {@link #isBindExceptionRequired(MethodParameter)}.
* @param binder the data binder used to perform data binding
* @param parameter the method parameter declaration
* @return {@code true} if the next method argument is not of type {@link Errors}
* @return {@code true} if the next method parameter is not of type {@link Errors}
* @see #isBindExceptionRequired(MethodParameter)
*/
protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) {
return isBindExceptionRequired(parameter);
}
/**
* Whether to raise a fatal bind exception on validation errors.
* @param parameter the method parameter declaration
* @return {@code true} if the next method parameter is not of type {@link Errors}
* @since 5.0
*/
protected boolean isBindExceptionRequired(MethodParameter parameter) {
int i = parameter.getParameterIndex();
Class<?>[] paramTypes = parameter.getExecutable().getParameterTypes();
boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));

View File

@ -45,6 +45,7 @@ import org.springframework.web.servlet.HandlerMapping;
* model attribute name and there is an appropriate type conversion strategy.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
*/
public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor {
@ -68,19 +69,19 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr
* @see #createAttributeFromRequestValue
*/
@Override
protected final Object createAttribute(String attributeName, MethodParameter methodParam,
protected final Object createAttribute(String attributeName, MethodParameter parameter,
WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {
String value = getRequestValueForAttribute(attributeName, request);
if (value != null) {
Object attribute = createAttributeFromRequestValue(
value, attributeName, methodParam, binderFactory, request);
value, attributeName, parameter, binderFactory, request);
if (attribute != null) {
return attribute;
}
}
return super.createAttribute(attributeName, methodParam, binderFactory, request);
return super.createAttribute(attributeName, parameter, binderFactory, request);
}
/**
@ -120,7 +121,7 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr
* {@link Converter} that can perform the conversion.
* @param sourceValue the source value to create the model attribute from
* @param attributeName the name of the attribute (never {@code null})
* @param methodParam the method parameter
* @param parameter the method parameter
* @param binderFactory for creating WebDataBinder instance
* @param request the current request
* @return the created model attribute, or {@code null} if no suitable
@ -129,16 +130,16 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr
*/
@Nullable
protected Object createAttributeFromRequestValue(String sourceValue, String attributeName,
MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request)
MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request)
throws Exception {
DataBinder binder = binderFactory.createBinder(request, null, attributeName);
ConversionService conversionService = binder.getConversionService();
if (conversionService != null) {
TypeDescriptor source = TypeDescriptor.valueOf(String.class);
TypeDescriptor target = new TypeDescriptor(methodParam);
TypeDescriptor target = new TypeDescriptor(parameter);
if (conversionService.canConvert(source, target)) {
return binder.convertIfNecessary(sourceValue, methodParam.getParameterType(), methodParam);
return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter);
}
}
return null;

View File

@ -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.
@ -35,9 +35,9 @@ import static org.junit.Assert.*;
/**
* Base class for tests using on the DispatcherServlet and HandlerMethod infrastructure classes:
* <ul>
* <li>RequestMappingHandlerMapping
* <li>RequestMappingHandlerAdapter
* <li>ExceptionHandlerExceptionResolver
* <li>RequestMappingHandlerMapping
* <li>RequestMappingHandlerAdapter
* <li>ExceptionHandlerExceptionResolver
* </ul>
*
* @author Rossen Stoyanchev
@ -46,21 +46,23 @@ public abstract class AbstractServletHandlerMethodTests {
private DispatcherServlet servlet;
@After
public void tearDown() {
this.servlet = null;
}
protected DispatcherServlet getServlet() {
assertNotNull("DispatcherServlet not initialized", servlet);
return servlet;
}
@After
public void tearDown() {
this.servlet = null;
}
/**
* Initialize a DispatcherServlet instance registering zero or more controller classes.
*/
protected WebApplicationContext initServletWithControllers(final Class<?>... controllerClasses)
throws ServletException {
return initServlet(null, controllerClasses);
}
@ -82,22 +84,17 @@ public abstract class AbstractServletHandlerMethodTests {
wac.registerBeanDefinition(clazz.getSimpleName(), new RootBeanDefinition(clazz));
}
Class<?> mappingType = RequestMappingHandlerMapping.class;
RootBeanDefinition beanDef = new RootBeanDefinition(mappingType);
beanDef.getPropertyValues().add("removeSemicolonContent", "false");
wac.registerBeanDefinition("handlerMapping", beanDef);
RootBeanDefinition mappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
mappingDef.getPropertyValues().add("removeSemicolonContent", "false");
wac.registerBeanDefinition("handlerMapping", mappingDef);
Class<?> adapterType = RequestMappingHandlerAdapter.class;
wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(adapterType));
wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(RequestMappingHandlerAdapter.class));
Class<?> resolverType = ExceptionHandlerExceptionResolver.class;
wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(resolverType));
wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(ExceptionHandlerExceptionResolver.class));
resolverType = ResponseStatusExceptionResolver.class;
wac.registerBeanDefinition("responseStatusResolver", new RootBeanDefinition(resolverType));
wac.registerBeanDefinition("responseStatusResolver", new RootBeanDefinition(ResponseStatusExceptionResolver.class));
resolverType = DefaultHandlerExceptionResolver.class;
wac.registerBeanDefinition("defaultResolver", new RootBeanDefinition(resolverType));
wac.registerBeanDefinition("defaultResolver", new RootBeanDefinition(DefaultHandlerExceptionResolver.class));
if (initializer != null) {
initializer.initialize(wac);

View File

@ -42,10 +42,10 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -66,7 +66,6 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.converter.Converter;
@ -131,7 +130,6 @@ import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.multipart.support.StringMultipartFileEditor;
import org.springframework.web.servlet.ModelAndView;
@ -142,14 +140,7 @@ import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
/**
* @author Rossen Stoyanchev
@ -247,13 +238,10 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void defaultExpressionParameters() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext context) {
RootBeanDefinition ppc = new RootBeanDefinition(PropertyPlaceholderConfigurer.class);
ppc.getPropertyValues().add("properties", "myKey=foo");
context.registerBeanDefinition("ppc", ppc);
}
initServlet(wac -> {
RootBeanDefinition ppc = new RootBeanDefinition(PropertyPlaceholderConfigurer.class);
ppc.getPropertyValues().add("properties", "myKey=foo");
wac.registerBeanDefinition("ppc", ppc);
}, DefaultExpressionValueParamController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myApp/myPath.do");
@ -271,17 +259,14 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void typeNestedSetBinding() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext context) {
RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
csDef.getPropertyValues().add("converters", new TestBeanConverter());
RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
wbiDef.getPropertyValues().add("conversionService", csDef);
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef);
context.registerBeanDefinition("handlerAdapter", adapterDef);
}
initServlet(wac -> {
RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
csDef.getPropertyValues().add("converters", new TestBeanConverter());
RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
wbiDef.getPropertyValues().add("conversionService", csDef);
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, NestedSetController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
@ -293,17 +278,14 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test // SPR-12903
public void pathVariableWithCustomConverter() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext context) {
RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
csDef.getPropertyValues().add("converters", new AnnotatedExceptionRaisingConverter());
RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
wbiDef.getPropertyValues().add("conversionService", csDef);
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef);
context.registerBeanDefinition("handlerAdapter", adapterDef);
}
initServlet(wac -> {
RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
csDef.getPropertyValues().add("converters", new AnnotatedExceptionRaisingConverter());
RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
wbiDef.getPropertyValues().add("conversionService", csDef);
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, PathVariableWithCustomConverterController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath/1");
@ -335,13 +317,10 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void emptyParameterListHandleMethod() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext context) {
RootBeanDefinition vrDef = new RootBeanDefinition(InternalResourceViewResolver.class);
vrDef.getPropertyValues().add("suffix", ".jsp");
context.registerBeanDefinition("viewResolver", vrDef);
}
initServlet(wac -> {
RootBeanDefinition vrDef = new RootBeanDefinition(InternalResourceViewResolver.class);
vrDef.getPropertyValues().add("suffix", ".jsp");
wac.registerBeanDefinition("viewResolver", vrDef);
}, EmptyParameterListHandlerMethodController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/emptyParameterListHandler");
@ -356,12 +335,9 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@SuppressWarnings("rawtypes")
@Test
public void sessionAttributeExposure() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext context) {
context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class));
}
}, MySessionAttributesController.class);
initServlet(
wac -> wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)),
MySessionAttributesController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
MockHttpServletResponse response = new MockHttpServletResponse();
@ -387,15 +363,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@SuppressWarnings("rawtypes")
@Test
public void sessionAttributeExposureWithInterface() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext context) {
context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class));
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(context.getBeanFactory());
context.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
context.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
}
initServlet(wac -> {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class));
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(wac.getBeanFactory());
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
}, MySessionAttributesControllerImpl.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
@ -422,12 +395,9 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@SuppressWarnings("rawtypes")
@Test
public void parameterizedAnnotatedInterface() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext context) {
context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class));
}
}, MyParameterizedControllerImpl.class);
initServlet(
wac -> wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)),
MyParameterizedControllerImpl.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
MockHttpServletResponse response = new MockHttpServletResponse();
@ -455,12 +425,9 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@SuppressWarnings("rawtypes")
@Test
public void parameterizedAnnotatedInterfaceWithOverriddenMappingsInImpl() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext context) {
context.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class));
}
}, MyParameterizedControllerImplWithOverriddenMappings.class);
initServlet(
wac -> wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class)),
MyParameterizedControllerImplWithOverriddenMappings.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
MockHttpServletResponse response = new MockHttpServletResponse();
@ -540,12 +507,9 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void formController() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
}
}, MyFormController.class);
initServlet(
wac -> wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)),
MyFormController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
request.addParameter("name", "name1");
@ -557,12 +521,9 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void modelFormController() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
}
}, MyModelFormController.class);
initServlet(
wac -> wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)),
MyModelFormController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
request.addParameter("name", "name1");
@ -574,16 +535,13 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void proxiedFormController() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(wac.getBeanFactory());
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
wac.getBeanFactory()
.registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
}
initServlet(wac -> {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(wac.getBeanFactory());
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
wac.getBeanFactory()
.registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
}, MyFormController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
@ -596,14 +554,11 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void commandProvidingFormControllerWithCustomEditor() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", new MyWebBindingInitializer());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
initServlet(wac -> {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", new MyWebBindingInitializer());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, MyCommandProvidingFormController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
@ -617,17 +572,14 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void typedCommandProvidingFormController() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", new MyWebBindingInitializer());
List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
argumentResolvers.add(new ServletWebArgumentResolverAdapter(new MySpecialArgumentResolver()));
adapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
initServlet(wac -> {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", new MyWebBindingInitializer());
List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();
argumentResolvers.add(new ServletWebArgumentResolverAdapter(new MySpecialArgumentResolver()));
adapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, MyTypedCommandProvidingFormController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
@ -657,12 +609,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void binderInitializingCommandProvidingFormController() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
}
}, MyBinderInitializingCommandProvidingFormController.class);
initServlet(wac -> wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)), MyBinderInitializingCommandProvidingFormController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
request.addParameter("defaultName", "myDefaultName");
@ -675,12 +622,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void specificBinderInitializingCommandProvidingFormController() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class));
}
}, MySpecificBinderInitializingCommandProvidingFormController.class);
initServlet(wac -> wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)), MySpecificBinderInitializingCommandProvidingFormController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
request.addParameter("defaultName", "myDefaultName");
@ -696,15 +638,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
final MockServletContext servletContext = new MockServletContext();
final MockServletConfig servletConfig = new MockServletConfig(servletContext);
WebApplicationContext webAppContext =
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
wac.setServletContext(servletContext);
AnnotationConfigUtils.registerAnnotationConfigProcessors(wac);
wac.getBeanFactory().registerResolvableDependency(ServletConfig.class, servletConfig);
}
}, MyParameterDispatchingController.class);
WebApplicationContext webAppContext =
initServlet(wac -> {
wac.setServletContext(servletContext);
AnnotationConfigUtils.registerAnnotationConfigProcessors(wac);
wac.getBeanFactory().registerResolvableDependency(ServletConfig.class, servletConfig);
}, MyParameterDispatchingController.class);
MockHttpServletRequest request = new MockHttpServletRequest(servletContext, "GET", "/myPath.do");
MockHttpServletResponse response = new MockHttpServletResponse();
@ -830,7 +769,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void pathOrdering() throws ServletException, IOException {
public void pathOrdering() throws Exception {
initServletWithControllers(PathOrderingController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/dir/myPath1.do");
@ -840,7 +779,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void requestBodyResponseBody() throws ServletException, IOException {
public void requestBodyResponseBody() throws Exception {
initServletWithControllers(RequestResponseBodyController.class);
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
@ -855,7 +794,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void httpPatch() throws ServletException, IOException {
public void httpPatch() throws Exception {
initServletWithControllers(RequestResponseBodyController.class);
MockHttpServletRequest request = new MockHttpServletRequest("PATCH", "/something");
@ -870,15 +809,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void responseBodyNoAcceptableMediaType() throws ServletException, IOException {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
StringHttpMessageConverter converter = new StringHttpMessageConverter();
adapterDef.getPropertyValues().add("messageConverters", converter);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
public void responseBodyNoAcceptableMediaType() throws Exception {
initServlet(wac -> {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
StringHttpMessageConverter converter = new StringHttpMessageConverter();
adapterDef.getPropertyValues().add("messageConverters", converter);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, RequestResponseBodyProducesController.class);
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
@ -892,7 +828,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void responseBodyWildCardMediaType() throws ServletException, IOException {
public void responseBodyWildCardMediaType() throws Exception {
initServletWithControllers(RequestResponseBodyController.class);
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
@ -906,14 +842,11 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void unsupportedRequestBody() throws ServletException, IOException {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("messageConverters", new ByteArrayHttpMessageConverter());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
public void unsupportedRequestBody() throws Exception {
initServlet(wac -> {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("messageConverters", new ByteArrayHttpMessageConverter());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, RequestResponseBodyController.class);
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
@ -927,7 +860,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void responseBodyNoAcceptHeader() throws ServletException, IOException {
public void responseBodyNoAcceptHeader() throws Exception {
initServletWithControllers(RequestResponseBodyController.class);
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
@ -941,14 +874,11 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void badRequestRequestBody() throws ServletException, IOException {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("messageConverters", new NotReadableMessageConverter());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
public void badRequestRequestBody() throws Exception {
initServlet(wac -> {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("messageConverters", new NotReadableMessageConverter());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, RequestResponseBodyController.class);
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
@ -961,7 +891,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void httpEntity() throws ServletException, IOException {
public void httpEntity() throws Exception {
initServletWithControllers(ResponseEntityController.class);
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo");
@ -983,23 +913,16 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertEquals(404, response.getStatus());
}
/*
* See SPR-6877
*/
@Test
public void overlappingMessageConvertersRequestBody() throws ServletException, IOException {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new StringHttpMessageConverter());
messageConverters
.add(new SimpleMessageConverter(new MediaType("application","json"), MediaType.ALL));
adapterDef.getPropertyValues().add("messageConverters", messageConverters);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
@Test // SPR-6877
public void overlappingMessageConvertersRequestBody() throws Exception {
initServlet(wac -> {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new StringHttpMessageConverter());
messageConverters
.add(new SimpleMessageConverter(new MediaType("application","json"), MediaType.ALL));
adapterDef.getPropertyValues().add("messageConverters", messageConverters);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, RequestResponseBodyController.class);
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
@ -1012,7 +935,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void responseBodyVoid() throws ServletException, IOException {
public void responseBodyVoid() throws Exception {
initServletWithControllers(ResponseBodyVoidController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something");
@ -1023,24 +946,21 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void responseBodyArgMismatch() throws ServletException, IOException {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(A.class, B.class);
try {
marshaller.afterPropertiesSet();
}
catch (Exception ex) {
throw new BeanCreationException(ex.getMessage(), ex);
}
MarshallingHttpMessageConverter messageConverter = new MarshallingHttpMessageConverter(marshaller);
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("messageConverters", messageConverter);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
public void responseBodyArgMismatch() throws Exception {
initServlet(wac -> {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(A.class, B.class);
try {
marshaller.afterPropertiesSet();
}
catch (Exception ex) {
throw new BeanCreationException(ex.getMessage(), ex);
}
MarshallingHttpMessageConverter messageConverter = new MarshallingHttpMessageConverter(marshaller);
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("messageConverters", messageConverter);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, RequestBodyArgMismatchController.class);
MockHttpServletRequest request = new MockHttpServletRequest("PUT", "/something");
@ -1054,7 +974,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void contentTypeHeaders() throws ServletException, IOException {
public void contentTypeHeaders() throws Exception {
initServletWithControllers(ContentTypeHeadersController.class);
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/something");
@ -1077,7 +997,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void consumes() throws ServletException, IOException {
public void consumes() throws Exception {
initServletWithControllers(ConsumesController.class);
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/something");
@ -1100,7 +1020,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void negatedContentTypeHeaders() throws ServletException, IOException {
public void negatedContentTypeHeaders() throws Exception {
initServletWithControllers(NegatedContentTypeHeadersController.class);
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/something");
@ -1117,7 +1037,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void acceptHeaders() throws ServletException, IOException {
public void acceptHeaders() throws Exception {
initServletWithControllers(AcceptHeadersController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something");
@ -1152,7 +1072,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void produces() throws ServletException, IOException {
public void produces() throws Exception {
initServletWithControllers(ProducesController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something");
@ -1187,7 +1107,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void responseStatus() throws ServletException, IOException {
public void responseStatus() throws Exception {
initServletWithControllers(ResponseStatusController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something");
@ -1199,15 +1119,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void mavResolver() throws ServletException, IOException {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
ModelAndViewResolver[] mavResolvers = new ModelAndViewResolver[] {new MyModelAndViewResolver()};
adapterDef.getPropertyValues().add("modelAndViewResolvers", mavResolvers);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
public void mavResolver() throws Exception {
initServlet(wac -> {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
ModelAndViewResolver[] mavResolvers = new ModelAndViewResolver[] {new MyModelAndViewResolver()};
adapterDef.getPropertyValues().add("modelAndViewResolvers", mavResolvers);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, ModelAndViewResolverController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
@ -1218,7 +1135,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void bindingCookieValue() throws ServletException, IOException {
public void bindingCookieValue() throws Exception {
initServletWithControllers(BindingCookieValueController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
@ -1229,7 +1146,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void ambiguousParams() throws ServletException, IOException {
public void ambiguousParams() throws Exception {
initServletWithControllers(AmbiguousParamsController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
@ -1327,14 +1244,11 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void requestMappingInterfaceWithProxy() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(wac.getBeanFactory());
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
}
initServlet(wac -> {
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(wac.getBeanFactory());
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
}, IMyControllerImpl.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/handle");
@ -1465,16 +1379,13 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void parameterCsvAsStringArray() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
wbiDef.getPropertyValues().add("conversionService", csDef);
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
initServlet(wac -> {
RootBeanDefinition csDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
RootBeanDefinition wbiDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
wbiDef.getPropertyValues().add("conversionService", csDef);
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("webBindingInitializer", wbiDef);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, CsvController.class);
MockHttpServletRequest request = new MockHttpServletRequest();
@ -1595,13 +1506,10 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void prototypeController() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext context) {
RootBeanDefinition beanDef = new RootBeanDefinition(PrototypeController.class);
beanDef.setScope(BeanDefinition.SCOPE_PROTOTYPE);
context.registerBeanDefinition("controller", beanDef);
}
initServlet(wac -> {
RootBeanDefinition beanDef = new RootBeanDefinition(PrototypeController.class);
beanDef.setScope(BeanDefinition.SCOPE_PROTOTYPE);
wac.registerBeanDefinition("controller", beanDef);
});
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/");
@ -1652,15 +1560,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void responseBodyAsHtml() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean();
factoryBean.afterPropertiesSet();
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
initServlet(wac -> {
ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean();
factoryBean.afterPropertiesSet();
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, TextRestController.class);
byte[] content = "alert('boo')".getBytes(StandardCharsets.ISO_8859_1);
@ -1678,15 +1583,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void responseBodyAsHtmlWithSuffixPresent() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean();
factoryBean.afterPropertiesSet();
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
initServlet(wac -> {
ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean();
factoryBean.afterPropertiesSet();
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, TextRestController.class);
byte[] content = "alert('boo')".getBytes(StandardCharsets.ISO_8859_1);
@ -1704,15 +1606,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void responseBodyAsHtmlWithProducesCondition() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean();
factoryBean.afterPropertiesSet();
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
initServlet(wac -> {
ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean();
factoryBean.afterPropertiesSet();
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, TextRestController.class);
byte[] content = "alert('boo')".getBytes(StandardCharsets.ISO_8859_1);
@ -1730,15 +1629,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Test
public void responseBodyAsTextWithCssExtension() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@Override
public void initialize(GenericWebApplicationContext wac) {
ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean();
factoryBean.afterPropertiesSet();
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
initServlet(wac -> {
ContentNegotiationManagerFactoryBean factoryBean = new ContentNegotiationManagerFactoryBean();
factoryBean.afterPropertiesSet();
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
adapterDef.getPropertyValues().add("contentNegotiationManager", factoryBean.getObject());
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}, TextRestController.class);
byte[] content = "body".getBytes(StandardCharsets.ISO_8859_1);
@ -1779,7 +1675,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void httpHead() throws ServletException, IOException {
public void httpHead() throws Exception {
initServletWithControllers(ResponseEntityController.class);
MockHttpServletRequest request = new MockHttpServletRequest("HEAD", "/baz");
@ -1803,7 +1699,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void httpHeadExplicit() throws ServletException, IOException {
public void httpHeadExplicit() throws Exception {
initServletWithControllers(ResponseEntityController.class);
MockHttpServletRequest request = new MockHttpServletRequest("HEAD", "/stores");
@ -1815,7 +1711,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void httpOptions() throws ServletException, IOException {
public void httpOptions() throws Exception {
initServletWithControllers(ResponseEntityController.class);
MockHttpServletRequest request = new MockHttpServletRequest("OPTIONS", "/baz");
@ -1828,7 +1724,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void dataClassBinding() throws ServletException, IOException {
public void dataClassBinding() throws Exception {
initServletWithControllers(DataClassController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
@ -1840,7 +1736,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
@Test
public void dataClassBindingWithAdditionalSetter() throws ServletException, IOException {
public void dataClassBindingWithAdditionalSetter() throws Exception {
initServletWithControllers(DataClassController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
@ -1852,6 +1748,66 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertEquals("value1-2-3", response.getContentAsString());
}
@Test
public void dataClassBindingWithResult() throws Exception {
initServletWithControllers(ValidatedDataClassController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
request.addParameter("param1", "value1");
request.addParameter("param2", "2");
request.addParameter("param3", "3");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals("value1-2-3", response.getContentAsString());
}
@Test
public void dataClassBindingWithConversionError() throws Exception {
initServletWithControllers(ValidatedDataClassController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
request.addParameter("param2", "x");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertTrue(response.getContentAsString().contains("field 'param2'"));
}
@Test
public void dataClassBindingWithValidationError() throws Exception {
initServletWithControllers(ValidatedDataClassController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
request.addParameter("param2", "2");
request.addParameter("param3", "3");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertTrue(response.getContentAsString().contains("field 'param1'"));
}
@Test
public void dataClassBindingWithOptional() throws Exception {
initServletWithControllers(OptionalDataClassController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
request.addParameter("param1", "value1");
request.addParameter("param2", "2");
request.addParameter("param3", "3");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals("value1-2-3", response.getContentAsString());
}
@Test
public void dataClassBindingWithOptionalAndConversionError() throws Exception {
initServletWithControllers(OptionalDataClassController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
request.addParameter("param2", "x");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertTrue(response.getContentAsString().contains("field 'param2'"));
}
@Controller
static class ControllerWithEmptyValueMapping {
@ -2195,11 +2151,8 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
@Controller
static class MyCommandProvidingFormController<T, TB, TB2> extends MyFormController {
@SuppressWarnings("unused")
@ModelAttribute("myCommand")
private ValidTestBean createTestBean(@RequestParam T defaultName,
Map<String, Object> model,
@RequestParam Date date) {
public ValidTestBean createTestBean(@RequestParam T defaultName, Map<String, Object> model, @RequestParam Date date) {
model.put("myKey", "myOriginalValue");
ValidTestBean tb = new ValidTestBean();
tb.setName(defaultName.getClass().getSimpleName() + ":" + defaultName.toString());
@ -2253,9 +2206,8 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
static class MyBinderInitializingCommandProvidingFormController
extends MyCommandProvidingFormController<String, TestBean, ITestBean> {
@SuppressWarnings("unused")
@InitBinder
private void initBinder(WebDataBinder binder) {
public void initBinder(WebDataBinder binder) {
binder.initBeanPropertyAccess();
binder.setRequiredFields("sex");
LocalValidatorFactoryBean vf = new LocalValidatorFactoryBean();
@ -2280,9 +2232,8 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
static class MySpecificBinderInitializingCommandProvidingFormController
extends MyCommandProvidingFormController<String, TestBean, ITestBean> {
@SuppressWarnings("unused")
@InitBinder({"myCommand", "date"})
private void initBinder(WebDataBinder binder, String date, @RequestParam("date") String[] date2) {
public void initBinder(WebDataBinder binder, String date, @RequestParam("date") String[] date2) {
LocalValidatorFactoryBean vf = new LocalValidatorFactoryBean();
vf.afterPropertiesSet();
binder.setValidator(vf);
@ -3382,6 +3333,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
public static class DataClass {
@NotNull
public final String param1;
public final int param2;
@ -3408,4 +3360,37 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
}
@RestController
public static class ValidatedDataClassController {
@InitBinder
public void initBinder(WebDataBinder binder) {
LocalValidatorFactoryBean vf = new LocalValidatorFactoryBean();
vf.afterPropertiesSet();
binder.setValidator(vf);
}
@RequestMapping("/bind")
public String handle(@Valid DataClass data, BindingResult result) {
if (result.hasErrors()) {
return result.toString();
}
return data.param1 + "-" + data.param2 + "-" + data.param3;
}
}
@RestController
public static class OptionalDataClassController {
@RequestMapping("/bind")
public String handle(Optional<DataClass> optionalData, BindingResult result) {
if (result.hasErrors()) {
assertNotNull(optionalData);
assertFalse(optionalData.isPresent());
return result.toString();
}
return optionalData.map(data -> data.param1 + "-" + data.param2 + "-" + data.param3).orElse("");
}
}
}