I am observing strange behavior with Freemarker.
I have an Iterable
in reportModel.affectedJars
. It is provided from a graph database - Tinkerpop/Titan.
${iterableHasContent(reportModel.affectedJars)?then("true", "false")}<br>
${reportModel.affectedJars?has_content?then("yes", "no")} has_content<br>
${reportModel.affectedJars?size}<br>
${reportModel.affectedJars}<br>
<#if reportModel.affectedJars?size == 0>
<p>No archives containing CVE vulnerabilities were found.</p>
<#else>
<#list reportModel.affectedJars.iterator() as file>
Something...
iterableHasContent
is an alternative of ?size
.
I would expect this to be quite consistent, in terms of:
false
no has_content
0
<p>No archives ...
But what is actually happening is:
false
yes has_content
6
--- and no iterations. ---
Which looks like there's some glitch that makes Freemarker think that the Iterable
is not empty, but then when iterated, it gives no items. No exception is thrown.
I was trying to debug, but the debugger doesn't stop at the relevant code for some reason.
Is there something I am missing in ?size
and ?has_content
paradigms that allows this behavior?
Don't try do anything with that Iterable
, except calling iterator()
on it. The problem is that FreeMarker was created before Iterable
was introduced, and it sees a pure Iterable
(i.e., one which doesn't also implement Collection
) as a generic object, rather than some listable thing. (Fixing this without breaking backward compatibility is not possible, though surely there should be a configuration option for it.) This is also where the size 6 comes from; it's the number of items in the hash, which contains its methods and JavaBean properties. Ugh...
So after you got the Itera*tor*
, the next thing you will find that it doesn't support ?size
. It supports ?has_content
though. (This assumes that you are using the default object wrapper, not pure BeansWrapper
, which is pure evil.) But if you can, use #list
with a nested #else
. Something like:
<#list reportModel.affectedJars.iterator() as file>
Something...
<#else>
<p>No archives containing CVE vulnerabilities were found.</p>
</#list>
or a more real life example:
<#list reportModel.affectedJars.iterator()>
<p>Found some archives containing CVE vulnerabilities:</p>
<#items as file>
Something...
</#items>
<#else>
<p>No archives containing CVE vulnerabilities were found.</p>
</#list>