.user.nameДоступ к переменным
Читайте корневые и вложенные значения из контекста и definitions.
JJT означает Java JSON Template: компактный язык шаблонов, который компилирует JSON-документы в оптимизированные деревья выражений для быстрого повторного рендеринга.
{
"definitions": [
{ "name": "Ada" },
{ "price": 420 },
{ "quantity": 3 },
{
"total": "{{ math:mul .price, .quantity }}"
}
],
"template": {
"customer": "{{ .name | string:trim }}",
"total": "{{ .total }}",
"tier": "{{ .total | gt 1000 ? 'priority' : 'standard' }}"
}
}
{ "customer": "Ada", "total": 1260, "tier": "priority" }
Добавьте библиотеку, скомпилируйте JSON-шаблон и передайте контекст для рендеринга.
implementation("io.github.sibmaks.jjtemplate:jjtemplate:1.0.0")
<dependency>
<groupId>io.github.sibmaks.jjtemplate</groupId>
<artifactId>jjtemplate</artifactId>
<version>1.0.0</version>
<type>pom</type>
</dependency>
Передайте definitions и JSON-совместимый template в TemplateScript.
Компилятор свернёт константы и подготовит дерево выражений.
Рендерите разные данные без повторной компиляции.
var script = TemplateScript.builder()
.template(
Map.of(
"message", "{{ string:concat 'Hello, ', .name }}",
"active", "{{ .enabled }}"
)
)
.build();
var compiler = TemplateCompiler.getInstance();
var compiled = compiler.compile(script);
// Повторно используйте compiled для каждого контекста.
var result = compiled.render(
Map.of(
"name", "Alice",
"enabled", true
)
);
Структура JSON остаётся видимой, а выражения отвечают за подстановку, условия и разворачивание.
.user.nameЧитайте корневые и вложенные значения из контекста и definitions.
{{ expression }}Вставляйте типизированный результат: boolean и number сохраняют тип.
{{? expression }}Пропускайте поле объекта или элемент массива, если результат равен null.
{{. expression }}Разворачивайте объект в объект, а коллекцию — в массив.
.value | string:trimПередавайте значение слева в функцию и составляйте цепочки преобразований.
.ready ? 'yes' : 'no'Выбирайте значение; ветви могут содержать вызовы, pipe и вложенные выражения.
.repository?.foo('bar')Получайте null, если свойства или подходящего метода нет; задавайте fallback через default.
Ключи definitions для switch и range используют те же разделители {{ ... }}, что и другие выражения.
Каждый пример сопоставляет JJT-документ и JSON-значение, полученное во время выполнения.
Функции сгруппированы по пространствам имён. Глобальные логические функции вызываются без namespace.
Преобразуйте значения через cast:str, cast:int, cast:float и cast:boolean.
Объединяйте и форматируйте строки, при необходимости с locale.
Меняйте регистр и удаляйте пробелы по краям строки.
Проверяйте длину, пустоту и наличие подстроки.
Разбивайте строки, получайте подстроки и ищите позиции.
Заменяйте литералы и совпадения регулярных выражений.
Создавайте списки и объединяйте массивы или коллекции.
Проверяйте, выбирайте и объединяйте элементы списка.
Создавайте map и сворачивайте свойства объектов.
Проверяйте размер, пустоту и наличие ключей.
Выполняйте десятичную арифметику, меняйте знак и scale.
Создавайте, разбирайте и форматируйте даты и время.
Создавайте форматтеры чисел и валют с учётом locale.
Сравнивайте значения без пространства имён.
Составляйте логические выражения; and и or используют короткое замыкание.
Возвращайте fallback только при значении null.
Функции не найдены.
Реализуйте публичный контракт TemplateFunction, зарегистрируйте экземпляр и вызывайте его по namespace и имени.
public final class ReverseTemplateFunction
implements TemplateFunction<String> {
public String invoke(List<Object> args) {
if (args.size() != 1) {
throw fail("exactly 1 argument required");
}
return reverse(args.get(0));
}
public String invoke(List<Object> args, Object pipeArg) {
if (!args.isEmpty()) {
throw fail("no arguments expected");
}
return reverse(pipeArg);
}
public String getNamespace() { return "custom"; }
public String getName() { return "reverse"; }
public boolean isDynamic() { return false; }
private String reverse(Object value) {
return value == null ? null
: new StringBuilder(value.toString()).reverse().toString();
}
}
var evaluation = TemplateEvaluationOptions.builder()
.functions(List.of(new ReverseTemplateFunction()))
.build();
var compiler = TemplateCompiler.getInstance(
TemplateCompileOptions.builder()
.evaluationOptions(evaluation)
.build());"{{ custom:reverse .value }}"
"{{ .value | custom:reverse }}"Возвращайте false из isDynamic() только для детерминированных функций без побочных эффектов.
Несколько правил делают шаблоны быстрыми, тестируемыми и предсказуемыми.
Создавайте CompiledTemplate при изменении конфигурации и повторно используйте его для разных контекстов.
Пользовательские функции должны быть thread-safe и не иметь побочных эффектов.
Используйте стабильное пространство имён, например billing:tax.
Переопределяйте isLazy() только для короткого замыкания и обращайтесь к аргументам по мере необходимости.
Храните рядом .jjt, контекст и ожидаемый JSON. Проверяйте значения, а не форматирование.
Предпочитайте небольшие definitions и pipe глубоко вложенным выражениям.
JJTemplate разделяет parsing, optimization и evaluation, чтобы сократить работу во время выполнения.
Разбивает JJT на токены.
Строит синтаксические деревья.
Создаёт исполняемые узлы.
Сворачивает и упрощает один раз.
Формирует JSON-совместимые значения.
Поддерживаемые API lexer, parser, compiler, runtime, exceptions и functions проверяются относительно опубликованного baseline.
Открыть политику →Готовы формировать JSON?