I'm using Spring Boot (2.5.2) and Freemarker to send the emails to the users. It's working fine without adding any internationalization support but I tried adding it today and it didn't work. For some reason, spring.ftl is complaining that it's not able to find the property in my message.properties file.
Below is my configuration file
@Configuration
public class CommonConfiguration implements WebMvcConfigurer {
@Bean
public LocaleResolver localeResolver() {
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(Locale.US);
return localeResolver;
}
@Override
public void addInterceptors(final InterceptorRegistry registry) {
final LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
registry.addInterceptor(localeChangeInterceptor);
}
@Bean(name = "messageSource")
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource ms = new ReloadableResourceBundleMessageSource();
ms.setBasenames("classpath:i18n/messages");
ms.setDefaultEncoding("UTF-8");
ms.setCacheSeconds(3600);
return ms;
}
}
application.yml file (for spring freemarker setup)
spring:
profiles:
active: dev
autoconfigure:
exclude: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
freemarker:
settings:
auto_import: /spring.ftl as spring
In my mail.ftl file, this line is causing the issue
<@spring.message "email.common.logo.alt.txt"/>
I've verified that this text exists and when I use the messageSource.getMessage("email.common.logo.alt.txt", null, LocaleContextHolder.getLocale()) in my java code, I can access the corresponding value.
Error log
2022-06-03 16:08:48.590 ERROR 67685 --- [ task-2] f.runtime : Error executing FreeMarker template
freemarker.core.InvalidReferenceException: The following has evaluated to null or missing:
==> springMacroRequestContext [in template "spring.ftl" at line 28, column 24]
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: ${springMacroRequestContext.getMessag... [in template "spring.ftl" in macro "message" at line 28, column 22]
- Reached through: @spring.message "email.common.logo.al... [in template "emails/layout/email-header.ftl" at line 3, column 109]
- Reached through: #include "email-header.ftl" [in template "emails/layout/email-layout.ftl" in macro "generalEmailLayout" at line 72, column 8]
- Reached through: @layout.generalEmailLayout headInclud... [in template "emails/user-management/mail.ftl" at line 2, column 1]
----
at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.UnexpectedTypeException.newDescriptionBuilder(UnexpectedTypeException.java:85) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.UnexpectedTypeException.<init>(UnexpectedTypeException.java:48) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.NonHashException.<init>(NonHashException.java:49) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Dot._eval(Dot.java:48) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Expression.eval(Expression.java:101) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.MethodCall._eval(MethodCall.java:55) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Expression.eval(Expression.java:101) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.BuiltInsForOutputFormatRelated$AbstractConverterBI.calculateResult(BuiltInsForOutputFormatRelated.java:50) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.MarkupOutputFormatBoundBuiltIn._eval(MarkupOutputFormatBoundBuiltIn.java:40) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Expression.eval(Expression.java:101) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.DollarVariable.calculateInterpolatedStringOrMarkup(DollarVariable.java:100) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.DollarVariable.accept(DollarVariable.java:63) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Environment.visit(Environment.java:383) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Environment.invokeMacroOrFunctionCommonPart(Environment.java:889) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Environment.invokeMacro(Environment.java:825) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.UnifiedCall.accept(UnifiedCall.java:84) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Environment.visit(Environment.java:347) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Environment.visit(Environment.java:353) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Environment.include(Environment.java:2955) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Include.accept(Include.java:171) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Environment.visit(Environment.java:383) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Environment.invokeMacroOrFunctionCommonPart(Environment.java:889) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.Environment.invokeMacro(Environment.java:825) ~[freemarker-2.3.31.jar:2.3.31]
at freemarker.core.UnifiedCall.accept(UnifiedCall.java:84) ~[freemarker-2.3.31.jar:2.3.31]