IllegalArgumentException:无法将类型 class org.omnifaces.el.ExpressionInspector$ValueExpressionType 的 属性 转换为 class java.lang.Boolean
IllegalArgumentException: Cannot convert PROPERTY of type class org.omnifaces.el.ExpressionInspector$ValueExpressionType to class java.lang.Boolean
我在 class 级别 (http://showcase.omnifaces.org/validators/validateBean)
遇到 OmniFaces 1.11 <o:validateBean />
的问题
基本上,我试图根据我单击的按钮使用两个验证组来验证同一个 bean :
<h:commandButton value="Mandatory">
<o:validateBean value="#{testBean.pojo}" validationGroups="bo.ihm.beans.Mandatory" />
</h:commandButton>
<h:commandButton value="Optional">
<o:validateBean value="#{testBean.pojo}" validationGroups="javax.validation.groups.Default" />
</h:commandButton>
每当我点击一个按钮时,我得到
GRAVE: Exception occured while doing validation.
javax.el.ELException: /testOmnifaces.xhtml @21,74 value="#{testBean.pojo.forain}": java.lang.IllegalArgumentException: Cannot convert PROPERTY of type class org.omnifaces.el.ExpressionInspector$ValueExpressionType to class java.lang.Boolean
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:114)
at org.omnifaces.el.ExpressionInspector.getValueReference(ExpressionInspector.java:43)
at org.omnifaces.taghandler.ValidateBean.invoke(ValidateBean.java:331)
at org.omnifaces.taghandler.ValidateBean.invoke(ValidateBean.java:326)
at org.omnifaces.util.Components$ForEach.visit(Components.java:508)
at org.omnifaces.util.Components$ForEach$TypesVisitCallback.visit(Components.java:573)
at com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:151)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1689)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at org.omnifaces.util.Components$ForEach.invoke(Components.java:541)
at org.omnifaces.util.Components$ForEach.invoke(Components.java:505)
at org.omnifaces.taghandler.ValidateBean.forEachInputWithMatchingBase(ValidateBean.java:326)
at org.omnifaces.taghandler.ValidateBean.access0(ValidateBean.java:151)
at org.omnifaces.taghandler.ValidateBean.run(ValidateBean.java:286)
at org.omnifaces.taghandler.ValidateBean$ValidateBeanCallback.invoke(ValidateBean.java:430)
at org.omnifaces.util.Events.invoke(Events.java:278)
at org.omnifaces.util.Events.beforePhase(Events.java:312)
at org.omnifaces.eventlistener.CallbackPhaseListener.beforePhase(CallbackPhaseListener.java:63)
at com.sun.faces.lifecycle.Phase.handleBeforePhase(Phase.java:228)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:99)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:696)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:521)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:138)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:564)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:213)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1097)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:448)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:175)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1031)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:136)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:200)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:446)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:271)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:246)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.run(AbstractConnection.java:358)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:601)
at org.eclipse.jetty.util.thread.QueuedThreadPool.run(QueuedThreadPool.java:532)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.el.ELException: java.lang.IllegalArgumentException: Cannot convert PROPERTY of type class org.omnifaces.el.ExpressionInspector$ValueExpressionType to class java.lang.Boolean
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:229)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
... 44 more
Caused by: java.lang.IllegalArgumentException: Cannot convert PROPERTY of type class org.omnifaces.el.ExpressionInspector$ValueExpressionType to class java.lang.Boolean
at com.sun.el.lang.ELSupport.coerceToBoolean(ELSupport.java:189)
at com.sun.el.lang.ELSupport.coerceToType(ELSupport.java:394)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:227)
... 45 more
testWithClassLevelValidation.xhtml :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:o="http://omnifaces.org/ui">
<f:metadata>
<f:viewAction action="#{testBean.init}" />
</f:metadata>
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Test</title>
</h:head>
<h:body>
<h:form id="formaliteACCRE">
<h:panelGrid columns="1" style="width: 100%;">
<h:panelGrid columns="2" style="width: 100%; display: inline-block;">
<h:outputLabel for="forain">Yes or No ?</h:outputLabel>
<h:selectBooleanCheckbox id="forain" value="#{testBean.pojo.forain}">
<f:ajax execute="forain" render="groupeDomicile" />
</h:selectBooleanCheckbox>
</h:panelGrid>
<h:panelGroup id="groupeDomicile">
<h:outputText value="Yes" rendered="#{testBean.pojo.forain}" />
<h:outputText value="No" rendered="#{not testBean.pojo.forain}" />
</h:panelGroup>
<h:inputText id="numeroSecu" value="#{testBean.pojo.numeroSecuriteSociale}" maxlength="13" size="13" />
<h:inputText id="numeroSecuCle" value="#{testBean.pojo.cleSecuriteSociale}" maxlength="2" size="3" />
<h:panelGrid columns="2" style="width: 100%; display: inline-block;">
<h:inputText id="mandatory" value="#{testBean.pojo.mandatory}" maxlength="13" size="13" />
<h:outputText value="*" style="color:red;" />
</h:panelGrid>
<f:ajax execute="@form" render="@form">
<h:commandButton value="Mandatory">
<o:validateBean value="#{testBean.pojo}" validationGroups="bo.ihm.beans.Mandatory" />
</h:commandButton>
<h:commandButton value="Optional">
<o:validateBean value="#{testBean.pojo}" validationGroups="javax.validation.groups.Default" />
</h:commandButton>
</f:ajax>
</h:panelGrid>
<ui:remove> ################################################################################################ </ui:remove>
<ui:remove> ===== MESSAGES D'ERREURS ===== </ui:remove>
<ui:remove> ################################################################################################ </ui:remove>
<h:panelGroup id="messagesErreur">
<h:panelGrid class="dr-pnl" width="100%" rendered="#{not empty facesContext.messageList}">
<h:messages style="color:red;" />
</h:panelGrid>
</h:panelGroup>
</h:form>
</h:body>
</html>
TestBean.java :
package bo.ihm.beans;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.validation.Valid;
@ViewScoped
@ManagedBean(name = "testBean")
public class TestBean implements Serializable {
private static final long serialVersionUID = 1L;
@Valid
private Pojo pojo;
public Pojo getPojo() {
return pojo;
}
public void init() {
pojo = new Pojo();
pojo.setNumeroSecuriteSociale("2531257351038");
pojo.setCleSecuriteSociale("22");
}
public void setPojo(final Pojo pPojo) {
this.pojo = pPojo;
}
}
Pojo.java :
package bo.ihm.beans;
import org.hibernate.validator.constraints.NotEmpty;
@NumeroSecuriteSociale
public class Pojo {
private boolean forain;
private String cleSecuriteSociale;
private String numeroSecuriteSociale;
@NotEmpty(groups = Mandatory.class)
private String mandatory;
public String getCleSecuriteSociale() {
return cleSecuriteSociale;
}
public String getMandatory() {
return mandatory;
}
public String getNumeroSecuriteSociale() {
return numeroSecuriteSociale;
}
public boolean isForain() {
return forain;
}
public void setCleSecuriteSociale(final String pCleSecuriteSociale) {
cleSecuriteSociale = pCleSecuriteSociale;
}
public void setForain(final boolean pForain) {
forain = pForain;
}
public void setMandatory(final String pMandatory) {
mandatory = pMandatory;
}
public void setNumeroSecuriteSociale(final String pNumeroSecuriteSociale) {
numeroSecuriteSociale = pNumeroSecuriteSociale;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Pojo [forain=");
builder.append(forain);
builder.append(", cleSecuriteSociale=");
builder.append(cleSecuriteSociale);
builder.append(", numeroSecuriteSociale=");
builder.append(numeroSecuriteSociale);
builder.append(", mandatory=");
builder.append(mandatory);
builder.append("]");
return builder.toString();
}
}
完整代码可在 https://github.com/ErwanLeroux/Bo_ihm_test_omnifaces just run clean jetty:run-war et go to http://localhost:14080/bo_ihm/testWithClassLevelValidation.xhtml
第二页 http://localhost:14080/bo_ihm/testWithoutClassLevelValidation.xhtml 是她用来证明 class 级别约束不起作用的,当我单击任何时候按钮时,我应该得到这样的验证错误消息:'Pojo [forain=false, cleSecuriteSociale=22, numeroSecuriteSociale=2531257351038, mandatory=null] is not valid'
事实证明,隐式 EL 强制转换是造成这一切的原因。我们传递了 ValueExpressionType.PROPERTY
和 ValueExpressionType.METHOD
等内部值,以指示 EL 表达式是表示 属性 (getter/setter) 调用还是方法(操作)调用。但是,如果该值具有隐式 EL 强制支持(如 java.lang.Boolean
),则此方法会失败,EL 将在其上隐式转换,例如"true"
到布尔值 true
.
的字符串
这种传递内部值以指示 EL 表达式类型的方法是因为 OmniFaces 2.0 用于分解 <o:grapicImage value>
中的 EL 表达式并提取任何 EL 方法参数,以便它们可以转换并传递为HTTP 查询字符串参数。这就解释了为什么它在 OmniFaces 1.x.
中仍然运行良好
根据 this commit,OmniFaces 2.2 已修复此问题。
我在 class 级别 (http://showcase.omnifaces.org/validators/validateBean)
遇到 OmniFaces 1.11<o:validateBean />
的问题
基本上,我试图根据我单击的按钮使用两个验证组来验证同一个 bean :
<h:commandButton value="Mandatory">
<o:validateBean value="#{testBean.pojo}" validationGroups="bo.ihm.beans.Mandatory" />
</h:commandButton>
<h:commandButton value="Optional">
<o:validateBean value="#{testBean.pojo}" validationGroups="javax.validation.groups.Default" />
</h:commandButton>
每当我点击一个按钮时,我得到
GRAVE: Exception occured while doing validation.
javax.el.ELException: /testOmnifaces.xhtml @21,74 value="#{testBean.pojo.forain}": java.lang.IllegalArgumentException: Cannot convert PROPERTY of type class org.omnifaces.el.ExpressionInspector$ValueExpressionType to class java.lang.Boolean
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:114)
at org.omnifaces.el.ExpressionInspector.getValueReference(ExpressionInspector.java:43)
at org.omnifaces.taghandler.ValidateBean.invoke(ValidateBean.java:331)
at org.omnifaces.taghandler.ValidateBean.invoke(ValidateBean.java:326)
at org.omnifaces.util.Components$ForEach.visit(Components.java:508)
at org.omnifaces.util.Components$ForEach$TypesVisitCallback.visit(Components.java:573)
at com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:151)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1689)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIForm.visitTree(UIForm.java:371)
at org.omnifaces.util.Components$ForEach.invoke(Components.java:541)
at org.omnifaces.util.Components$ForEach.invoke(Components.java:505)
at org.omnifaces.taghandler.ValidateBean.forEachInputWithMatchingBase(ValidateBean.java:326)
at org.omnifaces.taghandler.ValidateBean.access0(ValidateBean.java:151)
at org.omnifaces.taghandler.ValidateBean.run(ValidateBean.java:286)
at org.omnifaces.taghandler.ValidateBean$ValidateBeanCallback.invoke(ValidateBean.java:430)
at org.omnifaces.util.Events.invoke(Events.java:278)
at org.omnifaces.util.Events.beforePhase(Events.java:312)
at org.omnifaces.eventlistener.CallbackPhaseListener.beforePhase(CallbackPhaseListener.java:63)
at com.sun.faces.lifecycle.Phase.handleBeforePhase(Phase.java:228)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:99)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:696)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:521)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:138)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:564)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:213)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1097)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:448)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:175)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1031)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:136)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:200)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
at org.eclipse.jetty.server.Server.handle(Server.java:446)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:271)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:246)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.run(AbstractConnection.java:358)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:601)
at org.eclipse.jetty.util.thread.QueuedThreadPool.run(QueuedThreadPool.java:532)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.el.ELException: java.lang.IllegalArgumentException: Cannot convert PROPERTY of type class org.omnifaces.el.ExpressionInspector$ValueExpressionType to class java.lang.Boolean
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:229)
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
... 44 more
Caused by: java.lang.IllegalArgumentException: Cannot convert PROPERTY of type class org.omnifaces.el.ExpressionInspector$ValueExpressionType to class java.lang.Boolean
at com.sun.el.lang.ELSupport.coerceToBoolean(ELSupport.java:189)
at com.sun.el.lang.ELSupport.coerceToType(ELSupport.java:394)
at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:227)
... 45 more
testWithClassLevelValidation.xhtml :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:o="http://omnifaces.org/ui">
<f:metadata>
<f:viewAction action="#{testBean.init}" />
</f:metadata>
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Test</title>
</h:head>
<h:body>
<h:form id="formaliteACCRE">
<h:panelGrid columns="1" style="width: 100%;">
<h:panelGrid columns="2" style="width: 100%; display: inline-block;">
<h:outputLabel for="forain">Yes or No ?</h:outputLabel>
<h:selectBooleanCheckbox id="forain" value="#{testBean.pojo.forain}">
<f:ajax execute="forain" render="groupeDomicile" />
</h:selectBooleanCheckbox>
</h:panelGrid>
<h:panelGroup id="groupeDomicile">
<h:outputText value="Yes" rendered="#{testBean.pojo.forain}" />
<h:outputText value="No" rendered="#{not testBean.pojo.forain}" />
</h:panelGroup>
<h:inputText id="numeroSecu" value="#{testBean.pojo.numeroSecuriteSociale}" maxlength="13" size="13" />
<h:inputText id="numeroSecuCle" value="#{testBean.pojo.cleSecuriteSociale}" maxlength="2" size="3" />
<h:panelGrid columns="2" style="width: 100%; display: inline-block;">
<h:inputText id="mandatory" value="#{testBean.pojo.mandatory}" maxlength="13" size="13" />
<h:outputText value="*" style="color:red;" />
</h:panelGrid>
<f:ajax execute="@form" render="@form">
<h:commandButton value="Mandatory">
<o:validateBean value="#{testBean.pojo}" validationGroups="bo.ihm.beans.Mandatory" />
</h:commandButton>
<h:commandButton value="Optional">
<o:validateBean value="#{testBean.pojo}" validationGroups="javax.validation.groups.Default" />
</h:commandButton>
</f:ajax>
</h:panelGrid>
<ui:remove> ################################################################################################ </ui:remove>
<ui:remove> ===== MESSAGES D'ERREURS ===== </ui:remove>
<ui:remove> ################################################################################################ </ui:remove>
<h:panelGroup id="messagesErreur">
<h:panelGrid class="dr-pnl" width="100%" rendered="#{not empty facesContext.messageList}">
<h:messages style="color:red;" />
</h:panelGrid>
</h:panelGroup>
</h:form>
</h:body>
</html>
TestBean.java :
package bo.ihm.beans;
import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.validation.Valid;
@ViewScoped
@ManagedBean(name = "testBean")
public class TestBean implements Serializable {
private static final long serialVersionUID = 1L;
@Valid
private Pojo pojo;
public Pojo getPojo() {
return pojo;
}
public void init() {
pojo = new Pojo();
pojo.setNumeroSecuriteSociale("2531257351038");
pojo.setCleSecuriteSociale("22");
}
public void setPojo(final Pojo pPojo) {
this.pojo = pPojo;
}
}
Pojo.java :
package bo.ihm.beans;
import org.hibernate.validator.constraints.NotEmpty;
@NumeroSecuriteSociale
public class Pojo {
private boolean forain;
private String cleSecuriteSociale;
private String numeroSecuriteSociale;
@NotEmpty(groups = Mandatory.class)
private String mandatory;
public String getCleSecuriteSociale() {
return cleSecuriteSociale;
}
public String getMandatory() {
return mandatory;
}
public String getNumeroSecuriteSociale() {
return numeroSecuriteSociale;
}
public boolean isForain() {
return forain;
}
public void setCleSecuriteSociale(final String pCleSecuriteSociale) {
cleSecuriteSociale = pCleSecuriteSociale;
}
public void setForain(final boolean pForain) {
forain = pForain;
}
public void setMandatory(final String pMandatory) {
mandatory = pMandatory;
}
public void setNumeroSecuriteSociale(final String pNumeroSecuriteSociale) {
numeroSecuriteSociale = pNumeroSecuriteSociale;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("Pojo [forain=");
builder.append(forain);
builder.append(", cleSecuriteSociale=");
builder.append(cleSecuriteSociale);
builder.append(", numeroSecuriteSociale=");
builder.append(numeroSecuriteSociale);
builder.append(", mandatory=");
builder.append(mandatory);
builder.append("]");
return builder.toString();
}
}
完整代码可在 https://github.com/ErwanLeroux/Bo_ihm_test_omnifaces just run clean jetty:run-war et go to http://localhost:14080/bo_ihm/testWithClassLevelValidation.xhtml
第二页 http://localhost:14080/bo_ihm/testWithoutClassLevelValidation.xhtml 是她用来证明 class 级别约束不起作用的,当我单击任何时候按钮时,我应该得到这样的验证错误消息:'Pojo [forain=false, cleSecuriteSociale=22, numeroSecuriteSociale=2531257351038, mandatory=null] is not valid'
事实证明,隐式 EL 强制转换是造成这一切的原因。我们传递了 ValueExpressionType.PROPERTY
和 ValueExpressionType.METHOD
等内部值,以指示 EL 表达式是表示 属性 (getter/setter) 调用还是方法(操作)调用。但是,如果该值具有隐式 EL 强制支持(如 java.lang.Boolean
),则此方法会失败,EL 将在其上隐式转换,例如"true"
到布尔值 true
.
这种传递内部值以指示 EL 表达式类型的方法是因为 OmniFaces 2.0 用于分解 <o:grapicImage value>
中的 EL 表达式并提取任何 EL 方法参数,以便它们可以转换并传递为HTTP 查询字符串参数。这就解释了为什么它在 OmniFaces 1.x.
根据 this commit,OmniFaces 2.2 已修复此问题。