diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java
index b7dec53b2..c75ff3d54 100644
--- a/core/src/main/java/org/apache/struts2/StrutsConstants.java
+++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java
@@ -379,7 +379,7 @@ public final class StrutsConstants {
public static final String STRUTS_CONVERTER_FILE_PROCESSOR = "struts.converter.file.processor";
public static final String STRUTS_CONVERTER_ANNOTATION_PROCESSOR = "struts.converter.annotation.processor";
public static final String STRUTS_CONVERTER_CREATOR = "struts.converter.creator";
- public static final String STRUTS_CONVERTER_HOLDER = "struts..converter.holder";
+ public static final String STRUTS_CONVERTER_HOLDER = "struts.converter.holder";
public static final String STRUTS_EXPRESSION_PARSER = "struts.expression.parser";
@@ -462,4 +462,7 @@ public final class StrutsConstants {
public static final String STRUTS_URL_QUERY_STRING_PARSER = "struts.url.queryStringParser";
public static final String STRUTS_URL_ENCODER = "struts.url.encoder";
public static final String STRUTS_URL_DECODER = "struts.url.decoder";
+
+ /** A global flag to set property {@link org.apache.struts2.components.Checkbox#setSubmitUnchecked(String)} */
+ public static final String STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED = "struts.ui.checkbox.submitUnchecked";
}
diff --git a/core/src/main/java/org/apache/struts2/components/Checkbox.java b/core/src/main/java/org/apache/struts2/components/Checkbox.java
index 81ea73fa7..49e054eb1 100644
--- a/core/src/main/java/org/apache/struts2/components/Checkbox.java
+++ b/core/src/main/java/org/apache/struts2/components/Checkbox.java
@@ -18,13 +18,14 @@
*/
package org.apache.struts2.components;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.ValueStack;
+import org.apache.struts2.StrutsConstants;
import org.apache.struts2.views.annotations.StrutsTag;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
-import com.opensymphony.xwork2.util.ValueStack;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
/**
*
@@ -46,15 +47,19 @@ import com.opensymphony.xwork2.util.ValueStack;
*
*
*
- *
*/
@StrutsTag(
- name="checkbox",
- tldTagClass="org.apache.struts2.views.jsp.ui.CheckboxTag",
- description="Render a checkbox input field",
- allowDynamicAttributes=true)
+ name = "checkbox",
+ tldTagClass = "org.apache.struts2.views.jsp.ui.CheckboxTag",
+ description = "Render a checkbox input field",
+ allowDynamicAttributes = true)
public class Checkbox extends UIBean {
- final public static String TEMPLATE = "checkbox";
+
+ private static final String ATTR_SUBMIT_UNCHECKED = "submitUnchecked";
+
+ public static final String TEMPLATE = "checkbox";
+
+ private String submitUncheckedGlobal;
protected String fieldValue;
protected String submitUnchecked;
@@ -69,35 +74,45 @@ public class Checkbox extends UIBean {
protected void evaluateExtraParams() {
if (fieldValue != null) {
- addParameter("fieldValue", findString(fieldValue));
+ addParameter(ATTR_FIELD_VALUE, findString(fieldValue));
} else {
- addParameter("fieldValue", "true");
+ addParameter(ATTR_FIELD_VALUE, "true");
}
if (submitUnchecked != null) {
Object parsedValue = findValue(submitUnchecked, Boolean.class);
- addParameter("submitUnchecked", parsedValue == null ? Boolean.valueOf(submitUnchecked) : parsedValue);
+ addParameter(ATTR_SUBMIT_UNCHECKED, parsedValue == null ? Boolean.valueOf(submitUnchecked) : parsedValue);
+ } else if (submitUncheckedGlobal != null) {
+ addParameter(ATTR_SUBMIT_UNCHECKED, Boolean.parseBoolean(submitUncheckedGlobal));
} else {
- addParameter("submitUnchecked", false);
+ addParameter(ATTR_SUBMIT_UNCHECKED, false);
}
}
- protected Class getValueClassType() {
+ @Override
+ protected Class> getValueClassType() {
return Boolean.class; // for checkboxes, everything needs to end up as a Boolean
}
- @StrutsTagAttribute(description="The actual HTML value attribute of the checkbox.", defaultValue="true")
+ @Inject(value = StrutsConstants.STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED, required = false)
+ public void setSubmitUncheckedGlobal(String submitUncheckedGlobal) {
+ this.submitUncheckedGlobal = submitUncheckedGlobal;
+ }
+
+ @StrutsTagAttribute(description = "The actual HTML value attribute of the checkbox.", defaultValue = "true")
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
- @StrutsTagAttribute(description="If set to true, unchecked elements will be submitted with the form.", type="Boolean", defaultValue="false")
+ @StrutsTagAttribute(description = "If set to true, unchecked elements will be submitted with the form. " +
+ "Since Struts 6.1.1 you can use a constant \"" + StrutsConstants.STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED + "\" to set this attribute globally",
+ type = "Boolean", defaultValue = "false")
public void setSubmitUnchecked(String submitUnchecked) {
this.submitUnchecked = submitUnchecked;
}
@Override
- @StrutsTagAttribute(description="Define label position of form element (top/left), also 'right' is supported when using 'xhtml' theme")
+ @StrutsTagAttribute(description = "Define label position of form element (top/left), also 'right' is supported when using 'xhtml' theme")
public void setLabelPosition(String labelPosition) {
super.setLabelPosition(labelPosition);
}
diff --git a/core/src/main/java/org/apache/struts2/components/UIBean.java b/core/src/main/java/org/apache/struts2/components/UIBean.java
index dc7213f36..c28e54c66 100644
--- a/core/src/main/java/org/apache/struts2/components/UIBean.java
+++ b/core/src/main/java/org/apache/struts2/components/UIBean.java
@@ -435,8 +435,11 @@ import java.util.Map;
*
*/
public abstract class UIBean extends Component {
+
private static final Logger LOG = LogManager.getLogger(UIBean.class);
+ protected static final String ATTR_FIELD_VALUE = "fieldValue";
+
protected HttpServletRequest request;
protected HttpServletResponse response;
diff --git a/core/src/main/resources/template/simple/checkbox.ftl b/core/src/main/resources/template/simple/checkbox.ftl
index a344e6d30..af563f4b5 100644
--- a/core/src/main/resources/template/simple/checkbox.ftl
+++ b/core/src/main/resources/template/simple/checkbox.ftl
@@ -38,11 +38,11 @@
<#include "/${parameters.templateDir}/${parameters.expandTheme}/scripting-events.ftl" />
<#include "/${parameters.templateDir}/${parameters.expandTheme}/common-attributes.ftl" />
<#include "/${parameters.templateDir}/${parameters.expandTheme}/dynamic-attributes.ftl" />
-/>
+/><#rt/>
<#if parameters.submitUnchecked!false>
<#if parameters.disabled!false>
disabled="disabled"<#rt/>
#if>
- />
-#if><#rt/>
+ /><#rt/>
+#if>
diff --git a/core/src/site/resources/tags/checkbox-attributes.html b/core/src/site/resources/tags/checkbox-attributes.html
index de448af92..ffc6ab1f8 100644
--- a/core/src/site/resources/tags/checkbox-attributes.html
+++ b/core/src/site/resources/tags/checkbox-attributes.html
@@ -283,7 +283,7 @@
false
false
Boolean
-
If set to true, unchecked elements will be submitted with the form.
+
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
tabindex
diff --git a/core/src/test/java/org/apache/struts2/views/jsp/ui/CheckboxTest.java b/core/src/test/java/org/apache/struts2/views/jsp/ui/CheckboxTest.java
index 5f35b8acd..137b3db21 100644
--- a/core/src/test/java/org/apache/struts2/views/jsp/ui/CheckboxTest.java
+++ b/core/src/test/java/org/apache/struts2/views/jsp/ui/CheckboxTest.java
@@ -18,11 +18,21 @@
*/
package org.apache.struts2.views.jsp.ui;
-import java.util.Map;
-
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.inject.ContainerBuilder;
+import com.opensymphony.xwork2.test.StubConfigurationProvider;
+import com.opensymphony.xwork2.util.ValueStack;
+import com.opensymphony.xwork2.util.location.LocatableProperties;
+import org.apache.struts2.ServletActionContext;
+import org.apache.struts2.StrutsConstants;
import org.apache.struts2.TestAction;
import org.apache.struts2.views.jsp.AbstractUITagTest;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Map;
+
public class CheckboxTest extends AbstractUITagTest {
/**
@@ -31,7 +41,7 @@ public class CheckboxTest extends AbstractUITagTest {
* String, String[])} as properties to verify. This implementation extends testdata from AbstractUITag.
*
* @return A Map of PropertyHolders values bound to {@link org.apache.struts2.views.jsp.AbstractUITagTest.PropertyHolder#getName()}
- * as key.
+ * as key.
*/
@Override
protected Map initializedGenericTagTestProperties() {
@@ -73,7 +83,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testChecked_clearTagStateSet() throws Exception {
@@ -102,7 +112,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCheckedWithTopLabelPosition() throws Exception {
@@ -129,10 +139,10 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
- public void testCheckedWithTopLabelPosition_clearTagStateSet() throws Exception {
+ public void testCheckedWithTopLabelPosition_clearTagStateSet() throws Exception {
TestAction testAction = (TestAction) action;
testAction.setFoo("true");
@@ -159,7 +169,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCheckedWithLeftLabelPosition() throws Exception {
@@ -186,7 +196,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCheckedWithLeftLabelPosition_clearTagStateSet() throws Exception {
@@ -216,7 +226,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCheckedWithError() throws Exception {
@@ -245,7 +255,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCheckedWithError_clearTagStateSet() throws Exception {
@@ -277,7 +287,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCheckedWithErrorStyle() throws Exception {
@@ -306,7 +316,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testCheckedWithErrorStyle_clearTagStateSet() throws Exception {
@@ -338,7 +348,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testUnchecked() throws Exception {
@@ -362,7 +372,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testUnchecked_clearTagStateSet() throws Exception {
@@ -389,7 +399,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testDisabled() throws Exception {
@@ -414,7 +424,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertFalse("Tag state after doEndTag() under default tag clear state is equal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testDisabled_clearTagStateSet() throws Exception {
@@ -442,7 +452,7 @@ public class CheckboxTest extends AbstractUITagTest {
freshTag.setPageContext(pageContext);
assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " +
"May indicate that clearTagStateForTagPoolingServers() calls are not working properly.",
- strutsBodyTagsAreReflectionEqual(tag, freshTag));
+ strutsBodyTagsAreReflectionEqual(tag, freshTag));
}
public void testSubmitUncheckedAsFalse() throws Exception {
@@ -487,4 +497,29 @@ public class CheckboxTest extends AbstractUITagTest {
verify(CheckboxTag.class.getResource("Checkbox-8.txt"));
}
+ public void testSubmitUncheckedGlobalAsTrue() throws Exception {
+ initDispatcherWithConfigs("struts-default.xml, struts-checkbox-submit-unchecked.xml");
+ String submitUnchecked = container.getInstance(String.class, StrutsConstants.STRUTS_UI_CHECKBOX_SUBMIT_UNCHECKED);
+ assertEquals("true", submitUnchecked);
+
+ createMocks();
+
+ TestAction testAction = (TestAction) action;
+ testAction.setFoo("true");
+
+ CheckboxTag tag = new CheckboxTag();
+ tag.setPageContext(pageContext);
+ tag.setLabel("mylabel");
+ tag.setName("foo");
+ tag.setFieldValue("baz");
+ // tag.setSubmitUnchecked("true"); - value should be injected by container
+ tag.setTitle("mytitle");
+ tag.setDisabled("true");
+
+ tag.doStartTag();
+ tag.doEndTag();
+
+ verify(CheckboxTag.class.getResource("Checkbox-8.txt"));
+ }
+
}
diff --git a/core/src/test/resources/struts-checkbox-submit-unchecked.xml b/core/src/test/resources/struts-checkbox-submit-unchecked.xml
new file mode 100644
index 000000000..d94dde62f
--- /dev/null
+++ b/core/src/test/resources/struts-checkbox-submit-unchecked.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+