1. Perché serve la convalida JSON
Immaginiamo: avete scritto la classe User e vi aspettate che in ingresso arrivi sempre un JSON di questo tipo:
{
"id": 42,
"name": "Alice",
"email": "alice@example.com"
}
Ma all’improvviso vi arriva questo:
{
"id": "quarantadue",
"name": 123,
"email": null,
"admin": true
}
O addirittura:
{
"username": "Alice"
}
Nel migliore dei casi Jackson o Gson lanceranno un’eccezione durante il tentativo di deserializzazione. Nel peggiore — assegneranno silenziosamente ai campi i valori predefiniti, e il vostro codice di business inizierà a comportarsi in modo scorretto. E se si tratta della configurazione del vostro servizio — potreste imbattervi in bug «divertenti», che poi tutta la squadra dovrà cercare.
La convalida JSON è il processo di verifica che struttura, tipi e valori dei dati in JSON rispettino regole definite (uno schema). È come il controllo passaporti per i dati: se non lo superi — non si sale a bordo!
2. JSON Schema: che cos’è e come si presenta
Nel mondo JSON esiste uno standard ufficiale per descrivere la struttura dei dati — JSON Schema. È una sorta di «lista di controllo», con cui verificare che un JSON soddisfi i requisiti della vostra applicazione.
JSON Schema è anch’esso JSON, solo che con chiavi speciali: type, properties, required e così via.
Esempio di schema molto semplice
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" },
"email": { "type": "string", "format": "email" }
},
"required": ["id", "name"]
}
Che cosa succede qui:
- Ci si aspetta un oggetto (type: "object").
- L’oggetto può avere i campi "id", "name", "email" (descritti in properties).
- "id" — è obbligatoriamente un intero (type: "integer").
- "name" — è obbligatoriamente una stringa (type: "string").
- "email" — è una stringa che ha l’aspetto di un’email (chiave format con valore "email").
- required indica l’elenco dei campi obbligatori: "id" e "name".
Se nel JSON mancano "id" o "name", oppure il loro tipo non è quello previsto — la convalida non passerà.
Panoramica rapida delle funzionalità di JSON Schema
- Indicazione del tipo (type: "string", "integer", "array", "object", "boolean", "null").
- Descrizione di oggetti e array annidati (properties, items).
- Campi obbligatori e facoltativi (required).
- Verifica della lunghezza delle stringhe, dell’intervallo numerico (minLength, maximum e altro).
- Verifica del formato (format: "email", "date", "uri", ecc.).
- Elenchi di valori consentiti (enum: insieme di valori ammessi).
- Espressioni regolari per le stringhe (pattern).
- Condizioni complesse: anyOf, oneOf, allOf (per casi avanzati).
3. Convalida JSON in Java: panoramica delle librerie
La libreria standard di Java non include la convalida JSON basata su schema. Esistono però librerie di terze parti popolari. Ecco le più note:
- everit-org/json-schema — semplice, gratuita e popolare.
- networknt/json-schema-validator — veloce, supporta gli standard più recenti.
- Jackson-module-jsonSchema — estensione per Jackson (ma non supporta una convalida completa).
- Justify, Java JSON Tools — ce ne sono anche altre, ma sono meno comuni.
In questa lezione prenderemo in esame everit-org/json-schema — è semplice per i principianti, ben documentata e non richiede acrobazie.
Installazione di everit-org/json-schema
Aggiungete la dipendenza al vostro pom.xml (Maven):
<dependency>
<groupId>org.everit.json</groupId>
<artifactId>org.everit.json.schema</artifactId>
<version>1.14.2</version>
</dependency>
Oppure tramite Gradle:
implementation 'org.everit.json:org.everit.json.schema:1.14.2'
4. Esempio: convalida JSON basata su schema (passo dopo passo)
Proviamo a convalidare un JSON nella pratica. Ci serviranno lo schema, il JSON e un po’ di codice.
Esempio di schema (user-schema.json):
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string", "minLength": 2, "maxLength": 30 },
"email": { "type": "string", "format": "email" }
},
"required": ["id", "name"]
}
Esempio di JSON valido (user.json):
{
"id": 1,
"name": "Alice",
"email": "alice@example.com"
}
Esempio di JSON non valido:
{
"id": "uno",
"name": "",
"email": "not-an-email"
}
Codice per la convalida
import org.everit.json.schema.Schema;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONObject;
import org.json.JSONException;
import org.json.JSONTokener;
import org.everit.json.schema.ValidationException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class JsonValidationExample {
public static void main(String[] args) throws Exception {
// Caricamento dello schema dal file
String schemaString = new String(Files.readAllBytes(Paths.get("user-schema.json")));
JSONObject rawSchema = new JSONObject(new JSONTokener(schemaString));
Schema schema = SchemaLoader.load(rawSchema);
// Caricamento del JSON da verificare
String jsonString = new String(Files.readAllBytes(Paths.get("user.json")));
JSONObject json = new JSONObject(new JSONTokener(jsonString));
// Convalida
try {
schema.validate(json); // Se va tutto bene — non succederà nulla
System.out.println("JSON valido!");
} catch (ValidationException e) {
System.out.println("JSON NON valido!");
for (String msg : e.getAllMessages()) {
System.out.println("Errore: " + msg);
}
}
}
}
Commenti al codice:
- Si usa la classe Schema e il loader SchemaLoader.load(...).
- Il metodo schema.validate(json) lancia un’eccezione in caso di non conformità allo schema.
- Nel blocco catch è possibile ottenere tutti gli errori tramite getAllMessages().
Come integrarlo in un’applicazione?
Di solito lo schema è conservato tra le risorse (ad esempio nella cartella resources). Si convalida il JSON prima della deserializzazione in un oggetto Java. Se tutto è a posto — si deserializza e si procede.
5. Gestione degli errori di convalida
Quando un JSON non supera il controllo, la libreria lancia l’eccezione ValidationException. Nel messaggio è presente un elenco di errori: che cosa esattamente non è conforme allo schema.
Esempio di output degli errori
Per il JSON non valido di cui sopra, l’output sarà circa questo:
JSON NON valido!
Errore: #: required key [id] not found
Errore: #/name: expected minLength: 2, actual: 0
Errore: #/email: String [not-an-email] is invalid against requested format [email]
Errore: #/id: expected type: Integer, found: String
Come interpretare gli errori:
- required key [id] not found — manca un campo obbligatorio.
- expected minLength: 2, actual: 0 — la stringa è troppo corta.
- String [...] is invalid against requested format [email] — email non valida.
- expected type: Integer, found: String — il tipo non corrisponde.
Importante! I messaggi possono essere in inglese, ma sono molto comprensibili.
Come mostrare gli errori all’utente?
Potete raccogliere gli errori in un elenco e restituirli all’utente, ad esempio in un REST API o in una GUI. Questo permette di capire rapidamente che cosa non va nei dati in ingresso.
6. Pratica: convalida di un array di oggetti
Spesso bisogna convalidare non un singolo oggetto, ma un array:
[
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "id": 2, "name": "Bob" },
{ "id": "che cos'è?", "name": 123, "email": "not-an-email" }
]
Schema:
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string", "minLength": 2, "maxLength": 30 },
"email": { "type": "string", "format": "email" }
},
"required": ["id", "name"]
}
}
La convalida funziona allo stesso modo, solo che come JSON si passa un array. Gli errori conterranno gli indici degli elementi in cui qualcosa non va (per esempio, [#/2/id]).
7. Errori tipici nella convalida JSON
Errore n. 1: tipi di dati non corrispondenti. Molto spesso arriva una stringa al posto di un numero ("id": "123"), mentre lo schema si aspetta un integer. La convalida non passerà. Se non controllate la fonte dei dati — correggete lo schema oppure convertite i dati in anticipo.
Errore n. 2: campi obbligatori mancanti. Se nello schema è indicato che un campo è obbligatorio ("required": ["id","name"]), ma nel JSON manca — otterrete un errore. Talvolta accade inaspettatamente: il frontend ha dimenticato di inviare il campo o l’API è cambiata.
Errore n. 3: campi in più nel JSON. Per impostazione predefinita JSON Schema consente campi extra. Se volete uno schema rigoroso, non dimenticate di aggiungere "additionalProperties": false. Senza questo, nel JSON possono esserci campi «non previsti».
Errore n. 4: versione dello schema o sintassi errata. Se usate chiavi non presenti nella versione dello schema in uso, o fate errori di battitura, il validatore non potrà caricare lo schema. Verificate lo schema su https://www.jsonschemavalidator.net/ o servizi analoghi.
Errore n. 5: gestione degli errori scadente. Se vi limitate a catturare la prima eccezione e non mostrate all’utente i dettagli, sarà difficile capire che cosa non va nel JSON. Usate getAllMessages() per mostrare tutti gli errori.
Errore n. 6: formati troppo rigidi. La verifica di "format": "email" o "date" può essere piuttosto «superficiale». Se avete bisogno di una convalida rigorosa, aggiungete controlli supplementari nel codice.
GO TO FULL VERSION