2010-05-04 12 views
0

Nous avons des valeurs numériques dans notre base de données, représentant un état à deux valeurs. Bien sûr, cela correspond parfaitement à un booléen, mais Oracle ne possède pas ce type de données. Le type NUMBER (1,0) de la base de données correspond à un type java.lang.Short en Java (parfois, ils utilisaient NUMBER (*, 0) pour représenter les booléens, qui correspondent à java.math.BigDecimal).Comment enregistrer un rendu personnalisé dans JSF?

Comme il est en quelque sorte évident, je veux offrir de la glace: selectBooleanCheckbox dans la vue comme une représentation de la valeur et UIComponent à l'utilisateur. (J'utilise IceFaces comme implémentation JSF)

Puisque certaines personnes qui ont spécifié JSF pensent qu'il est évident de toujours faire correspondre la valeur d'un ice: selectBooleanCheckbox ou dans JSF h: selectBooleanCheckbox à un booléen dans le modèle, donc le rendu du composant appelle jamais convertisseur, même si vous spécifiez un: Issue disscused at java.net

J'ai donc essayé les éléments suivants:

J'ai créé un convertisseur pour spécifier dans la 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"; 
    } 
} 

Le convertisseur fonctionne correctement pour la phase de rendu (la méthode getAsString est appelée correctement), mais la méthode getAsObject (Ignorer que ce n'est pas correct pour le moment, car il n'est pas appelé, donc il sera corrigé!) n'est jamais appelé, parce que dans le moteur de rendu du UIComponent un convertisseur n'est pas prévu, comme vous pouvez le voir ici (sNIP de 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); 
} 

donc cela se traduit par une exception IllegalArgumentException, car dans la phase UpdateModelValues, on essaie d'appliquer une valeur booléenne à une valeur numérique (ignorez la confusion BigDecimal/Short ... il s'agit simplement d'un type numérique!).

J'ai donc essayé d'écraser le moteur de rendu par un nouveau comme celui-ci:

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

et enregistré comme celui-ci dans les 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> 

Je suppose que cela doit être correct , mais la méthode surchargée "getConvertedValue" n'est jamais appelée, pas plus que la méthode getAsObject(), donc je suppose que j'ai fait une erreur en enregistrant le rendu personnalisé, mais je ne trouve plus de documentation ou d'astuces pour le faire correctement et surtout comment trouver la bonne famille de composants (j'ai regardé celui que je utilisez dans icefaces.taglib.xml) et le type de rendu correct.

Je ne veux pas modifier le modèle complet pour cette raison. Des conseils, comment cela peut-il être résolu?

Répondre

5

Nous pourrions résoudre le problème et enregistrer correctement notre moteur de rendu personnalisé.

Le problème était de trouver les propriétés correctes pour le moteur de rendu prévu. Nos tentatives ont été fausses, puisque j'ai découvert comment obtenir l'information appropriée. C'est un peu de travail et de recherche, mais ça a finalement fait l'affaire.Il suffit de démarrer votre conteneur en mode débogage et d'ajouter un point d'arrêt au niveau de la classe dans la classe dérivée sur laquelle repose le moteur de rendu personnalisé (dans mon cas, com.icesoft.faces.renderkit.dom_html_basic.CheckboxRenderer).

Lors du démarrage du conteneur, ce point d'arrêt sera atteint et dans la pile, vous trouverez un appel de la méthode FacesConfigurator.configureRenderKits().

Cet objet contient une ArrayList de moteurs de rendu enregistrés. J'ai cherché dans la liste le moteur de rendu que j'aurais aimé écraser et j'ai pu trouver les informations dont j'avais besoin pour enregistrer mon moteur de rendu personnalisé. Dans mon cas, c'est l'entrée correcte dans les 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> 

Maintenant, le getAsObject() - méthode dans le convertisseur est appelé par le moteur de rendu personnalisé. Assurez-vous de remplacer correctement la méthode, si vous ne voulez pas un convertisseur sur chaque objet 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); 
} 

Sinon, vous obtiendrez un NullPointerException. PS: Il y a sûrement un moyen plus intelligent d'obtenir cette information, mais je ne suis pas assez intelligent. ;-)

+0

Je cours Mojarra 2.0.2 et ne peux pas trouver 'FacesConfigurator' de mon classpath. Cette classe est-elle uniquement ICEFaces? –

0

Vous ne dites pas si vous utilisez Hibernate mais je suppose que vous devez être un problème. Avez-vous essayé de traiter le numérique comme un booléen dans votre cartographie?

Voir cette thread from the Hibernate forums

+0

Salut, thx pour l'indice, mais non, nous utilisons Ibator Ibatis pour la cartographie des données. Je ne connais pas un moyen de faire les mêmes correspondances comme en hibernation (que j'adorerais utiliser!). – bl4ckb0l7