Re: freemarker error: Expected hash, evaluated instead to ...

Jake Ochs <[email protected]>
Newsgroups gmane.comp.web.freemarker.user
Message-ID <[email protected]>
Well, the problem is that the method has  parameters, and is called from 
within a template like so ${doc.lookup(parm1,parm2,parm3)} so just 
making it a hash value wouldn't work in my case. I tried a more generic 
TemplateModel, which didn't work at all, and prompted the original post 
in this thread. What combination of models do I need to wrap an object 
that has fields accessible through a get method on the wrapper and 
custom methods?

I'm wrapping a Document (Lotus.Domino.Document) object that has field 
values available through a getfirstItem(fieldName).getValues() method 
and a custom Lookup method that retrieves values from another document 
using the context of the current doc:

public class NotesDocWrapper implements TemplateHashModel {
     private Document doc;
     private Session s;
     private Database lookupDB = null;
     private View lookupV = null;
     private Document lookupDoc = null;
     boolean lookupDocSwitch = false;

     public NotesDocWrapper(Document doc) throws Exception {
         this.doc = doc;
         this.s = doc.getParentDatabase().getParent();
     }

     public Object lookup(String dbName, String VName, String key, 
String field)
             throws Exception {
         lookupDB = s.getDatabase(s.getCurrentDatabase().getServer(), 
dbName);
         lookupV = lookupDB.getView(VName);
         lookupDoc = lookupV.getDocumentByKey(key);
         lookupDocSwitch = true;
         Object ret = get(field);
         lookupDocSwitch = false;
         return ret;
     }
...


     @SuppressWarnings("unchecked")
     public TemplateModel get(String name) {
         try {
             Item item = lookupDocSwitch ? lookupDoc.getFirstItem(name) 
: doc.getFirstItem(name);
             if (item == null) return null;

             Vector<Object> vals = item.getValues();
             if (vals == null)
                 return null;
             // multi-values?
             boolean multi = (vals.size() > 1) ? true : false;
             int type = item.getType();
             System.out.println(item.getName() + " " + type);
             switch (type) {
             case Item.NAMES:
                 if (multi) {
                     ArrayList<String> names = new ArrayList<String>();
                     for (Object v : vals) {
                         Name n = s.createName((String) v);
                         names.add(n.getCommon());
                     }
                     return new SimpleSequence(names);
                 } else {
                     Name n = s.createName((String) vals.get(0));
                     return new SimpleScalar(n.getCommon());
                 }
             case Item.DATETIMES:
                 if (multi) {
                     ArrayList<String> dates = new ArrayList<String>();
                     for (Object v : vals) {
                         dates.add(v.toString());
                     }
                     return new SimpleSequence(dates);

                 } else {
                     return new SimpleScalar(vals.get(0).toString());
                 }
             default:
                 if (multi)
                     return new SimpleSequence(vals);
                 return new SimpleScalar(item.getText());
             }
         } catch (Exception e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
         return null;
     }

     @Override
     public boolean isEmpty() throws TemplateModelException {
         return (doc == null)
     }
}


On 12/16/2009 11:38 AM, Daniel Dekany wrote:
> Wednesday, December 16, 2009, 4:24:08 PM, Jake Ochs wrote:
>
>> I set the NotesDocWrapper to implement a TemplateHashModel and the
>> collection extends AbstractList and it works. The only issue is that the
>> NotesDocWrapper has a custom method that I want to call from Freemarker
>> (in addition to the standard 'get'). Again, this custom method is
>> available if I drop a NotesDocWrapper directly onto the root hash.
>
> That's strange because if NotesDocWrapper implements TemplateModel (or
> a subinterface of it) it shouldn't be re-wrapped, means, it should
> behave no how you retrieve it. Are you sure you don't mess up
> something there?
>
> Anyway... since NotesDocWrapper is already a TemplateMode, FreeMarker
> will not (should not) do any extra magic with it (like exposing
> methods). So if you want to call a method, you have to return it as a
> hash item.
>
>
>> On 12/16/2009 9:45 AM, Daniel Dekany wrote:
>>> Wednesday, December 16, 2009, 2:03:10 PM, Jake Ochs wrote:
>>>
>>>> I've created a custom collection that implements iterator and returns
>>>> another custom object - NotesDocWrapper (wraps a Lotus Domino Document
>>>> object.) My template then lists the docs collection I placed in the root
>>>> hash and iterates over the doc accessing a field like so:
>>>> <#list docs as doc>
>>>> <li>${doc.Subject}</li>
>>>> </#list>
>>>> The NotesDocWrapper implements TemplateModel and has a get method so it
>>>> can return a Notes Document field using the standard template dot syntax
>>>> as used above. I've used the NotesDocWrapper by itself, dropping it into
>>>> the root hash successfully, but when I attempt to nest it in this manner
>>>> I get a freemarker exception (see full stacktrace at bottom of post)
>>>>
>>>> How do I prevent Freemarker from expecting a hash instead of using the
>>>> wrapper I supplied for the nested object? (assuming this is the problem)
>>>> Any tips are appreciated.
>>>
>>> Exactly what does NotesDocWrapper extend and implement? It should
>>> implement TemplateHashModel (or TemplateHashModelEx).
>


------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.