MokaByte Numero 07 - Aprile 1997
La serializzazione
 
di
Massimo Carli
 

 


 



Una delle principali novitàdel JDK1.1 è sicuramente rappresentata dalla serializzazione.
Inquesto articolo vedremo brevemente in cosa consiste e quali sono i vantaggiche abbiamo utilizzando questa tecnica molto semplice.


 

Che cosa é la serializzazione

L’utilizzo di questa tecnica permette di ovviare ad un inconveniente molto frequente nella programmazione di applicazioniche permettano la creazione e la editazione di una qualche struttura dati. Supponiamo di avere una applicazione che permette di creare ed editare una lista di oggetti. Una volta che questa struttura dati è stata creata vi è il problema di salvarne il contenuto per eventualmente,ripristinarlo in un secondo tempo.
Prima del JDK1.1 come si doveva fare? Bisognava decidere un certo protocollo di memorizzazione su un file. Sedovevamo salvare dei record di dati di struttura simile avevamo dei vantaggiin quanto scrivevamo sullo stream una struttura fissa in modo testo o altro. Ma le cose divenivano sempre più complicate se la struttura datiera un po’ più complessa. Se la struttura consisteva in un albero,oggetti legati tra loro da una relazione padre figlio, o liste bilatereo altro, il problema assumeva una certa dimensione. Bisognava implementare due enormi metodi di conversione della struttura in un qualcosa di sequenziale,salvarlo e poi ripristinarlo e ricostruire la struttura originaria. Con la serializzazione questo problema diventa una banalità.

 

Come si indica che un oggetto è serializzabile

In Java non è cosa rara incontrare delle interfacce che non presentano la dichiarazione di metodi. Esse servono semplicemente a segnare o firmare una determinata classe. Nel nostro caso la interfaccia che permette di stabilire che una classe è serializzabileè la java.io.Serializable. Se un oggetto implemental’interfaccia Serializable, esso è serializzabile cioè può essere salvato, o meglio reso persistente, e poi ripristinato. La cosa importante è che l’oggetto ripristinato abbia le stesse proprietà dell’oggetto salvato. Questo non è completamentevero in quanto vi è la possibilità di definire alcune proprietà come transient per cui ne viene salvata l’istanza ma in fase di ripristino i suoi campi assumono i loro valori di default.
Supponiamo di avere una classe di nome Struttura. Per renderla serializzabile basterà scrivere

 

publicclass Struttura extends Parent implements java.io.Serializable {
  ....................
  ...................
}
 

Parent è una ipotetica classe di cui Struttura è estensione (ovviamente può anche non esserci, è solo un esempio). Una cosa da dire assolutamente è che, per essere serializzabile, una classe deve utilizzare alsuo interno classi serializzabili. Se una variabile pubblica di Struttura non fosse serializzabile, essa non sarebbe effettivamente serializzabile. Il processo di serializzazione, infatti, è ricorsivo.
Con il JDK1.1esiste uno strumento che permette di verificare se un a classe è, oppure no, serializzabile. Questo si chiama serialver.
Chiamando questo programma con l’opzione -show apparirà una finestra nella quale metterete il nome completo della classe che volete esaminare. Se la classe è serializzabile apparirà un valore identificativo della classe stessa, altrimenti non apparirà nulla.
In questo modo potrete verificare le vostre classi. La cosa, a dire ilvero non funziona molto bene in quanto se provate a verificare se la classe java.awt.Image è serializzabile avete risposta positivamentre se poi provate a serializzarla avete un errore. Questo èun bug conosciuto della JDK1.1 che si estende, oltre che alla classe Image, anche ai TextComponent nella beta3. Mah! Evidentemente il serialver verifica se la classe implementa Serializable insieme a tuttele classi utilizzate e niente altro, senza verificarne il funzionamento.
 
 




Il numero che appare nel serialver non è altro che un identificativo della classe e della sua versione. Infatti,quando una struttura viene serializzata, può capitare che diverseistanze di una stessa siano scritte sullo stream. Nel caso in cui questoavvenga, la prima volta si scriverà la classe con tutte le sue informazionie successivamente si scriverà solamente l’identificativo della classecon i valori caratteristici dell’istanza. In questo modo si ottiene anche una buona compressione dei dati scritti.
Un’altra cosa da sottolineare è la gestione delle versioni diverse della stessa classe. Se si rende persistente una classe e la si ripristina bisognerà fare in modo che il fileclass della classe di cui si dispone in fase di ripristino non siaconsiderevolmente differente da quella a disposizione in fase di creazione. Per considerevolmente differente intendiamo che la interfaccia che mettea disposizione non sia diversa. In questo caso si avrebbe quella che èla eccezione della serializzazione cioè java.io.ObjectStreamException.

 

Come si rende un oggetto persistente

Ora che abbiamo brevemente descritto che cosaè la persistenza, vediamo come si può serializzare una classe.La cosa è molto semplice in quanto il JDK mette a disposizione quelliche sono gli strumenti essenziali alla serializzazione. Questi sono l’interfacciajava.io.Serializable e le due nuove classi java.io.ObjectInputStreamed java.io.ObjectOutputStream. Queste classi implementanole interfaccia java.io.ObjectInput ed java.io.ObjectOutputrispettivamente. Queste, a loro volta estendono le interfacce java.io.DataInpute java.io.DataOutput introducendo i metodi readObjecte writeObject. Attraverso questi due metodi è possibile primascrivere e poi rileggere e ricostruire un qualunque oggetto serializzabile.
Supponiamo di voler salvare su un file dinome restore.ser un oggetto che abbiamo creato in una qualche altraparte di una applicazione. Chiamiamo questo oggetto salvato. Scriviamo,allora, il metodo scrivi che permette il salvataggio dell’oggettoindicato sul file.
 

Public void scrivi () {
 try{
   fos = new FileOutputStream ("restore.ser");
   oos = new ObjectOutputStream(fos);
   oos.writeObject(salvato);
   oos.close();
 }
 catch (Ioexception ioe){
   System.out.println("Errore:"+ioe.toString());
 }// fine catch
}// fine metodo scrivi
 
Il metodo non fa altro che legare un ObjectOutputStreamad un FileOuputStream per poter scrivere sul file l’oggettoattraverso il metodo writeObject.
Nel caso di ripristino basterà scrivere il seguente metodo leggi.
 
Public void leggi () {
  try{
    fis = new FileInputStream ("restore.ser");
    ois = new ObjectInputStream(fis);
    salvato = (TipoSalvato)(ois.readObject());
    ois.close();
  }
  catch (Ioexception ioe){
    System.out.println("Errore:"+ioe.toString());
  }// fine catch
}// fine metodo leggi
 

 

Il metodo di lettura è molto semplice. L’unica cosa da considerare con attenzione riguarda l’operazione di cast da fare all’atto del readObject. Infatti essa ritorna un Objectper cui tale operazione si rende necessaria. Nel nostro caso abbiamo eseguitouna operazione di cast relativamente al tipo TipoSalvato,tipo realtivo all’oggetto salvato.

 

Conclusioni

In questo breve articolo abbiamo visto checosa è la serializzazione e come si rende persistente un oggetto. Questa tecnica è molto utile e permette di risolvere, in poche righedi codice, problemi che in precedenza portavano via molto tempo, relativamentealla memorizzazione e ricostruzione di strutture dati complesse. Ovviamente la serializzazione non solo quello descritto qui ma offre tecniche piùsofisticate per la gestione delle versioni relativamente alle conversionidi tipo tra versioni diverse di stesse classi. Magari approfondiremo questiargomenti in un successivo articolo.
 
 
 
  

 

MokaByte rivista web su Java

MokaByte ricerca nuovi collaboratori
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it