I'm building a site using Freemarker and have started heavily using macros. I know in Freemarker 2.3 that passing a null value into a macro as a parameter is equivalent to not passing a parameter at all so I've created a global variable called "null" to simulate null checking in my macros:
<#assign null="NUL" />
Now in my macros I can do this:
<#maco doSomething param1=null>
<#if param1 != null>
<div>WIN!</div>
</#if>
</#macro>
The problem comes if I want to pass a parameter that isn't a scalar. For instance, passing a List (which in Freemarker is a SimpleSequence) to a macro and checking against my null keyword yields the error:
freemarker.template.TemplateException: The only legal comparisons are between two numbers, two strings, or two dates. Left hand operand is a freemarker.template.SimpleSequence Right hand operand is a freemarker.template.SimpleScalar
I took a look at the freemarker code and I can see the issue (ComparisonExpression.isTrue()):
if(ltm instanceof TemplateNumberModel && rtm instanceof TemplateNumberModel) {
...
}
else if(ltm instanceof TemplateDateModel && rtm instanceof TemplateDateModel) {
...
}
else if(ltm instanceof TemplateScalarModel && rtm instanceof TemplateScalarModel) {
...
}
else if(ltm instanceof TemplateBooleanModel && rtm instanceof TemplateBooleanModel) {
...
}
// Here we handle compatibility issues
else if(env.isClassicCompatible()) {
...
}
else {
throw new TemplateException("The only legal comparisons...", env);
}
So the only solution I can think of is to set isClassicCompatible to true, which I think will call toString() on both objects and compare the result. However, the documentation specifically says anything relying on old features should be rewritten.
My quesion is, is there a solution to this that doesn't rely on deprecated features?
The null
reference is by design an error in FreeMarker. Defining a custom null value - which is a string - is not a good idea for the reasons you mention. The following constructs should be used instead:
null
, you should use the ??
operator: <#if (name??)>
null
, you should use the !
operator to specify a default value: name!"No name"
?has_content
builtin: <#if (names?has_content)>
You can specify an empty sequence as default parameter value in a macro, and simply test whether it's empty.