Почему f: validateDoubleRange работает только для @SessionScoped? - PullRequest
11 голосов
/ 16 сентября 2011

Может кто-нибудь объяснить мне, почему Foo в моем примере всегда имеет значение null, когда он попадает в класс validateDoubleRange?Конечным результатом является минимальное значение для валидатора, всегда равное 0. Число 3 отлично отображается на странице в элементе outputText.Это хорошо, если я создаю 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>

Я использую JSF 2 наJBoss 6.1

Если вы находитесь там @BalusC, это самый простой пример, который я мог бы придумать, и это та же проблема, что и вчера, я надеюсь, что она прояснена и проще для репликации.

- отредактируйте, я должен добавить, что fooId устанавливается через параметр просмотра, поэтому вам нужно? FooId = 3 в конце вашего URL.

1 Ответ

15 голосов
/ 16 сентября 2011

Теперь я понимаю, почему я не смог воспроизвести это вчера.В моей игровой среде я случайно установил следующий контекстный параметр, отличный от значения по умолчанию:

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

Эта проблема связана с JSF , проблема 1492 .A <f:validateDoubleRange>, атрибуты которого по EL связаны со свойством bean-объекта области видимости, будет неявно воссоздавать весь bean-компонент из-за неприятной проблемы с куриным яйцом, потому что валидаторы создаются на основе запроса и эти свойства должны передаваться валидаторуconstruction.


Если вы не хотите отключать частичное сохранение состояния (очень разумное), тогда вам лучше всего создать и удерживать валидатор в управляемом bean-объекте вида:

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

(обратите внимание, что делать это в геттере - это плохой дизайн, но, поскольку вы готовите 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 г.).Так что, если вы натолкнетесь на это в эти дни, то вы также можете подумать об обновлении.

...