Search code examples
freemarker

Freemarker - dynamic name for user-defined directive invocation


I'm trying to port some old Apache Tiles stuff to Freemarker, and one of the things the tiles code does is pass around variables with the names of tiles (jsp files more or less). These variables decide at runtime which templates are transcluded into the current template.

I'm trying to figure out if there's a way to do that with Freemarker macros. Something like this:

<#macro mything>
test
</#macro>

<#macro myotherthing>
other
</#macro>

<@"my${which}thing" />

If which="other", then the result should be

other

If which="", then the result should be:

test

However, I get an error:

Syntax error in nameless template in line 9, column 12:
Encountered "}", but was expecting one of:
    "."
    ".."
    <DOT_DOT_LESS>
    "..*"
    "?"
    "??"
    "!"
    ","
    ":"
    "["
    "("
    <TERMINATING_EXCLAM>

I'm guessing a user-defined directive invocation can't be an expression or something. I guess I can use the include directive instead, but is there any way to do this with macro invocation--dynamically pick the macro name to invoke at runtime?


Solution

  • Like this:

    <@.vars["my${which}thing"] />
    

    Explanation:

    • <#macro m>...</#macro> just assigns the macro (macros are values) to the variable m
    • In <@m />, the m part is interpreted as a usual expression. It happens to be a simple variable reference expression in this case, but it could be a more complex expression as well (parenthesis may be needed around it though).
    • Variables with dynamic name can be read through the reserved .vars hash, like .vars[nameExpression].