Introduzione

La conversione e la validazione dei dati di interfaccia sono due problemi tipici nello sviluppo di una applicazione web. I dati inseriti in un form di una pagina HTML vengono inviati al server sotto forma di stringhe. Ma è chiaro che non tutti i dati nel dominio di un determinato problema sono rappresentabili da stringhe; in qualsiasi applicazione si ha a che fare con numeri, date, percentuali e così via. Questo comporta che è necessario effettuare una trasformazione del dato dalla sua digitazione da parte dell'utente nella pagina web al suo utilizzo in oggetti di business che rappresentano le entità del nostro sistema. È necessario quindi effettuare in genere una conversione del dato originario in un dato tipizzato che ha significato nel contesto di utilizzo. Allo stesso modo quando il valore di un oggetto deve essere visualizzato è necessario darne una rappresentazione sotto forma di stringa per poterlo presentare all'utente nell'interfaccia utente. È altresì importante che tutti i dati che arrivano al layer applicativo dal layer di interfaccia siano validi. Ovvero siano sottoposti ad un controllo formale prima di essere utilizzati per valorizzare gli attributi di oggetti di business. I tipi di validazione sono quelli tipici di una applicazione e hanno lo scopo di verificare che il dato inserito sia conforme alle regole che abbiamo stabilito per il nostro contesto applicativo: un dato obbligatorio deve necessariamente essere digitato, una data deve necessariamente avere un certo formato stabilito e così via. Ogni framework degno di questo nome deve mettere a disposizione dello sviluppatore strumenti che assolvono a questi due importanti compiti e che lo svincolino da scrivere codice ripetitivo e a scarso valore aggiunto. JSF mette a disposizione convertitori e validatori che assolvono al problema descritto. Abbiamo già discusso in [6] in quale momento del ciclo di vita di una richiesta JSF avvengono queste operazioni. Vediamo ora come si utilizzano convertitori e validatori nelle applicazioni,

Convertitori

Ogni giorno ciascuno di noi visualizza pagine web e invia ai server web dati digitati nei form delle pagine stesse. Chi non ha mai riempito un form di registrazione a un qualche servizio? Affinché una applicazione possa mostrare i dati ad un utente questi devono essere necessariamente convertiti in stringhe e l'utente li digiterà nell'interfaccia utente come stringhe. Ma nel dominio applicativo questi dati saranno rappresentati da oggetti con un tipo opportuno alla loro rappresentazione: un oggetto cha rappresenta una data, un numero e così via. I convertitori hanno proprio la funzione di creare una rappresentazione in forma di stringa di un oggetto e di creare un oggetto dalla rappresentazione in stringa del dato da questo rappresentato. JSF fornisce una serie di converters standard che coprono l'esigenza della conversione per tutti i tipi base del linguaggio Java quali Byte, Character, Integer, Short, Double, Float, Long BigDecimal, BigInteger, Boolean Character. Questo significa che se associo a un campo di input del mio form un attributo di un managed-bean di tipo Integer, sarà il framework a effettuare l'opportuna trasformazione della stringa digitata nel tipo desiderato. Analogamente il framework si occupa di fornire la rappresentazione sotto forma di stringa dell'attributo quando questo debba essere visualizzato nell'interfaccia utente. Il framework si occuperà anche di inviare all'utente un opportuno messaggio di errore qualora la conversione non sia possibile in base a quanto digitato dall'utente nell'interfaccia, Tutto ciò può sembrare quasi ovvio e banale ma chi ha sviluppato applicazioni web utilizzando Servlet e JSP senza l'ausilio di alcun framework sa quanto sia tedioso e a rischio di errori questo compito. Oltre ai converters standard, JSF dà allo sviluppatore la possibilità di costruire convertitori custom in base alle singole esigenze. Tipicamente i convertitori devono essere registrati sui componenti: è possibile farlo a livello di codice Java ma più comunemente lo si fa nella pagina JSP in diversi modi. Un modo è quello di utilizzare l'attributo converter dei tag JSF che lo prevedono, tipicamente componenti di input o di visualizzazione dati. In questo modo è possibile associare un convertitore a un campo di input dichiarando nell'attributo il suo identificatore. Ad esempio:

<h:outputText value="#{utente.codiceAvvPostale}" converter="cap"/>

<h:outputText value="#{utente.codiceAvvPostale}"> <f:converter converterId="cap"/> </h:outputText>

<converter> <converter-id>cap</converter-id> <converter-class>it.mokabyte.converter.CapConverter</converter-class> </converter>

Un convertitore deve corrispondere ad una classe che implementa l'interfaccia javax.faces.convert.Converter che definisce i metodi

public Object getAsObject(FacesContext facesContext,UIComponent uIComponent, String string)

throws ConverterException;

public String getAsString(FacesContext facesContext,UIComponent uIComponent, Object object)

throws ConverterException;

per le conversioni da stringa a oggetto e da oggetto a stringa rispettivamente.

Oltre che per identificatore, i converter possono essere dichiarati anche per classe, quindi associati a uno specifico tipo di oggetto Java. La registrazione è necessaria solo per i convertitori custom mentre non è necessaria per i convertitori standard. I convertitori standard di JSF sono essenzialmente due: il DateTime per le date e il Number per numeri, valute e percentuali. I tag corrispondenti sono <f:convertDateTime/> e <f:convertNumber/>. Oltre che a dare una rappresentazione in forma di stringa degli oggetti a cui fanno riferimento sono molto utili per impostare il formato del dato digitato nella pagina, Nell'applicazione di esempio (che potete scaricare dal menu in alto a sinistra nello ZIP che contiene l'applicazione sia per JBoss che per Tomcat) è stato aggiunto un esempio di utilizzo del convertitore per le date. Nei riferimenti al termine dell'articolo, è poi possibile trovare numerosi esempi di utilizzo dei converter standard. <h:inputText value="#{ utente.codiceAvvPostale }"> <mokabyte:capConverter param1="valore1" param2="valore2"/> </h:inputText>

<h:inputText id="nome_utente" validator="#{utente.validaNomeUtente}"
value="#{utente.username}/>
Altrimenti è possibile registrare sui componenti validatori standard e/o custom analogamente a quanto già visto per i convertitori, ovvero innestando il custom tag del validatore all'interno del tag del componente oppure utilizzando il tag <f:validator> facendo riferimento in esso all'identificatore del validatore che si vuole utilizzare. JSF fornisce alcuni validator standard, DoubleRange, Length, LongRange i cui corrispondenti tag JSF sono <f:validate-DoubleRange>, <f:validate-Length>, <f:validate-LongRange> che consentono di valicare la lunghezza di un dato o il range di valori in cui esso deve essere compreso. Tutti i componenti di input hanno poi un attributo required che definisce l'obbligatorietà del dato da digitare se posto al valore true. Non è proprio un validatore ma ha lo stesso significato, ed unito ai validatori standard può soddisfare molte delle esigenze comuni. Se gli strumenti standard forniti da JSF non sono sufficienti per le nostre esigenze è comunque possibile realizzare un validatore custom. Un validatore custom deve essere registrato nel file di configurazione di JSF dichiarandone la classe come segue
<validator> <validator-id>codiceFiscale</validator-id> <validator-class>it.mokabyte.validator.CodiceFiscaleValidator</validator-class> </validator>

e associadogli un identificatore che potrà essere poi utilizzato per referenziare il validatore nell'applicazione. Un validatore deve corrispondere ad una classe che implementa l'interfaccia javax.faces.validator.Validator che definisce il metodo

public void validate(FacesContext context, UIComponent component,Object value)

throws ValidatorException;

nel quale inserire la logica di validazione desiderata.

Messaggi di errore

Le operazioni di conversione e validazione dei dati possono dar luogo a errori che devono essere opportunamente segnalati agli utenti. La gestione degli errori e della loro visualizzazione nell'interfaccia è gestita completamente da JSF mediante i componenti HtmlMessage e HtmlMessages. HtmlMessage visualizza un singolo messaggio di errore associato a un singolo componente. HtmlMessages invece consente di visualizzare tutta la lista di messaggi di errore che si possono essere verificati durante l'elaborazione della richiesta JSF.

Se ad esempio ho un form con numerosi campi, potrei pensare di associare ad ogni singolo campo di input il proprio messaggio di errore da visualizzare accanto ad esso. In questo caso posso utilizzare il componente HtmlMessage e il suo corrispondente tag come segue:

<h:inputText id="username" required="true">
  <f:validateLength minimum="0" maximum="6"/>
</h:inputText>
<h:message for="username" />

<h:inputText value="#{utente.username}" required="true" alt="nome utente" id="utente" title="utente" > <f:validateLength minimum="6" maximum="12"/> </h:inputText> <h:message for="utente" />

<h:inputText id="data" value="#{utente.data}" required="true">
	<f:convertDateTime pattern="dd/MM/yyyy"/>
</h:inputText>
<h:message for="data"/>