Utilizzo di CDI in JSF 2.0

Introduzione

In questo post trattiamo l’integrazione di tre tecnologie che sono parte della specifica J2EE 6, ovvero:

  1. CDI Contexts and Dependency Injection (JSR-299);
  2. Dependency Injection For Java (JSR-330);
  3. JavaServer Faces 2.0 (JSR-314).

Iniziamo con fare un po’ di chiarezza tra le due specifiche JSR-299 e JSR-330. Quest’ultima fornisce una specifica per l’implementazione della Dependency Injection attraverso annotation. E’ molto basilare e definisce un certo numero di annotazioni standard contenute nel package javax.inject, nel quale troviamo i seguenti elementi: Inject, Qualifier, Scope, Singleton, Named e Provider. Elementi che sono alla base della definizione del significato di dependency injection. La specifica JSR-299 invece, utilizza i concetti della JSR-330 estendendola con i concetti di modularità, decorator, interceptor, custom scopes, etc. Volendo fare un paragone, la relazione tra tali specifiche è simile a quella esistente tra JPA e JDBC. JPA utilizza JDBC internamente, ma l’utente è ancora in grado di utilizzare JDBC senza JPA. Non c’è quindi una sovrapposizione tra le due specifiche.

CDI (Contexts and Dependency Injection)

La specifica JSR-299 fornisce un’architettura che consente a componenti standard di J2EE, come servlet ed EJB, di esistere all’interno del ciclo di vita di una applicazione enterprise con uno scope ben preciso. Inoltre, CDI fornisce servizi che consentono a EJB session bean e JSF managed bean, di essere iniettati e di interagire in modo scarsamente accoppiato, attraverso l’utilizzo di un modello ad eventi. Più semplicemente CDI unifica e semplifica i modelli di programmazione EJB e JSF, consentendo agli enterprise bean di agire come managed bean in una applicazione JSF. Inoltre, attraverso i suoi servizi, CDI porta il supporto transazionale al livello web, rendendo molto più semplice l’accesso alle risorse transazionali in applicazioni di questo tipo. Ad esempio, con CDI è immediato costruire una applicazione web Java EE che accede a un database con la persistenza fornito dal Java Persistence API.

In realtà, il concetto di managed bean va quindi oltre la specifica CDI. I managed bean, introdotti in Java EE 6, sono stati progettato per unificare tutti i vari tipi di bean in Java EE, tra cui JSF managed bean, enterprise bean, e CDI bean. Un managed bean non è altro che una classe Java che viene trattato come un componente gestito dal container Java EE. Opzionalmente, è possibile dargli un nome nello stesso spazio dei nomi utilizzato dai componenti EJB. Un managed bean può quindi contare su un piccolo numero di servizi forniti dal container, per lo più legate alla gestione del ciclo di vita e l’iniezione di risorse. Altre tecnologie Java EE come il JSF, EJB, e CDI sono costruire su questa definizione di base di un managed bean con l’aggiunta di specifici servizi. Così, per esempio, un managed bean JSF aggiunge lo scope al ciclo di vita del componente, un session bean EJB aggiunge servizi come il supporto per le transazioni, e un CDI bean aggiunge servizi come l’iniezione di dipendenza.

Una Applicazione di Esempio

Torniamo al progetto jsf-employees descritto nel post Creare Web App con JSF 2.0 e completiamolo con i service necessari alla ricerca degli impiegati (similmente a quanto visto in Create Web App con Bootstrap basato però su servlet e non su JSF).

Innanzitutto aggiorniamo le dipendenze del progetto considerando che gli Application Server conformi alla specifica J2EE includono al loro interno una implementazione di CDI. Ad esempio WildFly, JBoss EAP, GlassFish, IBM WebSphere Application Server (dalla 8.5.5 in poi) ed Oracle WebLogic utilizzano JBoss Weld, l’implementazione di riferimento di CDI. Diversamente nei Servlet Container come Apache TomCat and Eclipse Jetty, CDI no è incluso e deve quindi essere fornito dal progetto.

Nel nostro esempio ho utilizzato WildFly 8, quindi inseriamo nel pom.xml la dipendenza a Weld:

si noti che lo scope della dipendenza è provided come ci aspettavamo. Per completare la configurazione è obbligatoria la presenza nel progetto del file beans.xml, anche completamente vuoto (ha contenuto solo in alcune situazioni limitate). Per una applicazione web, tale file deve essere collocato nella directory WEB-INF, mentre per i moduli EJB o file JAR, il file deve essere collocato nella directory META-INF.

Si noti in particolare l’attributo bean-discovery-mode utilizzato dallo scanner per implementare la strategia di riconoscimento dei CDI managed bean. In particolare il valore annotated indica di identificazione è basata sull’uso delle annotazioni (@Named in particolare).

Completata la configurazione creiamo il servizio di recupero dei dipendenti per la nostra applicazione implementandolo come managed bean. Non utilizziamo una base dati quindi il servizio utilizza semplicemente una lista popolata a priori con un insieme di nominativi.

Ciò che rende tale classe un CDI managed bean è l’annotazione @Dependant. Durante la fase di inizializzazione dell’applicazione CDI esegue uno scan alla ricerca di tutti i bean annotati con una bean defining annotation. Al nostro servizio è quindi associato un nome di default che sarà employeeService ma che può essere modificato utilizzando l’annotazione @Named.

Proseguiamo definendo il JSF managed bean che sarà responsabile dell’interazione con la maschera di ricerca.

L’iniezione del bean EmployeeService avviene annotando la proprietà employeeName con @Inject. Si noti che non vi è necessità di creare i getter ed i setter per tali proprietà. Il metodo search rappresenta l’action invocata dall’interfaccia per eseguire la ricerca. Esso restituisce null indicando a JSF di ricaricare la stessa pagina da cui è stato invocato.

Infine vediamo la maschera di ricerca contenuta nel file index.hxtml:

L’interfaccia utilizza tutti componenti standard di JSF ed in particolare il dataTable che itera su una lista per creare una tabella HTML. La connessione tra interfaccia e bean avviene attraverso espressioni EL (Expression Language) le quali referenziano il managed bean recuperandolo dallo specifico contesto.

Se tutto è andato nel modo giusto avviando WildFly e aprendo la pagina http://localhost:8080/jsf-employees/ dovrebbe comparire:

jsf cdi ricerca

Download Codice Sorgente

Il progetto completo è disponibile qui jsf-employees.