2011-09-16 10 views
11

Czy ktoś może mi wyjaśnić, dlaczego Foo w moim przykładzie jest zawsze zerowy, gdy przechodzi do klasy validateDoubleRange? Wynik końcowy to minimalna wartość walidatora to zawsze 0. Liczba 3 wyświetla się dobrze na stronie w elemencie outputText. To potwierdza porządku, jeśli robię fasola @SessionScoped zamiast @ViewScopedDlaczego funkcja f: validateDoubleRange działa tylko dla @SessionScoped?

Kontroler:

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> 

Używam JSF 2 na JBoss 6.1

Jeżeli jesteś tam @BalusC, jest to najprostszy przykład, jaki mogłem wymyślić, i jest ten sam problem co wczoraj, mam tylko nadzieję, wyjaśniłem i prostsze do replikowania.

- edytuj, powinienem dodać, że fooId jest ustawiane za pomocą paramu widoku, więc potrzebujesz? FooId = 3 na końcu adresu URL.

Odpowiedz

14

Teraz widzę, dlaczego nie mogłem odtworzyć tego wczoraj. W moim otoczeniu zabaw miałem przypadkowo następujące kontekstowe param zestaw odmiennie od wartości domyślnej:

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

Ten problem jest związany z JSF issue 1492. A <f:validateDoubleRange>, którego atrybuty są powiązane przez EL z właściwością komponentu bean o widoku, domyślnie odtwarza cały komponent ze względu na nieprzyjemny problem z jajkami kurzymi, ponieważ weryfikatory są tworzone na żądanie, a właściwości te należy przekazywać w oparciu o konstrukcję walidatora.


Jeśli nie chcesz wyłączyć częściowe oszczędności państwa (bardzo rozsądne), to najlepiej jest stworzyć i utrzymać walidator w widoku scoped udało Bean się:

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

(uwaga, robienie tego w geterze jest złym projektem, ale ponieważ przygotowujesz foo w setera zamiast metody detektora preRenderView, nie ma innej drogi, w przeciwnym razie byłoby to zrobione dokładnie w tej samej metodzie słuchania)

z

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

lub, alternatywnie, aby utworzyć własny walidator za to, co zastępuje <f:validateDoubleRange>:

<f:validator validatorId="bindableDoubleRangeValidator" /> 
<f:attribute name="minimum" value="#{fooController.foo.minAmount}" /> 
<f:attribute name="maximum" value="#{fooController.foo.maxAmount}" /> 

z

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); 
    } 

} 

Aktualizacja: kwestia jaj kurzych 1492 została ustalona od wersji 2.1.18 Mojarry (styczeń 2013 r.). Więc jeśli natkniesz się na to w tych dniach, to możesz również rozważyć tylko upgrade.

+0

Wow, bardzo pouczające i pomocne. Myślałem, że oszalałem. Dziękuję bardzo. – Simon

+0

Nie ma za co. – BalusC

Powiązane problemy