Domanda

Abbiamo valori numerici nel nostro database, che rappresenta un valore di due stati. Naturalmente questo sarebbe perfettamente corrispondere un valore booleano, ma Oracle non ha tale tipo di dati. Il tipo di numero (1,0) dal database è abbinato ad un tipo java.lang.Short in Java (a volte hanno usato un numero (*, 0) per rappresentare booleani, che vengono abbinati a java.math.BigDecimal).

Dal momento che è in qualche modo ovvio, voglio offrire il ghiaccio: selectBooleanCheckbox nella vista come una rappresentazione del valore e UIComponent per l'utente. (Io uso IceFaces come implementazione JSF)

Dal momento che alcune persone che specificate JSF pensano che sia ovvio che corrisponda sempre il valore di un ghiaccio: selectBooleanCheckbox o in JSF h: selectBooleanCheckbox ad un valore booleano nel modello, in modo che il renderer della componente non chiama mai alcun convertitore, anche se specificare uno: disscused a java.net

Per questo ho provato il seguente:

Ho creato un convertitore per specificare nel UIComponent:

public class BooleanBigDecimalConverter implements Converter {

   public Object getAsObject(FacesContext context, UIComponent component, String str) {
     if (StringUtils.isEmptyString(str)) {
       return new BigDecimal(0);
     }
     if (str.equals("true")) {
       return new BigDecimal(1);
     } else {
       return new BigDecimal(0);
     }
   }

   public String getAsString(FacesContext context, UIComponent component, Object obj) {
     if (obj != null) {
       String str = obj.toString();
       if (str.equalsIgnoreCase("1")
       || str.equalsIgnoreCase("yes")
       || str.equalsIgnoreCase("true")
       || str.equalsIgnoreCase("on")) {
         return "true";
       } else {
         return "false";
       }
     }
     return "false";
   }
 }

Il convertitore funziona bene per la fase di rendering (il metodo getAsString viene chiamato correttamente), ma il getAsObject-metodo (Ignora che non è corretto in questo momento, perché non è chiamato comunque, quindi verrà risolto se si chiama !) non è mai chiamato, perché nel renderer del UIComponent un convertitore non è previsto, come si può vedere qui (snip da com.icesoft.faces.renderkit.dom_html_basic.CheckboxRenderer):

 public Object getConvertedValue(FacesContext facesContext, UIComponent uiComponent, Object submittedValue)  throws ConverterException
 {
   if(!(submittedValue instanceof String))
     throw new ConverterException("Expecting submittedValue to be String");
   else
     return Boolean.valueOf((String)submittedValue);
 }

Quindi, questo si traduce in un IllegalArgumentException, dal momento che nella fase UpdateModelValues ??si cerca di applicare un valore booleano per un valore numerico (si prega di ignorare la confusione BigDecimal / Short ... si tratta solo di un tipo numerico in ogni caso!).

Così ho provato a sovrascrivere il renderer con uno nuovo in questo modo:

import com.icesoft.faces.component.ext.renderkit.CheckboxRenderer;

 public class CustomHtmlSelectBooleanCheckbox extends CheckboxRenderer {

   public Object getConvertedValue(FacesContext context, UIComponent component, Object submittedValue) throws ConverterException {
   Converter converter = ((ValueHolder) component).getConverter();
   return converter.getAsObject(context, component, (String) submittedValue);  
   }
 }

e registrato in questo modo in faces-config.xml:

 <render-kit>
   <renderer>
     <component-family>com.icesoft.faces.HtmlSelectBooleanCheckbox</component-family>
     <renderer-type>com.icesoft.faces.Checkbox</renderer-type>
     <renderer-class>com.myapp.web.util.CustomHtmlSelectBooleanCheckbox</renderer-class>
   </renderer>
 </render-kit>

Credo che questo dovrebbe essere corretto, ma il metodo override "getConvertedValue" non viene mai chiamato, né è la getAsObject () - metodo, quindi credo che ho fatto un errore nella registrazione del renderer personalizzato, ma non riesco a trovare alcuna più documentazione o suggerimenti su come farlo correttamente e soprattutto come trovare la giusta componente della famiglia (ho guardato quello che uso in icefaces.taglib.xml) e la corretta renderer-tipo.

Non voglio per modificare il modello completo a causa di questo. Eventuali suggerimenti, come questo può essere risolto?

È stato utile?

Soluzione

Si potrebbe risolvere il problema e correttamente registrare il nostro renderer personalizzato.

Il problema era quello di trovare le proprietà corrette per il renderer previsto. I nostri tentativi avevano torto, dal momento che ho scoperto come ottenere le informazioni appropriate. E 'un po' di lavoro e di ricerca, ma alla fine ha fatto il trucco.

Basta iniziare il vostro contenitore in modalità debug e aggiungere un punto di interruzione livello di classe nella classe derivata il renderer personalizzato si basa su (nel mio caso com.icesoft.faces.renderkit.dom_html_basic.CheckboxRenderer).

Nel corso del contenitore di start-up questo punto di interruzione sarà raggiunto e nel stacktrace troverete un richiamo delle FacesConfigurator.configureRenderKits metodo ().

Questo oggetto contiene un ArrayList di renderer registrati. Ho cercato la lista per il renderer mi sarebbe piaciuto di sovrascrivere e riuscito a trovare le informazioni che ho bisogno di registrare il mio renderer personalizzato. Nel mio caso questo è la voce corretta in faces-config.xml:

<render-kit>
    <description>The ICEsoft Renderers.</description>
    <render-kit-id>ICEfacesRenderKit</render-kit-id>
    <render-kit-class>com.icesoft.faces.renderkit.D2DRenderKit</render-kit-class>
    <renderer>
            <component-family>javax.faces.SelectBoolean</component-family>
            <renderer-type>com.icesoft.faces.Checkbox</renderer-type>
            <renderer-class>com.myapp.web.util.CustomHtmlSelectBooleanCheckbox</renderer-class>
    </renderer>
 </render-kit>

Ora la getAsObject () - Metodo nel convertitore viene chiamato dal renderer personalizzato. Assicurarsi di eseguire l'override del metodo in modo corretto, nel caso in cui non si vuole un convertitore su ogni oggetto SelectBooleanCheckbox:

public Object getConvertedValue(FacesContext context,
        UIComponent component, Object submittedValue)
        throws ConverterException {
    Converter converter = ((ValueHolder) component).getConverter();
    if (converter == null) {
        if(!(submittedValue instanceof String))
            throw new ConverterException("Expecting submittedValue to be String");
        else
            return Boolean.valueOf((String)submittedValue);
    }
    return converter.getAsObject(context, component,
            (String) submittedValue);
}

In caso contrario si otterrà un NullPointerException.

PS: V'è sicuramente un modo più intelligente per ottenere queste informazioni, ma io non sono abbastanza intelligente. ; -)

Altri suggerimenti

Non c'è dire se si sta utilizzando Hibernate, ma suppongo che si deve essere per questo di essere un problema. Hai provato trattare il numerico come un valore booleano nella tua mappatura?

Vedere questa discussione dal forum Hibernate

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top