Search code examples
freemarker

Expected hash. myObject.id evaluated instead to freemarker.ext.beans.SimpleMethodModel


I have searched Google, read the docs etc, but I can still not figure out what is going wrong.

When I try to access a nested property, say ${myObject.id.str} of an object I get the following error: Expected hash. myObject.id evaluated instead to freemarker.ext.beans.SimpleMethodModel. When I remove the .str and simply attempt to output ${myObject.id} I get Expecting a string, date or number here, Expression myObject.id is instead a freemarker.ext.beans.SimpleMethodModel. Id is actually an object - it is a wrapper of java.lang.Number. I simply added the str() method as a convenient way of getting the number value because I thought that returning a string might help. This does not appear to be a problem however as the problem seems to be the Id-object itself. I am beginning to wonder whether I have got a naming issue because calling myobject.myId seems to work but not myobject.id. Coud this be true because the class-name Id is identical to the propety name id? I shouldn't think so normally, but why would myId work which has the same Id object.

The Object looks like this:

public class MyObject
{
    private Id id = null;

    @Override
    public Id getId()
    {
        return id;
    }

    @Override
    public void setId(Id id)
    {
        this.id = id;
    } 
}

The id class looks as follows:

public class Id extends Number
{
    private Number id = null;

    public String getStr()
    {
        return String.valueOf(id);
    }
}

The following does not work in the template:

${myObject.id}

The Freemarker documentation is good as long as you don't run into any problems. Unfortunately after reading the docs over and over again and googling I am still not getting any closer to a solution.

It would be excellent if anyone could shed a light on this.

Best regards, Michael


Solution

  • Just so it can be marked as solved... the problem was that there was an inherited Java method called "id" (no "get" before it). Since FreeMarker doesn't use separate name-space for methods and other members (methods are first-class values in FreeMarker, so you can get them without calling them), this will be a name clash, and the "id" method had priority over the "id" JavaBean property. In such case you can still use getId() to read the JavaBean property.