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

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

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

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

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

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

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

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

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

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

Редактор JEXL#

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

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

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

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

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

При открытии редактора отображается рабочее пространство с тремя функциональными областями:

panel

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

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

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

  3. Откатить.

  4. Обновить.

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

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

  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(21l);

Конкретное применение 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();