JBoss 7 e RESTEasy sempre più easy

Poco tempo fa abbiamo visto insieme un tutorial su RESTEasy e JBoss 6 e adesso scopro che con JBoss 7 (al momento 7.0.2) alcune cose sono cambiate, fortunatamente in meglio! Vediamole da vicino.

I contesti

Come nel post precedente, possiamo distinguere i servizi REST che risiedono in un modulo Web o in un modulo EJB: questa volta le differenze sono davvero minime, ma trattiamole ancora in due sezioni distinte per chiarezza.

La grande novità della nuova versione di RESTEasy sta nel fatto che è possibile creare un servizio REST in ben 3 modi, come riportato nella specifica JAR-RS 1.1, sezione 2.3.2 (sembra che l’abbia letta no? 😉 ). Il tutto ruota intorno alla nuova classe javax.ws.rs.core.Application, che serve per definire il path che farà da entrypoint alla nostra applicazione REST, creando una sorta di namespace. Vediamo nel dettaglio i tre modi:

javax.ws.rs.core.Application + @ApplicationPath
Come prima alternativa possiamo estendere la calsse Application e annotarla con @ApplicationPath come segue:
@ApplicationPath("/app")
public class MyRESTApp extends Application {

}

Questo significa che tutti gli URL REST della nostra applicazione saranno mappati su /myWebContextPath/app. I sotto-URL, come per esempio “/app/echo-service” seguiranno la stessa logica definita dall’annotazione @Path che abbiamo già incontrato. Da notare che nell’EAR deve esistere una ed una sola classe che estende Application. Volendo, questa classe può rimanere così com’è anche vuota!
javax.ws.rs.core.Application + web.xml
Rispetto alla versione precedente, invece che definire il mapping dell’applicazione con l’annotazione, lo definiamo tramite il web.xml
public class MyRESTApp extends Application {

}

<servlet-mapping>
   <servlet-name>
      it.cosenonjaviste.services.rest.MyRESTApp
   </servlet-name>
   <url-pattern>/app/*</url-pattern>
</servlet-mapping>
POJO + web.xml
Invece che legarsi alla classe Application, possiamo fare un semplice POJO e aggiungere il seguente mapping al web.xml

<servlet-mapping>
   <servlet-name>
      javax.ws.rs.core.Application
   </servlet-name>
   <url-pattern>/app/*</url-pattern>
</servlet-mapping>

Un po’ di pratica

Apprese le novità, vediamo come applicarle.

Servizio nel modulo Web

Per il modulo Web, l’approccio che preferisco è il POJO + web.xml, perché così possiamo creare classi indipendenti da REST e configurare il tutto con poche righe di XML. Possiamo quindi riprendere il servizio visto nel post su JBoss 6:

@Path(value="/service")
public class MyRESTService {
  
   @GET
   @Path(value="/echo/{message}")
   public String echo(@PathParam(value="message") String message) {
      return "Echo " + message;
   }
}

che, una volta mappata nel web.xml la classe Application come visto poco fa, risponderà all’URL del tipo

http://localhost:8080/JBossWebServiceProducerWeb/app/service/echo/sayonara

Se stiamo migrando quindi i servizi da JBoss 6 al 7, con questo approccio gli impatti lato server saranno pressoché nulli. Diversamente sarà il caso del client, perché in questo caso l’URL sarà diverso da prima… (c’è un /app/ in più!)

Servizio nel modulo EJB

Ovvero come un EJB mi diventa un servizio web! Ebbene si, la promessa di svincolare RESTEasy dal web.xml per gli EJB è stata mantenuta e in JBoss 7 vediamo i risultati! Se stiamo creando una applicazione che non prevede una interfaccia grafica, possiamo benissimo fare a meno del modulo Web e usare l’approccio javax.ws.rs.core.Application + @ApplicationPath. Vediamo come le annotazioni necessarie si distribuiscono tra l’interfaccia e l’implementazione dell’EJB.

@Local
@Path(value="/ejb")
public interface EchoEJBLocal {

     @GET
     @Path(value="/{text}")
     String echo(String textToEcho);
}

L’interfaccia conterrà le annotazioni tipiche del REST. Dobbiamo adesso prevedere che esista una ed una sola classe che estende Application. Questa potrebbe essere un qualsiasi POJO all’interno del modulo EJB

@ApplicationPath(value ="/app")
public class MyEJBApp extends Application {

}

oppure l’implementazione di EchoEJB stessa:

@Stateless
@ApplicationPath(value ="/app")
public class EchoEJB extends Application implements EchoEJBLocal {

      @Override
      public String echo(String textToEcho) {
      return "Echo " + textToEcho;
   }
}

Conclusioni

Anche se a prima vista sembra strano avere ben tre modi per istanziare un servizio REST, due di questi, almeno secondo me, sono quasi necessari se vogliamo mantenere la struttura dei nostri progetti “pulita” e le classi facilmente riusabili. A questo punto un dubbio potrebbe essere: “Che ci metto nella classe che estende Application, come nel caso di MyEJBApp”? Potrebbe essere sfruttata per esempio per mappare il percorso di root del servizio (@Path("/")) e dare qualche informazione sul servizio stesso.

Andrea Como

Sono un software engineer focalizzato nella progettazione e sviluppo di applicazioni web in Java. Presso OmniaGroup ricopro il ruolo di Tech Leader sulle tecnologie legate alla piattaforma Java EE 5 (come WebSphere 7.0, EJB3, JPA 1 (EclipseLink), JSF 1.2 (Mojarra) e RichFaces 3) e Java EE 6 con JBoss AS 7, in particolare di CDI, JAX-RS, nonché di EJB 3.1, JPA2, JSF2 e RichFaces 4. Al momento mi occupo di ECM, in particolar modo sulla customizzazione di Alfresco 4 e sulla sua installazione con tecnologie da devops come Vagrant e Chef. In passato ho lavorato con la piattaforma alternativa alla enterprise per lo sviluppo web: Java SE 6, Tomcat 6, Hibernate 3 e Spring 2.5. Nei ritagli di tempo sviluppo siti web in PHP e ASP. Per maggiori informazioni consulta il mio curriculum pubblico. Follow me on Twitter - LinkedIn profile - Google+