Reputation: 4740
I am using Spring Boot with Freemarker starter.
Given the following String:
<h2>${fragment.title}</h2>
I am attempting to perform some validation on this String to ensure that it contains correct Freemarker syntax.
I have attempted to do this with the following code:
@Autowired
private Configuration configuration;
private void validateTemplate(Fragment fragment) {
try {
ModelAndView model = new ModelAndView();
model.addObject("fragment", fragment);
StringTemplateLoader stringLoader = new StringTemplateLoader();
stringLoader.putTemplate("template", fragment.getDesign());
configuration.setTemplateLoader(stringLoader);
configuration.setDefaultEncoding("UTF-8");
Template template = configuration.getTemplate("template");
template.process(model, new OutputStreamWriter(System.out));
} catch (Exception e) {
// failed validation...
}
}
The above String should validate, as fragment
is not null. But the following error is thrown:
2017-11-19 11:11:11.732 ERROR 4956 --- [-nio-443-exec-8] freemarker.runtime : Error executing FreeMarker template
freemarker.core.InvalidReferenceException: The following has evaluated to null or missing: ==> fragment [in template "template" at line 1, column 7]
---- Tip: If the failing expression is known to be 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. (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: ${fragment.title} [in template "template" at line 1, column 5] ---- at freemarker.core.InvalidReferenceException.getInstance(InvalidReferenceException.java:134) ~[freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.UnexpectedTypeException.newDesciptionBuilder(UnexpectedTypeException.java:80) ~[freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.UnexpectedTypeException.(UnexpectedTypeException.java:43) ~[freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.NonHashException.(NonHashException.java:49) ~[freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.Dot._eval(Dot.java:48) ~[freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.Expression.eval(Expression.java:81) ~[freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.DollarVariable.calculateInterpolatedStringOrMarkup(DollarVariable.java:96) ~[freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.DollarVariable.accept(DollarVariable.java:59) ~[freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.Environment.visit(Environment.java:327) [freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.Environment.visit(Environment.java:333) [freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.core.Environment.process(Environment.java:306) [freemarker-2.3.25-incubating.jar:2.3.25] at freemarker.template.Template.process(Template.java:386) [freemarker-2.3.25-incubating.jar:2.3.25]
What am I missing in my setup that is causing Freemarker not to 'see' fragment
?
Upvotes: 1
Views: 2698
Reputation: 31112
Getting the Template
object itself is enough for syntactical validation. Validating if the template will fail on runtime can be rather tricky depending on the application, as you need a data-model similar to the real thing.
But let's assume you can provide such data-model in your case. Then the problem is that the ModelAndView
is not your model. It's you model and view, as the name suggests. It only contains your model, inside. (FreeMarker is not dependent on Spring, and so just use that object as a generic JavaBean, and thus your variables will be the JavaBean Properties of the ModeAndView
object itself.) Try to pass ModelAndView.getModel()
to Template.process
instead. (I'm not 100% sure if that always shows all your model variables, but I guess so. In any case, it extends java.util.Map
, which FreeMarker recognizes, and will use Map.get(varName)
to resolve variables.)
Upvotes: 1