2011-09-16 14 views
11

Qualcuno può spiegarmi perché Foo nel mio esempio è sempre nullo quando raggiunge la classe validateDoubleRange? Il risultato finale è il valore minimo per il validatore è sempre 0. Il numero 3 viene visualizzato correttamente nella pagina quando si trova nell'elemento outputText. Valida fino se faccio il fagiolo @SessionScoped invece di @ViewScopedPerché f: validateDoubleRange funziona solo per @SessionScoped?

Controller:

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> 

Sto usando JSF 2 su JBoss 6.1

Se sei là fuori @BalusC, questo è l'esempio più semplice che potrei inventare, ed è lo stesso problema di ieri, solo, spero, chiarito e più semplice da replicare.

- modifica, dovrei aggiungere che fooId è impostato tramite una vista param, quindi hai bisogno di? Fooid = 3 alla fine del tuo URL.

risposta

14

Ora capisco perché non sono riuscito a riprodurre questo ieri. Nel mio ambiente ho avuto un parco giochi per sbaglio il seguente param set contesto diverso dal valore di default:

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

Questo problema è legato alla JSF issue 1492. A <f:validateDoubleRange> i cui attributi sono legati da EL ad una proprietà del bean con scope view ricreeranno implicitamente l'intero bean a causa di un problema di pollo-uovo, perché i validatori vengono creati su una base di richiesta e quelle proprietà devono essere passate sulla costruzione del validatore.


Se non si desidera disattivare il risparmio parziale stato (molto ragionevole), allora la cosa migliore è quello di creare e mantenere il validatore nella vista con scope bean gestito da soli:

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

(nota, fare questa roba in un getter è un pessimo design, ma dal momento che stai preparando foo in un setter invece di un metodo listener preRenderView, non c'è altro modo, altrimenti sarebbe fatto proprio nello stesso metodo listener)

con

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

Oppure, in alternativa, per creare un validatore personalizzato per ciò che sostituisce il <f:validateDoubleRange>:

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

con

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

} 

Aggiornamento: il numero di uova di gallina 1492 è stato risolto da Mojarra 2.1.18 (gennaio 2013). Quindi se ti capita di incappare in questi giorni, allora potresti anche considerare di aggiornare.

+0

Wow, molto informativo e utile. Pensavo che avrei potuto diventare matto. Grazie mille. – Simon

+0

Prego. – BalusC

Problemi correlati