为什么f:validateDoubleRange仅适用于@SessionScoped?

时间:2011-09-16 13:29:08

标签: java validation jsf java-ee jsf-2

有人可以向我解释为什么我的示例中的Foo在到达validateDoubleRange类时始终为null?最终结果是验证器的最小值始终为0.在outputText元素中,数字3在页面上显示正常。 如果我将bean设为@SessionScoped而不是@ViewScoped

,则验证正常

控制器:

import java.io.Serializable;
import java.math.BigDecimal;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ViewScoped
@ManagedBean(name = "fooController")
public class FooController implements Serializable {

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FooController.class);
    private static final long serialVersionUID = 1L;
    private Foo foo;
    private BigDecimal amount;
    private Long fooId;

    public Long getFooId() {
        return fooId;
    }

    public void setFooId(Long fooId) {
        this.fooId = fooId;
        this.foo = new Foo();
        foo.setFooId(fooId);
        foo.setMinAmount(Double.valueOf(3));
        foo.setMaxAmount(Double.valueOf(10));
    }

    public Foo getFoo() {
        return foo;
    }

    public void sendAmount() {
        log.debug("sendAmount: " + amount);
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }

    public static class Foo {

        private Long fooId;
        private Double minAmount;
        private Double maxAmount;

        public Foo() {
        }

        public void setFooId(Long fooId) {
            this.fooId = fooId;
        }

        public void setMinAmount(Double minAmount) {
            this.minAmount = minAmount;
        }

        public void setMaxAmount(Double maxAmount) {
            this.maxAmount = maxAmount;
        }

        public Long getFooId() {
            return fooId;
        }

        public Double getMaxAmount() {
            return maxAmount;
        }

        public Double getMinAmount() {
            return minAmount;
        }
    }
}

JSP:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
            xmlns:ui="http://java.sun.com/jsf/facelets"
            xmlns:f="http://java.sun.com/jsf/core"
            xmlns:h="http://java.sun.com/jsf/html"
            >
<f:metadata>
    <f:viewParam name="fooId" value="#{fooController.fooId}" />        
</f:metadata>
<h:form id="myForm">
    <h:outputText value="This is correctly displayed: '#{fooController.foo.minAmount}'"/><br/>
    <h:outputText value="My Input:" />
    <h:inputText id="myInput"
                 value="#{fooController.amount}" 
                 required="true"
                 >
        <f:convertNumber maxFractionDigits="2"/>
        <f:validateDoubleRange minimum="#{fooController.foo.minAmount}" maximum="80"/>
    </h:inputText>
    <h:message for="myInput"/>
    <br/>
    <h:commandButton id="myButton"
                     value="Save Amount"
                     action="#{fooController.sendAmount}"
                     >
    </h:commandButton>
</h:form>
</ui:composition>

我在JBoss 6.1上使用JSF 2

如果你在那里@BalusC,这是我能想到的最简单的例子,和昨天一样,我希望,澄清并且更容易复制。

- 编辑,我应该补充说fooId是通过一个视图参数设置的,所以你需要在你的URL末尾使用?fooId = 3.

1 个答案:

答案 0 :(得分:15)

我现在明白为什么我昨天无法重现这一点。在我的游乐场环境中,我意外地将以下上下文参数设置为与默认值不同:

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

此问题与JSF issue 1492有关。一个<f:validateDoubleRange>的属性由EL绑定到视图范围的bean属性将隐式重新创建整个bean,因为一个讨厌的鸡蛋问题,因为验证器是基于每个请求创建的,那些属性将被传递关于验证者的建设。


如果您不想禁用部分状态保存(非常合理),那么最好的办法是自己在视图范围内的托管bean中创建并保存验证器:

public Validator getValidator() {
    return new DoubleRangeValidator(foo.getMaximum(), foo.getMinimum());
}

(注意,在getter中执行此操作是一个糟糕的设计,但由于您在setter而不是foo侦听器方法中准备preRenderView,所以没有其他办法,否则它将在同一个侦听器方法中完成)

<h:inputText validator="#{fooController.validator.validate}" ...>

或者,或者,为替换<f:validateDoubleRange>

的自定义验证器创建
<f:validator validatorId="bindableDoubleRangeValidator" />
<f:attribute name="minimum" value="#{fooController.foo.minAmount}" />
<f:attribute name="maximum" value="#{fooController.foo.maxAmount}" />

package com.example;

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

@FacesValidator("bindableDoubleRangeValidator")
public class BindableDoubleRangeValidator extends DoubleRangeValidator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        setMinimum((Double) component.getAttributes().get("minimum"));
        setMaximum((Double) component.getAttributes().get("maximum"));
        super.validate(context, component, value);
    }

}

更新:鸡蛋问题1492自Mojarra 2.1.18(2013年1月)起修复。所以,如果你这些日子偶然发现,那么你也可以考虑升级。