<h:selectManyCheckbox> 的 ClassCastException,在 INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL 处于活动状态时对 ajax 更新进行验证
ClassCastException for <h:selectManyCheckbox> with validation on ajax update when INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL is active
我有一个 <h:selectManyCheckbox>
需要验证。如果我提交表单,当没有选择任何内容时我会收到验证错误。到目前为止,这是预期的。但是,如果我在复选框上执行 ajax 更新,我会得到 ClassCastException
。但前提是空值被视为 null
.
所以,我有以下设置。在 web.xml
我设置
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
然后我有一个像这样的 xhtml 页面:
<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>
而这个辅助 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; }
}
还有这个enum
:
public enum TestValue { ONE, TWO, THREE }
我在 Wildfly 26.0.1-Final (JavaEE 8) 中 运行 这个。但这也发生在旧版本中(如 Wildfly 15)。我在做什么:
- 输入一些文本并保留该框:ajax 更新运行并在模型中成功设置值
- 我按下提交:弹出空复选框的验证错误
- 我修改输入中的文本并保留框:ajax 更新结果出现以下异常:
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')
com.sun.jsf-impl@2.3.17.SP01//com.sun.faces.renderkit.html_basic.MenuRenderer.getSubmittedSelectedValues(MenuRenderer.java:508)
com.sun.jsf-impl@2.3.17.SP01//com.sun.faces.renderkit.html_basic.SelectManyCheckboxListRenderer.encodeEnd(SelectManyCheckboxListRenderer.java:89)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:600)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1655)
com.sun.jsf-impl@2.3.17.SP01//com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:628)
com.sun.jsf-impl@2.3.17.SP01//com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:159)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIComponent.visitTree(UIComponent.java:1457)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIForm.visitTree(UIForm.java:355)
在 ajax 更新中未提交复选框。但是它们似乎包含一个空字符串作为之前验证步骤的提交值。
将上下文参数设置为 false
时,此方法有效。但我想将其保留在 true
。我有什么想法可以解决这个问题吗?
已转载。这确实是 Mojarra 中的一个错误。
归结为UIInput
超类中的以下方法...
@Override
public Object getSubmittedValue() {
if (submittedValue == null && !isValid() && considerEmptyStringNull(FacesContext.getCurrentInstance())) {
return "";
} else {
return submittedValue;
}
}
... 未 在 UISelectMany
超类中以 returns new String[0]
而不是 ""
的方式被覆盖.这是实施 Faces issue 671.
期间的疏忽
我已经在 Mojarra issue 5081 中修复了它。
与此同时,在升级到包含修复程序的 Mojarra 版本之前,您可以通过将 UISelectMany
的整个 source code 文件复制粘贴到您的项目中,同时维护打包并向其中添加以下方法:
@Override
public Object getSubmittedValue() {
Object submittedValue = super.getSubmittedValue();
return "".equals(submittedValue) ? new String[0] : submittedValue;
}
我有一个 <h:selectManyCheckbox>
需要验证。如果我提交表单,当没有选择任何内容时我会收到验证错误。到目前为止,这是预期的。但是,如果我在复选框上执行 ajax 更新,我会得到 ClassCastException
。但前提是空值被视为 null
.
所以,我有以下设置。在 web.xml
我设置
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
然后我有一个像这样的 xhtml 页面:
<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>
而这个辅助 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; }
}
还有这个enum
:
public enum TestValue { ONE, TWO, THREE }
我在 Wildfly 26.0.1-Final (JavaEE 8) 中 运行 这个。但这也发生在旧版本中(如 Wildfly 15)。我在做什么:
- 输入一些文本并保留该框:ajax 更新运行并在模型中成功设置值
- 我按下提交:弹出空复选框的验证错误
- 我修改输入中的文本并保留框:ajax 更新结果出现以下异常:
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')
com.sun.jsf-impl@2.3.17.SP01//com.sun.faces.renderkit.html_basic.MenuRenderer.getSubmittedSelectedValues(MenuRenderer.java:508)
com.sun.jsf-impl@2.3.17.SP01//com.sun.faces.renderkit.html_basic.SelectManyCheckboxListRenderer.encodeEnd(SelectManyCheckboxListRenderer.java:89)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:600)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1655)
com.sun.jsf-impl@2.3.17.SP01//com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:628)
com.sun.jsf-impl@2.3.17.SP01//com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:159)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIComponent.visitTree(UIComponent.java:1457)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIComponent.visitTree(UIComponent.java:1469)
javax.faces.api@3.1.0.SP01//javax.faces.component.UIForm.visitTree(UIForm.java:355)
在 ajax 更新中未提交复选框。但是它们似乎包含一个空字符串作为之前验证步骤的提交值。
将上下文参数设置为 false
时,此方法有效。但我想将其保留在 true
。我有什么想法可以解决这个问题吗?
已转载。这确实是 Mojarra 中的一个错误。
归结为UIInput
超类中的以下方法...
@Override
public Object getSubmittedValue() {
if (submittedValue == null && !isValid() && considerEmptyStringNull(FacesContext.getCurrentInstance())) {
return "";
} else {
return submittedValue;
}
}
... 未 在 UISelectMany
超类中以 returns new String[0]
而不是 ""
的方式被覆盖.这是实施 Faces issue 671.
我已经在 Mojarra issue 5081 中修复了它。
与此同时,在升级到包含修复程序的 Mojarra 版本之前,您可以通过将 UISelectMany
的整个 source code 文件复制粘贴到您的项目中,同时维护打包并向其中添加以下方法:
@Override
public Object getSubmittedValue() {
Object submittedValue = super.getSubmittedValue();
return "".equals(submittedValue) ? new String[0] : submittedValue;
}