Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access static members in a Velocity template?

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.

like image 256
matt b Avatar asked Jan 20 '09 17:01

matt b


People also ask

Which is used to directly access the static members?

Members of static classes can be accessed directly using the class name followed by a (.) and class member name. Class Members can be methods, fields, properties, or events. A static class can contain only the static members while a non-static class can contain static members.

How do you debug a Velocity template?

To use, either add this pair of macros to your template, or better yet, to your VM_Global_library. vm file. Then from the template you want to debug, you can simply add #showDebugPopup() to the bottom of the template you want to debug, and it will pop up a window with debugging information.

Can we access static members using object reference?

Since static variables belong to a class, we can access them directly using the class name. So, we don't need any object reference. We can only declare static variables at the class level. We can access static fields without object initialization.

How do I find static and non-static members?

In the static method, the method can only access only static data members and static methods of another class or same class but cannot access non-static methods and variables. Non-static method: Any method whose definition doesn't contain the static keyword is a non-static method.


2 Answers

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
like image 164
matt b Avatar answered Sep 24 '22 14:09

matt b


Yeah, Velocity doesn't natively grok classes and packages. You could do what you did, or use the FieldMethodizer class to automate that. Another option would be the FieldTool in VelocityTools 2.0.

like image 31
Nathan Bubna Avatar answered Sep 22 '22 14:09

Nathan Bubna