Why Apache Velocity sucks
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 valuefalse
,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
(probablyjavax.servlet.http.HttpSession
)key
(java.lang.String
, thekey
of thetool
insettings.xml
)requestPath
(java.lang.String
)scope
(java.lang.String
, thescope
of thetoolbox
insettings.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.
Filed under bugs
Nathan
No, no. You’ve outlined some of the ways that Velocity sucks, but not the *why*.
Velocity sucks because it was first written over 10 years ago and almost immediately achieved wide adoption. This created a large mass of inertia, people who wanted the latest fixes and improvements but did not want to update their old templates. Further, the original creators made many of these questionable decisions, then actively resisted changing them when newer contributors to the project came along. Those newer contributors (like me), then became accustomed to the quirks and found other things to do besides lobby for fixing them. By the time enough of the old crew was gone to open the way for backwards incompatible changes, there were even more templates and users accustomed to them.
In short, Velocity has most of these issues because it has gone too long without a 2.0 version. However, 2.0 is finally in the works. So, for all those who want to fix these things, NOW is the time to jump in and work for changes to the defaults.
Oh, and you are ignorant about the reasons for some things. Tools like $esc return null in situations like $esc.html($!thisisnull) instead of empty string, because it is very easy and clean to do $!esc.html($thisisnull) and it is very ugly to have to change #if($esc.html($thisisnull)) to something that treats empty string as false correctly. And that’s just the main reason, returning null is also more helpful in debugging tool method calls.
So, while i agree there are some outdated decisions that need to be changed, not everything you call stupid actually is stupid. :)
Scott
I have been programming in Java for about 15 years now. I have been doing templating for a little longer than that. I recently started playing with Velocity. There are some nice features with it considering that it will make use of reflection to access object attributes (user.getName). However, when they decided to use a preceding token of ‘#’ or ‘$’, I thought that was extremely stupid on their part.
Nathan was claiming it was made 10 years ago. Well, the coding is extremely strange with organization. It is not easy to use and not very flexible. It will work fine as long as you don’t have to use any special characters (that you want displayed and not to disappear with velocity usage) in your template. For example, using a html edit mask where the ## is used in the mask, this will cause a lot of problems for velocity. Yes there are some escape sequences you can do, but they are not very easy to use.
I would vote not to use velocity until they improve it a lot.
Tomek
I have to say that Apache Velocity works fine for the (simple) scenarios that I use it for. No complains from me.