oman
(Oleg SmaLL)
25.Апрель.2023 10:01:02
1
Добрый день!
Jmix version: 1.5.1
Jmix Studio plugin version: 1.5.3-223
IntelliJ version: IntelliJ IDEA 2022.3.3 (Community Edition)
Делаю email шаблон по доке:
https://docs.jmix.ru/jmix/email-template/getting-started.html#_creating_email_template
Пишу в тексе шаблона ${assignment.card.docDate?string("dd.MM.YYYY")}
При запуске получаю ошибку:
FreeMarkerException: For "...(...)" callee: Expected a method or function, but this has evaluated to a string (wrapper: f.t.SimpleScalar):
==> Root.fields.card.docDate?string [in template "template.html" at line 2, column 134]
----
FTL stack trace ("~" means nesting-related):
- Failed at: ${Root.fields.card.docDate... [in template "template.html" at line 2, column 132]
----. Template name [template.html] Report name [Оповещение]
А эти настройки игнорируются
oman
(Oleg SmaLL)
28.Апрель.2023 10:38:29
4
Нашел причину ошибки.
В документации форматируется поле типа Date, а у меня поле LocalDate.
Т.е. Freemarker поддерживает форматирование даты/времени из пакета java.util, а из пакета java.time - нет.
Нашел расширение GitHub - lazee/freemarker-java-8: Library that adds java.time support to FreeMarker templates. · GitHub и другие примеры добавления своих форматтеров в Freemarker, но они не работают, хотя код конфигурирования отрабатывает.
Такое ощущение, что конфигурирую не тот конфиг Feemarker, который используется, хотя он должен быть синглтоном.
Может кто-нибудь подскажет, куда дальше копать?
Пример конфигурации
@Configuration
public class FreemarkerConfig implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof FreeMarkerConfigurer configurer) {
configurer.getConfiguration().setObjectWrapper(new Java8ObjectWrapper(freemarker.template.Configuration.getVersion()));
// configurer.getConfiguration().setObjectWrapper(new CustomObjectWrapper());
/*configurer.getConfiguration().setObjectWrapper(new DefaultObjectWrapper(freemarker.template.Configuration.getVersion()) {
@Override
public TemplateModel wrap(Object object) throws TemplateModelException {
if (object instanceof LocalDate) {
return new SimpleDate(Date.valueOf((LocalDate) object));
}
if (object instanceof LocalTime) {
return new SimpleDate(Time.valueOf((LocalTime) object));
}
if (object instanceof LocalDateTime) {
return new SimpleDate(Timestamp.valueOf((LocalDateTime) object));
}
return super.wrap(object);
}
});*/
}
return bean;
}
private static class CustomObjectWrapper extends DefaultObjectWrapper {
@Override
public TemplateModel wrap(Object obj) throws TemplateModelException {
if (obj instanceof LocalDateTime) {
Timestamp timestamp = Timestamp.valueOf((LocalDateTime) obj);
return new SimpleDate(timestamp);
}
if (obj instanceof LocalDate) {
Date date = Date.valueOf((LocalDate) obj);
return new SimpleDate(date);
}
if (obj instanceof LocalTime) {
Time time = Time.valueOf((LocalTime) obj);
return new SimpleDate(time);
}
return super.wrap(obj);
}
}
}