Skip to content

Commit 1b53882

Browse files
Rob Winchrstoyanchev
authored andcommitted
Generate bracketless tag id in Velocity forms
Before this change if Velocity Spring form macro was bound to a path which contains square brackets, those brackets would also appear in id of generated tag, making the id invalid. As of this fix all Velocity Spring form macros generate tag with id that does not contain square brackets. Issue: SPR-5172
1 parent 73267d7 commit 1b53882

File tree

3 files changed

+101
-9
lines changed

3 files changed

+101
-9
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/view/velocity/spring.vm

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
*#
113113
#macro( springFormInput $path $attributes )
114114
#springBind($path)
115-
<input type="text" id="${status.expression}" name="${status.expression}" value="$!status.value" ${attributes}#springCloseTag()
115+
<input type="text" id="#xmlId(${status.expression})" name="${status.expression}" value="$!status.value" ${attributes}#springCloseTag()
116116
#end
117117

118118
#**
@@ -129,7 +129,7 @@
129129
*#
130130
#macro( springFormPasswordInput $path $attributes )
131131
#springBind($path)
132-
<input type="password" id="${status.expression}" name="${status.expression}" value="" ${attributes}#springCloseTag()
132+
<input type="password" id="#xmlId(${status.expression})" name="${status.expression}" value="" ${attributes}#springCloseTag()
133133
#end
134134

135135
#**
@@ -145,7 +145,7 @@
145145
*#
146146
#macro( springFormHiddenInput $path $attributes )
147147
#springBind($path)
148-
<input type="hidden" id="${status.expression}" name="${status.expression}" value="$!status.value" ${attributes}#springCloseTag()
148+
<input type="hidden" id="#xmlId(${status.expression})" name="${status.expression}" value="$!status.value" ${attributes}#springCloseTag()
149149
#end
150150

151151
#**
@@ -161,7 +161,7 @@
161161
*#
162162
#macro( springFormTextarea $path $attributes )
163163
#springBind($path)
164-
<textarea id="${status.expression}" name="${status.expression}" ${attributes}>$!status.value</textarea>
164+
<textarea id="#xmlId(${status.expression})" name="${status.expression}" ${attributes}>$!status.value</textarea>
165165
#end
166166

167167
#**
@@ -182,7 +182,7 @@
182182
*#
183183
#macro( springFormSingleSelect $path $options $attributes )
184184
#springBind($path)
185-
<select id="${status.expression}" name="${status.expression}" ${attributes}>
185+
<select id="#xmlId(${status.expression})" name="${status.expression}" ${attributes}>
186186
#foreach($option in $options.keySet())
187187
<option value="${option}"
188188
#if ("$!status.value" == "$option") selected="selected" #end>
@@ -204,7 +204,7 @@
204204
*#
205205
#macro( springFormMultiSelect $path $options $attributes )
206206
#springBind($path)
207-
<select multiple="multiple" id="${status.expression}" name="${status.expression}" ${attributes}>
207+
<select multiple="multiple" id="#xmlId(${status.expression})" name="${status.expression}" ${attributes}>
208208
#foreach($option in $options.keySet())
209209
<option value="${option}"
210210
#foreach($item in $status.actualValue)
@@ -274,8 +274,8 @@
274274
*#
275275
#macro( springFormCheckbox $path $attributes )
276276
#springBind($path)
277-
<input type="hidden" name="_${status.expression}" value="on"/>
278-
<input type="checkbox" id="${status.expression}" name="${status.expression}"#if ("$!{status.value}"=="true") checked="checked"#end ${attributes}/>
277+
<input type="hidden" name="_#xmlId(${status.expression})" value="on"/>
278+
<input type="checkbox" id="#xmlId(${status.expression})" name="${status.expression}"#if ("$!{status.value}"=="true") checked="checked"#end ${attributes}/>
279279
#end
280280

281281
#**
@@ -316,7 +316,7 @@
316316
*#
317317
#macro( springCloseTag )#if ($springXhtmlCompliant)/>#else>#end #end
318318

319-
319+
#macro( xmlId $id)#if($id)$id.replaceAll("\[","").replaceAll("\]","")#else$id#end#end
320320

321321

322322

spring-webmvc/src/test/java/org/springframework/web/servlet/view/velocity/VelocityMacroTests.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,66 @@ public void testAllMacros() throws Exception {
190190
}
191191
}
192192

193+
// SPR-5172
194+
public void testIdContainsBraces() throws Exception {
195+
DummyMacroRequestContext rc = new DummyMacroRequestContext(request);
196+
Map<String, String> msgMap = new HashMap<String, String>();
197+
msgMap.put("hello", "Howdy");
198+
msgMap.put("world", "Mundo");
199+
rc.setMessageMap(msgMap);
200+
Map<String, String> themeMsgMap = new HashMap<String, String>();
201+
themeMsgMap.put("hello", "Howdy!");
202+
themeMsgMap.put("world", "Mundo!");
203+
rc.setThemeMessageMap(themeMsgMap);
204+
rc.setContextPath("/springtest");
205+
206+
TestBean darren = new TestBean("Darren", 99);
207+
TestBean fred = new TestBean("Fred");
208+
fred.setJedi(true);
209+
darren.setSpouse(fred);
210+
darren.setJedi(true);
211+
darren.setStringArray(new String[] {"John", "Fred"});
212+
request.setAttribute("command", darren);
213+
214+
Map<String, String> names = new HashMap<String, String>();
215+
names.put("Darren", "Darren Davison");
216+
names.put("John", "John Doe");
217+
names.put("Fred", "Fred Bloggs");
218+
219+
VelocityConfigurer vc = new VelocityConfigurer();
220+
vc.setPreferFileSystemAccess(false);
221+
VelocityEngine ve = vc.createVelocityEngine();
222+
223+
Map<String, Object> model = new HashMap<String, Object>();
224+
model.put("command", darren);
225+
model.put("springMacroRequestContext", rc);
226+
model.put("nameOptionMap", names);
227+
228+
VelocityView view = new VelocityView();
229+
view.setBeanName("myView");
230+
view.setUrl("org/springframework/web/servlet/view/velocity/test-spr5172.vm");
231+
view.setEncoding("UTF-8");
232+
view.setExposeSpringMacroHelpers(false);
233+
view.setVelocityEngine(ve);
234+
235+
view.render(model, request, response);
236+
237+
// tokenize output and ignore whitespace
238+
String output = response.getContentAsString();
239+
String[] tokens = StringUtils.tokenizeToStringArray(output, "\t\n");
240+
241+
for (int i = 0; i < tokens.length; i++) {
242+
if (tokens[i].equals("FORM1")) assertEquals("<input type=\"text\" id=\"spouses0.name\" name=\"spouses[0].name\" value=\"Fred\" >", tokens[i + 1]); //
243+
if (tokens[i].equals("FORM2")) assertEquals("<textarea id=\"spouses0.name\" name=\"spouses[0].name\" >Fred</textarea>", tokens[i + 1]);
244+
if (tokens[i].equals("FORM3")) assertEquals("<select id=\"spouses0.name\" name=\"spouses[0].name\" >", tokens[i + 1]);
245+
if (tokens[i].equals("FORM4")) assertEquals("<select multiple=\"multiple\" id=\"spouses\" name=\"spouses\" >", tokens[i + 1]);
246+
if (tokens[i].equals("FORM5")) assertEquals("<input type=\"radio\" name=\"spouses[0].name\" value=\"Darren\"", tokens[i + 1]);
247+
if (tokens[i].equals("FORM6")) assertEquals("<input type=\"password\" id=\"spouses0.name\" name=\"spouses[0].name\" value=\"\" >", tokens[i + 1]);
248+
if (tokens[i].equals("FORM7")) assertEquals("<input type=\"hidden\" id=\"spouses0.name\" name=\"spouses[0].name\" value=\"Fred\" >", tokens[i + 1]);
249+
if (tokens[i].equals("FORM8")) assertEquals("<input type=\"hidden\" name=\"_spouses0.name\" value=\"on\"/>", tokens[i + 1]);
250+
if (tokens[i].equals("FORM8")) assertEquals("<input type=\"checkbox\" id=\"spouses0.name\" name=\"spouses[0].name\" />", tokens[i + 2]);
251+
if (tokens[i].equals("FORM9")) assertEquals("<input type=\"hidden\" name=\"_spouses0.jedi\" value=\"on\"/>", tokens[i + 1]);
252+
if (tokens[i].equals("FORM9")) assertEquals("<input type=\"checkbox\" id=\"spouses0.jedi\" name=\"spouses[0].jedi\" checked=\"checked\" />", tokens[i + 2]);
253+
}
254+
}
193255
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
##
2+
## test template for Velocity macro test class
3+
##
4+
5+
FORM1
6+
#springFormInput("command.spouses[0].name" "")
7+
8+
FORM2
9+
#springFormTextarea("command.spouses[0].name" "")
10+
11+
FORM3
12+
#springFormSingleSelect("command.spouses[0].name" $nameOptionMap "")
13+
14+
FORM4
15+
#springFormMultiSelect("command.spouses" $nameOptionMap "")
16+
17+
FORM5
18+
#springFormRadioButtons("command.spouses[0].name" $nameOptionMap " " "")
19+
20+
FORM6
21+
#springFormPasswordInput("command.spouses[0].name" "")
22+
23+
FORM7
24+
#springFormHiddenInput("command.spouses[0].name" "")
25+
26+
FORM8
27+
#springFormCheckbox("command.spouses[0].name" "")
28+
29+
FORM9
30+
#springFormCheckbox("command.spouses[0].jedi" "")

0 commit comments

Comments
 (0)