Confluence trunk development (2.8) will be based on Velocity 1.5. The migration to the latest version of Velocity brings with it some issues that Confluence developers need to be aware of.
In Velocity 1.4, the velocimacro syntax was changed to prevent the use of work tokens as the first argument to most directives (except for defining the macro itself). This makes the following, common webwork structure fail to parse in Velocity 1.4 and beyond.
1 2#bodytag (Select "label=$theLabel" "name='extraLevelName'" "list=levelTypes" "theme='notable'")
This means that you must quote the first argument to make it a proper string.
1 2#bodytag ("Select" "label=$theLabel" "name='extraLevelName'" "list=levelTypes" "theme='notable'")
For these directives to work correctly with the new syntax a patched version of Webwork 2.1 is also required. Confluence now depends on this custom version of Webwork 2.1.
When the old syntax is used, the following error will be produced (but with a different line, column and vm file):
1 2org.apache.velocity.exception.ParseErrorException: Invalid arg #0 in directive at line 37, column 41 of /templates/publishingconfiguration.vm
Due to an apparent bug in Velocity 1.5 VELOCITY-537, multi-line comments in Velocimacros can cause ParseExceptions
. Multi-line macro comments have mainly been used in Confluence to control the output of extraneous whitespace during the rendering of a macro. To work around this issue a new #trim()
directive has been introduced that can be used to strip whitespace from macro rendering. This unfortunately introduces a slight overhead to rendering as whitespace must be trimmed in every execution at runtime rather than stripped by the lexer at template parsing time.
Using comments to control whitespace
1 2#macro (globalLogoBlock)#* *##if ($settingsManager.getGlobalSettings().isDisableLogo())#* render nothing *##else#* *#<a href="$req.contextPath/homepage.action"><img src="#logo("")" align="absmiddle" border="0"></a>#* *##end#* *##end
Using the trim directive to control whitespace
1 2#macro (globalLogoBlock) #trim() #if ($settingsManager.getGlobalSettings().isDisableLogo()) #else <a href="$req.contextPath/homepage.action"><img src="#logo("")" align="absmiddle" border="0"></a> #end #end #end
We'll be able to revert to the previous method once VELOCITY-537 is fixed and integrated, although it's arguable that the new directive makes for more maintainable macros.
Due to another bug in Velocity 1.3, exceptions that occur during a method execution in a macro parameter evaluation were swallowed silently; the return value of such executions was null
. Velocity 1.5 contains a fix for this which means its likely that we are going to run into situations where pages which previously worked regardless of broken method calls are going to fail with a MethodInvocationException
. There's only one correct solution here: fix the broken method calls as we find them.
In previous versions of Velocity testing for equality using just a single =
worked. This has been made stricter in Velocity 1.5; you must use ==
otherwise a ParseException
will be thrown.
We realise that some of the changes that Velocity 1.5 brings to Confluence could cause annoying compatibility problems and lots of work for plugin maintainers, particulary the new Velocimacro syntax requirements. Confluence 2.8 will load all plugin templates using a special resource loader which will attempt to automatically fix loaded templates to work with the new Velocity engine (com.atlassian.confluence.util.velocity.Velocity13CompatibleResourceLoader
). This does add some additional overhead to plugin loading (the template is adjusted once at load time and then cached) but it will ease the burden on plugin developers during this transitional period.
It is still a good idea for plugin authors to use the new Velocimacro syntax; updating your templates can be made easier by looking for the info
messages logged by the resource loader whenever it finds incompatible syntax.
1 2Found incompatible Velocity 1.5 syntax in resource: [resource name]; [template fragment]
Dynamically loaded plugins only
For performance reasons, the compatibility layer is only applied to dynamically loaded plugins. Plugins loaded through WEB-INF/lib will not have the compatibility processing applied.
Rate this page: