Как Manifold революционизирует синтаксический анализ JSON в Java

Как Manifold революционизирует синтаксический анализ JSON в Java

3 мая 2023 г.

Разработчики Java часто завидовали JavaScript за его простоту синтаксического анализа JSON. Хотя Java предлагает большую надежность, она, как правило, требует больше работы и стандартного кода. Благодаря проекту Manifold у Java теперь есть потенциал превзойти JavaScript в анализе и обработке файлов JSON.

Manifold — это революционный набор языковых расширений для Java, который полностью меняет способ обработки JSON (и многое другое…).

https://www.youtube.com/watch?v=AoBnGZ7q6rk&embedable=true

Начало работы с коллектором

Код этого руководства можно найти на моей странице GitHub. Манифолд относительно молод, но уже широк в своих возможностях. Вы можете узнать больше о проекте на их веб-сайте и в Slack-канале.

Для начала вам необходимо установить подключаемый модуль Manifold, который в настоящее время доступен только для IDE JetBrains. Проект поддерживает LTS-версии Java, включая последнюю версию JDK 19.

Мы можем установить плагин из пользовательского интерфейса настроек IntelliJ/IDEA, перейдя на рынок и выполнив поиск Manifold. Подключаемый модуль гарантирует, что среда IDE не будет конфликтовать с работой, выполняемой подключаемым модулем Maven/Gradle.

Image description

Manifold состоит из нескольких небольших проектов, каждый из которых предлагает собственное языковое расширение. Сегодня мы обсудим одно из таких расширений, но впереди еще много интересного.

Настройка проекта Maven

Чтобы продемонстрировать Manifold, мы будем использовать простой проект Maven (он также работает с Gradle). Сначала нам нужно вставить текущую версию Manifold с их веб-сайта и добавить необходимые зависимости. Основной зависимостью для JSON является зависимость manifold-json-rt.

Другие зависимости могут быть добавлены для поддержки YAML, XML и CSV. Нам нужно добавить это в файл pom.xml в проекте.

Я знаю об иронии, когда сокращение шаблона для JSON начинается с большой конфигурации в сценарии сборки Maven. Но это конфигурация, а не «фактический код»; это в основном копирование & вставить.

Обратите внимание: если вы хотите сократить этот код, эквивалентный код Gradle будет кратким по сравнению с ним.

Эта строка должна войти в раздел свойств:

<manifold.version>2023.1.5</manifold.version>

Мы используем следующие зависимости:

<dependencies>
   <dependency>
       <groupId>systems.manifold</groupId>
       <artifactId>manifold-json-rt</artifactId>
       <version>${manifold.version}</version>
   </dependency>

Плагин компиляции — это шаблон, который вплетает Manifold в байт-код и делает его бесшовным для нас. Это последняя часть настройки pom:

<build>
   <plugins>
       <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>3.8.0</version>
           <configuration>
               <source>19</source>
               <target>19</target>
               <encoding>UTF-8</encoding>
               <compilerArgs>
                   <!-- Configure manifold plugin-->
                   <arg>-Xplugin:Manifold</arg>
               </compilerArgs>

               <!-- Add the processor path for the plugin -->
               <annotationProcessorPaths>
                   <path>
                       <groupId>systems.manifold</groupId>
                       <artifactId>manifold-json</artifactId>
                       <version>${manifold.version}</version>
                   </path>
               </annotationProcessorPaths>
           </configuration>
       </plugin>
   </plugins>
</build>

После завершения настройки давайте углубимся в код.

Анализ JSON с коллектором

Мы помещаем образец файла JSON в каталог проекта в иерархии ресурсов. Я поместил этот файл в src/main/resources/com/debugagent/json/Test.json:

{
  "firstName": "Shai",
  "surname": "Almog",
  "website": "https://debugagent.com/",
  "active": true,
  "details":[
    {"key": "value"}
  ]
}

В основном классе мы обновим проект Maven, и вы заметите, что появился новый класс Test. Этот класс динамически создается Manifold на основе файла JSON. Если вы измените JSON и обновите Maven, все обновится без проблем.

Важно понимать, что Manifold не является генератором кода. Он компилирует JSON, который мы только что написали, в байт-код.

Класс Test поставляется с несколькими встроенными возможностями, такими как безопасный для типов API построителя, который позволяет создавать объекты JSON с использованием методов построителя. Вы также можете создавать вложенные объекты и преобразовывать JSON в строку с помощью методов write() и toJson().

Это означает, что теперь мы можем написать:

Test test = Test.builder().withFirstName("Someone")
        .withSurname("Surname")
        .withActive(true)
        .withDetails(List.of(
                Test.details.detailsItem.builder().
                        withKey("Value 1").build()
        ))
        .build();

Который распечатает следующий JSON:

{
  "firstName": "Someone",
  "surname": "Surname",
  "active": true,
  "details": [
    {
      "key": "Value 1"
    }
  ]
}

Точно так же мы можем прочитать файл JSON, используя такой код:

Test readObject = Test.load().fromJson("""
        {
          "firstName": "Someone",
          "surname": "Surname",
          "active": true,
          "details": [
            {
              "key": "Value 1"
            }
          ]
        }
        """);

Обратите внимание на использование синтаксиса Java 15 TextBlock для записи длинной строки. Метод load() возвращает объект, включающий различные API для чтения JSON. В этом случае он читается из String, но есть API для чтения из URL, файла и т. д.

Manifold поддерживает различные форматы, включая CSV, XML и YAML, что позволяет вам генерировать и анализировать любой из этих форматов без написания стандартного кода и без ущерба для безопасности типов. Чтобы добавить эту поддержку, нам потребуется добавить дополнительные зависимости в файл pom.xml:

   <dependency>
       <groupId>systems.manifold</groupId>
       <artifactId>manifold-csv-rt</artifactId>
       <version>${manifold.version}</version>
   </dependency>
   <dependency>
       <groupId>systems.manifold</groupId>
       <artifactId>manifold-xml-rt</artifactId>
       <version>${manifold.version}</version>
   </dependency>
   <dependency>
       <groupId>systems.manifold</groupId>
       <artifactId>manifold-yaml-rt</artifactId>
       <version>${manifold.version}</version>
   </dependency>
</dependencies>

С этими дополнительными зависимостями этот код будет печатать те же данные, что и файл JSON... С помощью test.write().toCsv() вывод будет таким:

"firstName","surname","active","details"
"Someone","Surname","true","[manifold.json.rt.api.DataBindings@71070b9c]"

Обратите внимание, что вывод значений, разделенных запятыми (CSV), не включает информацию об иерархии. Это ограничение формата CSV, а не вина Manifold.

С помощью test.write().toXml() вывод знаком и на удивление лаконичен:

<root_object firstName="Someone" surname="Surname" active="true">
  <details key="Value 1"/>
</root_object>

С помощью test.write().toYaml() мы снова получаем знакомую распечатку:

firstName: Someone
surname: Surname
active: true
details:
- key: Value 1

Работа со схемой JSON

Manifold также легко работает со схемой JSON, что позволяет применять строгие правила и ограничения. Это особенно полезно при работе с датами и перечислениями.

Manifold легко создает/обновляет байт-код, соответствующий схеме, что значительно упрощает работу со сложными данными JSON.

Эта схема скопирована и вставлена ​​из проекта Manifold GitHub:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://example.com/schemas/User.json",
  "type": "object",
  "definitions": {
    "Gender": {
      "type": "string",
      "enum": ["male", "female"]
    }
  },
  "properties": {
    "name": {
      "type": "string",
      "description": "User's full name.",
      "maxLength": 80
    },
    "email": {
      "description": "User's email.",
      "type": "string",
      "format": "email"
    },
    "date_of_birth": {
      "type": "string",
      "description": "Date of uses birth in the one and only date standard: ISO 8601.",
      "format": "date"
    },
    "gender": {
      "$ref" : "#/definitions/Gender"
    }
  },
  "required": ["name", "email"]
}

Это относительно простая схема, но я хотел бы обратить ваше внимание на несколько моментов. Он определяет имя и адрес электронной почты по мере необходимости. Вот почему, когда мы пытаемся создать объект User с помощью построителя в Manifold, метод build() требует оба параметра:

User.builder("Name", "email@domain.com")

Это только начало... Схема включает дату. Даты — болезненная перспектива в JSON, стандартизация плохая и чреватая проблемами. Схема также включает гендерное поле, которое фактически является перечислением.

Все это преобразуется в типобезопасную семантику с использованием общих классов Java, таких как LocalDate:

User u = User.builder("Name", "email@domain.com")
       .withDate_of_birth(LocalDate.of(1999, 10, 11))
       .withGender(User.Gender.male)
       .build();

Это можно сделать еще короче с помощью статического импорта, но суть идеи ясна. JSON фактически встроен в Java в Manifold.

Верхушка айсберга

Manifold — мощный и захватывающий проект. Он революционизирует синтаксический анализ JSON в Java, но это лишь малая часть того, что он может сделать!

В этом посте мы только коснулись его возможностей. В следующей статье мы углубимся в Manifold и рассмотрим некоторые дополнительные неожиданные функции.

Пожалуйста, поделитесь своим опытом и мыслями о Manifold в разделе комментариев. Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE