Перейти к основному содержанию
`Ctrl`+`K`

# Введение и основы JEXL

## Введение в языки выражений

Языки выражений — специализированные языки для вычисления выражений во время работы программы. Они позволяют динамически выполнять математические, логические и строковые операции, обращаться к свойствам объектов и вызывать методы без компиляции кода.

Языки выражений работают в работающей программе, позволяя гибко менять логику — например, проверять условия `user.age > 18` или вычислять формулы `price * quantity` без перезапуска приложения.

Зачем они нужны:

- Гибкость — изменение логики без перекомпиляции приложения.

- Безопасность — ограниченный набор операций снижает риски выполнения вредоносного кода.

- Удобство — простой синтаксис для нетривиальных вычислений.

- Динамическая оценка — выражения могут загружаться из внешних источников.

JEXL — библиотека, реализующая язык выражений для вычисления и выполнения скриптов в Java-приложениях.

## Редактор JEXL

Путь доступа:

1. Откройте главное меню системы.

2. Перейдите в раздел Сервисы.

3. Выберите подраздел Инструменты.

4. Нажмите пункт Выполнить JEXL-скрипт.

Рабочее пространство состоит из трёх областей:

Панель инструментов — набор кнопок для управления скриптами:

1. Выполнить — запуск текущего скрипта.

2. Сохранить.

3. Откатить.

4. Обновить.

5. Открыть скрипт из библиотеки JEXL — выбор скрипта из общего/личного хранилища.

6. Информация + Аудит JEXL — просмотр метаданных и истории изменений .

7. Проверить правильность JEXL скрипта — проверка синтаксиса написанного кода.

8. Помощь — краткая справка по существующим методам:

   - Помощь — вкладка с методами и их кратким описанием.

   - Список объектов — список объектов API всей системы.

   - Контекст — фильтр отображения методов по контексту, API, математическим функциям.

   - К оглавлению — возврат к редактору кода.

   - Обновить.

   - Проверить правильность Jexl скрипта.

   - Официальная документация.

9. Выход.

Рабочая область — написание и редактирование JEXL-кода.

Журнал выполнения — хронология выполнения скриптов, ошибки и предупреждения, системные сообщения.

- Очистить логи — удаление всей текущей истории сообщений из журнала.

## Основы синтаксиса выражений

### Простые выражения

JEXL поддерживает стандартные операторы, аналогичные Java.

Арифметика:

    var sum = 5 + 3;       // 8
    var total = 8 * 10;      // 80
    var remainder = 10 % 3; // 1

Логические операции:

    var isActive = true;
    var isEligible = (age >= 18) && isActive;
    var isAdmin = (role == "admin") || (role == "superuser");

Сравнения:

    price == 100
    name != 'admin'
    score > 90

### Поддерживаемые типы данных

JEXL работает с основными типами:

- числа — целые (42), дробные (3.14);

- строки — в одинарных („text“), двойных («text») или обратных кавычках (`test`);

- булевы значения — true, false;

- null — отсутствие значения;

- коллекции — списки [1, 2, 3], мапы {„key“: „value“}, множества {1, 2, 3}.

### Обертки для безопасной передачи данных

В JEXL для работы со Scala-методами, требующими строгой типизации и поддержки null, используются специальные обертки.

Scala — статически типизированный язык, где:

- null для примитивов (Long, Int) запрещен.

При вызове Scala-методов из JEXL:

- JEXL передает «сырые» значения (String, Number, null);

- Scala ожидает строгие типы (`NLong`, `NGid`).

Null-типы и их назначения:

Null-тип | Назначение
--- | ---
`NLong` | Работа с идентификаторами (ID)
`NNumber` | Работа с целыми/дробными числами
`NGid` | Работа с глобальными идентификаторами (GUID)
`NDate` | Работа с датами
`NString` | Работа со строками (с поддержкой null)
`NBigDecimal` | Точные расчеты (деньги, финансы)
`NDuration` | Арифметика временных промежутков

Создание Null-типа на примере `NLong`:

    var NLong = function(number) {
        return new ("ru.bitec.app.gtk.lang.NLong", number);
    };
    var nlValue = NLong(21);

Конкретное применение null-типов:

    // Создаем Map с параметрами для заказа
    Map1.put(
        new ("ru.bitec.app.gtk.lang.NLong", ropStageDet.id),
        new ("ru.bitec.app.gtk.lang.NNumber", ropStageDet.nQty)
    );

    // Создаем заказ
    idvOrder = Stm_OrderOutApi.createOrderByContractStage(
        ropStage.id,
        idvDepOwner,
        idvOrderType,
        asScala(Map1), // Основные параметры
        asScala(EmptyMap), // Доп. параметры 1
        asScala(EmptyMap), // Доп. параметры 2
        null
    );

## Работа с переменными

### Способы объявления переменных

JEXL предоставляет три способа объявления переменных: let, const и var, каждый с своей областью видимости и правилами изменяемости.

let — Локальная переменная

Ключевое слово let создаёт переменную, доступную только внутри блока { }, где она объявлена, включая вложенные блоки. Переменная не может быть переопределена в той же области.

Пример:

    if (56 < 100) {
        let sText = "Example text";
    }
    dialogs.showMessage(sText) // ошибка: переменная объявлена в другом блоке

const — Неизменяемая переменная

Переменная, объявленная через const, имеет блочную область видимости, но её значение нельзя изменить после инициализации.

Пример:

    if (56 < 100) {
        const sText = "Example text";
        sText = "Changed text"; // Ошибка: изменение константы
    }

Исключение: если const ссылается на объект, его внутренние свойства могут изменяться — неизменной остаётся только ссылка.

Пример:

    const arrayEven = [2, 4, 6, 8];
    arrayEven[0] = 10;
    dialogs.showMessage(arrayEven[0]); // Вывод: 10

var — Глобальная переменная

По умолчанию var создаёт переменную, видимую во всём скрипте, и позволяет её переопределять:

    if (56 < 100) {
        var sText = "Example text";
        sText = "Changed text";
    }
    sText = "Outer text"; // Изменение разрешено
    dialogs.showMessage(sText); // Вывод: Outer text

Когда что использовать:

- const — для значений, которые не должны меняться;

- let — для обычных переменных внутри блоков;

- var — для глобальных переменных (с осторожностью).

### Объявления переменных поддерживаемых типов

Числовые типы:

    var nValue = 42; // Целое число
    var fValue = 42.0f; // Число с плавающей точкой
    var lValue = 42L; // Длинное целое
    var dValue = 42.0d; // Число двойной точности
    var bigIntValue = 42H; // Большое целое
    var bigDecValue = 42.0B; // Число высокой точности
    var hexValue = 0x2A; // Шестнадцатеричное число
    var octValue = 052; // Восьмеричное число
    var sciValue = 4.2E+1D; // Число в научной нотации

Строковые типы:

    var sStr1 = "Hello"; // Строка (двойные кавычки)
    var sStr2 = 'World'; // Строка (одинарные кавычки)
    var sStr3 = `line1 // Многострочный комментарий
    line2
    line3
    `;
    var intValue = 10
    var interpolatedStr = `Value: ${intValue}`; // Строка с подстановкой
    var regex = ~/pattern\d+/; // Регулярное выражение

Специальные значения:

    var bVal = true; // Логическое значение
    var nVal = null; // Пустое значение
    var tuple2 = (v1, v2) -> { return new(`scala.Tuple2`, v1, v2); }; // Кортеж

Коллекции:

    var array = [1, 2, 3]; // Массив
    var objArray = [1, "two", 3.0]; // Массив объектов
    var list = [1, 2, 3, ...]; // Список
    var set = {"a", "b", "c"}; // Множество
    var map = {"key1": 1, "key2": 2}; // Карта
    var range = 1..10; // Диапазон чисел
    var rop = Stm_OrderOutApi.load(id); // Строка роп соответствующая объекту БД

Пустые коллекции:

    var emptyArray = []; // Пустой массив
    var emptyList = [...]; // Пустой список
    var emptySet = {}; // Пустое множество
    var emptyMap = {:}; // Пустая карта

### Доступ к свойствам объектов

Два варианта доступа к объекту:

    // Через точку (автоматически вызывает getter)
    var sClientName = order.client.name;

    // Через метод
    var nTotal = order.getTotal();