Struts2 + Freemarker + DisplayTag: how to make it work
I am currently upgrading our application from Webwork to Struts2. Today I run into strange error: displayTag s开发者_如何学运维topped working after the upgrade.
This is a snipped from my FTL file:
<#assign display=JspTaglibs["http://displaytag.sf.net"]> <@s.set name="entries" value="historyEntries" scope="page"/> <@display.table class="data" name="pageScope.entries" sort="list" pagesize=30 id="entry" defaultsort=5 defaultorder="descending"> <@display.column property="folderName" title="Folder" sortable=true/> </@display.table>
The error I get is:
freemarker.template.TemplateModelException: javax.servlet.jsp.JspException: Exception: [.LookupUtil] Error looking up property "folderName" in object type "freemarker.template.SimpleSequence". Cause: Unknown property 'folderName'
Standard struts tags are working correctly, I have JspSupportServlet
added in my configuration. Any idead why this isn't working?
I found a way to solve this (not sure if it the only way or if it is the best, worked for me though).
The root of the problem was that freemarker.template.SimpleSequence
does not out-of-the-box implement any standard Collections API, it is not a Collection, Enumerable etc.
In order to solve this I created custom FreemarkerManager
and provided custom BeansWrapper
:
@Override protected BeansWrapper getObjectWrapper() { BeansWrapper wrapper = super.getObjectWrapper(); class CustomBeansWrapper extends BeansWrapper { private BeansWrapper internalWrapper; public Xp2BeansWrapper(BeansWrapper wrapper) { this.internalWrapper = wrapper; } //delegate methods public TemplateModel wrap(Object object) throws TemplateModelException { TemplateModel model = internalWrapper.wrap(object); if (model instanceof SimpleSequence) { class SimpleSequenceWithIterator extends SimpleSequence { private SimpleSequence internalSequence; public SimpleSequenceWithIterator(SimpleSequence sequence) { this.internalSequence = sequence; } //delegate methods //IteratorUtils from Apache Commons is used internally //by DisplayTag library, it can use public iterator() method public Iterator iterator() throws TemplateModelException { return toList().iterator(); } } return new SimpleSequenceWithIterator((SimpleSequence) model); } return model; } } return new CustomBeansWrapper(wrapper); }
Now I just needed to change one setting in struts.properties
:
struts.freemarker.manager.classname=xyz.CustomFreemarkerManager
You can also certify if your deployment copy all dependecies to WEB-INF/lib. TaglibFactory searches every TLD under /META-INF/ inside jar there.
Take a look at https://stackoverflow.com/a/37092269/1113510
精彩评论