Deserializzazione: cos’è, processo di ripristino dei dati

Autore: IT Sectr Pubblicato: 2026-03-08 Tempo di lettura: 9 min

La deserializzazione è il processo di ripristino di un oggetto da un flusso di dati JSON, XML o Protobuf, essenziale per qualsiasi applicazione mobile che lavori con un’API remota. Secondo Apple Developer (2026), la gestione incorretta dei dati in entrata rimane una delle cause comuni di crash sui dispositivi. JSONDecoder su iOS e Gson su Android sono strumenti standard, ma ciascuno ha le proprie caratteristiche e limitazioni.

Punti chiave

  • Deserializzazione è il ripristino di un oggetto tipizzato da JSON, XML o Protobuf per l’uso nel codice.
  • Codable è il protocollo di Apple per la deserializzazione automatica in Swift con supporto per la generazione del codice.
  • Moshi è una libreria Android di Square con opzioni codegen e reflection per diversi scenari.
  • Type mismatch è l’errore più comune quando i tipi dei campi JSON e le proprietà del modello non corrispondono.
  • kotlinx.serialization è la soluzione ufficiale di JetBrains con generazione di codice sicura dal compilatore.

Cos’è la deserializzazione?

Deserializzazione è il processo di conversione di un flusso di byte o di un testo strutturato in un oggetto di un linguaggio di programmazione. Nello sviluppo mobile, questo processo si verifica ogni volta che un’applicazione riceve una risposta dal server: una stringa JSON si trasforma in un’istanza della classe User, Order o Product. La stabilità degli schermi che mostrano i dati all’utente dipende direttamente dalla correttezza della deserializzazione.

Differenza dalla serializzazione

La serializzazione e la deserializzazione sono processi mutuamente inversi, raramente simmetrici nella pratica. La serializzazione converte un oggetto in una stringa per l’invio al server, mentre la deserializzazione ripristina l’oggetto dalla stringa ricevuta. Il server può inviare un campo che non esiste nel modello del client, utilizzare un formato di data diverso o restituire null invece di un numero. Secondo Square Engineering (2025), l’asimmetria dei formati causa il 23% degli errori del livello di rete nelle applicazioni Android. Per ridurre il rischio, si utilizzano il versionamento dello schema e la specifica contrattuale rigorosa tramite OpenAPI.

Formati di dati per la deserializzazione

JSON rimane il formato più popolare per le API mobili grazie alla sua leggibilità umana e al supporto integrato. Protobuf di Google viene utilizzato nei sistemi ad alto carico — è da 3 a 6 volte più compatto di JSON e analizza più velocemente, ma richiede la generazione di codice da file .proto e non è leggibile senza strumenti. XML è meno comune nelle applicazioni mobili moderne, tuttavia viene utilizzato nei servizi SOAP dei sistemi aziendali e nei file di configurazione di Android. MessagePack è un formato binario simile a JSON nella struttura ma più compatto, popolare nei sistemi in tempo reale.

Come funziona la deserializzazione

Il processo di deserializzazione attraversa tre fasi. Innanzitutto, la tokenizzazione divide il testo grezzo in token: chiavi, stringhe, numeri e delimitatori. Poi, l’analisi sintattica verifica la correttezza della struttura — se le parentesi sono chiuse, se il tipo di virgolette è corretto, se il formato è conforme alla RFC 8259. La fase finale è il mapping sul modello a oggetti dell’applicazione, dove a ogni chiave JSON viene assegnata una proprietà della classe tenendo conto della strategia di denominazione.

Reflection vs Code generation

Due approcci al mapping sono emersi nello sviluppo mobile. Reflection (Gson, JSONSerialization) analizza la struttura della classe a runtime tramite Java Reflection API o Objective-C runtime — è flessibile e non richiede configurazione aggiuntiva, ma è più lento e consuma più memoria. Code generation (Moshi codegen, kotlinx.serialization, Codable) genera codice in fase di compilazione: più veloce, più sicuro dal punto di vista dei tipi e non espone la struttura interna tramite reflection. JetBrains e Square raccomandano la generazione di codice per le build di produzione — i guadagni di prestazioni raggiungono 2-4 volte nei benchmark di Google.

swift
struct User: Codable {
    let id: Int
    let name: String
    let email: String
    let createdAt: Date
}

let json = """
{
    "id": 42,
    "name": "Alice",
    "email": "alice@example.com",
    "created_at": "2026-06-01T12:00:00Z"
}
"""
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let user = try decoder.decode(User.self, from: data)

Esempio di deserializzazione JSON in un modello User in Swift. La strategia convertFromSnakeCase converte automaticamente le chiavi API in snake_case in proprietà del modello in camelCase — una pratica standard nei progetti iOS. Il parametro data sono i byte grezzi della risposta del server ottenuti tramite URLSession. La gestione degli errori tramite try consente di intercettare JSON malformato senza bloccare l’applicazione.

Il ruolo delle strategie di decodifica

JSONDecoder supporta quattro strategie di chiavi: useDefaultKeys (corrispondenza esatta), convertFromSnakeCase (snake_case → camelCase), custom (closure) e convertFromKebabCase (kebab-case → camelCase). Per le date, sono disponibili .iso8601, .secondsSince1970, .millisecondsSince1970 e un dateFormatter personalizzato. Scegliere la strategia giusta è il primo passo verso una deserializzazione robusta, prevenendo la maggior parte degli errori di disallineamento dei formati.

Deserializzazione su iOS

JSONDecoder è il meccanismo standard di deserializzazione nell’SDK iOS, che funziona con il protocollo Codable. JSONDecoder analizza automaticamente JSON in istanze di struct o class, supportando oggetti annidati, array e primitivi. Per la logica personalizzata, viene utilizzato il metodo init(from: Decoder) — consente di gestire formati non standard, campi mancanti in una vecchia versione dell’API o combinare più chiavi JSON in un’unica proprietà.

swift
struct Order: Decodable {
    let orderId: String
    let amount: Double
    let status: OrderStatus

    enum OrderStatus: String, Decodable {
        case pending, confirmed, shipped, cancelled
    }
}

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let order = try decoder.decode(Order.self, from: jsonData)

DateDecodingStrategy determina come JSONDecoder interpreta le stringhe di data. .iso8601 è il più utilizzato — il formato standard delle API REST. L’enum annidato OrderStatus viene decodificato automaticamente dai valori di stringa JSON. Questo evita numeri magici e rende il codice autodocumentante — lo stato dell’ordine ha sempre un insieme rigorosamente definito di valori.

Property Wrappers in Codable

Da Swift 4.2, Codable supporta i property wrappers per la deserializzazione personalizzata di singole proprietà. @DefaultValue è un wrapper popolare che imposta un valore predefinito se il campo è assente nel JSON. @LosslessString converte una stringa in un numero e viceversa. Ciò è particolarmente utile quando il server invia un id come stringa "123" ma il modello si aspetta un Int. I property wrappers riducono il codice boilerplate in init(from:) e rendono i modelli più puliti.

Deserializzazione su Android

Su Android, la scelta della libreria di deserializzazione dipende dalla lingua e dai requisiti del progetto. Gson di Google è l’opzione più comune, che funziona tramite reflection ma ha problemi di prestazioni con gerarchie complesse. Moshi di Square supporta sia reflection che code generation, consuma meno memoria e elabora risposte grandi più velocemente. kotlinx.serialization di JetBrains è una soluzione Kotlin nativa con integrazione nel compilatore che non utilizza affatto la reflection.

kotlin
@Serializable
data class User(
    @SerialName("user_id")
    val userId: Int,
    val name: String,
    val email: String,
    @SerialName("created_at")
    val createdAt: String
)

val json = Json { ignoreUnknownKeys = true }
val user = json.decodeFromString<User>(response)

@Serializable è un’annotazione del compilatore Kotlin che attiva la generazione di codice per la classe. Il parametro ignoreUnknownKeys previene i crash se il server invia un campo mancante nel modello. Per il mapping delle chiavi snake_case, si utilizza @SerialName — l’equivalente di convertFromSnakeCase da iOS. Secondo JetBrains (2026), la libreria supporta il multipiattaforma: la stessa classe Serializable funziona su Android, iOS (KMP) e Kotlin lato server.

Confronto tra Gson, Moshi e kotlinx.serialization

La scelta tra le librerie si riduce a un compromesso velocità-flessibilità. Gson è buono per prototipi e progetti Java — non richiede annotazioni e funziona immediatamente. Moshi occupa una posizione intermedia: codegen tramite @JsonClass(generateAdapter = true) offre una velocità vicina a kotlinx.serialization, mentre la modalità reflection offre la flessibilità di Gson. kotlinx.serialization è l’opzione più veloce per progetti Kotlin puri, ma richiede Kotlin 1.4+ e il plugin Kotlin Serialization in Gradle.

LibreriaMeccanismoVelocitàKMP
GsonReflectionBassaNo
MoshiReflection / CodegenMedia / AltaNo
kotlinx.serializationCodegen del compilatoreAlta

Errori tipici e loro prevenzione

Type mismatch è una situazione in cui JSON contiene un valore di un tipo ma il modello ne aspetta un altro. Il server ha inviato la stringa "42" invece di un numero, o il numero 1 invece di un booleano true. Su iOS, JSONDecoder lancerà DecodingError.typeMismatch per impostazione predefinita; su Android, Gson tenterà la conversione, mentre Moshi e kotlinx.serialization richiedono adattatori espliciti. La soluzione è utilizzare strategie lenient o deserializzatori personalizzati per campi specifici.

Campi mancanti e nullable

Quando il server non include un campo opzionale, il codice si blocca con un errore. I campi Optional in Swift e i tipi nullable in Kotlin risolvono il problema: se il campo è null o assente nel JSON, la proprietà riceve nil/null e l’applicazione continua a funzionare. Per i campi obbligatori, è opportuno verificarne la presenza a livello di client API prima della deserializzazione. Moshi e kotlinx.serialization richiedono tutti i campi per impostazione predefinita — la marcatura nullable e i valori predefiniti rimuovono questa restrizione.

Incompatibilità delle versioni API

Le modifiche alla struttura JSON sul server sono una fonte comune di crash in produzione. La pratica standard è il versionamento dello schema tramite un campo version nell’oggetto radice e il supporto di 2-3 versioni precedenti sul client. kotlinx.serialization consente di dichiarare più modelli per diverse versioni e selezionare quello corretto in base al campo version dopo l’analisi iniziale in JsonElement. La protezione aggiuntiva include ignoreUnknownKeys per i nuovi campi e valori predefiniti per i campi che potrebbero essere rimossi.

ErroreSintomoLibreria con protezione
Type mismatchDecodingError / Eccezionekotlinx — coerceInputValues = true
Campo mancanteCrash all’accessoMoshi — @Transient + default
Formato data erratoErrore di decodificaJSONDecoder — dateDecodingStrategy
Campi extraIgnorati o crashkotlinx — ignoreUnknownKeys = true
Null in campo non nullableCrash a runtimeMoshi — lenient con @Nullable

Registrazione degli errori di deserializzazione è una pratica obbligatoria in produzione. Avvolgi decode in do/catch, registra il JSON grezzo e il tipo di modello previsto in Crashlytics o Sentry. Ciò consentirà di identificare rapidamente quale campo di quale API si è rotto e su quale versione dell’app. Senza registrazione, un errore di deserializzazione sembra un crash misterioso senza contesto.

Domande frequenti

In cosa si differenzia la deserializzazione dal parsing?

Il parsing è l’analisi di un testo strutturato in elementi costitutivi senza creare necessariamente un modello tipizzato. La deserializzazione è un caso specifico del parsing il cui risultato è un oggetto linguistico completo con tipi di proprietà noti. Il parsing può essere a flusso, la deserializzazione crea sempre un oggetto completo.

Quale libreria di deserializzazione scegliere per un nuovo progetto Android?

Per un progetto in Kotlin puro, si raccomanda kotlinx.serialization — è integrata nel compilatore, non usa reflection e supporta Kotlin Multiplatform. Per un progetto Java esistente — Moshi con code generation. Gson è meglio lasciarlo per progetti legacy dove la sua sostituzione richiederebbe uno sforzo significativo.

Cosa fare se il server invia snake_case ma il modello usa camelCase?

Su iOS, usa keyDecodingStrategy = .convertFromSnakeCase in JSONDecoder. Su Android con kotlinx.serialization, usa @SerialName per ogni campo. In Moshi, applica @Json(name="field_name") o un JsonAdapter.Factory globale. Uno stile coerente a livello di progetto è una best practice concordata nel contratto API.

Perché la deserializzazione crasha in produzione ma non in sviluppo?

La ragione più comune è un null inaspettato dal server su un campo dichiarato come obbligatorio. In sviluppo, il server restituisce dati completi; in produzione, restituisce una risposta ridotta. Soluzione: marcare tutti i campi potenzialmente assenti come nullable (Kotlin) o optional (Swift), usare ignoreUnknownKeys e valori predefiniti.

Cosa è più veloce — Reflection o Code generation nella deserializzazione?

Code generation (Moshi codegen, kotlinx.serialization, Codable) è da 2 a 4 volte più veloce della reflection nei benchmark di Google. Oltre alla velocità, la generazione di codice è più sicura dal punto di vista dei tipi, non richiede metadati delle classi a runtime e gli errori di tipo vengono rilevati in fase di compilazione, non durante la deserializzazione.

Riepilogo

  • Deserializzazione è un processo fondamentale dello sviluppo mobile che ripristina un oggetto da JSON, XML o Protobuf per l’uso nel codice dell’applicazione.
  • iOS usa JSONDecoder con il protocollo Codable, fornendo conversione automatica da JSON a modello con strategie di chiavi e date.
  • Android offre tre strumenti: Gson (reflection), Moshi (reflection/codegen) e kotlinx.serialization (generazione tramite compilatore via @Serializable).
  • Errori comuni — type mismatch, campi mancanti, null in campi non nullable e incompatibilità delle versioni API — sono prevenuti da tipi nullable, ignoreUnknownKeys e versionamento.
  • Code generation è più sicura e veloce della reflection, quindi raccomandata per le build di produzione delle applicazioni mobili.
  • Strategia di mapping — keyDecodingStrategy su iOS e @SerialName su Android risolvono la mancata corrispondenza degli stili di denominazione tra server e client.
  • Assicurati di registrare gli errori di deserializzazione in Crashlytics o Sentry per una rapida diagnosi degli incidenti di produzione.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche