How to access static members in a Velocity template?

matt b picture matt b · Jan 20, 2009 · Viewed 13.9k times · Source

I'm not sure if there is a way to do this in Velocity or not:

I have a User POJO which a property named Status, which looks like an enum (but it is not, since I am stuck on Java 1.4), the definition looks something like this:

public class User  {

    // default status to User
    private Status status = Status.USER;

    public void setStatus(Status status) {
        this.status = status;
    }

    public Status getStatus() {
        return status;
    }

And Status is a static inner class:

public static final class Status {

    private String statusString;

    private Status(String statusString) {
        this.statusString = statusString;
    }

    public final static Status USER = new Status("user");
    public final static Status ADMIN = new Status("admin");
    public final static Status STATUS_X = new Status("blah");

    //.equals() and .hashCode() implemented as well
}

With this pattern, a user status can easily be tested in a conditional such as

if(User.Status.ADMIN.equals(user.getStatus())) ...

... without having to reference any constants for the status ID, any magic numbers, etc.

However, I can't figure out how to test these conditionals in my Velocity template with VTL. I'd like to just print a simple string based upon the user's status, such as:

Welcome <b>${user.name}</b>!
<br/>
<br/>

#if($user.status == com.company.blah.User.Status.USER)
    You are a regular user
#elseif($user.status == com.company.blah.User.Status.ADMIN)
    You are an administrator
#etc...

#end

But this throws an Exception that looks like org.apache.velocity.exception.ParseErrorException: Encountered "User" at webpages/include/dashboard.inc[line 10, column 21] Was expecting one of: "[" ...

From the VTL User Guide, there is no mention of accessing a Java class/static member directly in VTL, it appears that the right hand side (RHS) of a conditional can only be a number literal, string literal, property reference, or method reference.

So is there any way that I can access static Java properties/references in a Velocity template? I'm aware that as a workaround, I could embed the status ID or some other identifier as a reference in my controller (this is a web MVC application using Velocity as the View technology), but I strongly do not want to embed any magic numbers or constants in the view layer.

Answer

matt b picture matt b · Jan 20, 2009

I figured out a workaround that allows me to add each User.Status object to the Velocity context, which avoids any sort of references to constants or magic numbers in the template.

On the controller/Java side:

// put the statuses directly into the model
Map statusMap = new HashMap();
statusMap.put("user", User.Status.USER);
statusMap.put("groupOperator", User.Status.ADMIN);
...
modelAndView.addObject("statusmap", statusMap);

And then in the template these values can be referenced like so:

#if($user.status == $statusmap.user)
   You are a regular user
#elseif($user.status == $statusmap.admin)
    You are an administrator
##etc...
#end