Candid’s brain

Why Apache Velocity sucks

Posted on: March 29th, 2011

I was just giving Apache Velocity a try because it seems to be the most popular Java template engine on the Internet. I don’t really understand why, as it seems to be completely immature and badly-designed.

References to undefined variables

When you reference a variable $test in Velocity and this variable is not defined, the string $test is returned instead. To avoid this (for example in case of optional parameters), you can use the Quiet Reference Notation writing $!test, in which case an empty string is returned. Stupidly though, this behaviour does not work consistently. When you use the variable as a parameter instead of printing it out for example, $esc.html($!test) does not output an empty string as expected but instead the string $esc.html($!test). Instead, you have to use the notation $!esc.html($test). How stupid is that?

To avoid mistakes in your template, you can set the property runtime.references.strict to true, in which case undefined references aren’t replaced by their names, but instead an exception is thrown. In that case however, $!test also throws an exception instead of returning an empty string!

Now, when the variable $test is defined and you actually want to output the string $test instead of its value, you do this by writing \$test instead. This works only when $test is defined though, and when it is not defined, it outputs \$test instead of $test. So depending on whether the variable is defined or not, you have to write either \$test or $test to get the string $test. Things will get very confusing when you are dealing with optional parameters. The funny thing is that every undefined reference produces an error message in the log file, and because of that, there is an official “better” way to do this: to define an own variable that contains the value $!

Another way is to set the configuration property runtime.references.strict.escape to true. In that case, a backslash is also interpreted as an escape character in front of a non-existent reference. Stupidly, this property is (like most other configuration properties as well) only documented in the manual of the most recent development version. Also confusing is its name, as it is only remotely related and in no way a sub-property of runtime.references.strict.

Output formatting

This code:

<ul>
#foreach( $a in $b )
    #if( $a )
    <li>$a</li>
    #end
#end
</ul>

Will produce the following output (assuming that $b is a list [1,2,3]):

<ul>
        <li>1</li>
            <li>2</li>
            <li>3</li>
    </ul>

Notice how messed up the indentation is? At least it has to be said that Velocity, in contrast to JSP, is that intelligent that it does not output the newlines of those lines that only contain Velocity directives. But it keeps all the other whitespaces from those lines?!

Documentation

As mentioned before, most configuration properties are only documented in the manual of the most recent development version. When you use the VelocityViewServlet from the VelocityTools, additionally to the velocity.properties file, there is a settings.xml file where you can define global variable that can be referred to in templates. The following important things are missing from the documentation:

  • It is described how to create string, number, boolean, list and object variables. However, Velocity also knows Map variables. The documentation does not say how to define these in the settings.xml file, it is probably not possible. Also, it does not specify how to define items in a list that have the value false, n or similar (as those are converted to booleans) or that contain a comma (as that is the list separator). This is probably also not possible, at least it does not work using a backslash (or, as the documentation sometimes calls it, a “forward slash”).
  • When defining objects in that file (that is, instances that are created from a given class), you can pass properties to those objects that are either set using setters or using a method called configure. The documentation does not mention that there are some predefined properties that you can use. Those would be:
    • servletContext (javax.servlet.ServletContext)
    • request (javax.servlet.http.HttpServletRequest)
    • response (javax.servlet.http.HttpServletResponse)
    • log (org.apache.velocity.runtime.log.Log)
    • velocityContext (org.apache.velocity.tools.view.context.ChainedContext)
    • velocityEngine (org.apache.velocity.app.VelocityEngine)
    • session (probably javax.servlet.http.HttpSession)
    • key (java.lang.String, the key of the tool in settings.xml)
    • requestPath (java.lang.String)
    • scope (java.lang.String, the scope of the toolbox in settings.xml)
    • locale (java.util.Locale)

Properties and Methods

Properties in Velocity either refer to a value in a hashtable or to the return value of a getter. Suppose you are working with an object of this class, though:

public class SampleData {
    public final int value1;
    public final String value2;
}

Trying to access those properties using $sampleData.value1 will not work, instead, the class will have to be added a method getValue1() (see VELOCITY-12).

Also stupid is that the naming conventions for properties and for methods don’t fit the naming conventions for Java, as those allow a _ and a $ sign in every part of the identifier. This means that properties and methods that start with an underscore or that contain a dollar sign can’t be accessed from Velocity. For gettext, for example, I use a method with the simple name _ (which is quite a common way to use gettext). In order to use Velocity, I will have to change this class now.