JavaRush /Курсы /JAVA 25 SELF /Валидация JSON: JSON Schema, ошибки валидации

Валидация JSON: JSON Schema, ошибки валидации

JAVA 25 SELF
46 уровень , 4 лекция
Открыта

1. Зачем нужна валидация JSON

Давайте представим: вы написали класс User и ожидаете, что на вход вам всегда будет приходить вот такой JSON:

{
  "id": 42,
  "name": "Alice",
  "email": "alice@example.com"
}

Но вдруг вам прилетает вот это:

{
  "id": "сорок два",
  "name": 123,
  "email": null,
  "admin": true
}

Или вообще:

{
  "username": "Alice"
}

В лучшем случае Jackson или Gson выбросят исключение при попытке десериализации. В худшем — молча присвоят полям значения по умолчанию, и ваш бизнес-код начнёт работать некорректно. А если это конфиг для вашего сервиса — можно нарваться на весёлые баги, которые потом ищут всей командой.

Валидация JSON — это процесс проверки, что структура, типы и значения данных в JSON соответствуют определённым правилам (схеме). Это как паспортный контроль для данных: не прошёл — на борт не пускаем!

2. JSON Schema: что это и как выглядит

В мире JSON есть официальный стандарт описания структуры данных — JSON Schema. Это такой «чек-лист», по которому можно проверить, что JSON подходит под требования вашей программы.

JSON Schema — это тоже JSON, только со специальными ключами: type, properties, required и так далее.

Пример самой простой схемы

{
  "$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"]
}

Что здесь происходит:

  • Ожидается объект (type: "object").
  • У объекта могут быть поля "id", "name", "email" (описываются в properties).
  • "id" — обязательно целое число (type: "integer").
  • "name" — обязательно строка (type: "string").
  • "email" — строка, которая выглядит как email (ключ format со значением "email").
  • required указывает список обязательных полей: "id" и "name".

Если в JSON будет отсутствовать "id" или "name", или их тип будет не тот — валидация не пройдёт.

Кратко о возможностях JSON Schema

  • Указание типа (type: "string", "integer", "array", "object", "boolean", "null").
  • Описание вложенных объектов и массивов (properties, items).
  • Обязательные и необязательные поля (required).
  • Проверка длины строк, диапазона чисел (minLength, maximum и др.).
  • Проверка формата (format: "email", "date", "uri", и др.).
  • Перечисления (enum: список допустимых значений).
  • Регулярные выражения для строк (pattern).
  • Сложные условия: anyOf, oneOf, allOf (для продвинутых случаев).

3. Валидация JSON в Java: обзор библиотек

В стандартную библиотеку Java валидация JSON по схеме не входит. Но есть популярные сторонние библиотеки. Вот самые известные:

  • everit-org/json-schema — простая, бесплатная и популярная.
  • networknt/json-schema-validator — быстрая, поддерживает последние стандарты.
  • Jackson-module-jsonSchema — расширение для Jackson (но не поддерживает полноценную валидацию).
  • Justify, Java JSON Tools — есть и другие, но они встречаются реже.

В этой лекции мы рассмотрим everit-org/json-schema — она проста для новичков, хорошо документирована и не требует танцев с бубном.

Установка everit-org/json-schema

Добавьте зависимость в ваш pom.xml (Maven):

<dependency>
  <groupId>org.everit.json</groupId>
  <artifactId>org.everit.json.schema</artifactId>
  <version>1.14.2</version>
</dependency>

Или через Gradle:

implementation 'org.everit.json:org.everit.json.schema:1.14.2'

4. Пример: валидация JSON по схеме (пошагово)

Давайте попробуем провалидировать JSON на практике. Для этого нам понадобится сама схема, JSON и немного кода.

Пример схемы (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"]
}

Пример валидного JSON (user.json):

{
  "id": 1,
  "name": "Alice",
  "email": "alice@example.com"
}

Пример невалидного JSON:

{
  "id": "один",
  "name": "",
  "email": "not-an-email"
}

Код для валидации

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 {
        // Загрузка схемы из файла
        String schemaString = new String(Files.readAllBytes(Paths.get("user-schema.json")));
        JSONObject rawSchema = new JSONObject(new JSONTokener(schemaString));
        Schema schema = SchemaLoader.load(rawSchema);

        // Загрузка JSON для проверки
        String jsonString = new String(Files.readAllBytes(Paths.get("user.json")));
        JSONObject json = new JSONObject(new JSONTokener(jsonString));

        // Валидация
        try {
            schema.validate(json); // Если всё ок — ничего не произойдет
            System.out.println("JSON валиден!");
        } catch (ValidationException e) {
            System.out.println("JSON НЕ валиден!");
            for (String msg : e.getAllMessages()) {
                System.out.println("Ошибка: " + msg);
            }
        }
    }
}

Комментарии к коду:

  • Используется класс Schema и загрузчик SchemaLoader.load(...).
  • Метод schema.validate(json) выбрасывает исключение при несоответствии схеме.
  • В блоке catch можно получить все ошибки через getAllMessages().

Как это интегрировать в приложение?

Обычно схема хранится в ресурсе (например, в папке resources). Вы валидируете JSON до десериализации в Java-объект. Если всё хорошо — десериализуете и работаете дальше.

5. Обработка ошибок валидации

Когда JSON не проходит проверку, библиотека выбрасывает исключение ValidationException. В сообщении содержится список ошибок: что именно не соответствует схеме.

Пример вывода ошибок

Для невалидного JSON выше вывод будет примерно таким:

JSON НЕ валиден!
Ошибка: #: required key [id] not found
Ошибка: #/name: expected minLength: 2, actual: 0
Ошибка: #/email: String [not-an-email] is invalid against requested format [email]
Ошибка: #/id: expected type: Integer, found: String

Как интерпретировать ошибки:

  • required key [id] not found — отсутствует обязательное поле.
  • expected minLength: 2, actual: 0 — строка слишком короткая.
  • String [...] is invalid against requested format [email] — некорректный email.
  • expected type: Integer, found: String — тип не совпадает.

Важно! Сообщения могут быть на английском, но они очень понятны.

Как показать ошибки пользователю?

Вы можете собрать ошибки в список и отдать пользователю, например, в REST API или GUI. Это позволит быстро понять, что именно не так с входными данными.

6. Практика: валидация массива объектов

Часто приходится валидировать не один объект, а массив:

[
  { "id": 1, "name": "Alice", "email": "alice@example.com" },
  { "id": 2, "name": "Bob" },
  { "id": "что это?", "name": 123, "email": "not-an-email" }
]

Схема:

{
  "type": "array",
  "items": {
    "type": "object",
    "properties": {
      "id":    { "type": "integer" },
      "name":  { "type": "string", "minLength": 2, "maxLength": 30 },
      "email": { "type": "string", "format": "email" }
    },
    "required": ["id", "name"]
  }
}

Валидация работает так же, только в качестве JSON передаём массив. Ошибки будут содержать индексы элементов, где что-то не так (например, [#/2/id]).

7. Типичные ошибки при валидации JSON

Ошибка №1: Несовпадение типов данных. Очень часто приходит строка вместо числа ("id": "123"), а схема ждёт integer. Валидация не пройдёт. Если вы не контролируете источник данных — либо исправьте схему, либо конвертируйте данные заранее.

Ошибка №2: Отсутствие обязательных полей. Если в схеме указано, что поле обязательно ("required": ["id","name"]), а в JSON его нет — получите ошибку. Иногда это бывает неожиданно: фронтенд забыл отправить поле или API изменилось.

Ошибка №3: Лишние поля в JSON. По умолчанию JSON Schema разрешает лишние поля. Если вы хотите строгую схему, не забудьте добавить "additionalProperties": false. Без этого в JSON могут быть любые «левые» поля.

Ошибка №4: Неправильная версия схемы или синтаксис. Если вы используете ключи, которых нет в вашей версии схемы, или делаете опечатки, валидатор не сможет загрузить схему. Проверяйте схему на https://www.jsonschemavalidator.net/ или аналогичных сервисах.

Ошибка №5: Плохая обработка ошибок. Если просто ловить первое исключение и не показывать пользователю подробности, будет сложно понять, что именно не так с JSON. Используйте getAllMessages() для вывода всех ошибок.

Ошибка №6: Слишком строгие форматы. Проверка "format": "email" или "date" бывает довольно «поверхностной». Если вам нужна строгая валидация, используйте дополнительные проверки в коде.

1
Задача
JAVA 25 SELF, 46 уровень, 4 лекция
Недоступна
Инспекция новых пользовательских досье 🧐
Инспекция новых пользовательских досье 🧐
1
Задача
JAVA 25 SELF, 46 уровень, 4 лекция
Недоступна
Страж входа в онлайн-клуб: проверка email 🚫
Страж входа в онлайн-клуб: проверка email 🚫
1
Опрос
Сериализация JSON, 46 уровень, 4 лекция
Недоступен
Сериализация JSON
Сериализация JSON
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ