SPR-8484 Add path variables to the model via AbstractView.render(..) rather than HandlerMethodArgumentResolver

This commit is contained in:
Rossen Stoyanchev 2011-06-24 10:09:28 +00:00
parent df5e4d6d56
commit 2122cbcb1b
17 changed files with 422 additions and 162 deletions

View File

@ -45,11 +45,18 @@ public interface View {
/** /**
* Name of the {@link HttpServletRequest} attribute that contains the response status code. * Name of the {@link HttpServletRequest} attribute that contains the response status code.
* <p>Note: This attribute is not required to be supported by all * <p>Note: This attribute is not required to be supported by all View implementations.
* View implementations.
*/ */
String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus"; String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
/**
* Name of the {@link HttpServletRequest} attribute that contains a Map with path variables.
* The map consists of String-based URI template variable names as keys and their corresponding
* Object-based values -- extracted from segments of the URL and type converted.
*
* <p>Note: This attribute is not required to be supported by all View implementations.
*/
String PATH_VARIABLES = View.class.getName() + ".pathVariables";
/** /**
* Return the content type of the view, if predetermined. * Return the content type of the view, if predetermined.

View File

@ -16,10 +16,9 @@
package org.springframework.web.servlet.mvc.method.annotation.support; package org.springframework.web.servlet.mvc.method.annotation.support;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletException;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
@ -30,6 +29,7 @@ import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.annotation.support.AbstractNamedValueMethodArgumentResolver; import org.springframework.web.method.annotation.support.AbstractNamedValueMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.View;
/** /**
* Resolves method arguments annotated with an @{@link PathVariable}. * Resolves method arguments annotated with an @{@link PathVariable}.
@ -78,14 +78,20 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
} }
@Override @Override
@SuppressWarnings("unchecked")
protected void handleResolvedValue(Object arg, protected void handleResolvedValue(Object arg,
String name, String name,
MethodParameter parameter, MethodParameter parameter,
ModelAndViewContainer mavContainer, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) { NativeWebRequest request) {
if (mavContainer != null) { String key = View.PATH_VARIABLES;
mavContainer.addAttribute(name, arg); int scope = RequestAttributes.SCOPE_REQUEST;
Map<String, Object> pathVars = (Map<String, Object>) request.getAttribute(key, scope);
if (pathVars == null) {
pathVars = new HashMap<String, Object>();
request.setAttribute(key, pathVars, scope);
} }
pathVars.put(name, arg);
} }
private static class PathVariableNamedValueInfo extends NamedValueInfo { private static class PathVariableNamedValueInfo extends NamedValueInfo {

View File

@ -70,6 +70,8 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
/** Map of static attributes, keyed by attribute name (String) */ /** Map of static attributes, keyed by attribute name (String) */
private final Map<String, Object> staticAttributes = new HashMap<String, Object>(); private final Map<String, Object> staticAttributes = new HashMap<String, Object>();
/** Whether or not the view should add path variables in the model */
private boolean exposePathVariables = true;
/** /**
* Set the view's name. Helpful for traceability. * Set the view's name. Helpful for traceability.
@ -216,10 +218,31 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
* manipulating the Map but rather just for checking the contents. * manipulating the Map but rather just for checking the contents.
* @return the static attributes in this view * @return the static attributes in this view
*/ */
public Map getStaticAttributes() { public Map<String, Object> getStaticAttributes() {
return Collections.unmodifiableMap(this.staticAttributes); return Collections.unmodifiableMap(this.staticAttributes);
} }
/**
* Whether to add path variables in the model or not.
* <p>Path variables are commonly bound to URI template variables through the {@code @PathVariable}
* annotation. They're are effectively URI template variables with type conversion applied to
* them to derive typed Object values. Such values are frequently needed in views for
* constructing links to the same and other URLs.
* <p>Path variables added to the model override static attributes (see {@link #setAttributes(Properties)})
* but not attributes already present in the model.
* <p>By default this flag is set to {@code true}. Concrete view types can override this.
* @param exposePathVariables {@code true} to expose path variables, and {@code false} otherwise.
*/
public void setExposePathVariables(boolean exposePathVariables) {
this.exposePathVariables = exposePathVariables;
}
/**
* Returns the value of the flag indicating whether path variables should be added to the model or not.
*/
public boolean isExposePathVariables() {
return exposePathVariables;
}
/** /**
* Prepares the view given the specified model, merging it with static * Prepares the view given the specified model, merging it with static
@ -233,10 +256,19 @@ public abstract class AbstractView extends WebApplicationObjectSupport implement
" and static attributes " + this.staticAttributes); " and static attributes " + this.staticAttributes);
} }
@SuppressWarnings("unchecked")
Map<String, Object> pathVars = this.exposePathVariables ?
(Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null;
// Consolidate static and dynamic model attributes. // Consolidate static and dynamic model attributes.
Map<String, Object> mergedModel = int size = this.staticAttributes.size();
new HashMap<String, Object>(this.staticAttributes.size() + (model != null ? model.size() : 0)); size += (model != null) ? model.size() : 0;
size += (pathVars != null) ? pathVars.size() : 0;
Map<String, Object> mergedModel = new HashMap<String, Object>(size);
mergedModel.putAll(this.staticAttributes); mergedModel.putAll(this.staticAttributes);
if (pathVars != null) {
mergedModel.putAll(pathVars);
}
if (model != null) { if (model != null) {
mergedModel.putAll(model); mergedModel.putAll(model);
} }

View File

@ -238,9 +238,9 @@ public class RedirectView extends AbstractUrlBasedView {
model = removeKeys(model, redirectUri.getVariableNames()); model = removeKeys(model, redirectUri.getVariableNames());
} }
if (this.exposeModelAttributes) { if (this.exposeModelAttributes) {
List<String> uriTemplateVarNames = getUriTemplateVarNames(request); List<String> pathVarNames = getPathVarNames(request);
if (!uriTemplateVarNames.isEmpty()) { if (!pathVarNames.isEmpty()) {
model = removeKeys(model, uriTemplateVarNames); model = removeKeys(model, pathVarNames);
} }
appendQueryProperties(targetUrl, model, enc); appendQueryProperties(targetUrl, model, enc);
} }
@ -274,12 +274,12 @@ public class RedirectView extends AbstractUrlBasedView {
} }
/** /**
* Returns URI template variable names for the current request; or an empty list. * Returns the names of PathVariable for the current request; or an empty list.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private List<String> getUriTemplateVarNames(HttpServletRequest request) { private List<String> getPathVarNames(HttpServletRequest request) {
String key = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE; String key = View.PATH_VARIABLES;
Map<String, String> map = (Map<String, String>) request.getAttribute(key); Map<String, Object> map = (Map<String, Object>) request.getAttribute(key);
return (map != null) ? new ArrayList<String>(map.keySet()) : Collections.<String>emptyList(); return (map != null) ? new ArrayList<String>(map.keySet()) : Collections.<String>emptyList();
} }
@ -307,7 +307,7 @@ public class RedirectView extends AbstractUrlBasedView {
boolean first = (getUrl().indexOf('?') < 0); boolean first = (getUrl().indexOf('?') < 0);
for (Map.Entry<String, Object> entry : queryProperties(model).entrySet()) { for (Map.Entry<String, Object> entry : queryProperties(model).entrySet()) {
Object rawValue = entry.getValue(); Object rawValue = entry.getValue();
Iterator valueIter; Iterator<Object> valueIter;
if (rawValue != null && rawValue.getClass().isArray()) { if (rawValue != null && rawValue.getClass().isArray()) {
valueIter = Arrays.asList(ObjectUtils.toObjectArray(rawValue)).iterator(); valueIter = Arrays.asList(ObjectUtils.toObjectArray(rawValue)).iterator();
} }

View File

@ -121,6 +121,7 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
/** Map of static attributes, keyed by attribute name (String) */ /** Map of static attributes, keyed by attribute name (String) */
private final Map<String, Object> staticAttributes = new HashMap<String, Object>(); private final Map<String, Object> staticAttributes = new HashMap<String, Object>();
private Boolean exposePathVariables;
/** /**
* Set the view class that should be used to create views. * Set the view class that should be used to create views.
@ -337,6 +338,22 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
return this.order; return this.order;
} }
/**
* Whether views resolved by this resolver should add path variables the model or not.
* The default setting is to allow each View decide (see {@link AbstractView#setExposePathVariables(boolean)}.
* However, you can use this property to override that.
* @param exposePathVariables
* <ul>
* <li>{@code true} - all Views resolved by this resolver will expose path variables
* <li>{@code false} - no Views resolved by this resolver will expose path variables
* <li>{@code null} - individual Views can decide for themselves (this is used by the default)
* <ul>
* @see AbstractView#setExposePathVariables(boolean)
*/
public void setExposePathVariables(Boolean exposePathVariables) {
this.exposePathVariables = exposePathVariables;
}
@Override @Override
protected void initApplicationContext() { protected void initApplicationContext() {
super.initApplicationContext(); super.initApplicationContext();
@ -345,7 +362,6 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
} }
} }
/** /**
* This implementation returns just the view name, * This implementation returns just the view name,
* as this ViewResolver doesn't support localized resolution. * as this ViewResolver doesn't support localized resolution.
@ -444,6 +460,9 @@ public class UrlBasedViewResolver extends AbstractCachingViewResolver implements
} }
view.setRequestContextAttribute(getRequestContextAttribute()); view.setRequestContextAttribute(getRequestContextAttribute());
view.setAttributesMap(getAttributesMap()); view.setAttributesMap(getAttributesMap());
if (this.exposePathVariables != null) {
view.setExposePathVariables(exposePathVariables);
}
return view; return view;
} }

View File

@ -73,6 +73,7 @@ public class MappingJacksonJsonView extends AbstractView {
*/ */
public MappingJacksonJsonView() { public MappingJacksonJsonView() {
setContentType(DEFAULT_CONTENT_TYPE); setContentType(DEFAULT_CONTENT_TYPE);
setExposePathVariables(false);
} }
/** /**

View File

@ -18,6 +18,7 @@ package org.springframework.web.servlet.view.xml;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -58,6 +59,7 @@ public class MarshallingView extends AbstractView {
*/ */
public MarshallingView() { public MarshallingView() {
setContentType(DEFAULT_CONTENT_TYPE); setContentType(DEFAULT_CONTENT_TYPE);
setExposePathVariables(false);
} }
/** /**
@ -67,6 +69,7 @@ public class MarshallingView extends AbstractView {
Assert.notNull(marshaller, "'marshaller' must not be null"); Assert.notNull(marshaller, "'marshaller' must not be null");
setContentType(DEFAULT_CONTENT_TYPE); setContentType(DEFAULT_CONTENT_TYPE);
this.marshaller = marshaller; this.marshaller = marshaller;
setExposePathVariables(false);
} }
/** /**
@ -93,8 +96,9 @@ public class MarshallingView extends AbstractView {
} }
@Override @Override
protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) protected void renderMergedOutputModel(Map<String, Object> model,
throws Exception { HttpServletRequest request,
HttpServletResponse response) throws Exception {
Object toBeMarshalled = locateToBeMarshalled(model); Object toBeMarshalled = locateToBeMarshalled(model);
if (toBeMarshalled == null) { if (toBeMarshalled == null) {
throw new ServletException("Unable to locate object to be marshalled in model: " + model); throw new ServletException("Unable to locate object to be marshalled in model: " + model);
@ -119,7 +123,7 @@ public class MarshallingView extends AbstractView {
* supported by the marshaller * supported by the marshaller
* @see #setModelKey(String) * @see #setModelKey(String)
*/ */
protected Object locateToBeMarshalled(Map model) throws ServletException { protected Object locateToBeMarshalled(Map<String, Object> model) throws ServletException {
if (this.modelKey != null) { if (this.modelKey != null) {
Object o = model.get(this.modelKey); Object o = model.get(this.modelKey);
if (o == null) { if (o == null) {

View File

@ -88,8 +88,7 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebA
* *
* <p>If you wish to add high-level tests, consider the following other "integration"-style tests: * <p>If you wish to add high-level tests, consider the following other "integration"-style tests:
* <ul> * <ul>
* <li>{@link HandlerMethodAdapterAnnotationDetectionTests} * <li>{@link HandlerMethodAnnotationDetectionTests}
* <li>{@link HandlerMethodMappingAnnotationDetectionTests}
* <li>{@link ServletHandlerMethodTests} * <li>{@link ServletHandlerMethodTests}
* </ul> * </ul>
* *
@ -293,7 +292,7 @@ public class RequestMappingHandlerAdapterIntegrationTests {
@ModelAttribute OtherUser otherUser, @ModelAttribute OtherUser otherUser,
Model model) throws Exception { Model model) throws Exception {
model.addAttribute("cookie", cookie).addAttribute("header", header) model.addAttribute("cookie", cookie).addAttribute("pathvar", pathvar).addAttribute("header", header)
.addAttribute("systemHeader", systemHeader).addAttribute("headerMap", headerMap) .addAttribute("systemHeader", systemHeader).addAttribute("headerMap", headerMap)
.addAttribute("dateParam", dateParam).addAttribute("paramMap", paramMap) .addAttribute("dateParam", dateParam).addAttribute("paramMap", paramMap)
.addAttribute("paramByConvention", paramByConvention).addAttribute("value", value) .addAttribute("paramByConvention", paramByConvention).addAttribute("value", value)

View File

@ -698,11 +698,6 @@ public class ServletHandlerMethodTests {
assertNotNull(deserialized.session); assertNotNull(deserialized.session);
} }
@Test @Test
public void relativePathDispatchingController() throws Exception { public void relativePathDispatchingController() throws Exception {
initDispatcherServlet(MyRelativePathDispatchingController.class, null); initDispatcherServlet(MyRelativePathDispatchingController.class, null);

View File

@ -17,14 +17,19 @@
package org.springframework.web.servlet.mvc.method.annotation; package org.springframework.web.servlet.mvc.method.annotation;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.junit.Test; import org.junit.Test;
@ -42,9 +47,12 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
import org.springframework.web.servlet.mvc.annotation.UriTemplateServletAnnotationControllerTests; import org.springframework.web.servlet.mvc.annotation.UriTemplateServletAnnotationControllerTests;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
import org.springframework.web.servlet.view.AbstractView;
/** /**
* The origin of this test class is {@link UriTemplateServletAnnotationControllerTests} with the tests in this class * The origin of this test class is {@link UriTemplateServletAnnotationControllerTests} with the tests in this class
@ -79,6 +87,29 @@ public class UriTemplateServletHandlerMethodTests {
assertEquals("test-42-21-other", response.getContentAsString()); assertEquals("test-42-21-other", response.getContentAsString());
} }
@Test
public void pathVarsInModel() throws Exception {
final Map<String, Object> pathVars = new HashMap<String, Object>();
pathVars.put("hotel", "42");
pathVars.put("booking", 21);
pathVars.put("other", "other");
WebApplicationContext wac =
initDispatcherServlet(ViewRenderingController.class, new BeanDefinitionRegistrar() {
public void register(GenericWebApplicationContext context) {
RootBeanDefinition beanDef = new RootBeanDefinition(ModelValidatingViewResolver.class);
beanDef.getConstructorArgumentValues().addGenericArgumentValue(pathVars);
context.registerBeanDefinition("viewResolver", beanDef);
}
});
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/42/bookings/21-other");
servlet.service(request, new MockHttpServletResponse());
ModelValidatingViewResolver resolver = wac.getBean(ModelValidatingViewResolver.class);
assertEquals(3, resolver.validatedAttrCount);
}
@Test @Test
public void binding() throws Exception { public void binding() throws Exception {
initDispatcherServlet(BindingUriTemplateController.class, null); initDispatcherServlet(BindingUriTemplateController.class, null);
@ -349,6 +380,17 @@ public class UriTemplateServletHandlerMethodTests {
} }
@Controller
public static class ViewRenderingController {
@RequestMapping("/hotels/{hotel}/bookings/{booking}-{other}")
public void handle(@PathVariable("hotel") String hotel, @PathVariable int booking, @PathVariable String other) {
assertEquals("Invalid path variable value", "42", hotel);
assertEquals("Invalid path variable value", 21, booking);
}
}
@Controller @Controller
public static class BindingUriTemplateController { public static class BindingUriTemplateController {
@ -588,18 +630,47 @@ public class UriTemplateServletHandlerMethodTests {
} }
} }
public static class ModelValidatingViewResolver implements ViewResolver {
private final Map<String, Object> attrsToValidate;
int validatedAttrCount;
public ModelValidatingViewResolver(Map<String, Object> attrsToValidate) {
this.attrsToValidate = attrsToValidate;
}
public View resolveViewName(final String viewName, Locale locale) throws Exception {
return new AbstractView () {
public String getContentType() {
return null;
}
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
for (String key : attrsToValidate.keySet()) {
assertTrue("Model should contain attribute named " + key, model.containsKey(key));
assertEquals(attrsToValidate.get(key), model.get(key));
validatedAttrCount++;
}
}
};
}
}
private interface BeanDefinitionRegistrar { private interface BeanDefinitionRegistrar {
public void register(GenericWebApplicationContext context); public void register(GenericWebApplicationContext context);
} }
@SuppressWarnings("serial") @SuppressWarnings("serial")
private void initDispatcherServlet(final Class<?> controllerClass, final BeanDefinitionRegistrar registrar) private WebApplicationContext initDispatcherServlet(final Class<?> controllerClass, final BeanDefinitionRegistrar registrar)
throws ServletException { throws ServletException {
final GenericWebApplicationContext wac = new GenericWebApplicationContext();
servlet = new DispatcherServlet() { servlet = new DispatcherServlet() {
@Override @Override
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) { protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
GenericWebApplicationContext wac = new GenericWebApplicationContext();
wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass)); wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerClass));
Class<?> mappingType = RequestMappingHandlerMapping.class; Class<?> mappingType = RequestMappingHandlerMapping.class;
@ -625,7 +696,10 @@ public class UriTemplateServletHandlerMethodTests {
return wac; return wac;
} }
}; };
servlet.init(new MockServletConfig()); servlet.init(new MockServletConfig());
return wac;
} }
// @Ignore("ControllerClassNameHandlerMapping") // @Ignore("ControllerClassNameHandlerMapping")

View File

@ -18,6 +18,7 @@ package org.springframework.web.servlet.mvc.method.annotation.support;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -35,7 +36,7 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.support.PathVariableMethodArgumentResolver; import org.springframework.web.servlet.View;
/** /**
* Test fixture with {@link PathVariableMethodArgumentResolver}. * Test fixture with {@link PathVariableMethodArgumentResolver}.
@ -76,14 +77,40 @@ public class PathVariableMethodArgumentResolverTests {
} }
@Test @Test
public void resolveStringArgument() throws Exception { public void resolveArgument() throws Exception {
Map<String, String> uriTemplateVars = new HashMap<String, String>(); Map<String, String> uriTemplateVars = new HashMap<String, String>();
uriTemplateVars.put("name", "value"); uriTemplateVars.put("name", "value");
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars); request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars);
String result = (String) resolver.resolveArgument(paramNamedString, mavContainer, webRequest, null); String result = (String) resolver.resolveArgument(paramNamedString, mavContainer, webRequest, null);
assertEquals("PathVariable not resolved correctly", "value", result); assertEquals("PathVariable not resolved correctly", "value", result);
assertEquals("PathVariable not added to the model", "value", mavContainer.getAttribute("name"));
@SuppressWarnings("unchecked")
Map<String, Object> pathVars = (Map<String, Object>) request.getAttribute(View.PATH_VARIABLES);
assertNotNull(pathVars);
assertEquals(1, pathVars.size());
assertEquals("value", pathVars.get("name"));
}
@SuppressWarnings("unchecked")
@Test
public void resolveArgumentWithExistingPathVars() throws Exception {
Map<String, String> uriTemplateVars = new HashMap<String, String>();
uriTemplateVars.put("name", "value");
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars);
Map<String, Object> pathVars = new HashMap<String, Object>();
uriTemplateVars.put("oldName", "oldValue");
request.setAttribute(View.PATH_VARIABLES, uriTemplateVars);
String result = (String) resolver.resolveArgument(paramNamedString, mavContainer, webRequest, null);
assertEquals("PathVariable not resolved correctly", "value", result);
pathVars = (Map<String, Object>) request.getAttribute(View.PATH_VARIABLES);
assertNotNull(pathVars);
assertEquals(2, pathVars.size());
assertEquals("value", pathVars.get("name"));
assertEquals("oldValue", pathVars.get("oldName"));
} }
@Test(expected = ServletRequestBindingException.class) @Test(expected = ServletRequestBindingException.class)

View File

@ -15,6 +15,10 @@
*/ */
package org.springframework.web.servlet.view; package org.springframework.web.servlet.view;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -28,13 +32,13 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.context.ApplicationContextException; import org.springframework.context.ApplicationContextException;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext; import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.View;
/** /**
* Tests for AbstractView. Not called AbstractViewTests as * Tests for AbstractView. Not called AbstractViewTests as
@ -45,21 +49,21 @@ import org.springframework.web.context.WebApplicationContext;
public class BaseViewTests extends TestCase { public class BaseViewTests extends TestCase {
public void testRenderWithoutStaticAttributes() throws Exception { public void testRenderWithoutStaticAttributes() throws Exception {
MockControl mc = MockControl.createControl(WebApplicationContext.class);
WebApplicationContext wac = (WebApplicationContext) mc.getMock(); WebApplicationContext wac = createMock(WebApplicationContext.class);
wac.getServletContext(); wac.getServletContext();
mc.setReturnValue(new MockServletContext()); expectLastCall().andReturn(new MockServletContext());
mc.replay(); replay(wac);
HttpServletRequest request = new MockHttpServletRequest(); HttpServletRequest request = new MockHttpServletRequest();
HttpServletResponse response = new MockHttpServletResponse(); HttpServletResponse response = new MockHttpServletResponse();
TestView tv = new TestView(request, response, wac); TestView tv = new TestView(wac);
// Check superclass handles duplicate init // Check superclass handles duplicate init
tv.setApplicationContext(wac); tv.setApplicationContext(wac);
tv.setApplicationContext(wac); tv.setApplicationContext(wac);
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put("foo", "bar"); model.put("foo", "bar");
model.put("something", new Object()); model.put("something", new Object());
tv.render(model, request, response); tv.render(model, request, response);
@ -68,22 +72,21 @@ public class BaseViewTests extends TestCase {
checkContainsAll(model, tv.model); checkContainsAll(model, tv.model);
assertTrue(tv.inited); assertTrue(tv.inited);
mc.verify(); verify(wac);
} }
/** /**
* Test attribute passing, NOT CSV parsing. * Test attribute passing, NOT CSV parsing.
*/ */
public void testRenderWithStaticAttributesNoCollision() throws Exception { public void testRenderWithStaticAttributesNoCollision() throws Exception {
MockControl mc = MockControl.createControl(WebApplicationContext.class); WebApplicationContext wac = createMock(WebApplicationContext.class);
WebApplicationContext wac = (WebApplicationContext) mc.getMock();
wac.getServletContext(); wac.getServletContext();
mc.setReturnValue(new MockServletContext()); expectLastCall().andReturn(new MockServletContext());
mc.replay(); replay(wac);
HttpServletRequest request = new MockHttpServletRequest(); HttpServletRequest request = new MockHttpServletRequest();
HttpServletResponse response = new MockHttpServletResponse(); HttpServletResponse response = new MockHttpServletResponse();
TestView tv = new TestView(request, response, wac); TestView tv = new TestView(wac);
tv.setApplicationContext(wac); tv.setApplicationContext(wac);
Properties p = new Properties(); Properties p = new Properties();
@ -91,8 +94,8 @@ public class BaseViewTests extends TestCase {
p.setProperty("something", "else"); p.setProperty("something", "else");
tv.setAttributes(p); tv.setAttributes(p);
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put("one", new HashMap()); model.put("one", new HashMap<Object, Object>());
model.put("two", new Object()); model.put("two", new Object());
tv.render(model, request, response); tv.render(model, request, response);
@ -101,19 +104,52 @@ public class BaseViewTests extends TestCase {
checkContainsAll(p, tv.model); checkContainsAll(p, tv.model);
assertTrue(tv.inited); assertTrue(tv.inited);
mc.verify(); verify(wac);
} }
public void testDynamicModelOverridesStaticAttributesIfCollision() throws Exception { public void testPathVarsOverrideStaticAttributes() throws Exception {
MockControl mc = MockControl.createControl(WebApplicationContext.class); WebApplicationContext wac = createMock(WebApplicationContext.class);
WebApplicationContext wac = (WebApplicationContext) mc.getMock();
wac.getServletContext(); wac.getServletContext();
mc.setReturnValue(new MockServletContext()); expectLastCall().andReturn(new MockServletContext());
mc.replay(); replay(wac);
HttpServletRequest request = new MockHttpServletRequest(); HttpServletRequest request = new MockHttpServletRequest();
HttpServletResponse response = new MockHttpServletResponse(); HttpServletResponse response = new MockHttpServletResponse();
TestView tv = new TestView(request, response, wac);
TestView tv = new TestView(wac);
tv.setApplicationContext(wac);
Properties p = new Properties();
p.setProperty("one", "bar");
p.setProperty("something", "else");
tv.setAttributes(p);
Map<String, Object> pathVars = new HashMap<String, Object>();
pathVars.put("one", new HashMap<Object, Object>());
pathVars.put("two", new Object());
request.setAttribute(View.PATH_VARIABLES, pathVars);
tv.render(new HashMap<String, Object>(), request, response);
// Check it contains all
checkContainsAll(pathVars, tv.model);
assertTrue(tv.model.size() == 3);
// will have old something from properties
assertTrue(tv.model.get("something").equals("else"));
assertTrue(tv.inited);
verify(wac);
}
public void testDynamicModelOverridesStaticAttributesIfCollision() throws Exception {
WebApplicationContext wac = createMock(WebApplicationContext.class);
wac.getServletContext();
expectLastCall().andReturn(new MockServletContext());
replay(wac);
HttpServletRequest request = new MockHttpServletRequest();
HttpServletResponse response = new MockHttpServletResponse();
TestView tv = new TestView(wac);
tv.setApplicationContext(wac); tv.setApplicationContext(wac);
Properties p = new Properties(); Properties p = new Properties();
@ -121,8 +157,8 @@ public class BaseViewTests extends TestCase {
p.setProperty("something", "else"); p.setProperty("something", "else");
tv.setAttributes(p); tv.setAttributes(p);
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put("one", new HashMap()); model.put("one", new HashMap<Object, Object>());
model.put("two", new Object()); model.put("two", new Object());
tv.render(model, request, response); tv.render(model, request, response);
@ -133,7 +169,40 @@ public class BaseViewTests extends TestCase {
assertTrue(tv.model.get("something").equals("else")); assertTrue(tv.model.get("something").equals("else"));
assertTrue(tv.inited); assertTrue(tv.inited);
mc.verify(); verify(wac);
}
public void testDynamicModelOverridesPathVariables() throws Exception {
WebApplicationContext wac = createMock(WebApplicationContext.class);
wac.getServletContext();
expectLastCall().andReturn(new MockServletContext());
replay(wac);
TestView tv = new TestView(wac);
tv.setApplicationContext(wac);
MockHttpServletRequest request = new MockHttpServletRequest();
MockHttpServletResponse response = new MockHttpServletResponse();
Map<String, Object> pathVars = new HashMap<String, Object>();
pathVars.put("one", "bar");
pathVars.put("something", "else");
request.setAttribute(View.PATH_VARIABLES, pathVars);
Map<String, Object> model = new HashMap<String, Object>();
model.put("one", new HashMap<Object, Object>());
model.put("two", new Object());
tv.render(model, request, response);
// Check it contains all
checkContainsAll(model, tv.model);
assertEquals(3, tv.model.size());
// will have old something from path variables
assertTrue(tv.model.get("something").equals("else"));
assertTrue(tv.inited);
verify(wac);
} }
public void testIgnoresNullAttributes() { public void testIgnoresNullAttributes() {
@ -170,7 +239,7 @@ public class BaseViewTests extends TestCase {
public void testAttributeCSVParsingValidWithWeirdCharacters() { public void testAttributeCSVParsingValidWithWeirdCharacters() {
AbstractView v = new ConcreteView(); AbstractView v = new ConcreteView();
String fooval = "owfie fue&3[][[[2 \n\n \r \t 8£3"; String fooval = "owfie fue&3[][[[2 \n\n \r \t 8<EFBFBD>3";
// Also tests empty value // Also tests empty value
String kingval = ""; String kingval = "";
v.setAttributesCSV("foo=(" + fooval + "),king={" + kingval + "},f1=[we]"); v.setAttributesCSV("foo=(" + fooval + "),king={" + kingval + "},f1=[we]");
@ -224,9 +293,10 @@ public class BaseViewTests extends TestCase {
* @param expected * @param expected
* @param actual * @param actual
*/ */
private void checkContainsAll(Map expected, Map actual) { @SuppressWarnings({ "rawtypes", "unchecked" })
Set keys = expected.keySet(); private void checkContainsAll(Map expected, Map<String, Object> actual) {
for (Iterator iter = keys.iterator(); iter.hasNext();) { Set<String> keys = expected.keySet();
for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
String key = (String) iter.next(); String key = (String) iter.next();
//System.out.println("Checking model key " + key); //System.out.println("Checking model key " + key);
assertTrue("Value for model key '" + key + "' must match", actual.get(key) == expected.get(key)); assertTrue("Value for model key '" + key + "' must match", actual.get(key) == expected.get(key));
@ -239,7 +309,7 @@ public class BaseViewTests extends TestCase {
*/ */
private class ConcreteView extends AbstractView { private class ConcreteView extends AbstractView {
// Do-nothing concrete subclass // Do-nothing concrete subclass
protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -250,21 +320,17 @@ public class BaseViewTests extends TestCase {
* behaviour * behaviour
*/ */
private class TestView extends AbstractView { private class TestView extends AbstractView {
private HttpServletRequest request;
private HttpServletResponse response;
private WebApplicationContext wac; private WebApplicationContext wac;
public boolean inited; public boolean inited;
/** Captured model in render */ /** Captured model in render */
public Map model; public Map<String, Object> model;
public TestView(HttpServletRequest request, HttpServletResponse response, WebApplicationContext wac) { public TestView(WebApplicationContext wac) {
this.request = request;
this.response = response;
this.wac = wac; this.wac = wac;
} }
protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { throws ServletException, IOException {
// do nothing // do nothing
this.model = model; this.model = model;

View File

@ -16,6 +16,11 @@
package org.springframework.web.servlet.view; package org.springframework.web.servlet.view;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
@ -23,12 +28,12 @@ import java.util.Set;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.easymock.MockControl;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockRequestDispatcher; import org.springframework.mock.web.MockRequestDispatcher;
import org.springframework.mock.web.MockServletContext; import org.springframework.mock.web.MockServletContext;
import org.springframework.web.servlet.View;
import org.springframework.web.util.WebUtils; import org.springframework.web.util.WebUtils;
/** /**
@ -52,7 +57,7 @@ public class InternalResourceViewTests extends TestCase {
} }
public void testForward() throws Exception { public void testForward() throws Exception {
HashMap model = new HashMap(); HashMap<String, Object> model = new HashMap<String, Object>();
Object obj = new Integer(1); Object obj = new Integer(1);
model.put("foo", "bar"); model.put("foo", "bar");
model.put("I", obj); model.put("I", obj);
@ -77,8 +82,8 @@ public class InternalResourceViewTests extends TestCase {
view.render(model, request, response); view.render(model, request, response);
assertEquals(url, response.getForwardedUrl()); assertEquals(url, response.getForwardedUrl());
Set keys = model.keySet(); Set<String> keys = model.keySet();
for (Iterator it = keys.iterator(); it.hasNext();) { for (Iterator<String> it = keys.iterator(); it.hasNext();) {
String key = (String) it.next(); String key = (String) it.next();
assertEquals(model.get(key), request.getAttribute(key)); assertEquals(model.get(key), request.getAttribute(key));
} }
@ -91,7 +96,7 @@ public class InternalResourceViewTests extends TestCase {
} }
public void testForwardWithForwardAttributesPresent() throws Exception { public void testForwardWithForwardAttributesPresent() throws Exception {
HashMap model = new HashMap(); HashMap<String, Object> model = new HashMap<String, Object>();
Object obj = new Integer(1); Object obj = new Integer(1);
model.put("foo", "bar"); model.put("foo", "bar");
model.put("I", obj); model.put("I", obj);
@ -122,8 +127,8 @@ public class InternalResourceViewTests extends TestCase {
view.render(model, request, response); view.render(model, request, response);
assertEquals(url, response.getForwardedUrl()); assertEquals(url, response.getForwardedUrl());
Set keys = model.keySet(); Set<String> keys = model.keySet();
for (Iterator it = keys.iterator(); it.hasNext();) { for (Iterator<String> it = keys.iterator(); it.hasNext();) {
String key = (String) it.next(); String key = (String) it.next();
assertEquals(model.get(key), request.getAttribute(key)); assertEquals(model.get(key), request.getAttribute(key));
} }
@ -136,25 +141,26 @@ public class InternalResourceViewTests extends TestCase {
} }
public void testAlwaysInclude() throws Exception { public void testAlwaysInclude() throws Exception {
HashMap model = new HashMap(); HashMap<String, Object> model = new HashMap<String, Object>();
Object obj = new Integer(1); Object obj = new Integer(1);
model.put("foo", "bar"); model.put("foo", "bar");
model.put("I", obj); model.put("I", obj);
String url = "forward-to"; String url = "forward-to";
MockControl reqControl = MockControl.createControl(HttpServletRequest.class); HttpServletRequest request = createMock(HttpServletRequest.class);
HttpServletRequest request = (HttpServletRequest) reqControl.getMock(); request.getAttribute(View.PATH_VARIABLES);
Set keys = model.keySet(); expectLastCall().andReturn(null);
for (Iterator iter = keys.iterator(); iter.hasNext();) { Set<String> keys = model.keySet();
for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
String key = (String) iter.next(); String key = (String) iter.next();
request.setAttribute(key, model.get(key)); request.setAttribute(key, model.get(key));
reqControl.setVoidCallable(1); expectLastCall().times(1);
} }
request.getRequestDispatcher(url); request.getRequestDispatcher(url);
reqControl.setReturnValue(new MockRequestDispatcher(url)); expectLastCall().andReturn(new MockRequestDispatcher(url));
reqControl.replay(); replay(request);
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
InternalResourceView v = new InternalResourceView(); InternalResourceView v = new InternalResourceView();
@ -164,31 +170,32 @@ public class InternalResourceViewTests extends TestCase {
// Can now try multiple tests // Can now try multiple tests
v.render(model, request, response); v.render(model, request, response);
assertEquals(url, response.getIncludedUrl()); assertEquals(url, response.getIncludedUrl());
reqControl.verify(); verify(request);
} }
public void testIncludeOnAttribute() throws Exception { public void testIncludeOnAttribute() throws Exception {
HashMap model = new HashMap(); HashMap<String, Object> model = new HashMap<String, Object>();
Object obj = new Integer(1); Object obj = new Integer(1);
model.put("foo", "bar"); model.put("foo", "bar");
model.put("I", obj); model.put("I", obj);
String url = "forward-to"; String url = "forward-to";
MockControl reqControl = MockControl.createControl(HttpServletRequest.class); HttpServletRequest request = createMock(HttpServletRequest.class);
HttpServletRequest request = (HttpServletRequest) reqControl.getMock(); request.getAttribute(View.PATH_VARIABLES);
Set keys = model.keySet(); expectLastCall().andReturn(null);
for (Iterator iter = keys.iterator(); iter.hasNext();) { Set<String> keys = model.keySet();
for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
String key = (String) iter.next(); String key = (String) iter.next();
request.setAttribute(key, model.get(key)); request.setAttribute(key, model.get(key));
reqControl.setVoidCallable(1); expectLastCall().times(1);
} }
request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE); request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE);
reqControl.setReturnValue("somepath"); expectLastCall().andReturn("somepath");
request.getRequestDispatcher(url); request.getRequestDispatcher(url);
reqControl.setReturnValue(new MockRequestDispatcher(url)); expectLastCall().andReturn(new MockRequestDispatcher(url));
reqControl.replay(); replay(request);
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
InternalResourceView v = new InternalResourceView(); InternalResourceView v = new InternalResourceView();
@ -197,31 +204,32 @@ public class InternalResourceViewTests extends TestCase {
// Can now try multiple tests // Can now try multiple tests
v.render(model, request, response); v.render(model, request, response);
assertEquals(url, response.getIncludedUrl()); assertEquals(url, response.getIncludedUrl());
reqControl.verify(); verify(request);
} }
public void testIncludeOnCommitted() throws Exception { public void testIncludeOnCommitted() throws Exception {
HashMap model = new HashMap(); HashMap<String, Object> model = new HashMap<String, Object>();
Object obj = new Integer(1); Object obj = new Integer(1);
model.put("foo", "bar"); model.put("foo", "bar");
model.put("I", obj); model.put("I", obj);
String url = "forward-to"; String url = "forward-to";
MockControl reqControl = MockControl.createControl(HttpServletRequest.class); HttpServletRequest request = createMock(HttpServletRequest.class);
HttpServletRequest request = (HttpServletRequest) reqControl.getMock(); request.getAttribute(View.PATH_VARIABLES);
Set keys = model.keySet(); expectLastCall().andReturn(null);
for (Iterator iter = keys.iterator(); iter.hasNext();) { Set<String> keys = model.keySet();
for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
String key = (String) iter.next(); String key = (String) iter.next();
request.setAttribute(key, model.get(key)); request.setAttribute(key, model.get(key));
reqControl.setVoidCallable(1); expectLastCall().times(1);
} }
request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE); request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE);
reqControl.setReturnValue(null); expectLastCall().andReturn(null);
request.getRequestDispatcher(url); request.getRequestDispatcher(url);
reqControl.setReturnValue(new MockRequestDispatcher(url)); expectLastCall().andReturn(new MockRequestDispatcher(url));
reqControl.replay(); replay(request);
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
response.setCommitted(true); response.setCommitted(true);
@ -231,7 +239,7 @@ public class InternalResourceViewTests extends TestCase {
// Can now try multiple tests // Can now try multiple tests
v.render(model, request, response); v.render(model, request, response);
assertEquals(url, response.getIncludedUrl()); assertEquals(url, response.getIncludedUrl());
reqControl.verify(); verify(request);
} }
} }

View File

@ -25,7 +25,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.View;
public class RedirectViewUriTemplateTests { public class RedirectViewUriTemplateTests {
@ -84,7 +84,7 @@ public class RedirectViewUriTemplateTests {
Map<String, String> uriTemplatVars = new HashMap<String, String>(); Map<String, String> uriTemplatVars = new HashMap<String, String>();
uriTemplatVars.put("name1", "value1"); uriTemplatVars.put("name1", "value1");
uriTemplatVars.put("name2", "value2"); uriTemplatVars.put("name2", "value2");
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplatVars); request.setAttribute(View.PATH_VARIABLES, uriTemplatVars);
String url = "http://url.somewhere.com"; String url = "http://url.somewhere.com";
RedirectView redirectView = new RedirectView(url + "/{name2}"); RedirectView redirectView = new RedirectView(url + "/{name2}");

View File

@ -74,6 +74,11 @@ public class MappingJacksonJsonViewTest {
view = new MappingJacksonJsonView(); view = new MappingJacksonJsonView();
} }
@Test
public void isExposePathVars() {
assertEquals("Must not expose path variables", false, view.isExposePathVariables());
}
@Test @Test
public void renderSimpleMap() throws Exception { public void renderSimpleMap() throws Exception {

View File

@ -16,10 +16,20 @@
package org.springframework.web.servlet.view.velocity; package org.springframework.web.servlet.view.velocity;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -31,16 +41,14 @@ import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.tools.generic.DateTool; import org.apache.velocity.tools.generic.DateTool;
import org.apache.velocity.tools.generic.MathTool; import org.apache.velocity.tools.generic.MathTool;
import org.apache.velocity.tools.generic.NumberTool; import org.apache.velocity.tools.generic.NumberTool;
import org.easymock.MockControl;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import org.springframework.context.ApplicationContextException; import org.springframework.context.ApplicationContextException;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext; import org.springframework.mock.web.MockServletContext;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.view.AbstractView; import org.springframework.web.servlet.view.AbstractView;
@ -54,13 +62,12 @@ public class VelocityViewTests {
@Test @Test
public void testNoVelocityConfig() throws Exception { public void testNoVelocityConfig() throws Exception {
VelocityView vv = new VelocityView(); VelocityView vv = new VelocityView();
MockControl wmc = MockControl.createControl(WebApplicationContext.class); WebApplicationContext wac = createMock(WebApplicationContext.class);
WebApplicationContext wac = (WebApplicationContext) wmc.getMock();
wac.getBeansOfType(VelocityConfig.class, true, false); wac.getBeansOfType(VelocityConfig.class, true, false);
wmc.setReturnValue(new HashMap()); expectLastCall().andReturn(new HashMap<String, Object>());
wac.getParentBeanFactory(); wac.getParentBeanFactory();
wmc.setReturnValue(null); expectLastCall().andReturn(null);
wmc.replay(); replay(wac);
vv.setUrl("anythingButNull"); vv.setUrl("anythingButNull");
try { try {
@ -72,7 +79,7 @@ public class VelocityViewTests {
assertTrue(ex.getMessage().contains("VelocityConfig")); assertTrue(ex.getMessage().contains("VelocityConfig"));
} }
wmc.verify(); verify(wac);
} }
@Test @Test
@ -118,13 +125,12 @@ public class VelocityViewTests {
* If it's non null it will be checked * If it's non null it will be checked
*/ */
private void testValidTemplateName(final Exception mergeTemplateFailureException) throws Exception { private void testValidTemplateName(final Exception mergeTemplateFailureException) throws Exception {
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put("foo", "bar"); model.put("foo", "bar");
final String templateName = "test.vm"; final String templateName = "test.vm";
MockControl wmc = MockControl.createControl(WebApplicationContext.class); WebApplicationContext wac = createMock(WebApplicationContext.class);
WebApplicationContext wac = (WebApplicationContext) wmc.getMock();
MockServletContext sc = new MockServletContext(); MockServletContext sc = new MockServletContext();
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
@ -135,14 +141,14 @@ public class VelocityViewTests {
} }
}; };
wac.getBeansOfType(VelocityConfig.class, true, false); wac.getBeansOfType(VelocityConfig.class, true, false);
Map configurers = new HashMap(); Map<String, Object> configurers = new HashMap<String, Object>();
configurers.put("velocityConfigurer", vc); configurers.put("velocityConfigurer", vc);
wmc.setReturnValue(configurers); expectLastCall().andReturn(configurers);
wac.getParentBeanFactory(); wac.getParentBeanFactory();
wmc.setReturnValue(null); expectLastCall().andReturn(null);
wac.getServletContext(); wac.getServletContext();
wmc.setReturnValue(sc, 3); expectLastCall().andReturn(sc).times(3);
wmc.replay(); replay(wac);
HttpServletRequest request = new MockHttpServletRequest(); HttpServletRequest request = new MockHttpServletRequest();
final HttpServletResponse expectedResponse = new MockHttpServletResponse(); final HttpServletResponse expectedResponse = new MockHttpServletResponse();
@ -172,15 +178,14 @@ public class VelocityViewTests {
assertEquals(ex, mergeTemplateFailureException); assertEquals(ex, mergeTemplateFailureException);
} }
wmc.verify(); verify(wac);
} }
@Test @Test
public void testKeepExistingContentType() throws Exception { public void testKeepExistingContentType() throws Exception {
final String templateName = "test.vm"; final String templateName = "test.vm";
MockControl wmc = MockControl.createControl(WebApplicationContext.class); WebApplicationContext wac = createMock(WebApplicationContext.class);
WebApplicationContext wac = (WebApplicationContext) wmc.getMock();
MockServletContext sc = new MockServletContext(); MockServletContext sc = new MockServletContext();
sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac); sc.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
@ -191,14 +196,14 @@ public class VelocityViewTests {
} }
}; };
wac.getBeansOfType(VelocityConfig.class, true, false); wac.getBeansOfType(VelocityConfig.class, true, false);
Map configurers = new HashMap(); Map<String, Object> configurers = new HashMap<String, Object>();
configurers.put("velocityConfigurer", vc); configurers.put("velocityConfigurer", vc);
wmc.setReturnValue(configurers); expectLastCall().andReturn(configurers);
wac.getParentBeanFactory(); wac.getParentBeanFactory();
wmc.setReturnValue(null); expectLastCall().andReturn(null);
wac.getServletContext(); wac.getServletContext();
wmc.setReturnValue(sc, 3); expectLastCall().andReturn(sc).times(3);
wmc.replay(); replay(wac);
HttpServletRequest request = new MockHttpServletRequest(); HttpServletRequest request = new MockHttpServletRequest();
final HttpServletResponse expectedResponse = new MockHttpServletResponse(); final HttpServletResponse expectedResponse = new MockHttpServletResponse();
@ -209,16 +214,16 @@ public class VelocityViewTests {
assertTrue(template == expectedTemplate); assertTrue(template == expectedTemplate);
assertTrue(response == expectedResponse); assertTrue(response == expectedResponse);
} }
protected void exposeHelpers(Map model, HttpServletRequest request) throws Exception { protected void exposeHelpers(Map<String, Object> model, HttpServletRequest request) throws Exception {
model.put("myHelper", "myValue"); model.put("myHelper", "myValue");
} }
}; };
vv.setUrl(templateName); vv.setUrl(templateName);
vv.setApplicationContext(wac); vv.setApplicationContext(wac);
vv.render(new HashMap(), request, expectedResponse); vv.render(new HashMap<String, Object>(), request, expectedResponse);
wmc.verify(); verify(wac);
assertEquals("myContentType", expectedResponse.getContentType()); assertEquals("myContentType", expectedResponse.getContentType());
} }
@ -226,12 +231,12 @@ public class VelocityViewTests {
public void testExposeHelpers() throws Exception { public void testExposeHelpers() throws Exception {
final String templateName = "test.vm"; final String templateName = "test.vm";
MockControl wmc = MockControl.createControl(WebApplicationContext.class); WebApplicationContext wac = createMock(WebApplicationContext.class);
WebApplicationContext wac = (WebApplicationContext) wmc.getMock();
wac.getParentBeanFactory(); wac.getParentBeanFactory();
wmc.setReturnValue(null); expectLastCall().andReturn(null);
wac.getServletContext(); wac.getServletContext();
wmc.setReturnValue(new MockServletContext()); expectLastCall().andReturn(new MockServletContext());
final Template expectedTemplate = new Template(); final Template expectedTemplate = new Template();
VelocityConfig vc = new VelocityConfig() { VelocityConfig vc = new VelocityConfig() {
public VelocityEngine getVelocityEngine() { public VelocityEngine getVelocityEngine() {
@ -239,19 +244,21 @@ public class VelocityViewTests {
} }
}; };
wac.getBeansOfType(VelocityConfig.class, true, false); wac.getBeansOfType(VelocityConfig.class, true, false);
Map configurers = new HashMap(); Map<String, Object> configurers = new HashMap<String, Object>();
configurers.put("velocityConfigurer", vc); configurers.put("velocityConfigurer", vc);
wmc.setReturnValue(configurers); expectLastCall().andReturn(configurers);
wmc.replay(); replay(wac);
// let it ask for locale // let it ask for locale
MockControl reqControl = MockControl.createControl(HttpServletRequest.class); HttpServletRequest req = createMock(HttpServletRequest.class);
HttpServletRequest req = (HttpServletRequest) reqControl.getMock(); req.getAttribute(View.PATH_VARIABLES);
expectLastCall().andReturn(null);
req.getAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE); req.getAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE);
reqControl.setReturnValue(new AcceptHeaderLocaleResolver()); expectLastCall().andReturn(new AcceptHeaderLocaleResolver());
req.getLocale(); req.getLocale();
reqControl.setReturnValue(Locale.CANADA); expectLastCall().andReturn(Locale.CANADA);
reqControl.replay(); replay(req);
final HttpServletResponse expectedResponse = new MockHttpServletResponse(); final HttpServletResponse expectedResponse = new MockHttpServletResponse();
@ -272,7 +279,7 @@ public class VelocityViewTests {
assertTrue(numberTool.getLocale().equals(Locale.CANADA)); assertTrue(numberTool.getLocale().equals(Locale.CANADA));
} }
protected void exposeHelpers(Map model, HttpServletRequest request) throws Exception { protected void exposeHelpers(Map<String, Object> model, HttpServletRequest request) throws Exception {
model.put("myHelper", "myValue"); model.put("myHelper", "myValue");
} }
}; };
@ -286,10 +293,10 @@ public class VelocityViewTests {
vv.setNumberToolAttribute("numberTool"); vv.setNumberToolAttribute("numberTool");
vv.setExposeSpringMacroHelpers(false); vv.setExposeSpringMacroHelpers(false);
vv.render(new HashMap(), req, expectedResponse); vv.render(new HashMap<String, Object>(), req, expectedResponse);
wmc.verify(); verify(wac);
reqControl.verify(); verify(req);
assertEquals(AbstractView.DEFAULT_CONTENT_TYPE, expectedResponse.getContentType()); assertEquals(AbstractView.DEFAULT_CONTENT_TYPE, expectedResponse.getContentType());
} }

View File

@ -50,12 +50,22 @@ public class MarshallingViewTests {
assertEquals("Invalid content type", "application/xml", view.getContentType()); assertEquals("Invalid content type", "application/xml", view.getContentType());
} }
@Test
public void isExposePathVars() {
assertEquals("Must not expose path variables", false, view.isExposePathVariables());
}
@Test
public void isExposePathVarsDefaultConstructor() {
assertEquals("Must not expose path variables", false, new MarshallingView().isExposePathVariables());
}
@Test @Test
public void renderModelKey() throws Exception { public void renderModelKey() throws Exception {
Object toBeMarshalled = new Object(); Object toBeMarshalled = new Object();
String modelKey = "key"; String modelKey = "key";
view.setModelKey(modelKey); view.setModelKey(modelKey);
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put(modelKey, toBeMarshalled); model.put(modelKey, toBeMarshalled);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
@ -76,7 +86,7 @@ public class MarshallingViewTests {
Object toBeMarshalled = new Object(); Object toBeMarshalled = new Object();
String modelKey = "key"; String modelKey = "key";
view.setModelKey("invalidKey"); view.setModelKey("invalidKey");
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put(modelKey, toBeMarshalled); model.put(modelKey, toBeMarshalled);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
@ -97,7 +107,7 @@ public class MarshallingViewTests {
@Test @Test
public void renderNullModelValue() throws Exception { public void renderNullModelValue() throws Exception {
String modelKey = "key"; String modelKey = "key";
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put(modelKey, null); model.put(modelKey, null);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
@ -120,7 +130,7 @@ public class MarshallingViewTests {
Object toBeMarshalled = new Object(); Object toBeMarshalled = new Object();
String modelKey = "key"; String modelKey = "key";
view.setModelKey(modelKey); view.setModelKey(modelKey);
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put(modelKey, toBeMarshalled); model.put(modelKey, toBeMarshalled);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
@ -143,7 +153,7 @@ public class MarshallingViewTests {
public void renderNoModelKey() throws Exception { public void renderNoModelKey() throws Exception {
Object toBeMarshalled = new Object(); Object toBeMarshalled = new Object();
String modelKey = "key"; String modelKey = "key";
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put(modelKey, toBeMarshalled); model.put(modelKey, toBeMarshalled);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
@ -163,7 +173,7 @@ public class MarshallingViewTests {
public void testRenderUnsupportedModel() throws Exception { public void testRenderUnsupportedModel() throws Exception {
Object toBeMarshalled = new Object(); Object toBeMarshalled = new Object();
String modelKey = "key"; String modelKey = "key";
Map model = new HashMap(); Map<String, Object> model = new HashMap<String, Object>();
model.put(modelKey, toBeMarshalled); model.put(modelKey, toBeMarshalled);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();