CERCA SITEMAP FEED RSS 1280
Ultimo aggiornamento: 30 Agosto 2009

Convertitori in JavaServer Faces

Quando un utente clicca su un bottone per inviare i dati inseriti in un form questi non vengono subito memorizzati in backing bean ma vengono dapprima convertiti e validati.
In particolare, nella fase di Apply Request Values i valori inviati dal browser sotto forma di stringhe vengono memorizzati nei corrispondenti oggetti lato server (ad ogni tag corrisponde oggetto lato server), quindi ne viene effettuata la conversione nei tipi definiti ed infine si passa alla fase di Process Validation nella quale i dati convertiti vengono validati.
La fase di Update Values Model viene eseguita soltanto se tutte le operazioni di validazione si concludono con successo.

Convertitori standard

L’interfaccia web di un’applicazione è in grado di trattare esclusivamente stringhe e quando un utente compila un form ed effettua una richiesta http i valori inseriti nei campi vengono inviati al server sottoforma di stringhe.
Dal momento che una web application potrebbe avere necessità di trattare dati di tipi differenti è necessario ricorrere un processo di conversione dei dati di tipo String nel corrispondente tipo.
L’implementazione JSF fornisce un certo numero di convertitori standard che possono essere utilizzati all’interno di una pagina JSF innestando il corrispondente tag all’interno del tag del componente del quale si vuole convertire il valore.
Se ad esempio si vuole convertire il contenuto di un componente di testo in una data è possibile ricorrere al convertitore standard definito dal tag convertDateTime come nel seguente esempio:
<h:inputText value="#{miobean.miadata}">
  <f:convertDateTime pattern="MM/yyyy"/>
</h:inputText>
dove l’attributo pattern definisce il formato della data (in questo caso vengono considerati solo il mese e l’anno).
Un modo alternativo per collegare un convertitore ad un componente consiste nel fare uso dell’attributo converter del tag componente specificando l’ID del convertitore.

Questa forma:
<h:outputText value="#{miobean.miadata}" converter="javax.faces.DateTime"/>
è del tutto equivalente alla seguente:
<h:inputText value="#{miobean.miadata}">
  <f:convertDateTime/>
</h:inputText>
Infine è possibile fare uso del tag f:converter specificando l’id del convertitore (definito nel file di configurazione dell’applicazione) mediande l’attributo converterID:
<h:inputText value="#{miobean.miadata}">
  <f:convert converterID="javax.faces.DateTime" />
</h:inputText>
Oppure referenziando la proprietà di un bean che deve essere dello stesso tipo del convertitore mediante l’attributo binding:
<h:inputText value="#{miobean.miadata}">
  <f:convert binding="#{miobean.mioconverter}" />
</h:inputText>
Tutte le implementazioni JavaServer Faces devono fornire i seguenti convertitori standard:
  • javax.faces.DateTime
  • javax.faces.Number
  • javax.faces.Boolean, javax.faces.Byte, javax.faces.Character, javax.faces.Double, javax.faces.Float, javax.faces.Integer, javax.faces.Long, javax.faces.Short
  • javax.faces.BigDecimal, javax.faces.BigInteger

Errori di conversione

Quando si verifica un errore in fase di conversione dei dati dei componenti, viene prodotto un messaggio di errore e dopo la fase di Validation Process, la pagina corrente viene ricaricata.
Per mostrare i messaggi di errore, siano questi errori di conversione o di validazione, si fa uso del tag h:message.
<h:inputText  value="#{miobean.miaproprieta}"/>
<h:message for="miaproprieta"/>
Un messaggio di errore è costituito da due parti: un sommario e un dettaglio che possono essere visualizzati mediante gli attributi showSummary e showDetail
<h:message for="amount" showSummary="true" showDetail="false"/>
E’ possibile definire l’apparenza del messaggio di errore mediante gli attributi style e styleClass: il primo definisce inline lo stile CSS del messaggio, il secondo invece fa riferimento ad una classe CSS.
E’ possibile mostrare una lista di messaggi di errore per tutti i componenti facendo uso dell’elemento h:messages il quale di default mostra il dettaglio dei messaggi di errore e non il sommario.
<h:message layout="table"/>
L’attributo layout posto al valore "table" mostra i messaggi allineati verticalmente piuttosto che concatenati orizzontalmente.
E’ possibile modificare i messaggi di errore standard definendo un message-bundle nel file di configurazione dell’applicazione e associando all’appropriata chiave il messaggio, come nel seguente esempio:
javax.faces.component.UIInput.CONVERSION=Errore di conversione
<faces-config>
  <application>
    <message-bundle>miopackage.messaggi</message-bundle>
  </application>
   ...
</faces-config>
In questo caso l’errore di conversione su un UIInput produrrà il messaggio “Errore di conversione”.

Implementare convertitori personalizzati

Affinchè sia possibile implementare dei convertitori personalizzati è necessario implementare l’interfaccia Converter che presenta due metodi:
Object getAsObject(FacesContext context, UIComponent component, String newValue) 

String getAsString(FacesContext context, UIComponent component, Object value)
Il primo metodo viene invocato quando viene ricevuta una stringa dal client (fra i parametri della richiesta) e provvede ad effettuarne la conversione nel tipo di oggetto desiderato producendo una ConverterException se la conversione non può essere effettuata.
Il secondo metodo invece provvede a convertire un oggetto in una stringa che sarà successivamente visualizzata nell’interfaccia utente. Per poter utilizzare il convertitore è necessario associare un ID mediante il file di configurazione dell’applicazione:
<converter>
   <converter-id>id_convertitore</converter-id>
   <converter-class>miopackage.MioConverter</converter-class>
</converter>
E quindi fare riferimento a tale id nell’attributo converter del componenente di input:
<h:inputText value="#{miobean.miovalore}" converter="id_convertitore"/>
Alternativamente è possibile, sempre attraverso l’attributo converter del tag componente, fare riferimento alla proprietà di un backing bean di tipo Converter:
<h:inputText value="#{miobean.miovalore}" converter="#{miobean2.mioconverter}"/>
Il vantaggio in quest’ultimo caso è rappresentato dalla possibilità di accedere ai dati privati del bean.
public class BackingBean 
{
  Converter mioconverter;

  public Converter getMioconverter() 
  {

    return new Converter() 
    {
      public Object getAsObject(FacesContext context, UIComponent component,String newValue) throws ConverterException 
      { 
        ... 
      }

      public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException 
      { 
        ... 
      }
    };

  }
}
E’ possibile infine definire nel file di configurazione un convertitore di default mediante l’elemento converter-for-class
<converter>
  <converter-for-class>miopackage.mia_classe</converter-for-class>
  <converter-class>miopackage.mio_convertitore</converter-class>
</converter>
A questo punto se l’attributo value è collegato ad una proprietà di un bean di tipo miopackage.mia_classe il convertitore miopackage.mio_convertitore verrà applicato automaticamente.

Messaggi di errore

Quando un convertitore non è in grado di effettuare la conversione deve produrre una ConverterException passando come argomento il corrispondente messaggio che deve essere visualizzato sulla pagina.
if (condizione_errore) 
{
  FacesMessage message = new FacesMessage("Errore di conversione", "Dettaglio dell'errore");
  message.setSeverity(FacesMessage.SEVERITY_ERROR);
  throw new ConverterException(message);
}
La classe FacesMessage rappresenta un messaggio di errore e contiene al suo interno il sommario e il dettaglio del messaggio.

Implementare tag personalizzati

Una volta creata la classe che implementa l’interfaccia Converter può essere utile definire un tag personalizzato che consenta di utilizzare tale convertitore all’interno di un tag componente in una data pagina.

Per definire un tag personalizzato per un convertitore occorre:
  • definire un Tag Library Descriptor, ovvero un file xml che contiene la descrizione del tag che si vuole definire
    <?xml version="1.0" encoding="ISO-8859-1" ?>
      <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
    <taglib>
      <tlib-version>1.0</tlib-version>
      <jsp-version>1.2</jsp-version>
      <uri>http://giuseppesicari.it/mioconverter</uri>
      <tag>
        <name>mioconverter</name>
        <tag-class>miopackage.GestoreTagConverter</tag-class>
        <attribute>
          <name>mioattributo</name>
        </attribute>
      </tag>
    </taglib>
    
    dove tlib-versione e jsp-version indicano le versioni della tag library e di JavaServer Pages, uri identifica univocamente la tag library e tag definisce il tag personalizzato.
    L'elemento tag deve contenere il nome del tag (name) il riferimento al gestore del tag (tag-class) e opzionalmente degli attributi (attribute).
  • implementare una classe tag handler che si occupi di:
    • specificare la classe convertitore (che estende l’interfaccia Converter)
    • raccogliere gli attributi del tag
    • configurare l’oggetto convertitore tramite tali attributi
Nel caso di un convertitore il tag handler deve essere una sottoclasse di ConverterTag e deve specificare un metodo set per ogni attributo del tag:
public class GestoreTagConverter extends ConverterTag 
{
  private String mioattributo;
  public void setMioattributo(String valore) 
  {
    mioattributo = valore;
  }

  ...

}
Il tag handler deve inoltre configurare l’oggetto convertitore definendo ad esempio l’id (definito nel file di configurazione dell’applicazione) all’interno del tag handler come nel seguente esempio:
public GestoreTagConverter() 
{
  setConverterId("id_convertitore");
}
Per configurare l’oggetto convertitore occorre sovrascrivere il metodo createConverter del tag handler invocando, come prima operazione, il metodo createConverter della super-class e quindi settandone le proprietà:
public Converter createConverter() throws JspException 
{
  MioConverter converter = (MioConverter) super.createConverter();
  converter.setMioattributo(eval(mioattributo));

  return converter;
}
A questo punto occorre definire il metodo eval per la valutazione dell’attributo value nel tag componente:
public static String eval(String expression) 
{
  if (expression != null && UIComponentTag.isValueReference(expression)) 
  {
    FacesContext context = FacesContext.getCurrentInstance();
    Application app = context.getApplication();
    return "" + app.createValueBinding(expression).getValue(context);
  }

  else return expression;
}
e il metodo release che effettua un reset degli attributi del tag handler:
public void release()
{
  mioattributo=null;
}
Naturalmente per fare riferimento al tag personalizzato all’interno della pagina occorre utilizzare la direttiva taglib:
<%@ taglib uri="http://coreJSF.com/converter3" prefix="mioprefisso" %>
Quindi sarà possibile scrivere:
<h:outputText value="#{miobean.valore}">
  <mioprefisso:mioconverter mioattributo="miovalore"/>
</h:outputText>
In generale l’implementazione di un tag personalizzato deriva dalla necessità di poter configurare i parametri del convertitore mediante attributi del tag.
Dal momento che l’implementazione di un tag personalizzato comporta una procedura particolarmente onerosa, è possibile ricorrere ad una procedura alternativa.
Tale procedura prevede l’indicazione del convertitore da utilizzare attraversoil tag f:converter innestato all’interno del tag componente e l’utilizzo del tag f:attribute per specificare gli attributi del validatore mediante attributi del componente:
<h:outputText value="#{miobean.valore}">
  <f:converter converterID="id_convertitore" />
  <f:attribute name="mioattributo" value="miovalore"/>
</h:outputText>
Tali attributi possono essere successivamente recuperati nel seguente modo
separator = (String) component.getAttributes().get("separator");