Статьи

Обработка JSON (JSON-P)

JSON (JavaScript Object Notation) — это формат компактного текстового файла, который можно использовать для хранения и передачи данных. За последние годы он стал очень популярным, так как его очень просто читать и анализировать. Кроме того, каждая конструкция JSON должна быть допустимым JavaScript, и должна быть возможность оценить его с помощью функции JavaScript eval (). Последнее сделало его популярным в сообществе веб-разработчиков, поскольку данные JSON, полученные с сервера, можно легко оценить на стороне клиента.
Популярность JSON вызвала потребность использовать его и на стороне сервера. Со временем были разработаны различные библиотеки Java, которые поддерживают чтение и запись данных JSON (например, google-gson , flexjson или Jackson ). Следовательно, вопрос времени пока JSON-обработка не станет частью спецификации Java EE.

В прошлой статье я пролил свет на новые функции параллелизма Java EE 7. В этой статье мы хотим изучить новую функцию JSON Processing. После этих вступительных слов пришло время взяться за некоторый код. Следующий код показывает, как написать очень простой файл JSON:

01
02
03
04
05
06
07
08
09
10
11
12
13
JsonObject model = Json.createObjectBuilder()
        .add("firstName", "Martin")
        .add("phoneNumbers", Json.createArrayBuilder()
                .add(Json.createObjectBuilder()
                        .add("mobile", "1234 56789"))
                .add(Json.createObjectBuilder()
                        .add("home", "2345 67890")))
        .build();
try (JsonWriter jsonWriter = Json.createWriter(new FileWriter(Paths.get(System.getProperty("user.dir"), "target/myData.json").toString()))) {
    jsonWriter.write(model);
} catch (IOException e) {
    LOGGER.severe("Failed to create file: " + e.getMessage());
}

API конструктора позволяет легко добавлять следующий вызов к предыдущему. Мне все еще нужно привыкнуть к тому, что вам нужно вызывать createArrayBuilder () или createObjectBuilder () каждый раз, когда вы хотите создать массив или объект. При чтении файла JSON вы должны определить тип, который вы сейчас читаете, вызвав getValueType ():

1
2
3
4
5
6
7
try (JsonReader jsonReader = Json.createReader(new FileReader(Paths.get(System.getProperty("user.dir"), "target/myData.json").toString()))) {
    JsonStructure jsonStructure = jsonReader.read();
    JsonValue.ValueType valueType = jsonStructure.getValueType();
    if (valueType == JsonValue.ValueType.OBJECT) {
        JsonObject jsonObject = (JsonObject) jsonStructure;
        JsonValue firstName = jsonObject.get("firstName");
        ...

Функциональность сопоставления полного файла JSON с существующей структурой классов Java (в некоторых случаях, например, JAX-B для файлов XML) не является частью стандарта. Но вместо этого JSON-P предлагает полный API потоковой передачи для чтения огромного количества данных JSON:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
try (FileWriter writer = new FileWriter(Paths.get(System.getProperty("user.dir"), "target/myStream.json").toString())) {
    JsonGenerator gen = Json.createGenerator(writer);
    gen
    .writeStartObject()
        .write("firstName", "Martin")
        .writeStartArray("phoneNumbers")
            .writeStartObject()
                .write("mobile", 123456789)
                .write("home", "2345 67890")
            .writeEnd()
        .writeEnd()
    .writeEnd();
    gen.close();
} catch (IOException e) {
    LOGGER.severe("Failed to write to file: " + e.getMessage());
}

Код для потокового API читается очень похоже на обычный API. Основное отличие состоит в том, что вы должны пометить конец массива или объекта с помощью writeEnd (). Чтение файла JSON выглядит очень похоже на [Streaming API for XML (StAX)] ( http://stax.codehaus.org/Home ):

01
02
03
04
05
06
07
08
09
10
11
12
try (FileReader fileReader = new FileReader(Paths.get(System.getProperty("user.dir"), "target/myStream.json").toString())) {
    JsonParser parser = Json.createParser(fileReader);
    while (parser.hasNext()) {
        JsonParser.Event event = parser.next();
        switch (event) {
            case START_OBJECT:
                LOGGER.info("{");
                break;
            case END_OBJECT:
                LOGGER.info("}");
                break;
...

Просто сказав, что приведенный выше код выглядит очень похоже на код StAX, давайте попробуем сравнить обе реализации по размеру файла и времени выполнения. На следующей диаграмме показано среднее время выполнения для записи и чтения файла JSON / XML с 100 000 записей.

comparison_diagram
Одна запись состоит из простого объекта с именем и массива из двух телефонных номеров:

1
{"firstName":"Martin","phoneNumbers":[{"mobile":123456789,"home":"2345 67890"}]}

Вот как это выглядит в XML:

1
<firstName>Martin</firstName><phoneNumbers><mobile>123456789</mobile><home>234567890</home></phoneNumbers>

Удивительно, что реализация StAX намного медленнее при записи больших файлов. Если присмотреться к размеру файла, мы увидим, что файл XML примерно в 1,31 раза больше, чем файл JSON, хотя он содержит те же данные.

Вывод: JSON-P предоставляет стандартизированный API для обработки JSON вместе с потоковым API, подобным StAX. Хотя ему все еще не хватает привязки к структуре класса Java, он работает даже лучше, чем реализация StAX, благодаря более компактному размеру файла.

PS: реализации, используемые в сравнении, перечислены ниже:

01
02
03
04
05
06
07
08
09
10
<dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.json</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>stax</groupId>
        <artifactId>stax</artifactId>
        <version>1.2.0</version>
    </dependency>
Ссылка: JSON Processing (JSON-P) от нашего партнера по JCG Мартина Мойса из блога Martin’s Developer World .