JSON

Этот раздел перенесён из документации Camunda 7 и в дальнейшем будет доработан с учётом особенностей OpenBPM Engine

Для работы с JSON в качестве точек вхождения могут использоваться Spin-функции io.openbpm.spin.Spin.S и io.openbpm.spin.Spin.JSON. Последняя предлагает строго типизированный доступ к JSON API от Spin, предпочтительный при написании кода на Java. В окружениях, предназначенных для написания скриптов, доступна только функция S. Возвращаемая Spin-обертка предлагает методы для манипуляции данными и их записи в JSON, а также для маппинга JSON на Java. Более того, функции для вхождений могут быть предоставлены с Java объектами, которые неявно преобразуются в промежуточный JSON формат от Spin.

Далее приведены примеры того, как Camunda Spin может использоваться в движке обработки процессов для работы с JSON данными. Для целей иллюстрации предположим, что существует процессная переменная типа String с именем customer, которая содержит JSON. Ее содержимое выглядит следующим образом:

{
  "name" : "jonny",
  "address" : {
    "street" : "12 High Street",
    "post code" : 1234
  }
}

Если вы хотите узнать, как использовать JSON объекты в их встроенной форме, обратитесь к справочнику встроенных форм.

Больше документация об использовании Spin можно найти в справочнике Camunda Spin по форматам данных.

Интеграция языка выражений

Функции вхождений от Spin можно использовать везде, где движок управления процессами позволяет использовать язык выражений. Следующий фрагмент BPMN показывает выражение последовательного алгоритма с условием, которое основано на почтовом коде клиента:

...
<sequenceFlow>
  <conditionExpression xsi:type="tFormalExpression">
    ${S(customer).prop("address").prop("post code").numberValue() == 1234}
  </conditionExpression>
</sequenceFlow>
...

Если ваша переменная уже входит в число JSON переменных, а не является строкой, как в предыдущем примере, вы можете опустить вызов S(…​) и напрямую обратиться к переменной:

...
<sequenceFlow>
  <conditionExpression xsi:type="tFormalExpression">
    ${customer.jsonPath("$.address.post code").numberValue() == 1234}
  </conditionExpression>
</sequenceFlow>
...

Интеграция механизма написания скриптов

Нижеприведенный пример — это скрипт, написанный на JavaScript. Скрипт использует Spin API для извлечения адреса объекта из переменной customer, добавления названия города и установки ее в качестве процессной переменной:

...
<scriptTask id="task" name="Script Task" scriptFormat="javascript">
  <script>
    <![CDATA[
    var address = S(customer).prop("address");
    address.prop("city", "New York");
    execution.setVariable("address", address.toString());
    ]]>
  </script>
</scriptTask>
...

Значения нативных переменных JSON

Концепция значений нативных переменных для JSON делает возможным ранний парсинг JSON строки и ее оборачивание внутри объекта без необходимости наличия класса, представляющего JSON. Допустим, мы хотим сохранить JSON внутри процессной переменной для последующего использования; мы можем сделать следующее внутри JavaDelegate:

public class MyDelegate implements JavaDelegate {
  @Override
  public void execute(DelegateExecution execution) throws Exception {
    String json = "{\"name\" : \"jonny\","
        + "\"address\" : {"
          + "\"street\" : \"12 High Street\","
          + "\"post code\" : 1234"
          + "}"
        + "}";
    JsonValue jsonValue = SpinValues.jsonValue(json).create();
    execution.setVariable("customerJonny", jsonValue);
  }
}

Вызов SpinValues.jsonValue(…​).create() преобразует строку в Jackson объект в обертке от Spin.

Если бы мы хотели извлечь JSON в другом JavaDelegate и, например, добавить больше информации, мы могли бы легко сделать это:

public class AddDataDelegate implements JavaDelegate {
  @Override
  public void execute(DelegateExecution execution) throws Exception {
    JsonValue customer = execution.getVariableTyped("customerJonny");
    customer.getValue().prop("creditLimit", 1000.00);
    //{"name":"jonny","address":{"street":"12 High Street","post code":1234},"creditLimit":1000.0}
  }
}

При извлечении JSON-значения через execution.getVariableTyped() имеются две опции: сериализованное и десериализованное значение. При извлечении десериализованной переменной через вызов либо getVariableTyped("name"), либо getVariableTyped("name", true), JsonValue будет содержать обернутый Jackson объект для представления JSON данных. Вызов getVariableTyped("name", false) приведет к тому, что JsonValue будет содержать только сырую строку, что может быть преимуществом, если вам нужна только строка, например, чтобы передать ее в другой API.

Сериализация процессных переменных

Java объект можно сериализовать, используя встроенный формат данных JSON от Spin. Предположим, что у нас есть только два Java класса, com.example.Customer и com.example.Address, со следующей структурой:

public class Customer {
  protected String name;
  protected Address address;

  /* constructor, getters and setters omitted for brevity */
}

public class Address {
  protected String street;
  protected int postCode;

  /* constructor, getters and setters omitted for brevity */
}

Следующий код на Java устанавливает процессную переменную на объект типа Customer, который сериализуется с использованием формата данных JSON от Spin:

Address address = new Address("12 High Street", 1234);
Customer customer = new Customer("jonny", address);

ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("aProcess");

ObjectValue typedCustomerValue =
  Variables.objectValue(customer).serializationDataFormat("application/json").create();

runtimeService.setVariable(processInstance.getId(), "customer", typedCustomerValue);

Определяющая команда здесь:

ObjectValue typedCustomerValue =
  Variables.objectValue(customer).serializationDataFormat("application/json").create();

Она создает значение переменной для объекта типа Customer. Вызов serializationDataFormat("application/json") говорит движку управления процессами, в каком формате должна сериализоваться переменная. Это имя должно совпадать с именем формата данных, известного Spin. Например, application/json — это имя встроенного формата данных JSON.

Как только переменная установлена, ее сериализованное значение может быть извлечено с использованием API типов переменных. Например:

ObjectValue customer = runtimeService.getVariableTyped(processInstance.getId(), "customer");
String customerJson = customer.getValueSerialized();

/*
customerJson matches:
{
  "name" : "jonny",
  "address" : {
    "street" : "12 High Street",
    "postCode" : 1234
  }
}
*/

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

Движок можно сконфигурировать таким образом, чтобы он сохранял в базе данных все объекты, для которых ни один из явно указанных форматов данных на задан как JSON. Конфигурация движка управления процессами предлагает свойство defaultSerializationFormat. Чтобы сконфигурировать сериализацию JSON по умолчанию, установите это свойство в application/json. Теперь вызов runtimeService.setVariable(processInstance.getId(), "customer", new Customer()) напрямую сериализует объект customer как JSON без явного указания формата.

Лицензия и атрибуция

Эта документация была создана на базе материала "Camunda 7 Docs" от Camunda, находится под лицензией Creative Commons Attribution-ShareAlike 3.0 Unported License .

Оригинал документации: https://docs.camunda.org