开发者

Treat a java.lang.Iterable as a #list expression in Freemarker

开发者 https://www.devze.com 2023-03-09 07:09 出处:网络
I have a java.lang.Iterable (in fact, a com.google.gson.JsonArray instance). I would like to enumerate the items in the list using freemarker (2.3.16).

I have a java.lang.Iterable (in fact, a com.google.gson.JsonArray instance).

I would like to enumerate the items in the list using freemarker (2.3.16).

[#assign sports = controller.sports]
[#-- At this point, sports is bound to a com.google.gson.JsonArray instance. --]

[#list sports as sport]
  ${sport_index}
[/#list]

I would like to avoid having to write a custom bean and Gson deserializer just to have an explicit collection of items. Using Gson (which already deserializes the JSON string to a JsonObject for me) to then create my own DAG of objects from that JsonObject seems wasteful to me.

Unfortunately, I haven't been able to work out a way of getting Freemarker to treat the java.lang.Iterable as a list. I get:

freemarker.template.TemplateException : Expected collection or sequence.
  controller.sports evaluated instead to freemarker.ext.beans.XMLStringModel on line 8, column 16 in sports.html.
freemarker.core.Templat开发者_运维技巧eObject.invalidTypeException(line:135)
freemarker.core.IteratorBlock$Context.runLoop(line:190)
freemarker.core.Environment.visit(line:417)
freemarker.core.IteratorBlock.accept(line:102)
freemarker.core.Environment.visit(line:210)


Explicitly looping over the iterator should work, e.g.:

[#list sports.iterator() as sport]
   ${sport_index}
[/#list]


All you have to do is add the result of iterator() on your JsonArray to the context. Freemarker is smart enough to handle it from there, and you can reference it in your template like you do any other list-like variable.


Freemarker now supports Iterable's by creating your freemarker config via:

configuration = new Configuration(VERSION_2_3_28);
DefaultObjectWrapper objectWrapper = new DefaultObjectWrapper(VERSION_2_3_28);
objectWrapper.setIterableSupport(true);
configuration.setObjectWrapper(objectWrapper);

and updating to the 2.3.28 release (I'm not exactly sure which version added this, but .23 didn't have it), then simply instantiate your Template passing in that configuration.

return new Template("somename", someReader, configuration);
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号