Как заставить JinJava выдавать ошибку, если не удается найти привязку
Мне нужно использовать JinJava для обработки небольших шаблонов, которые могут содержать разные токены. Например:
Hello,{{ user }}...
где привязка user
требуется, потому что без него вывод не имеет никакого смысла.
Мой класс не знает, что использует шаблон токенов, и получает список привязок от удаленных сервисов.
Поэтому может быть случай, когда привязка, указанная в шаблоне, не существует. Поведение JinJava по умолчанию заключается в использовании null
это преобразовано в пустую строку в выходной строке. Это не работает в моем случае, мне нужно, чтобы было выброшено исключение, если какая-либо из привязок пропущена.
Мое текущее решение заключается в использовании пользовательских Filter
/**
* A filter for JinJava that verifies that a value is not null and if the value is null, writes a fatal error to interpreter's log
*/
public class RequiredFilter implements Filter {
@Override
public Object filter(Object var, JinjavaInterpreter interpreter, String... args) {
if (var == null) {
interpreter.addError(new TemplateError(TemplateError.ErrorType.FATAL, TemplateError.ErrorReason.MISSING, "Value of a required key is null", "", 1, null));
}
return var;
}
@Override
public String getName() {
return "required";
}
}
И заставьте клиентов явно указывать эту функцию для всех токенов в шаблонах. Пример выше теперь выглядит так:
Hello, {{ user|required }}...
и если обязательна user
не существует, я получаю свое исключение. Однако требование пользовательской функции выглядит странно.
Есть ли способ настроить JinJava для достижения аналогичного поведения и не беспокоить клиента требованием указать фильтр required
каждый раз?
2 ответа
Вы можете сделать что-то вроде этого,
JinjavaConfig jc = JinjavaConfig.newBuilder().withFailOnUnknownTokens(true).build();
Jinjava jinjava = new Jinjava(jc);
// set context and other processes and then render
RenderResult renderResult = jinjava.renderForResult(template, properties);
if (renderResult.getErrors().isEmpty()) {
return renderResult.getOutput();
} else {
throw new IllegalArgumentException(renderResult.getErrors().stream()
.map(Object::toString)
.collect(Collectors.joining(",")));
}
Есть много других
JinjavaConfig
что вы, возможно, захотите проверить.
Основываясь на вашем решении с фильтрами токенов, я сделал это, зарегистрировав для этой цели специальные теги.
public static String fillTemplateTagsWithProperties(
String template, Map<String, String> properties) throws IllegalArgumentException
{
if (template == null) throw new IllegalArgumentException("template is null");
Jinjava jinjava = new Jinjava();
properties.forEach((k, v) -> jinjava.getGlobalContext().registerTag(new Tag() {
@Override
public String interpret(TagNode tagNode, JinjavaInterpreter interpreter) {
if (v == null) {
interpreter.addError(new TemplateError(
TemplateError.ErrorType.FATAL,
TemplateError.ErrorReason.MISSING,
"Value of a required key is null",
k, 1, null));
}
return v;
}
@Override
public String getEndTagName() {
return null;
}
@Override
public String getName() {
return k;
}
}));
RenderResult renderResult = jinjava.renderForResult(template, properties);
if (renderResult.getErrors().size() == 0) {
return renderResult.getOutput();
} else {
throw new IllegalArgumentException(renderResult.getErrors().stream()
.map(Object::toString)
.collect(Collectors.joining(",")));
}
}
@Test
public void jinjavaWithCustomTags(){
String template = "Hallo {% hallo %}\n" +
"I am {% unrendered %}";
Map<String, String> props = new HashMap<>();
props.put("hallo", "Welt");
//props.put("unrendered", "[try null here]");
System.out.println(fillTemplateTagsWithProperties(template, props));
}
который выводит:
Hallo Welt
I am [try null here]
или бросает:
### java.lang.IllegalArgumentException: TemplateError{severity=FATAL, reason=SYNTAX_ERROR, message=UnknownTagException: Syntax error in '{% unrendered %}': Unknown tag: unrendered, fieldName=null, lineno=2, item=OTHER}