Skip to content

Commit 279cef1

Browse files
committed
WW-5260 Introduces a constant to set submitUnchecked attribute of checkbox tag globally
1 parent 1af3e31 commit 279cef1

File tree

6 files changed

+116
-36
lines changed

6 files changed

+116
-36
lines changed

core/src/main/java/org/apache/struts2/StrutsConstants.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ public final class StrutsConstants {
379379
public static final String STRUTS_CONVERTER_FILE_PROCESSOR = "struts.converter.file.processor";
380380
public static final String STRUTS_CONVERTER_ANNOTATION_PROCESSOR = "struts.converter.annotation.processor";
381381
public static final String STRUTS_CONVERTER_CREATOR = "struts.converter.creator";
382-
public static final String STRUTS_CONVERTER_HOLDER = "struts..converter.holder";
382+
public static final String STRUTS_CONVERTER_HOLDER = "struts.converter.holder";
383383

384384
public static final String STRUTS_EXPRESSION_PARSER = "struts.expression.parser";
385385

@@ -462,4 +462,7 @@ public final class StrutsConstants {
462462
public static final String STRUTS_URL_QUERY_STRING_PARSER = "struts.url.queryStringParser";
463463
public static final String STRUTS_URL_ENCODER = "struts.url.encoder";
464464
public static final String STRUTS_URL_DECODER = "struts.url.decoder";
465+
466+
/** A global flag to set property {@link org.apache.struts2.components.Checkbox#setSubmitUnchecked(String)} */
467+
public static final String STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED = "struts.ui.checkbox.submitUnchecked";
465468
}

core/src/main/java/org/apache/struts2/components/Checkbox.java

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@
1818
*/
1919
package org.apache.struts2.components;
2020

21-
import javax.servlet.http.HttpServletRequest;
22-
import javax.servlet.http.HttpServletResponse;
23-
21+
import com.opensymphony.xwork2.inject.Inject;
22+
import com.opensymphony.xwork2.util.ValueStack;
23+
import org.apache.struts2.StrutsConstants;
2424
import org.apache.struts2.views.annotations.StrutsTag;
2525
import org.apache.struts2.views.annotations.StrutsTagAttribute;
2626

27-
import com.opensymphony.xwork2.util.ValueStack;
27+
import javax.servlet.http.HttpServletRequest;
28+
import javax.servlet.http.HttpServletResponse;
2829

2930
/**
3031
* <!-- START SNIPPET: javadoc -->
@@ -46,16 +47,17 @@
4647
*
4748
* <!-- END SNIPPET: example -->
4849
* </pre>
49-
*
5050
*/
5151
@StrutsTag(
52-
name="checkbox",
53-
tldTagClass="org.apache.struts2.views.jsp.ui.CheckboxTag",
54-
description="Render a checkbox input field",
55-
allowDynamicAttributes=true)
52+
name = "checkbox",
53+
tldTagClass = "org.apache.struts2.views.jsp.ui.CheckboxTag",
54+
description = "Render a checkbox input field",
55+
allowDynamicAttributes = true)
5656
public class Checkbox extends UIBean {
5757
final public static String TEMPLATE = "checkbox";
5858

59+
private String submitUncheckedGlobal;
60+
5961
protected String fieldValue;
6062
protected String submitUnchecked;
6163

@@ -77,27 +79,36 @@ protected void evaluateExtraParams() {
7779
if (submitUnchecked != null) {
7880
Object parsedValue = findValue(submitUnchecked, Boolean.class);
7981
addParameter("submitUnchecked", parsedValue == null ? Boolean.valueOf(submitUnchecked) : parsedValue);
82+
} else if (submitUncheckedGlobal != null) {
83+
addParameter("submitUnchecked", Boolean.parseBoolean(submitUncheckedGlobal));
8084
} else {
8185
addParameter("submitUnchecked", false);
8286
}
8387
}
8488

85-
protected Class getValueClassType() {
89+
protected Class<?> getValueClassType() {
8690
return Boolean.class; // for checkboxes, everything needs to end up as a Boolean
8791
}
8892

89-
@StrutsTagAttribute(description="The actual HTML value attribute of the checkbox.", defaultValue="true")
93+
@Inject(value = StrutsConstants.STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED, required = false)
94+
public void setSubmitUncheckedGlobal(String submitUncheckedGlobal) {
95+
this.submitUncheckedGlobal = submitUncheckedGlobal;
96+
}
97+
98+
@StrutsTagAttribute(description = "The actual HTML value attribute of the checkbox.", defaultValue = "true")
9099
public void setFieldValue(String fieldValue) {
91100
this.fieldValue = fieldValue;
92101
}
93102

94-
@StrutsTagAttribute(description="If set to true, unchecked elements will be submitted with the form.", type="Boolean", defaultValue="false")
103+
@StrutsTagAttribute(description = "If set to true, unchecked elements will be submitted with the form. " +
104+
"Since Struts 6.1.1 you can use a constant \"" + StrutsConstants.STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED + "\" to set this attribute globally",
105+
type = "Boolean", defaultValue = "false")
95106
public void setSubmitUnchecked(String submitUnchecked) {
96107
this.submitUnchecked = submitUnchecked;
97108
}
98109

99110
@Override
100-
@StrutsTagAttribute(description="Define label position of form element (top/left), also 'right' is supported when using 'xhtml' theme")
111+
@StrutsTagAttribute(description = "Define label position of form element (top/left), also 'right' is supported when using 'xhtml' theme")
101112
public void setLabelPosition(String labelPosition) {
102113
super.setLabelPosition(labelPosition);
103114
}

core/src/main/resources/template/simple/checkbox.ftl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@
3838
<#include "/${parameters.templateDir}/${parameters.expandTheme}/scripting-events.ftl" />
3939
<#include "/${parameters.templateDir}/${parameters.expandTheme}/common-attributes.ftl" />
4040
<#include "/${parameters.templateDir}/${parameters.expandTheme}/dynamic-attributes.ftl" />
41-
/>
41+
/><#rt/>
4242
<#if parameters.submitUnchecked!false>
4343
<input type="hidden" id="__checkbox_${parameters.id}" name="__checkbox_${parameters.name}" value="${parameters.fieldValue}"<#rt/>
4444
<#if parameters.disabled!false>
4545
disabled="disabled"<#rt/>
4646
</#if>
47-
/>
48-
</#if><#rt/>
47+
/><#rt/>
48+
</#if>

core/src/site/resources/tags/checkbox-attributes.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@
283283
<td class="tag-attribute">false</td>
284284
<td class="tag-attribute">false</td>
285285
<td class="tag-attribute">Boolean</td>
286-
<td class="tag-attribute">If set to true, unchecked elements will be submitted with the form.</td>
286+
<td class="tag-attribute">If set to true, unchecked elements will be submitted with the form. Since Struts 6.1.1 you can use a constant "struts.ui.checkbox.submitUnchecked" to set this property globally</td>
287287
</tr>
288288
<tr>
289289
<td class="tag-attribute">tabindex</td>

core/src/test/java/org/apache/struts2/views/jsp/ui/CheckboxTest.java

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,21 @@
1818
*/
1919
package org.apache.struts2.views.jsp.ui;
2020

21-
import java.util.Map;
22-
21+
import com.opensymphony.xwork2.ActionContext;
22+
import com.opensymphony.xwork2.config.ConfigurationException;
23+
import com.opensymphony.xwork2.config.ConfigurationProvider;
24+
import com.opensymphony.xwork2.inject.ContainerBuilder;
25+
import com.opensymphony.xwork2.test.StubConfigurationProvider;
26+
import com.opensymphony.xwork2.util.ValueStack;
27+
import com.opensymphony.xwork2.util.location.LocatableProperties;
28+
import org.apache.struts2.ServletActionContext;
29+
import org.apache.struts2.StrutsConstants;
2330
import org.apache.struts2.TestAction;
2431
import org.apache.struts2.views.jsp.AbstractUITagTest;
2532

33+
import javax.servlet.http.HttpServletRequest;
34+
import java.util.Map;
35+
2636
public class CheckboxTest extends AbstractUITagTest {
2737

2838
/**
@@ -31,7 +41,7 @@ public class CheckboxTest extends AbstractUITagTest {
3141
* String, String[])} as properties to verify.<br> This implementation extends testdata from AbstractUITag.
3242
*
3343
* @return A Map of PropertyHolders values bound to {@link org.apache.struts2.views.jsp.AbstractUITagTest.PropertyHolder#getName()}
34-
* as key.
44+
* as key.
3545
*/
3646
@Override
3747
protected Map<String, PropertyHolder> initializedGenericTagTestProperties() {
@@ -73,7 +83,7 @@ public void testChecked() throws Exception {
7383
freshTag.setPageContext(pageContext);
7484
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
7585
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
76-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
86+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
7787
}
7888

7989
public void testChecked_clearTagStateSet() throws Exception {
@@ -102,7 +112,7 @@ public void testChecked_clearTagStateSet() throws Exception {
102112
freshTag.setPageContext(pageContext);
103113
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
104114
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
105-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
115+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
106116
}
107117

108118
public void testCheckedWithTopLabelPosition() throws Exception {
@@ -129,10 +139,10 @@ public void testCheckedWithTopLabelPosition() throws Exception {
129139
freshTag.setPageContext(pageContext);
130140
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
131141
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
132-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
142+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
133143
}
134144

135-
public void testCheckedWithTopLabelPosition_clearTagStateSet() throws Exception {
145+
public void testCheckedWithTopLabelPosition_clearTagStateSet() throws Exception {
136146
TestAction testAction = (TestAction) action;
137147
testAction.setFoo("true");
138148

@@ -159,7 +169,7 @@ public void testCheckedWithTopLabelPosition_clearTagStateSet() throws Exception
159169
freshTag.setPageContext(pageContext);
160170
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
161171
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
162-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
172+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
163173
}
164174

165175
public void testCheckedWithLeftLabelPosition() throws Exception {
@@ -186,7 +196,7 @@ public void testCheckedWithLeftLabelPosition() throws Exception {
186196
freshTag.setPageContext(pageContext);
187197
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
188198
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
189-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
199+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
190200
}
191201

192202
public void testCheckedWithLeftLabelPosition_clearTagStateSet() throws Exception {
@@ -216,7 +226,7 @@ public void testCheckedWithLeftLabelPosition_clearTagStateSet() throws Exception
216226
freshTag.setPageContext(pageContext);
217227
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
218228
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
219-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
229+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
220230
}
221231

222232
public void testCheckedWithError() throws Exception {
@@ -245,7 +255,7 @@ public void testCheckedWithError() throws Exception {
245255
freshTag.setPageContext(pageContext);
246256
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
247257
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
248-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
258+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
249259
}
250260

251261
public void testCheckedWithError_clearTagStateSet() throws Exception {
@@ -277,7 +287,7 @@ public void testCheckedWithError_clearTagStateSet() throws Exception {
277287
freshTag.setPageContext(pageContext);
278288
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
279289
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
280-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
290+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
281291
}
282292

283293
public void testCheckedWithErrorStyle() throws Exception {
@@ -306,7 +316,7 @@ public void testCheckedWithErrorStyle() throws Exception {
306316
freshTag.setPageContext(pageContext);
307317
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
308318
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
309-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
319+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
310320
}
311321

312322
public void testCheckedWithErrorStyle_clearTagStateSet() throws Exception {
@@ -338,7 +348,7 @@ public void testCheckedWithErrorStyle_clearTagStateSet() throws Exception {
338348
freshTag.setPageContext(pageContext);
339349
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
340350
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
341-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
351+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
342352
}
343353

344354
public void testUnchecked() throws Exception {
@@ -362,7 +372,7 @@ public void testUnchecked() throws Exception {
362372
freshTag.setPageContext(pageContext);
363373
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
364374
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
365-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
375+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
366376
}
367377

368378
public void testUnchecked_clearTagStateSet() throws Exception {
@@ -389,7 +399,7 @@ public void testUnchecked_clearTagStateSet() throws Exception {
389399
freshTag.setPageContext(pageContext);
390400
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
391401
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
392-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
402+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
393403
}
394404

395405
public void testDisabled() throws Exception {
@@ -414,7 +424,7 @@ public void testDisabled() throws Exception {
414424
freshTag.setPageContext(pageContext);
415425
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
416426
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
417-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
427+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
418428
}
419429

420430
public void testDisabled_clearTagStateSet() throws Exception {
@@ -442,7 +452,7 @@ public void testDisabled_clearTagStateSet() throws Exception {
442452
freshTag.setPageContext(pageContext);
443453
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
444454
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
445-
strutsBodyTagsAreReflectionEqual(tag, freshTag));
455+
strutsBodyTagsAreReflectionEqual(tag, freshTag));
446456
}
447457

448458
public void testSubmitUncheckedAsFalse() throws Exception {
@@ -487,4 +497,29 @@ public void testSubmitUncheckedAsTrue() throws Exception {
487497
verify(CheckboxTag.class.getResource("Checkbox-8.txt"));
488498
}
489499

500+
public void testSubmitUncheckedGlobalAsTrue() throws Exception {
501+
initDispatcherWithConfigs("struts-default.xml, struts-checkbox-submit-unchecked.xml");
502+
String submitUnchecked = container.getInstance(String.class, StrutsConstants.STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED);
503+
assertEquals("true", submitUnchecked);
504+
505+
createMocks();
506+
507+
TestAction testAction = (TestAction) action;
508+
testAction.setFoo("true");
509+
510+
CheckboxTag tag = new CheckboxTag();
511+
tag.setPageContext(pageContext);
512+
tag.setLabel("mylabel");
513+
tag.setName("foo");
514+
tag.setFieldValue("baz");
515+
// tag.setSubmitUnchecked("true"); - value should be injected by container
516+
tag.setTitle("mytitle");
517+
tag.setDisabled("true");
518+
519+
tag.doStartTag();
520+
tag.doEndTag();
521+
522+
verify(CheckboxTag.class.getResource("Checkbox-8.txt"));
523+
}
524+
490525
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
-->
22+
<!DOCTYPE struts PUBLIC
23+
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
24+
"https://struts.apache.org/dtds/struts-6.0.dtd">
25+
<struts>
26+
<constant name="struts.ui.checkbox.submitUnchecked" value="true"/>
27+
28+
<package name="default" extends="struts-default">
29+
</package>
30+
31+
</struts>

0 commit comments

Comments
 (0)