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