1. Por qué necesitamos validar JSON
Imaginemos que has escrito la clase User y esperas que siempre te llegue un JSON como este:
{
"id": 42,
"name": "Alice",
"email": "alice@example.com"
}
Pero de repente te llega esto:
{
"id": "cuarenta y dos",
"name": 123,
"email": null,
"admin": true
}
O incluso:
{
"username": "Alice"
}
En el mejor de los casos, Jackson o Gson lanzarán una excepción al intentar deserializar. En el peor — asignarán silenciosamente valores por defecto a los campos y tu código de negocio comenzará a comportarse de forma incorrecta. Y si se trata de la configuración de tu servicio — puedes toparte con bugs divertidos que luego tenga que rastrear todo el equipo.
La validación de JSON es el proceso de comprobar que la estructura, los tipos y los valores de los datos en JSON cumplen unas reglas determinadas (un esquema). Es como el control de pasaportes de los datos: si no lo pasas, ¡no embarcas!
2. JSON Schema: qué es y cómo se ve
En el mundo JSON hay un estándar oficial para describir estructuras de datos — JSON Schema. Es como una «lista de comprobación» con la que puedes verificar que un JSON se ajusta a los requisitos de tu programa.
JSON Schema también es JSON, solo que con claves especiales: type, properties, required, etc.
Ejemplo del esquema más sencillo
{
"$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"]
}
Qué está pasando aquí:
- Se espera un objeto (type: "object").
- El objeto puede tener los campos "id", "name", "email" (se describen en properties).
- "id" es un número entero obligatorio (type: "integer").
- "name" es una cadena obligatoria (type: "string").
- "email" es una cadena con aspecto de email (clave format con valor "email").
- required indica la lista de campos obligatorios: "id" y "name".
Si en el JSON falta "id" o "name", o su tipo no es el correcto, la validación fallará.
Resumen de las posibilidades de JSON Schema
- Especificación de tipo (type: "string", "integer", "array", "object", "boolean", "null").
- Descripción de objetos y arrays anidados (properties, items).
- Campos obligatorios y opcionales (required).
- Comprobación de longitud de cadenas y rango numérico (minLength, maximum, etc.).
- Comprobación de formato (format: "email", "date", "uri", etc.).
- Enumeraciones (enum: lista de valores permitidos).
- Expresiones regulares para cadenas (pattern).
- Condiciones complejas: anyOf, oneOf, allOf (para casos avanzados).
3. Validación de JSON en Java: panorama de bibliotecas
La biblioteca estándar de Java no incluye validación de JSON por esquema. Pero hay bibliotecas de terceros populares. Estas son las más conocidas:
- everit-org/json-schema — simple, gratuita y popular.
- networknt/json-schema-validator — rápida y compatible con los últimos estándares.
- Jackson-module-jsonSchema — una extensión para Jackson (pero no admite validación completa).
- Justify, Java JSON Tools — hay otras, pero se usan con menos frecuencia.
En esta lección veremos everit-org/json-schema: es sencilla para principiantes, está bien documentada y no requiere complicaciones.
Instalación de everit-org/json-schema
Añade la dependencia a tu pom.xml (Maven):
<dependency>
<groupId>org.everit.json</groupId>
<artifactId>org.everit.json.schema</artifactId>
<version>1.14.2</version>
</dependency>
O mediante Gradle:
implementation 'org.everit.json:org.everit.json.schema:1.14.2'
4. Ejemplo: validación de JSON con esquema (paso a paso)
Vamos a validar un JSON en la práctica. Para ello necesitamos el esquema, el JSON y un poco de código.
Ejemplo de esquema (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"]
}
Ejemplo de JSON válido (user.json):
{
"id": 1,
"name": "Alice",
"email": "alice@example.com"
}
Ejemplo de JSON no válido:
{
"id": "uno",
"name": "",
"email": "not-an-email"
}
Código para la validación
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 {
// Carga del esquema desde un archivo
String schemaString = new String(Files.readAllBytes(Paths.get("user-schema.json")));
JSONObject rawSchema = new JSONObject(new JSONTokener(schemaString));
Schema schema = SchemaLoader.load(rawSchema);
// Carga del JSON a validar
String jsonString = new String(Files.readAllBytes(Paths.get("user.json")));
JSONObject json = new JSONObject(new JSONTokener(jsonString));
// Validación
try {
schema.validate(json); // Si todo va bien, no ocurrirá nada
System.out.println("JSON es válido!");
} catch (ValidationException e) {
System.out.println("¡JSON NO es válido!");
for (String msg : e.getAllMessages()) {
System.out.println("Error: " + msg);
}
}
}
}
Comentarios al código:
- Se utiliza la clase Schema y el cargador SchemaLoader.load(...).
- El método schema.validate(json) lanza una excepción si no se ajusta al esquema.
- En el bloque catch puedes obtener todos los errores mediante getAllMessages().
¿Cómo integrarlo en una aplicación?
Normalmente el esquema se guarda como un recurso (por ejemplo, en la carpeta resources). Validas el JSON antes de deserializarlo a un objeto Java. Si todo está bien, lo deserializas y sigues trabajando.
5. Gestión de errores de validación
Cuando el JSON no pasa la comprobación, la biblioteca lanza la excepción ValidationException. El mensaje contiene una lista de errores: qué exactamente no se ajusta al esquema.
Ejemplo de salida de errores
Para el JSON no válido anterior, la salida será aproximadamente así:
¡JSON NO es válido!
Error: #: required key [id] not found
Error: #/name: expected minLength: 2, actual: 0
Error: #/email: String [not-an-email] is invalid against requested format [email]
Error: #/id: expected type: Integer, found: String
Cómo interpretar los errores:
- required key [id] not found — falta un campo obligatorio.
- expected minLength: 2, actual: 0 — la cadena es demasiado corta.
- String [...] is invalid against requested format [email] — email no válido.
- expected type: Integer, found: String — el tipo no coincide.
Importante: los mensajes pueden estar en inglés, pero son bastante claros.
¿Cómo mostrar los errores al usuario?
Puedes recopilar los errores en una lista y devolvérselos al usuario, por ejemplo, en un REST API o en un GUI. Esto permitirá entender rápidamente qué está mal con los datos de entrada.
6. Práctica: validación de un array de objetos
A menudo hay que validar no un solo objeto, sino un array:
[
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "id": 2, "name": "Bob" },
{ "id": "¿qué es esto?", "name": 123, "email": "not-an-email" }
]
Esquema:
{
"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 validación funciona igual, solo que pasamos un array como JSON. Los errores incluirán los índices de los elementos donde algo esté mal (por ejemplo, [#/2/id]).
7. Errores típicos al validar JSON
Error n.º 1: Incompatibilidad de tipos de datos. Muy a menudo llega una cadena en lugar de un número ("id": "123") y el esquema espera un integer. La validación fallará. Si no controlas la fuente de datos — corrige el esquema o convierte los datos de antemano.
Error n.º 2: Falta de campos obligatorios. Si en el esquema se indica que un campo es obligatorio ("required": ["id","name"]) y en el JSON no está — obtendrás un error. A veces es inesperado: el frontend olvidó enviar el campo o el API cambió.
Error n.º 3: Campos extra en el JSON. Por defecto, JSON Schema permite campos extra. Si quieres un esquema estricto, no olvides añadir "additionalProperties": false. Sin esto, el JSON puede contener campos «ajenos».
Error n.º 4: Versión del esquema o sintaxis incorrectas. Si utilizas claves que no existen en tu versión del esquema o cometes erratas, el validador no podrá cargar el esquema. Comprueba el esquema en https://www.jsonschemavalidator.net/ u otros servicios similares.
Error n.º 5: Mala gestión de errores. Si solo capturas la primera excepción y no muestras al usuario los detalles, será difícil entender qué está mal con el JSON. Utiliza getAllMessages() para mostrar todos los errores.
Error n.º 6: Formatos demasiado estrictos. La comprobación de "format": "email" o "date" a veces es bastante «superficial». Si necesitas una validación estricta, añade comprobaciones adicionales en el código.
GO TO FULL VERSION