使用转换器的 JSF 验证失败时出现 Nullpointerexception
Nullpointerexception when validation fails JSF using convertor
我正在使用 OmniFaces 的 omnifaces.SelectItemsConverter
,因此我可以在 selectOneMenu
中显示对象的字符串值。一切正常,直到验证失败 (f:validateDoubleRange
)。一旦验证失败,无论我做什么,我都会在 selectOneMenu
中显示的对象的 equals 方法中得到一个 NullPointerException
。
这是 equals 方法:
@Override
public boolean equals(Object obj) {
Car other = (Car) obj;
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
if (!number.equals(other.number))
return false;
return true;
}
这是我使用 OmniFaces 转换器的地方
<h:selectOneMenu id="id_1" value="#{myBean.car}" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{myBean.cars}" />
</h:selectOneMenu>
这是导致 NullPointerException
的验证
<h:inputText id="nom" value="#{myBean.num}"
style="height: 24px; "><f:validateDoubleRange minimum="0.0"/></h:inputText>
我在这一行得到异常:
if (!number.equals(other.number))
other.number
可以,但是 number
为空
为什么 this.number
为空?
根本原因
问题的根本原因是在视图内的任何输入组件验证失败后,JSF 默认处理输入组件状态。
这个accepted answer解释得很好。
解决方案
因此在您的特定情况下,如前所述的答案建议,您需要指示 JSF 重置输入组件状态(对 h:selectOneMenu
最重要)和 pull/refresh 它们在验证失败后来自支持 bean 模型的值。
如果您使用的是 JSF 2.2 及更高版本,您可以这样做,例如,像这样
<h:commandButton value="Submit" actionListener="#{myBean.onSubmit()}" >
<f:ajax execute=":form:nom :form:id_1"
render=":form:messages :form:id_1"
resetValues="true"/>
</h:commandButton>
更新: 如果你是 pre-JSF 2.2,你可以使用 Primefaces p:ajax
,例如,像这样(解决方案和解释可以在参考文献 accepted answer 以及 Primefaces showcase 中找到)
<h:commandButton value="Submit" actionListener="#{dtSelectionView.onSubmit()}">
<p:ajax process="@form" update="@form" resetValues="true" />
</h:commandButton>
(虽然我不建议仅仅为了这个目的导入 Primefaces...最好探索其他可能性)
this.number
为空的实际原因
我注意到,如果您在第一次验证失败后尝试提交(并且如果您不重置 h:selectOneMenu
的输入值),以下一些 类 会创建新的Car
对象调用 default constructor(并将 number
属性 初始化为默认值,在您的情况下等于 null
)
Severe: java.lang.NullPointerException
at entities.Car.equals(Car.java:107)
at javax.faces.component.UIInput.compareValues(UIInput.java:1224)
at javax.faces.component.UIInput.validate(UIInput.java:990)
at javax.faces.component.UIInput.executeValidate(UIInput.java:1248)
at javax.faces.component.UIInput.processValidators(UIInput.java:712)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:575)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1689)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:403)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:266)
at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:57)
at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:219)
at org.omnifaces.context.OmniPartialViewContext.processPartial(OmniPartialViewContext.java:139)
at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1193)
at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
坦率地说,我无法解释发生这种情况的地点和原因,因为它超出了我对这个主题的了解。
我正在使用 OmniFaces 的 omnifaces.SelectItemsConverter
,因此我可以在 selectOneMenu
中显示对象的字符串值。一切正常,直到验证失败 (f:validateDoubleRange
)。一旦验证失败,无论我做什么,我都会在 selectOneMenu
中显示的对象的 equals 方法中得到一个 NullPointerException
。
这是 equals 方法:
@Override
public boolean equals(Object obj) {
Car other = (Car) obj;
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
if (!number.equals(other.number))
return false;
return true;
}
这是我使用 OmniFaces 转换器的地方
<h:selectOneMenu id="id_1" value="#{myBean.car}" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{myBean.cars}" />
</h:selectOneMenu>
这是导致 NullPointerException
<h:inputText id="nom" value="#{myBean.num}"
style="height: 24px; "><f:validateDoubleRange minimum="0.0"/></h:inputText>
我在这一行得到异常:
if (!number.equals(other.number))
other.number
可以,但是 number
为空
为什么 this.number
为空?
根本原因
问题的根本原因是在视图内的任何输入组件验证失败后,JSF 默认处理输入组件状态。
这个accepted answer解释得很好。
解决方案
因此在您的特定情况下,如前所述的答案建议,您需要指示 JSF 重置输入组件状态(对 h:selectOneMenu
最重要)和 pull/refresh 它们在验证失败后来自支持 bean 模型的值。
如果您使用的是 JSF 2.2 及更高版本,您可以这样做,例如,像这样
<h:commandButton value="Submit" actionListener="#{myBean.onSubmit()}" >
<f:ajax execute=":form:nom :form:id_1"
render=":form:messages :form:id_1"
resetValues="true"/>
</h:commandButton>
更新: 如果你是 pre-JSF 2.2,你可以使用 Primefaces p:ajax
,例如,像这样(解决方案和解释可以在参考文献 accepted answer 以及 Primefaces showcase 中找到)
<h:commandButton value="Submit" actionListener="#{dtSelectionView.onSubmit()}">
<p:ajax process="@form" update="@form" resetValues="true" />
</h:commandButton>
(虽然我不建议仅仅为了这个目的导入 Primefaces...最好探索其他可能性)
this.number
为空的实际原因
我注意到,如果您在第一次验证失败后尝试提交(并且如果您不重置 h:selectOneMenu
的输入值),以下一些 类 会创建新的Car
对象调用 default constructor(并将 number
属性 初始化为默认值,在您的情况下等于 null
)
Severe: java.lang.NullPointerException
at entities.Car.equals(Car.java:107)
at javax.faces.component.UIInput.compareValues(UIInput.java:1224)
at javax.faces.component.UIInput.validate(UIInput.java:990)
at javax.faces.component.UIInput.executeValidate(UIInput.java:1248)
at javax.faces.component.UIInput.processValidators(UIInput.java:712)
at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:575)
at com.sun.faces.component.visit.PartialVisitContext.invokeVisitCallback(PartialVisitContext.java:183)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1689)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:403)
at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:266)
at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:57)
at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:219)
at org.omnifaces.context.OmniPartialViewContext.processPartial(OmniPartialViewContext.java:139)
at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1193)
at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
坦率地说,我无法解释发生这种情况的地点和原因,因为它超出了我对这个主题的了解。