验证者的JSF2禁用属性仅针对第一个周期进行评估?

时间:2012-01-13 07:57:12

标签: validation jsf-2

我发现,如果我的托管bean是ViewScoped,那么我在JSF2中使用的任何验证器的disabled属性仅在第一个周期进行评估。

但我想根据我从第4个更新阶段获得的数据,为验证器使用 disabled 属性。所以我希望在同一视图上执行的所有循环中重新评估。

示例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:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">

<h:head></h:head>
<h:body>
    <h:form>
        <h:panelGrid id="pnlGrid">          
            <h:inputText id="someValueId" value="#{testPageBean.someValue}">                
                <f:validateLength minimum="2" maximum="4" 
                   disabled="#{testPageBean.disableValidateLength}"/>
            </h:inputText>
            <h:messages for="someValueId"/>

            <h:commandButton action="#{testPageBean.doSomething}" 
               value="Do something" />
        </h:panelGrid>
    </h:form>
</h:body>
</html>

及其视图作用域托管bean

package cz.kamosh;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean
@ViewScoped
public class TestPageBean implements Serializable {

    boolean disableValidateLength = false;

    private String someValue;

    public TestPageBean() {
        System.out.println("Constructor TestPageBean");
    }

    public String getSomeValue() {
        return someValue;
    }

    public void setSomeValue(String someValue) {
        this.someValue = someValue;
    }

    /**
     *  Some action without any navigation as a result
     */
    public void doSomething() {
        disableValidateLength = !disableValidateLength;
        System.out.printf(
                "DoSomething, someValue: %1$s, disableValidateLength: %2$b\n",
                someValue, disableValidateLength);
    }

    public boolean isDisableValidateLength() {
        System.out.printf("IsValidateLength, disableValidateLength: %1$b\n", 
                disableValidateLength);
        return disableValidateLength;
    }
}

我知道我应该责怪实施 com.sun.faces.facelets.tag.jsf.ValidatorTagHandlerDelegateImpl

private void applyNested(FaceletContext ctx,
                             UIComponent parent) {

        // only process if it's been created
        if (!ComponentHandler.isNew(parent)) {
            return;
        }
    ...
}

当我执行操作时,这三行导致验证程序未被重新评估其禁用属性: - (

有些人可以给我一个提示,JSF2家伙以这种方式实施的动机是什么,甚至更好地解决我的问题?

编辑:

JSF2的版本: 2.0.3-SNAPSHOT

的web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <display-name>JSF2Testing</display-name>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
        <param-value>false</param-value>
    </context-param>

</web-app>

<小时/>

EDIT2 尝试关注BalusC' suggestion

页面上的更改:

<h:inputText id="someValueId" value="#{testPageBean.someValue}">                
    <f:validator validatorId="myLengthValidator"/>
    <f:attribute name="disableMyLengthValidator" value="#{testPageBean.disableValidateLength}"/>
    <f:attribute name="minimum" value="2" />
    <f:attribute name="maximum" value="4" />
</h:inputText>

使用自己的验证器代替标准

import java.io.Serializable;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.LengthValidator;
import javax.faces.validator.ValidatorException;

@FacesValidator("myLengthValidator")
public class MyLengthValidator extends LengthValidator implements Serializable {

    public MyLengthValidator() {
        System.out.println("MyLengthValidator constructor");
    }

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {     
        if((Boolean)component.getAttributes().get("disableMyLengthValidator")) {
            return;
        }       
        setMinimum(Integer.valueOf((String)component.getAttributes().get("minimum")));
        setMaximum(Integer.valueOf((String)component.getAttributes().get("maximum")));
        super.validate(context, component, value);
    }
}

关于此解决方案的说明:

  • 即使是标准验证器也要求自己实施
  • 依赖于组件(inputText)级别
  • 上的属性
  • 验证器即使不应该
  • 也会被触发
  • 我很确定在为验证器
  • 提供客户端验证时,它不会像我们预期的那样运行
  • 我认为非常难看并且不遵循JSF2: - (

1 个答案:

答案 0 :(得分:0)

你已成为鸡蛋问题的另一个受害者,部分状态保存和查看范围内的bean,如issue 1492中所述,将在即将到来的Mojarra 2.2中修复。

当你看到在每个请求上调用视图范围bean的构造函数时,你应该立刻意识到某些东西并不完全正确,而不是只在第一次请求视图时调用一次。

解决此问题的方法之一是完全禁用部分状态保存:

<context-param>
    <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
    <param-value>false</param-value>
</context-param>

另见: