crmepham
crmepham

Reputation: 4740

How to process Freemarker String template?

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

Answers (1)

ddekany
ddekany

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

Related Questions