Consistent iteration over actualValue in Velocity and FreeMarker macros
This requires consistent exposure of an actualValue in BindStatus, even if no BindingResult available.
Issue: SPR-10837
(cherry picked from commit 4f60b98)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -61,13 +61,13 @@ public class BindStatus {
|
||||
|
||||
private Object value;
|
||||
|
||||
private Class valueType;
|
||||
private Class<?> valueType;
|
||||
|
||||
private Object actualValue;
|
||||
|
||||
private PropertyEditor editor;
|
||||
|
||||
private List objectErrors;
|
||||
private List<? extends ObjectError> objectErrors;
|
||||
|
||||
private String[] errorCodes;
|
||||
|
||||
@@ -90,7 +90,7 @@ public class BindStatus {
|
||||
this.htmlEscape = htmlEscape;
|
||||
|
||||
// determine name of the object and property
|
||||
String beanName = null;
|
||||
String beanName;
|
||||
int dotPos = path.indexOf('.');
|
||||
if (dotPos == -1) {
|
||||
// property not set, only the object itself
|
||||
@@ -124,6 +124,9 @@ public class BindStatus {
|
||||
this.actualValue = this.bindingResult.getRawFieldValue(this.expression);
|
||||
this.editor = this.bindingResult.findEditor(this.expression, null);
|
||||
}
|
||||
else {
|
||||
this.actualValue = this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -143,8 +146,9 @@ public class BindStatus {
|
||||
}
|
||||
if (this.expression != null && !"*".equals(this.expression) && !this.expression.endsWith("*")) {
|
||||
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(target);
|
||||
this.valueType = bw.getPropertyType(this.expression);
|
||||
this.value = bw.getPropertyValue(this.expression);
|
||||
this.valueType = bw.getPropertyType(this.expression);
|
||||
this.actualValue = this.value;
|
||||
}
|
||||
this.errorCodes = new String[0];
|
||||
this.errorMessages = new String[0];
|
||||
@@ -161,7 +165,7 @@ public class BindStatus {
|
||||
private void initErrorCodes() {
|
||||
this.errorCodes = new String[this.objectErrors.size()];
|
||||
for (int i = 0; i < this.objectErrors.size(); i++) {
|
||||
ObjectError error = (ObjectError) this.objectErrors.get(i);
|
||||
ObjectError error = this.objectErrors.get(i);
|
||||
this.errorCodes[i] = error.getCode();
|
||||
}
|
||||
}
|
||||
@@ -173,7 +177,7 @@ public class BindStatus {
|
||||
if (this.errorMessages == null) {
|
||||
this.errorMessages = new String[this.objectErrors.size()];
|
||||
for (int i = 0; i < this.objectErrors.size(); i++) {
|
||||
ObjectError error = (ObjectError) this.objectErrors.get(i);
|
||||
ObjectError error = this.objectErrors.get(i);
|
||||
this.errorMessages[i] = this.requestContext.getMessage(error, this.htmlEscape);
|
||||
}
|
||||
}
|
||||
@@ -214,7 +218,7 @@ public class BindStatus {
|
||||
* '{@code getValue().getClass()}' since '{@code getValue()}' may
|
||||
* return '{@code null}'.
|
||||
*/
|
||||
public Class getValueType() {
|
||||
public Class<?> getValueType() {
|
||||
return this.valueType;
|
||||
}
|
||||
|
||||
@@ -318,7 +322,7 @@ public class BindStatus {
|
||||
* @param valueClass the value class that an editor is needed for
|
||||
* @return the associated PropertyEditor, or {@code null} if none
|
||||
*/
|
||||
public PropertyEditor findEditor(Class valueClass) {
|
||||
public PropertyEditor findEditor(Class<?> valueClass) {
|
||||
return (this.bindingResult != null ? this.bindingResult.findEditor(this.expression, valueClass) : null);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
*
|
||||
* @param path the name of the field to bind to
|
||||
* @param attributes any additional attributes for the element (such as class
|
||||
* or CSS styles or size
|
||||
* or CSS styles or size)
|
||||
*
|
||||
*#
|
||||
#macro( springFormInput $path $attributes )
|
||||
@@ -124,7 +124,7 @@
|
||||
*
|
||||
* @param path the name of the field to bind to
|
||||
* @param attributes any additional attributes for the element (such as class
|
||||
* or CSS styles or size
|
||||
* or CSS styles or size)
|
||||
*
|
||||
*#
|
||||
#macro( springFormPasswordInput $path $attributes )
|
||||
@@ -140,7 +140,7 @@
|
||||
*
|
||||
* @param path the name of the field to bind to
|
||||
* @param attributes any additional attributes for the element (such as class
|
||||
* or CSS styles or size
|
||||
* or CSS styles or size)
|
||||
*
|
||||
*#
|
||||
#macro( springFormHiddenInput $path $attributes )
|
||||
@@ -156,7 +156,7 @@
|
||||
*
|
||||
* @param path the name of the field to bind to
|
||||
* @param attributes any additional attributes for the element (such as class
|
||||
* or CSS styles or size
|
||||
* or CSS styles or size)
|
||||
*
|
||||
*#
|
||||
#macro( springFormTextarea $path $attributes )
|
||||
@@ -178,16 +178,14 @@
|
||||
* @param path the name of the field to bind to
|
||||
* @param options a map (value=label) of all the available options
|
||||
* @param attributes any additional attributes for the element (such as class
|
||||
* or CSS styles or size
|
||||
* or CSS styles or size)
|
||||
*#
|
||||
#macro( springFormSingleSelect $path $options $attributes )
|
||||
#springBind($path)
|
||||
<select id="${status.expression}" name="${status.expression}" ${attributes}>
|
||||
#foreach($option in $options.keySet())
|
||||
<option value="${option}"
|
||||
#if("$!status.value" == "$option")
|
||||
selected="selected"
|
||||
#end>
|
||||
#if("$!status.value" == "$option") selected="selected" #end>
|
||||
${options.get($option)}</option>
|
||||
#end
|
||||
</select>
|
||||
@@ -202,17 +200,15 @@
|
||||
* @param path the name of the field to bind to
|
||||
* @param options a map (value=label) of all the available options
|
||||
* @param attributes any additional attributes for the element (such as class
|
||||
* or CSS styles or size
|
||||
* or CSS styles or size)
|
||||
*#
|
||||
#macro( springFormMultiSelect $path $options $attributes )
|
||||
#springBind($path)
|
||||
<select multiple="multiple" id="${status.expression}" name="${status.expression}" ${attributes}>
|
||||
#foreach($option in $options.keySet())
|
||||
<option value="${option}"
|
||||
#foreach($item in $status.value)
|
||||
#if($item == $option)
|
||||
selected="selected"
|
||||
#end
|
||||
#foreach($item in $status.actualValue)
|
||||
#if($item == $option) selected="selected" #end
|
||||
#end
|
||||
>${options.get($option)}</option>
|
||||
#end
|
||||
@@ -229,15 +225,13 @@
|
||||
* @param separator the html tag or other character list that should be used to
|
||||
* separate each option. Typically ' ' or '<br>'
|
||||
* @param attributes any additional attributes for the element (such as class
|
||||
* or CSS styles or size
|
||||
* or CSS styles or size)
|
||||
*#
|
||||
#macro( springFormRadioButtons $path $options $separator $attributes )
|
||||
#springBind($path)
|
||||
#foreach($option in $options.keySet())
|
||||
<input type="radio" name="${status.expression}" value="${option}"
|
||||
#if("$!status.value" == "$option")
|
||||
checked="checked"
|
||||
#end
|
||||
#if("$!status.value" == "$option") checked="checked" #end
|
||||
${attributes}
|
||||
#springCloseTag()
|
||||
${options.get($option)} ${separator}
|
||||
@@ -252,15 +246,15 @@
|
||||
* @param path the name of the field to bind to
|
||||
* @param options a map (value=label) of all the available options
|
||||
* @param separator the html tag or other character list that should be used to
|
||||
* separate each option. Typically ' ' or '<br>'
|
||||
* separate each option. Typically ' ' or '<br>'.
|
||||
* @param attributes any additional attributes for the element (such as class
|
||||
* or CSS styles or size
|
||||
* or CSS styles or size)
|
||||
*#
|
||||
#macro( springFormCheckboxes $path $options $separator $attributes )
|
||||
#springBind($path)
|
||||
#foreach($option in $options.keySet())
|
||||
<input type="checkbox" name="${status.expression}" value="${option}"
|
||||
#foreach($item in $status.value)
|
||||
#foreach($item in $status.actualValue)
|
||||
#if($item == $option) checked="checked" #end
|
||||
#end
|
||||
${attributes} #springCloseTag()
|
||||
@@ -276,7 +270,7 @@
|
||||
*
|
||||
* @param path the name of the field to bind to
|
||||
* @param attributes any additional attributes for the element (such as class
|
||||
* or CSS styles or size
|
||||
* or CSS styles or size)
|
||||
*#
|
||||
#macro( springFormCheckbox $path $attributes )
|
||||
#springBind($path)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,27 +16,26 @@
|
||||
|
||||
package org.springframework.web.servlet.view.freemarker;
|
||||
|
||||
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.FileWriter;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.SimpleHash;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.test.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.test.MockServletContext;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
@@ -47,10 +46,7 @@ import org.springframework.web.servlet.support.RequestContext;
|
||||
import org.springframework.web.servlet.theme.FixedThemeResolver;
|
||||
import org.springframework.web.servlet.view.DummyMacroRequestContext;
|
||||
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.SimpleHash;
|
||||
import freemarker.template.Template;
|
||||
import freemarker.template.TemplateException;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Darren Davison
|
||||
@@ -69,6 +65,7 @@ public class FreeMarkerMacroTests {
|
||||
|
||||
private FreeMarkerConfigurer fc;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
wac = new StaticWebApplicationContext();
|
||||
@@ -219,6 +216,7 @@ public class FreeMarkerMacroTests {
|
||||
}
|
||||
|
||||
// TODO verify remaining output (fix whitespace)
|
||||
|
||||
@Test
|
||||
public void testForm9() throws Exception {
|
||||
assertEquals("<input type=\"password\" id=\"name\" name=\"name\" value=\"\" >", getMacroOutput("FORM9"));
|
||||
@@ -272,8 +270,8 @@ public class FreeMarkerMacroTests {
|
||||
assertTrue("Wrong output: " + output, output.contains("<input type=\"checkbox\" id=\"spouses0.jedi\" name=\"spouses[0].jedi\" checked=\"checked\" />"));
|
||||
}
|
||||
|
||||
private String getMacroOutput(String name) throws Exception {
|
||||
|
||||
private String getMacroOutput(String name) throws Exception {
|
||||
String macro = fetchMacro(name);
|
||||
assertNotNull(macro);
|
||||
|
||||
@@ -296,6 +294,7 @@ public class FreeMarkerMacroTests {
|
||||
fred.setJedi(true);
|
||||
darren.setSpouse(fred);
|
||||
darren.setJedi(true);
|
||||
darren.setStringArray(new String[] {"John", "Fred"});
|
||||
request.setAttribute("command", darren);
|
||||
|
||||
Map<String, String> names = new HashMap<String, String>();
|
||||
|
||||
@@ -61,7 +61,7 @@ FORM7
|
||||
<@spring.formRadioButtons "command.name", nameOptionMap, " ", ""/>
|
||||
|
||||
FORM8
|
||||
<@spring.formCheckboxes "command.spouses", nameOptionMap, " ", ""/>
|
||||
<@spring.formCheckboxes "command.stringArray", nameOptionMap, " ", ""/>
|
||||
|
||||
FORM9
|
||||
<@spring.formPasswordInput "command.name", ""/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.web.servlet.view.velocity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -27,10 +26,10 @@ import org.apache.velocity.Template;
|
||||
import org.apache.velocity.app.VelocityEngine;
|
||||
import org.apache.velocity.context.Context;
|
||||
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.mock.web.test.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.test.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.test.MockServletContext;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.support.StaticWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
@@ -94,7 +93,7 @@ public class VelocityMacroTests extends TestCase {
|
||||
vv.setApplicationContext(wac);
|
||||
vv.setExposeSpringMacroHelpers(true);
|
||||
|
||||
Map model = new HashMap();
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put("tb", new TestBean("juergen", 99));
|
||||
vv.render(model, request, response);
|
||||
}
|
||||
@@ -112,7 +111,7 @@ public class VelocityMacroTests extends TestCase {
|
||||
vv.setApplicationContext(wac);
|
||||
vv.setExposeSpringMacroHelpers(true);
|
||||
|
||||
Map model = new HashMap();
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put(VelocityView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE, helperTool);
|
||||
|
||||
try {
|
||||
@@ -126,11 +125,11 @@ public class VelocityMacroTests extends TestCase {
|
||||
|
||||
public void testAllMacros() throws Exception {
|
||||
DummyMacroRequestContext rc = new DummyMacroRequestContext(request);
|
||||
Map msgMap = new HashMap();
|
||||
Map<String, String> msgMap = new HashMap<String, String>();
|
||||
msgMap.put("hello", "Howdy");
|
||||
msgMap.put("world", "Mundo");
|
||||
rc.setMessageMap(msgMap);
|
||||
Map themeMsgMap = new HashMap();
|
||||
Map<String, String> themeMsgMap = new HashMap<String, String>();
|
||||
themeMsgMap.put("hello", "Howdy!");
|
||||
themeMsgMap.put("world", "Mundo!");
|
||||
rc.setThemeMessageMap(themeMsgMap);
|
||||
@@ -138,9 +137,10 @@ public class VelocityMacroTests extends TestCase {
|
||||
|
||||
TestBean tb = new TestBean("Darren", 99);
|
||||
tb.setJedi(true);
|
||||
tb.setStringArray(new String[] {"John", "Fred"});
|
||||
request.setAttribute("command", tb);
|
||||
|
||||
HashMap names = new HashMap();
|
||||
Map<String, String> names = new HashMap<String, String>();
|
||||
names.put("Darren", "Darren Davison");
|
||||
names.put("John", "John Doe");
|
||||
names.put("Fred", "Fred Bloggs");
|
||||
@@ -149,7 +149,7 @@ public class VelocityMacroTests extends TestCase {
|
||||
vc.setPreferFileSystemAccess(false);
|
||||
VelocityEngine ve = vc.createVelocityEngine();
|
||||
|
||||
Map model = new HashMap();
|
||||
Map<String, Object> model = new HashMap<String, Object>();
|
||||
model.put("command", tb);
|
||||
model.put("springMacroRequestContext", rc);
|
||||
model.put("nameOptionMap", names);
|
||||
|
||||
@@ -45,7 +45,7 @@ FORM7
|
||||
#springFormRadioButtons("command.name" $nameOptionMap " " "")
|
||||
|
||||
FORM8
|
||||
#springFormCheckboxes("command.spouses" $nameOptionMap " " "")
|
||||
#springFormCheckboxes("command.stringArray" $nameOptionMap " " "")
|
||||
|
||||
FORM9
|
||||
#springFormPasswordInput("command.name" "")
|
||||
|
||||
Reference in New Issue
Block a user