Формат сериализации это способ записать состояние объекта в последовательность байт. Одну и ту же задачу форматы решают по-разному: JSON и YAML читаются человеком и живут в веб-API и файлах конфигурации, XML многословнее, но давно стал стандартом в корпоративных системах, BSON это двоичный JSON, на котором работает MongoDB, а position based protocol передает одни значения без имен полей и занимает минимум места. Выбирают формат по трем вопросам: кто будет читать данные, сколько их и насколько важна скорость передачи.

Кратко

  • Формат сериализации определяет, как состояние объекта превращается в последовательность байт. Один и тот же объект можно записать десятком разных способов.
  • JSON: синтаксис пришел из литералов объектов JavaScript, шесть типов данных, читается человеком, стандарт де-факто для веб-API.
  • YAML: структура задается отступами, поэтому он компактнее JSON. Умеет якоря и алиасы, чтобы не повторять одно и то же, и знает больше типов структур данных.
  • XML: дерево тегов, самый многословный из читаемых форматов, но по распространенности не уступает JSON и YAML.
  • BSON: двоичный JSON. Человеку не читается, зато умеет даты и бинарные вложения. На нем работает MongoDB.
  • Protocol Buffers: двоичный формат со схемой в отдельном файле. Имена полей не передаются вовсе, поэтому он компактнее всех остальных, но без схемы данные не прочитать.
  • Position based protocol: только значения через разделитель, без имен полей. Занимает в разы меньше места, но без описания структуры данные не разобрать.
Привет! Давай поговорим о сериализации в Java. Ты наверняка помнишь, что лекции по сериализации у нас уже были. Так и есть :) Вот первая А вот вторая Если ты уже не очень хорошо помнишь, как работает сериализация, зачем она нужна, и какие в Java есть инструменты для нее, можешь пробежаться по этим лекциям. Сегодняшняя же лекция будет теоретической, и в ней мы подробнее рассмотрим форматы сериализации.Красный блокнот, на обложке двоичный код, который расшифровывается как I LOVE YOU, рядом прозрачный навесной замок и раскрытая книгаДля начала вспомним, что же такое сериализация. Сериализация это процесс сохранения состояния объекта в последовательность байт. Десериализация это процесс восстановления объекта из этих байт. Java-объект можно сериализовать и передать по сети (например, на другой компьютер). Так вот, эта самая последовательность байт может быть представлена в разных форматах. Тебе это знакомо из повседневного использования компьютера. К примеру, электронная книга (или простой текстовый документ), которую ты читаешь, может быть записана в куче разных форматов:
  • docx (формат Microsoft Word);
  • pdf (формат Adobe);
  • mobi (обычно используется в устройствах Amazon Kindle);
  • и еще много всего (ePub, djvu, fb2...).
Казалось бы, задача одна и та же: представить текст в человеко-читаемом виде. Но люди изобрели целую россыпь форматов. Даже не вдаваясь в подробности их работы, мы можем предположить, что сделано это не просто так. Вероятно, у каждого из них есть свои преимущества и недостатки по сравнению с остальными. Может, и форматы сериализации были созданы по тому же принципу? Что ж, хорошее предположение, студент! :) Так оно и есть. Дело в том, что передача данных на расстояние это штука довольно тонкая, и в ней есть много факторов. Кто передает данные? Куда? Какой объем? В качестве принимающей стороны будет человек или машина (т.е. должны ли данные быть human-readable)? Что за устройство будет читать данные? Очевидно, что ситуации бывают разные. Одно дело, когда нужно передать картинку размером 500Кб с одного смартфона на другой. И совсем другое, когда речь идет о 500 терабайтах бизнес-данных, которые нужно сжать максимально эффективно и при этом передать максимально быстро. Давай же познакомимся с основными форматами сериализации и рассмотрим преимущества и недостатки каждого из них! Вот они все сразу, чтобы дальше было понятно, о чем речь:
Формат Читается человеком Объем Чем интересен Где чаще встречается
JSON Да Средний Шесть типов данных, библиотеки под любой язык Веб-API, обмен фронтенда с бэкендом
YAML Да Компактнее JSON: структура на отступах Якоря и алиасы, набор структур !!map, !!omap, !!pairs, !!set, !!seq Файлы конфигурации
XML Да Самый многословный Дерево тегов с вложенными элементами Корпоративные системы, конфигурации
BSON Нет, двоичный Компактнее JSON Даты, бинарные вложения, куски JavaScript-кода MongoDB
Protocol Buffers Нет, двоичный Самый компактный из текстовых и двоичных: имена полей не передаются Схема в отдельном файле, генерация классов, встроенное версионирование Общение сервисов между собой, gRPC
Position based protocol Да, но без имен полей Минимальный Только значения через разделитель Там, где важен объем передаваемых данных
А теперь по каждому подробно.

JSON

JavaScript Object Notation. С ним ты уже немного знаком! Мы говорили о нем вот в этой лекции, а сериализацию в JSON рассматривали вот тут. Свое название он получил не просто так. Объекты Java, преобразованные в JSON, действительно выглядят точно так же, как объекты в языке JavaScript. Тебе вовсе не нужно знать JavaScript, чтобы понять смысл нашего объекта:

{
   "title": "Война и мир",
   "author": "Лев Толстой",
   "year": 1869
}
Не обязательно передавать один объект. JSON может содержать и массив объектов:

[
 {
   "title": "Война и мир",
   "author": "Лев Толстой",
   "year": 1869
 },

 {
   "title": "Бесы",
   "author": "Федор Достоевский",
   "year": 1872
 },

 {
   "title": "Чайка",
   "author": "Антон Чехов",
   "year": 1896
 }
]
Синтаксис JSON вырос из литералов объектов JavaScript, оттуда же у него и набор типов данных:
  • строки (string);
  • числа (number);
  • объекты (object);
  • массивы (array);
  • boolean-значения (true и false);
  • null.

Преимущества JSON

Какие же преимущества есть у JSON?
  1. Human-readable («человеко-читаемый») формат. Это очевидное преимущество, если твой конечный пользователь это человек. К примеру, на твоем сервере хранится база данных с расписанием авиаперелетов. Клиент-человек запрашивает данные из этой базы с помощью веб-приложения, сидя дома за компьютером. Поскольку тебе нужно предоставить данные в формате, который он сможет понять, JSON будет отличным решением.

  2. Простота. Можно сказать, элементарность :) Выше мы привели пример двух JSON-файлов. И даже если ты вообще не слышал о существовании JavaScript (и уж тем более о его объектах), ты легко поймешь, что за объекты там описаны.
    Вся документация JSON это одна веб-страница с парой картинок.

  3. Широкая распространенность. JavaScript это доминирующий язык фронтенда, и он диктует свои условия. Использование JSON это необходимость. Поэтому огромное число веб-сервисов используют JSON в качестве формата для обмена данными. Каждая современная IDE поддерживает JSON-формат (в том числе Intellij IDEA). Для работы с JSON написана куча библиотек для всех возможных языков программирования.

Например, ты уже работал с библиотекой Jackson в лекции, где мы учились сериализовывать Java-объекты в JSON. Но помимо Jackson есть, например, GSON, очень удобная библиотека от Google.

Недостатки JSON

Раз обещали и недостатки, вот они.
  • Нет комментариев. В формате их просто не предусмотрено, так что пояснить что-то прямо в файле не выйдет. Для конфигураций это ощутимо.
  • Скудный набор типов. Даты нет, ее передают строкой или числом и договариваются о формате отдельно. Двоичных данных тоже нет: картинку придется закодировать в Base64 и смириться с тем, что она подрастет примерно на треть.
  • Объем. Имена полей повторяются в каждом объекте массива, а числа и даты записаны текстом. На тех же данных двоичные форматы заметно компактнее.
  • Структура сама себя не описывает. Проверить, что пришел ожидаемый набор полей нужного типа, можно только отдельным инструментом вроде JSON Schema.

YAML

В начале своего существования расшифровывался как Yet Another Markup Language, то есть «еще один язык разметки». В то время его позиционировали как конкурента XML. Сейчас же, по прошествии времени, он расшифровывается как «YAML Ain’t Markup Language» («YAML не язык разметки»). Что же он из себя представляет? Давай представим, что нам нужно создать 3 класса персонажей для нашей компьютерной игры: Воин, Маг и Вор. У них будут следующие характеристики: сила, ловкость, выносливость, набор оружия. Вот как будет выглядеть наш YAML-файл с описанием классов:

classes:
 class-1:
   title: Warrior
   power: 8
   agility: 4
   stamina: 7
   weapons:
     - sword
     - spear
    
 class-2:
   title: Mage
   power: 5
   agility: 7
   stamina: 5
   weapons:
     - magic staff

 class-3:
   title: Thief
   power: 6
   agility: 6
   stamina: 5
   weapons:
     - dagger
     - poison
YAML-файл имеет древовидную структуру: одни элементы вложены в другие. Вложенностью мы можем управлять при помощи некоторого количества пробелов, которым обозначаем каждый уровень.

Преимущества YAML

Какими же преимуществами обладает YAML-формат?
  1. Human-readable. Опять же, даже увидев yaml-файл без описания, ты легко поймешь, какие объекты там описаны. YAML насколько хорошо читается человеком, что главная страница yaml.org это обычный yaml-файл :)

  2. Компактность. Структура файла формируется за счет пробелов: нет необходимости использовать скобки или кавычки.

  3. Поддержка структур данных, «родных» для языков программирования. Огромное преимущество YAML перед JSON и многими другими форматами заключается в том, что он поддерживает разные структуры данных. В их числе:

    • !!map
      Неупорядоченный набор пар ключ:значение без возможности дубликатов;

    • !!omap
      Упорядоченная последовательность пар ключ:значение без возможности дубликатов;

    • !!pairs
      Упорядоченная последовательность пар ключ:значение с возможностью дубликатов;

    • !!set
      Неупорядоченная последовательность значений, которые не равны друг другу;
    • !!seq
      Последовательность произвольных значений;

    Некоторые из этих структур знакомы тебе по Java! :) За счет этой фичи в формат YAML можно сериализовать разные структуры данных из языков программирования.

  4. Возможность использования anchor и alias

    Переводятся слова «anchor» и «alias» как «якорь» и «псевдоним». В принципе, он довольно точно описывает суть этих терминов в YAML.

    Они позволяют тебе идентифицировать какой-то элемент в yaml-файле, и ссылаться на него в остальных частях этого файла, если он встречается повторно. Anchor создается с помощью символа &, а alias с помощью *.

    Допустим, у нас есть файл с описанием книг Льва Толстого. Чтобы не писать имя автора каждый раз вручную, мы просто создадим якорь «leo» и будем ссылаться на него с помощью алиаса, когда нам это будет нужно:

    
    books:
     book-1:
       title: War and Peace
       author: &leo Leo Tolstoy
       year: 1869
    
     book-2:
       title: Anna Karenina
       author: *leo
       year: 1873
    
     book-3:
       title: Family Happiness
       author: *leo
       year: 1859
    

    Когда мы будем считывать этот файл каким-то парсером, на месте нашего алиаса в нужных местах будет подставляться значение «Leo Tolstoy».

  5. В YAML можно встроить данные в других форматах. Например, JSON:
    
    books: [
            {
              "title": "War and Peace",
              "author": "Leo Tolstoy",
              "year": 1869
            },
    
            {
              "title": "Anna Karenina",
              "author": "Leo Tolstoy",
              "year": 1873
            },
    
            {
              "title": "Family Happiness",
              "author": "Leo Tolstoy",
              "year": 1859
            }
          ]
    

Недостатки YAML

Обратная сторона у YAML тоже есть, и растет она из тех же самых свойств.
  • Структура держится на пробелах. Лишний или потерянный пробел меняет вложенность, и файл либо не читается вовсе, либо читается не так, как задумано. Табуляцию для отступов спецификация прямо запрещает: «tab characters must not be used in indentation, since different systems treat tabs differently».
  • Простота обманчива. Документация JSON помещается на одну страницу, а спецификация YAML это несколько десятков страниц с якорями, тегами типов, несколькими документами в одном файле и прочим. Язык целиком мало кто знает.
  • Парсеры ведут себя по-разному. Из-за размера спецификации библиотеки поддерживают ее не полностью, и один и тот же файл в разных инструментах может разобраться неодинаково.
  • Глубокую вложенность тяжело читать глазами: на пятом уровне отступов уже не видно, к чему относится ключ.

Другие форматы сериализации

XML

Этот формат основан на так называемом дереве тегов.

<book>
   <title>Harry Potter and the Philosopher’s Stone</title>
   <author>J. K. Rowling</author>
   <year>1997</year>
</book>
Каждый элемент состоит из открывающего и закрывающего тега (<> и </>). У каждого элемента могут быть вложенные элементы. XML это распространенный формат, не уступающий JSON и YAML (если говорить об использовании в реальных проектах). Об XML у нас есть отдельная лекция.

BSON (binary JSON)

Как и следует из его названия, очень похож на JSON, но не является human-readable и оперирует данными в двоичном формате. За счет этого он очень удобен при хранении и передаче изображений и других вложений. Кроме того, BSON поддерживает некоторые типы данных, недоступные в JSON. Например, в BSON-файл можно записать дату (в формате миллисекунд) или даже кусок JavaScript кода. Популярная NoSQL база данных MongoDB хранит информацию именно в BSON формате.

Protocol Buffers

Формат от Google и самый распространенный двоичный формат обмена в индустрии. Устроен он иначе, чем все предыдущие: сначала структуру сообщения описывают в отдельном файле схемы с расширением .proto,

message Book {
  string title = 1;
  string author = 2;
  int32 year = 3;
}
а потом по этой схеме генерируют классы для нужного языка, в том числе для Java. Что это дает. В поток попадают только номера полей и значения, имена полей туда не пишутся вообще, поэтому сообщение получается в разы компактнее JSON. Разбор быстрее: парсеру не нужно ничего угадывать, структура известна заранее. И версионирование встроено в сам формат: старый код спокойно прочитает сообщение с новыми полями и просто пропустит то, чего не знает. Плата очевидна: без схемы данные не прочитать ни человеку, ни программе. Поэтому Protocol Buffers берут там, где обе стороны свои, а объем и скорость важнее удобства чтения: во внутреннем общении сервисов, в gRPC, в мобильных приложениях.

Position based protocol

В некоторых ситуациях нам необходимо резко снизить количество передаваемых данных (например, если данных очень много и нужно уменьшить нагрузку). В этой ситуации мы можем использовать position based protocol, то есть передавать значения параметров без названий самих параметров.

"Leo Tolstoy" | "Anna Karenina" | 1873
Данные в таком формате занимают в разы меньше места, чем полноценный JSON файл. Конечно, существуют и другие форматы сериализации, но тебе сейчас не нужно знать их все :) Хорошо, если ты будешь знаком с теми форматами, которые сейчас являются промышленным стандартом при разработке приложений, и будешь помнить их преимущества и отличия друг от друга. А наша лекция на этом подошла к концу :) Не забудь решить пару задач сегодня! До новых встреч! :)

Вопросы и ответы

Что такое формат сериализации?

Это способ записать состояние объекта в последовательность байт. Сериализация превращает объект в байты, десериализация собирает объект обратно, а формат определяет, как именно эти байты устроены. Одни и те же данные можно записать текстом, который прочитает человек, а можно двоичным блоком, который человеку не разобрать, зато он занимает меньше места и быстрее передается.

Чем YAML отличается от JSON?

Прежде всего синтаксисом: в JSON структуру задают фигурные и квадратные скобки, в YAML отступы, поэтому файл получается компактнее и без лишних кавычек. Кроме того, YAML знает больше типов структур данных и умеет якоря с алиасами, то есть позволяет объявить значение один раз и потом ссылаться на него. Обратная сторона отступов в том, что случайный лишний пробел ломает файл.

Что такое BSON и зачем он нужен?

BSON это двоичная версия JSON. Человеку он не читается, зато занимает меньше места и умеет то, чего в JSON нет: хранить дату, бинарные вложения вроде картинок и даже куски JavaScript-кода. Самое известное применение это база данных MongoDB, которая хранит документы именно в BSON.

Какой формат сериализации выбрать?

Смотрите на три вещи. Кто читает данные: если человек, нужен текстовый формат, JSON или YAML. Сколько данных: чем их больше, тем весомее аргумент в пользу двоичного формата. И где это работает: у веб-API стандарт де-факто это JSON, у файлов конфигурации YAML, у MongoDB BSON, во внутреннем общении сервисов Protocol Buffers, а в корпоративных системах часто остается XML.

Что такое anchor и alias в YAML?

Это способ не повторять одно и то же значение. Якорь помечает значение символом амперсанда и дает ему имя, а алиас подставляет это значение по имени через звездочку. Например, имя автора можно объявить один раз якорем и дальше во всем файле ссылаться на него алиасом. При чтении парсер сам подставит настоящее значение на место каждого алиаса.

Почему XML до сих пор используют?

Из-за инерции и из-за возможностей, которых нет у более простых форматов. XML старше JSON, на нем построены целые слои корпоративных систем, и переписывать их никто не станет. Плюс у XML есть схемы для описания и проверки структуры документа, атрибуты у элементов и развитые инструменты обработки. Расплата это многословность: тот же объект в XML занимает заметно больше места, чем в JSON.

Читайте также