I have a <h:selectManyCheckbox>
that has a required-validation on. If I submit the form, I get a validation error when nothing is selected. So far, this ist expected. However, if I do an ajax update on the checkbox then, I get a ClassCastException
. But only if empty values are treated as null
.
So, I have the following setup. In the web.xml
I set
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
Then I have an xhtml-page like this:
<h:form id="main">
<h:selectManyCheckbox id="value" value="#{testcb.selected}" required="true" requiredMessage="Select at least one entry">
<f:selectItems value="#{testcb.available}"/>
</h:selectManyCheckbox>
<div><h:message for="value" style="color:red;"/></div>
<h:outputLabel for="checkit" value="Enter some text: "/>
<h:inputText id="checkit" value="#{testcb.text}">
<f:ajax event="change" execute="@this" render=":main:value"/>
</h:inputText>
<div><h:commandButton type="submit" value="Submit" action="#{testcb.action}"/></div>
</h:form>
And this backing bean:
@Named("testcb")
@SessionScoped
public class TestCBBean implements Serializable {
private final Set<TestValue> available = EnumSet.allOf(TestValue.class);
private final Set<TestValue> selected = EnumSet.noneOf(TestValue.class);
private String text;
public void action() {}
public Set<TestValue> getAvailable() { return available; }
public void setAvailable(Set<TestValue> available) {
this.available.clear();
this.available.addAll(available);
}
public Set<TestValue> getSelected() { return selected; }
public void setSelected(Set<TestValue> selected) {
this.selected.clear();
this.selected.addAll(selected);
}
public String getText() { return text; }
public void setText(String text) { this.text = text; }
}
And this enum
:
public enum TestValue { ONE, TWO, THREE }
I am running this in Wildfly 26.0.1-Final (JavaEE 8). But this also happens in older versions (like Wildfly 15). What I am doing:
- enter some text and leave the box: an ajax update runs setting the value successfully in the model
- I press submit: the validation error for the empty checkboxes pops up
- I modify the text in the input and leave the box: the ajax update results in the following Exception:
java.lang.ClassCastException: class java.lang.String cannot be cast to class [Ljava.lang.Object; (java.lang.String and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')
[email protected]//com.sun.faces.renderkit.html_basic.MenuRenderer.getSubmittedSelectedValues(MenuRenderer.java:508)
[email protected]//com.sun.faces.renderkit.html_basic.SelectManyCheckboxListRenderer.encodeEnd(SelectManyCheckboxListRenderer.java:89)
[email protected]//javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:600)
[email protected]//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1655)
[email protected]//com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:628)
[email protected]//com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:159)
[email protected]//javax.faces.component.UIComponent.visitTree(UIComponent.java:1457)
[email protected]//javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
[email protected]//javax.faces.component.UIForm.visitTree(UIForm.java:355)
On the ajax update the checkboxes are not submitted. But they seem to contain an empty string as submitted value from the validation step before.
When setting the context parameter to false
this works. But I want to keep it on true
. Any ideas how I could work around this problem?
Reproduced. This is indeed a bug in Mojarra.
It boils down to that the following method in
UIInput
superclass ...... is not overridden in
UISelectMany
superclass in such way that it returnsnew String[0]
instead of""
. This was an oversight during implementing Faces issue 671.I have fixed it in Mojarra issue 5081.
In the meanwhile, until you can upgrade to the Mojarra version containing the fix, you can temporarily work around it by copy pasting the entire source code file of
UISelectMany
into your project while maintaining the package and adding the following method to it: