Serializzazione in gerarchie di classi

Abbiamo già parlato più volte dell’interfaccia Java Serializable e di quanto è importante utilizzarla correttamente in application server J2EE in cluster (vedi Sviluppare Applicazioni Java Web Cluster Aware, Parte I e Parte II). In quest post vediamo un comportamento abbastanza peculiare e poco documentato che avviene quando implementiamo questa interfaccia in una gerarchia di classi.

Usiamo un semplice esempio per spiegare meglio questa caratteristica. Scriviamo una classe Java (con molta originalità chiamata Base) con un solo campo id e i corrispondenti getter e setter:

public class Base {
	private int id;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
}

Creiamo un’altra classe che estende la classe Base (con altrettanta originalità chiamata Figlia) aggiungendo un campo nome:

public class Figlia extends Base implements Serializable {
	private String nome;

	public void setNome(String nome) {
		this.nome = nome;
	}

	public String getNome() {
		return nome;
	}
}

Scriviamo un blocco di codice di prova per serializzare (usando un ObjectOutputStream) e deserializzare (usando un ObjectInputStream) un oggetto:

Figlia f = new Figlia();
f.setId(123);
f.setNome("ABC");

System.out.println(f.getId() + " " + f.getNome());

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(f);
out.close();

ObjectInputStream in = new ObjectInputStream(
	new ByteArrayInputStream(bos.toByteArray()));
f = (Figlia) in.readObject();
in.close();

System.out.println(f.getId() + " " + f.getNome());

Eseguiamo questo codice ed ecco uscire la sorpresa come da un uovo pasquale: invece di vedere stampato nella console due volte 123 ABC vediamo che il secondo println stampa 0 ABC!
I più attenti si saranno accorti che solo la classe Figlia implementa Serializable, di conseguenza solo il campo della classe Figlia viene serializzato e deserializzato. Questo comportamento è abbastanza bizzarro, mi sarei aspettato un errore di serializzazione oppure una serializzazione anche dei campi della classe Base, ma non una via di mezzo come effettivamente avviene!
L’esempio presentato può sembrare un po’ “fuori dal mondo”, ma purtroppo ne parlo perchè era alla base di un bug stranissimo che mi è capitato su Folder Organizer, una applicazione Android che ho sviluppato. L’implementazione di Serializable non era prevista dall’inizio ma l’ho aggiunta in un secondo momento non facendo caso al fatto che estendesse un’altra classe. Per complicare ancora di più le cose il bug non era facilmente riproducibile in quanto la serializzazione e deserializzazione dell’oggetto avveniva solo se l’applicazione veniva terminata dal sistema per mancanza di memoria disponibile.

La morale di questo breve post è che bisogna porre molta attenzione quando si implementa l’interfaccia Serializable, sia in ambito di applicazioni J2EE in cluster che anche in ambito Android. Gli errori dovuti a un uso non corretto sono spesso imprevedibili e difficili da capire.

Fabio Collini

Software Architect con esperienza su piattaforma J2EE e attualmente focalizzato principalmente in progetti di sviluppo di applicazioni Android. Attualmente sono nel team Android di Cynny, ci stiamo occupando dello sviluppo dell'app Morphcast. Coautore della seconda edizione di Android Programmazione Avanzata e docente di corsi di sviluppo su piattaforma Android. Follow me on Twitter - LinkedIn profile - Google+