Введение
Работая в области создания RIA, рано или поздно приходится задумываться над выбором протоколов для передачи данных между сервером и его клиентами. Если раньше я безоговорочно использовал XML, то сейчас все чаще задумываюсь над тем, чтобы поменять свой приоритет в данном вопросе в пользу JSON. Выше я не ошибся, говоря о клиентах, все чаще для своего сервиса заказчики требуют мобильную версию и поэтому приходится думать о создании серверной инфраструктуры, способной поддерживать несколько клиентов (браузер и, допустим, приложение для iPhone) и их версий. Вроде бы по всем параметрам подходит XML, но тут возникают сомнения.
Сомнения
Последние пару лет с опаской замечаю повсеместное использование XML — да формат универсальный, но надо знать меру. Главный флаг XML — машинночитаемый и человекочитаемый формат хранения данных, замечу — легко читаемый. В литературе вы найдете упоминание о том, что XML — это иерархическая структура, предназначенная для хранения любых данных, визуально структура может быть представлена как дерево.
И тут возникает первое сомнение: а вот если взять небольшое дерево, узлов на двести и сохранить в виде XML, так ли будет просто его прочитать. Человеку без специального редактора с подстветкой уже практически нереально читать такие файлы (особенно, если они записаны в одну строчку без переносов и табуляций). С этим утверждением сложно не согласиться.
Таким образом, следует откинуть человекочитаемость формата как преимущество и рассматривать XML прежде всего как средство коммуникаций между сервисими, программами или платформами, этакое платформонезависимое средство общения систем.
Исходя из вышеобоснованной позиции, возникает второе сомнение. А не дорого ли? В данном случае оценивается процессорное время. В последнем проекте пришлось замерять производительность (можно сказать жёстко «профайлить») и, надо сказать, одним из самых узких мест оказалась сериализация объектов в XML и их реинкарнация из него. Можно предположить, что руки надо мыть чаще, но за почти месяц борьбы за чистоту рядов, — производительность хоть и поднялась, но не настолько, чтобы радовать коллектив разработчиков.
Последний из камней сомнений, самый легкий и, в тоже время, фундаментально непоправимый, связан с объемом передаваемых данных, то есть объемом генерируемого трафика. Пока клиентов было мало, этой проблемы как бы и не существовало. Однако, когда появился мобильный клиент к сервису и одновременно в систему устремились толпы корпоративщиков, объем генерируемого трафика ясно указал на избыточность XML (генерирование белого шума), как протокола для работы с клиентскими приложения (с их большой массой).
Можно сделать вывод, что сложность использования XML превышает сложность тех проблем, которые эта технология решает. Вы сами можете придумать массу доводов за и массу против, как, в том числе, это делают даже создатели XML [TB, TB2]. Но в пользу XML, хочу заметить следующее: использование его в качестве протокола для синхронизации серверов практически идеально, а средства автоматизации разработки позволяют расслабиться и получать удовольствие. Но проблема клиентского трафика заставила обратить внимание на формат представления данных JSON.
Альтернатива
Главным источником информации о JSON является официальный сайт [JSON], содержащий следующее определение: JSON (JavaScript Object Notation) — простой формат обмена данными, удобный для чтения и написания как человеком, так и компьютером. С ходу отметая определение, которое ориентированно на продвижение JSON в массы, отметим, что формат является: текстовым, открытым, простым и неплохо документированным [JSONdoc].
На мой взгляд, удобность читаемости человеком формата JSON по сравнению с XML еще ниже. Для проверки этого утверждения выполните любой запрос к поисковому API twitter.com, например: search.twitter.com/search.json?q=golodnyj, и попробуйте интерпретировать результат без ознакомления с самим API. У вас возникнут сложности, как минимум из-за того, что JSON не передает семантику, а предназначен для представления содержания. Исходя из вышесказанного, JSON следует определять как текстовый, открытый, легкий протокол сопряжения клиент-серверных приложений, ориентированный на передачу объектов.
Переход на использование JSON действительно значительно (до 25-30%) сократил объем пользовательского трафика и позволил значительно снизить нагрузку на сетевую инфраструктуру сервиса. Однако, как вы понимаете, пришлось заменить генерирование и парсинг с XML на JSON. Казалось бы, ничего хорошего в этом нет — значительный рефакторинг кода, отладка и длительное тестирование, но нам повезло.
Герой дня
Спасителем человечества в отдельно взятых его областях стал фреймфорк XStream [XS], который, по счастливому стечению обстоятельств, использовался для работы с XML именно в той части системы, над которой проводился эксперимент.
В качестве примера рассмотрим класс Client (полный исходный код смотрите в приложении 1), который имеет три атрибута, конструктор, геттеры и сеттеры:
package ru.golodnyj.lection.json;
public class Client {
private String userName;
private boolean verified;
private int userId;
public Client(String userName, boolean verified, int userId) {
this.userName = userName;
this.verified = verified;
this.userId = userId;
}
...
}
* This source code was highlighted with Source Code Highlighter.
А также класс ConsoleJSON (приложение 2), в котором сначала демонстрируется сериализация экземпляра класса Client в формат XML, а потом в JSON:
package ru.golodnyj.lection.json;
...
public class ConsoleJSON {
public static void main(String[] args) {
Client c = new Client("name",true , 5);
// Создание XML
XStream xstream = new XStream(new DomDriver());
String xml = xstream.toXML(c );
System.out.println("xml "+ xml.length() +" : \n" + xml);
// Создание JSON
XStream xstream1 = new XStream(new JsonHierarchicalStreamDriver());
String json = xstream1.toXML(c );
System.out.println("json "+ json.length() +" : \n" + json);
}
}
* This source code was highlighted with Source Code Highlighter.
После запуска программы вы получите сообщение в консоле вида:
xml 145 :
<ru.golodnyj.lection.json.Client>
<userName>name</userName>
<verified>true</verified>
<userId>5</userId>
</ru.golodnyj.lection.json.Client>
json 96 :
{"ru.golodnyj.lection.json.Client": {
"userName": "name",
"verified": true,
"userId": 5
}}
* This source code was highlighted with Source Code Highlighter.
Сначала идет отображение XML — объем получившейся строки 145 символов, а затем JSON длинной 96 символом. Разница в длине строк при сериализации такого простого объекта значительная, что же говорить о сложных конструкциях. Конечно вывод для XML и для JSON можно сделать компактным, например, для передачи данных совершенно неважно полное каноническое имя класса и форматированный вывод.
Для улучшения вывода можно воспользоваться механизмом алиасов в XStream, который позволяет сопоставить с именем класса некоторую строковую переменную. А также, для формата JSON необходимо изменить драйвер с JsonHierarchicalStreamDriver(), обеспечивающий форматированный вывод, на JettisonMappedXmlDriver(), предназначенный для поточного вывода.
XStream xstream1 = new XStream(new JettisonMappedXmlDriver());
xstream1.alias(«client», Client.class);
* This source code was highlighted with Source Code Highlighter.
В таком случае JSON вариант для экземпляра объекта Client будет длинной 57 символов и выглядеть следующим образом:
{"client":{"userName":"name","verified":true,"userId":5}}
Процесс десериализации из XML в POJO также прост и заключается в вызове метода fromXML() экземпляра класса XStream, в качестве параметра которому передана JSON-строка, с последующим приведением типов данных.
Выводы
Если вы еще раз обратите внимание на класс ConsoleJSON, вы заметите как мало требуется для того, чтобы заменить вывод с XML на JSON. В результате имеем значительную экономию объема генерируемого трафика. В данном конкретном случае с серверной стороны процесс рефакторинга, имевший целью замену протокола передачи данных с XML на JSON, был очень простым и не потребовал значительных усилий.
ЛИТЕРАТУРА
[TB] Tim Bray www.tbray.org/ongoing/When/200x/2003/03/16/XML-Prog
[TB2] Tim Bray www.tbray.org/ongoing/When/200x/2003/03/24/XMLisOK
[JSON] www.json.org
[JSONdoc] www.json.org/json-ru.html
[XS] xstream.codehaus.org
Приложения
Приложение 1 dumpz.org/12012
Приложение 2 dumpz.org/12013