Tecniche di serializzazione degli oggetti in Java
Esaminiamo diverse tecniche di serializzazione degli oggetti in java. Quella standard proposta dalla sun e quelle alternative
Salvare il contenuto delle strutture dati su persistenza è un problema ricorrente, in tutti i linguaggi di programmazione. Una prima soluzione potrebbe essere quella manuale: un metodo dell’oggetto che salva, con un protocollo da noi scelto, i campi dati della classe su un file, attraverso le File API.
Dovremo quindi scrivere un metodo di scrittura e ovviamente di lettura per ogni oggetto.Questa soluzione è tutt’altro che veloce e conveniente. Molto più semplice è invece la soluzione proposta dalla Sun per mezzo dell’interfaccia java.io.Serializable
Tutte le classi che implementano questa interfaccia, possono essere salvate su persistenza attraverso un ObjectOutputStream e caricate con un ObjectInputStream
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public void salva (Object daSalvare) { try{ fos = new FileOutputStream ("oggetto.sav"); oos = new ObjectOutputStream(fos); oos.writeObject(daSalvare); oos.close(); } catch (Exception e){ System.out.println("Errore in salvataggio:"+e); } } public Object carica () { try{ fis = new FileInputStream ("oggetto.sav"); ois = new ObjectInputStream(fis); Object daCaricare = (TipoOggetto)(ois.readObject()); ois.close(); return daCaricare; } catch (Exception e){ System.out.println("Errore in caricamento:"+e); return null; } } |
Questa soluzione è veloce e poco dispendiosa (in termini di fatica). D’altra parte, il file è stato salvato in un formato binario compatibile solo con una applicazione java. Questo può essere poco conveniente se volessimo utilizzare i dati con un applicativo scritto in un altro linguaggio.
Molto meglio in questo caso, una serializzazione in xml, formato “franco” e facilmente parsabile. Per farlo, possiamo ricorrere a java.beans.XMLEncoder il cui utilizzo è altrettanto semplice:
1 2 3 4 |
XMLEncoder e = new XMLEncoder(new BufferedOutputStream( new FileOutputStream("Oggetto.xml"))); e.writeObject(daSalvare); e.close(); |
Il caricamento dell’oggetto è altrettanto semplice, attraverso java.beans.XMLDecoder.
Un pò più macchinosa, ma più performante e soprattutto più customizzabile la soluzione proposta da Javolution. Non analizzeremo tutti i dettagli, per i quali rimando al sito del progetto, mi limito a presentare un esempio:
1 2 3 4 5 6 7 8 9 10 |
public void format(Object obj, XmlElement xml) { Polygon polygon = (Polygon) obj; xml.getContent().addAll(polygon._vertices); } public Object parse(XmlElement xml) { Polygon polygon = (Polygon) xml.object(); polygon._vertices.addAll(xml.getContent()); return polygon; } |
In pratica si tratta di definire in ogni classe i metodi format e parse da utilizzare in salvataggio e caricamento
1 2 3 4 5 6 7 |
ObjectWriter ow = new ObjectWriter(); ByteBuffer bb = ByteBuffer.allocateDirect(XML_SIZE); ow.write(obj, bb); ObjectReader or = new ObjectReader(); ByteBuffer bb = ByteBuffer.allocateDirect(XML_SIZE); Object obj = or.read(bb); |
Qualsiasi soluzione scegliate, non dimenticate che potete utilizzare la serializzazione non solo per scrivere su file, ma anche per scambiare dati fra applicazioni, per esempio su socket:
1 2 3 4 5 6 7 8 9 |
ObjectWriter ow = new ObjectWriter(); ByteBuffer bb = ByteBuffer.allocateDirect(XML_SIZE); ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(PORT)); SocketChannel sc = ssc.accept(); // Waits for connections. ow.write(obj, bb); // Formats object into byte buffer. bb.flip(); sc.write(bb); // Sends byte buffer. bb.clear(); |