CodeGym /Corsi /JAVA 25 SELF /Formati standard di serializzazione: binario, testuale

Formati standard di serializzazione: binario, testuale

JAVA 25 SELF
Livello 42 , Lezione 2
Disponibile

1. Serializzazione binaria in Java

La serializzazione binaria è il meccanismo standard di Java con cui un oggetto viene trasformato in un flusso di byte nel modo più compatto e veloce possibile. Per questo si usano le classi ObjectOutputStream e ObjectInputStream. Il file risultante è un insieme di byte che non è pensato per essere letto da esseri umani.

Si chiama binaria perché tutto viene serializzato in forma «grezza»: numeri, stringhe, array, persino i riferimenti tra oggetti diventano byte. È come una valigia ben stipata: efficiente e veloce, ma senza istruzioni non è evidente dove sia cosa.

Come funziona in Java?

Supponiamo di avere una classe User:

import java.io.Serializable;

public class User implements Serializable {
    private String name;
    private int age;

    // Costruttore, getter e setter
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }
}

Serializzazione in file binario

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

User user = new User("Vasya", 30);

try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.bin"))) {
    out.writeObject(user);
    System.out.println("Oggetto User serializzato nel file user.bin");
} catch (Exception e) {
    e.printStackTrace();
}

Deserializzazione da file binario

import java.io.FileInputStream;
import java.io.ObjectInputStream;

try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.bin"))) {
    User loadedUser = (User) in.readObject();
    System.out.println("Letto dal file: " + loadedUser.getName() + ", " + loadedUser.getAge());
} catch (Exception e) {
    e.printStackTrace();
}

Attenzione: se aprite il file user.bin in un editor di testo, vedrete qualcosa come: ¬í sr ... — è normale, è proprio così che deve essere!

Vantaggi della serializzazione binaria

  • Compattezza e velocità. Salvataggio e lettura sono il più possibile rapidi, senza «fronzoli» superflui.
  • Vengono salvati tutti i campi dell’oggetto, inclusi gli oggetti annidati (se anche loro sono serializzabili tramite Serializable).
  • Semplice da usare per cache interne o per lo scambio tra programmi Java.

Svantaggi

  • Illeggibilità. Una persona non potrà «sbirciare» il contenuto e capirne il significato.
  • Forte dipendenza dalla versione della classe. Cambiare la struttura (aggiunta/rimozione di campi) può «rompere» la lettura dei file più vecchi.
  • Problemi di compatibilità tra diverse versioni di Java e JVM.
  • Non adatto allo scambio con altri linguaggi di programmazione.
  • Sicurezza: la deserializzazione di dati da fonti non verificate è una via diretta alle vulnerabilità.

2. Formati di serializzazione testuali: JSON, XML e altri

La serializzazione binaria è ottima per l’uso interno, ma spesso serve trasferire dati tra diversi linguaggi (Java, JavaScript, Python) o conservarli in forma leggibile — comodo per configurazioni, log, API. A questo scopo si usano formati testuali: JSON, XML, YAML, CSV ecc.

JSON — il più popolare

JSON (JavaScript Object Notation) è un formato compatto e leggibile. Esempio di oggetto User serializzato:

{
  "name": "Vasya",
  "age": 30
}

In Java per lavorare con JSON si usano spesso librerie come: Jackson (la più diffusa), Gson, nonché Moshi, JSON-B ecc.

XML — il vecchio amico del programmatore

XML (Extensible Markup Language) è più «verboso», ma formale e rigoroso.

<User>
  <name>Vasya</name>
  <age>30</age>
</User>

Per XML in Java si utilizza spesso la libreria standard JAXB (o la più datata XStream).

YAML, CSV e altri

  • YAML — simile a JSON, ma più conciso; più spesso usato per configurazioni che per la serializzazione di oggetti complessi.
  • CSV — valido per tabelle «piatte», ma poco adatto a strutture annidate.
  • Esistono formati per tutti i gusti, ma in Java si usano più spesso JSON e XML.

3. Confronto dei formati: quando usare cosa?

Formato Leggibilità Compattezza Velocità Compatibilità Quando usarlo
Binario No ++ ++ Solo Java Cache interna, salvataggio rapido tra JVM
JSON + + Qualsiasi linguaggio REST API, integrazione con servizi esterni, config
XML - - Qualsiasi linguaggio Integrazione, schemi rigorosi, sistemi legacy
  • Binario — sceglietelo per uso interno, quando non è necessario lo scambio con sistemi esterni e serve la massima performance.
  • JSON — la scelta migliore per lo scambio con applicazioni web, client mobile e REST API, nonché per la memorizzazione delle impostazioni.
  • XML — utile quando servono schemi rigorosi e per l’integrazione con soluzioni «enterprise».

Importante! La serializzazione binaria è adatta solo al trasferimento di dati tra programmi Java e, anche in questo caso, è più sicuro usarla tra programmi della stessa versione. I formati testuali come JSON e XML sono più universali: si prestano allo scambio di dati tra linguaggi e piattaforme diversi, rendendo le informazioni leggibili e portabili.

4. Pratica: serializzazione in formato binario e testuale

Serializzazione binaria (ObjectOutputStream/ObjectInputStream)

L’abbiamo già visto sopra, ma ripetiamo per fissare i concetti:

// Serializzazione
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.bin"))) {
    out.writeObject(user);
}

// Deserializzazione
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.bin"))) {
    User loadedUser = (User) in.readObject();
}

Serializzazione in JSON con Jackson (breve)

Per lavorare con Jackson bisogna aggiungere le sue librerie al progetto. Più avanti studieremo Maven e Gradle; per ora si possono aggiungere i file JAR manualmente. Esempio di dipendenza per Maven:

<!-- Maven -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.0</version>
</dependency>

Esempio di serializzazione/deserializzazione:

import com.fasterxml.jackson.databind.ObjectMapper;

User user = new User("Vasya", 30);
ObjectMapper mapper = new ObjectMapper();

try {
    // Serializzazione in stringa
    String json = mapper.writeValueAsString(user);
    System.out.println(json); // {"name":"Vasya","age":30}

    // Serializzazione in file
    mapper.writeValue(new File("user.json"), user);

    // Deserializzazione da stringa
    User loadedUser = mapper.readValue(json, User.class);

    // Deserializzazione da file
    User loadedFromFile = mapper.readValue(new File("user.json"), User.class);

} catch (Exception e) {
    e.printStackTrace();
}

Il file JSON può essere aperto in qualsiasi editor di testo, rendendo i dati facilmente leggibili e trasferibili tra applicazioni e linguaggi differenti.

5. Quando usare quale formato: consigli pratici

  • Cache interna, file temporanei, scrittura/lettura rapida tra programmi Java: usate la serializzazione binaria standard. Ma ricordate la compatibilità tra versioni!
  • Scambio con servizi esterni, memorizzazione delle impostazioni, integrazione con il frontend: usate JSON (Jackson, Gson).
  • Integrazione con sistemi «enterprise» dove è richiesto uno schema rigoroso: XML (JAXB).
  • Serve che una persona possa aprire e leggere il file: JSON o XML, non il formato binario.

6. Errori tipici nel lavoro con i formati di serializzazione

Errore n. 1: si tenta di serializzare un oggetto con campi non serializzabili. Se la vostra classe ha un campo che non implementa Serializable (ad esempio uno stream o una connessione al DB), la serializzazione binaria restituirà un errore. Per JSON non è così critico, ma anche con tipi «non standard» possono sorgere problemi.

Errore n. 2: si apre un file binario in un editor di testo e ci si spaventa. È normale! I file binari non sono destinati alla lettura da parte di persone.

Errore n. 3: si cambia la struttura della classe e i vecchi file binari smettono di essere letti. La serializzazione binaria è sensibile alle modifiche nella struttura della classe — spesso compare InvalidClassException. In JSON/XML è meno critico: i campi sconosciuti di solito vengono ignorati o ricevono valori predefiniti.

Errore n. 4: si usa la serializzazione binaria per lo scambio con sistemi esterni. Non funziona: il formato binario è compreso solo da Java, e per di più a parità di versione.

Errore n. 5: per JSON/XML ci si dimentica di aggiungere le annotazioni necessarie. Alcune librerie richiedono annotazioni come @JsonProperty, @XmlElement, altrimenti serializzazione/deserializzazione potrebbero non funzionare come previsto.

Errore n. 6: non si verifica che tutti gli oggetti annidati siano serializzabili. Per la serializzazione binaria è un problema frequente; per JSON può esserlo ugualmente se nel modello compaiono tipi complessi.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION