Cos’è JAX-B

Mi piacerebbe approfondire meglio il discorso su JAX-B che avevo lanciato nell’articolo web service RESTful in Java

Fondamentalmente con questa libreria possiamo far si che un web services, in questo caso RESTful, produca direttamente in uscita XML o JSON. Spingendoci oltre potremmo effettuare processi di marshalling.

In un certo senso l’annotation che si usa in JAX-B per produrre XML già trasforma un oggetto Java in un dato XML. L’inverso vale per i processi di unmarshlling. Cioè da un dato ricostruire un oggetto (Java) utilizzabile dalla jvm.

Possiamo spingerci a far servire dal nostro url qualcosa in più rispetto ad XML. Semplicemente implementando un metodo con un diverso Media-Type.

Ma vediamo le fondamenta dell’annotation JAX-B.

Proviamo a scrivere un nuovo bean java.

@XmlRootElement(name="accordodisettima")
public class AccordoSettima{
   private String tonica;
   private String modale;
   private String dominante;
   private String settima;

   @XmlElement;
   public String getTonica(){
      return this.tonica;
   }
   
   public void setTonica(String tonica) {
      this.tonica = tonica;
   }

   @XmlElement
   public String getModale() {
      return this.modale;
   }

   public void setModale(String modale) {
      this.modale = modale;
   }

   @XmlElement
   public String getDominante() {
      return this.dominante;
   }

   public void setDominante(String dominante) {
      this.dominante = dominante;
   }

   @XmlElement
   public String getSettima() {
      return this.settima;
   }

   public void setSettima(String settima) {
      this.settima = settima;
   }
}

Poi riprendiamo il web service RESTful in Java e aggiungiamo un nuovo metodo GET.


   @GET
   @Path("Cmaj7")
   @Produces("application/xml")
   public AccordoSettima getSettima(@QueryParam("settima") String settima){
      AccordoSettima accordo = new AccordoSettima();
      accordo.setTonica("Do");
      accordo.setModale("Mi");
      accordo.setDominante("Sol");
      accordo.setSettima(settima);
      return accordo;
   }

Puoi vedere che il metodo esposto ritorna direttamente un oggetto Java. Tramite l’annotation @Produces vincoliamo a produrre XML.
In più ho aggiunto un parametro di query al GET che permette all’utente di dichiarare direttamente la settima.

Portiamoci nel browser su
http://[servername]:[porta]/[nomeApplicazione]/wsrs/mybase/Cmaj7
vedremo la rappresentazione XML del nostro accordo.

Web Service RESTful in Java

Per scrivere un servizio RESTful in Java occorre avere innanzi tutto la voglia. E poi potete iniziare a cercare un framework che contenga javax.ws.rs.
javax.ws.rs come implementazione è fondamentale se si vuole realizzare un REST in Java.
Molto spesso la potete trovare nell’application server che utilizzate normalmente. Ma se utilizzate un servlet container come Tomcat avete bisogno di scovare sul web delle librerie (meglio un framework) che implementino JAX-RS.
Di base sono indispensabili le estensioni per configurare il vostro server come capace di istanziare una servlet che apra un base url sul cui costruire l’alberatura dei vostri servizi. Ultimamente non va più neanche dichiarata nel web.xml, ma basta utilizzare l’annotation.
In questo how-to però utilizzerò il web.xml in parte.
Poi un framework RESTful che si rispetti deve includere almeno JAX-B e Json. Questo permettere ai servizi in entrata come in uscita di parlare via XML o Json. Parte fondamentale se si vuole dare ad un WS-RESTful quello strato di “rappresentazione” nel momento di interscambio dati via HTTP. Difatti si parla di Representation State Transfer.

  1. Step 1
    inserire nel web.xml :

    <servlet>
       <servlet-name>MyRestfulApplication</servlet-name>
       <servlet-class>classe di implementazione RestServlet del vostro framwork</servlet-class>
       <init-param>
          <param-name>javax.ws.rs.Application</param-name>
          <param-value>it.er.MyWSRSApplication</param-value>
       </init-param>
       <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
       <servlet-name>MyRestfulApplication</servlet-name>
       <url-pattern>/wsrs/*<url-pattern>
    </servlet-mapping>
    
  2. Step 2
    Scrivere il servizio

    import javax.ws.rs.*;
    @Path("/mybase")
    public class MyBaseRestfulService{
    
       @GET
       @Path("hello")
       public String getHello(){
          return "Ciao mondo!!!";
       }
    }
    
  3. Step 3
    Creare la classe MyWSRSApplication.java che veniva richiamata nel web.xml

    import java.util.HashSet;
    import java.util.Set;
    import javax.ws.rs.core.Application;
    
    public class MyWSRSApplication extends Application{
    
       @Override
       public Set<Class<?>> getClasses() {
          Set<Class<?>> classes = new HashSet<Class<?>>();
          classes.add(MyBaseRestfulService.class);
          return classes;
       }
    }
    

Avvia il tuo server web java e recati all’indirizzo:
http://[servername]:[porta]/[nomeApplicazione]/wsrs/mybase/hello
Se tutto è andato per il verso giusto hai aperto un servizio sull’url …/wsrs/mybase/hello che utilizza il protocollo HTTP ed è esposto come GET. Quindi rispetto all’acronimo “CRUD” siamo in R. Read :)

Le classi nella OOP

La classe può essere vista come un calco attraverso il quale si possono creare più forme simili. Alcuni parlano anche di stampo per rendere l’idea. Il calco o lo stampo vengono usati per contesti diversi ma la loro funzione è la stessa. Creare delle forme simili.
Le forme di cui parliamo, nella programmazione orientata agli oggetti (OOP), non sono altro che delle istanze ed il calco è rappresentato dal vero e proprio codice sorgente scritto dallo sviluppatore.
La variabile istanziata con l’operatore new è un reference. Attraverso esso si ha accesso ai vari metodi e attributi caratteristici dell’oggetto presenti nelle singole e separate istanze.
Per capire meglio vediamo degli esempi in Java, PHP e Python

  1. Java
    public class Telefono{
       private String numero;
       public Telefono(String n){
          this.numero = n;
          System.out.print("New number...");
       } 
       public void chiama(){
          for (int j=0;j&amp;amp;amp;lt;this.numero.length();j++){
             System.out.print(this.numero.charAt(j));
          }
          System.out.println("I m calling");
          System.out.println("Attention!!! No line :D");
       }
    
       public static void main(String[] args){
          if ((args[0] != null && args[0].length() != 0) && (args[1] != null && args[1].length() != 0)){
             Telefono x = new Telefono(args[0]);
             x.chiama();
             Telefono y = new Telefono(args[1]);
             y.chiama();
          } else {
             System.out.println("Insert two number when run this class");
          }
       }
    }
    
  2. PHP
    class Telefono {
       private $numero;
       function __construct($n){
          $this->numero = str_split($n);
          print "\nNew number\n";
       }
      
       function chiama(){
          for ($j=0;$j<sizeof($this->numero);$j++){
             sleep(1);
             print $this->numero[$j];
          }
          print "\nI m calling...";
          sleep(3);
          print "\nAttention!!! No line :D\n";
       }
    
       if (isset($argv[1]) and isset($argv[2])){
          $x = new Telefono($argv[1]);
          $x->chiama();
          $y = new Telefono($argv[2]);
          $y-&amp;amp;amp;gt;chiama();
       } else {
          print "Insert two number when you run this script\n";
       }
    }
  3. Python
    import sys
    import time
    
    class Telefono:
    def __init__(self, numero):
       self.numero = numero
       def chiama(self):
          for n in self.numero:
             print(n,end='')
             print("\nI m calling...",end='\n')
             time.sleep(3)
             print("Attention!!! No line :D",end='\n')
    
    if __name__ == '__main__':
       len(sys.argv) > 2:
          x = Telefono(sys.argv[1])
          x.chiama()
          y = Telefono(sys.argv[2])
          y.chiama()
    else:
       print("Insert two number when you run script",end='\n')
    

In questi tre esempi come reference abbiamo sia la x che la y. Questi danno accesso al metodo “chiama” dell’oggetto Telefono.
Come potete vedere, se eseguite gli scripts, partono due chiamate distinte con numeri diversi che rappresentano le due istanze dell’oggetto telefono. (la simulazione con il metodo sleep aiuta la visualizzazione, ma ho preferito non inserirla in Java altrimenti avrei dovuto appesantire il codice con eccezioni e Threads).Quindi la classe è una. Ma abbiamo creato, in questo caso, due forme simili e con attributi e metodi indipendenti.

Post scriptum: Tra l’altro riprendendo la funzione chiama in Python c’è una differenza rispetto a quella in PHP. Usando Python3 sembra ci sia un’anomalia se inserisco sleep dopo l’istruzione print. Vediamo:

def chiama(self):
   for n in self.numero:
      print(n,end='')
      time.sleep(1)
      print("\nI m calling...",end='\n')
      time.sleep(3)
      print("Attention!!! No line :D",end='\n')

Se si esegue lo script ora il ciclo for visualizza (con print(n,end=”)) il numero tutto alla fine. Strano! Sembra un bug! Il comportamento aspettato sarebbe printare le cifre una alla volta.

Infatti se si usa una normale print(n) vedremo il comportamento aspettato. Solo che la keyword di default per print in python3 è end=’\n’. Quindi vedremo le cifre andare a capo sul terminale.
Con l’uso della keyword insieme a sleep l’output di print resta in qualche modo nel buffer fino alla fine del ciclo. Basta inserire un sys.stdout.flush