Re: Preserving ordering in a Freemarker sequence when iterating over an OrderedBidiMap.
Attila Szegedi <[email protected]>
| Newsgroups | gmane.comp.web.freemarker.user |
|---|---|
| Message-ID | <[email protected]> |
In your application context XML, you'll use some sort of FreeMarker
configurer, i.e. in web UI you'd use a org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer
.
You can specify a wrapper using freemarkerSettings:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer
">
<property name="freemarkerSettings">
<props>
<prop key="object_wrapper">beans</prop>
</props>
</property>
</bean>
to use a shared singleton BeansWrapper instance or
<prop key="object_wrapper">freemarker.ext.beans.BeansWrapper</prop>
to have it create a new one. This way, you didn't expose the wrapper
to the app context. But there are advantages to instantiating the
configuration (and wrapper) in the context (and they needn't be named
singletons, they can be embedded bean within the property setter if
you don't want them visible to the application context's clients). An
advantage is that you can further configure the beans wrapper, i.e. if
you want to set "simpleMapWrapper" on it:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer
">
<property name="configuration">
<bean class="freemarker.template.Configuration">
<property name="objectWrapper">
<bean class="freemarker.ext.beans.BeansWrapper">
<property name="simpleMapWrapper" value="true"/>
</bean>
</property>
</bean>
</property>
</bean>
(Also, Spring does not allow you access to all configuration options
FreeMarker has, but that's really an issue to raise with Spring
developers).
Attila.
On 2008.02.03., at 15:45, Stephen Smith wrote:
> Hi Jonathan,
>
> Thanks for your explanation. Your answer makes a lot of sense, but
> as we using Freemarker in conjunction with Spring we
> can't access a Freemarker ObjectWrapper directly without exposing it
> in the Spring application context, which seems like
> a bit of a smell. So, our current workaround is to put our
> OrderedBidiMap inside a LinkedHashMap before sending it to
> the Freemarker ViewResolver.
>
> I haven't had a chance yet to poke around inside the Freemarker
> codebase, but I'm a little hazy on why Freemarker knows
> about java.util.Map implementations specifically within java.util.*,
> but not other packages. Is Freemarker explicitly
> checking map implementation type for performance reasons?
>
> Thanks
>
> Steve.
>
> ---
> Stephen Smith, MEng (Wales).
> http://www.stephen-smith.co.uk/
>
> Jonathan Revusky wrote:
>> Stephen Smith wrote:
>>> Hi,
>>>
>>> We're using an OrderedBidiMap from Commons Collections 3.x to
>>> store a
>>> mapping of
>>> keys<->values (the implementation we use is TreeBidiMap). Our
>>> Freemarker syntax
>>> is as follows:
>>>
>>> <#list subjectsMap?keys as subjectName>
>>> ${subjectName}
>>> </#if>
>>>
>>> The problem is that the sequence is returning an unordered list of
>>> keys. The same
>>> Freemarker syntax seems to work with a LinkedHashMap, but I don't
>>> understand what
>>> Freemarker is doing under the hood when getting the map's keys.
>>> Surely
>>> it is just
>>> calling Map#keySet, in which case our ordering should be preserved?
>>
>> I think the problem is that the DefaultObjectWrapper is copying the
>> map,
>> and by default, is using HashMap. The code in there is aware, for
>> example, of things in java.util.* such as LinkedHashMap or TreeMap
>> and
>> will preserve order, but the default behavior with maps otherwise
>> is to
>> copy them into a HashMap.
>>
>> Perhaps you need to explicitly use the BeansWrapper. Just use:
>>
>> BeansWrapper bw = new BeansWrapper();
>> dataModel.put("subjectsMap", bw.wrap(subjectsMap));
>>
>> Or, you could just set it as the default wrapper, and that would be
>> something like:
>>
>> freeMarkerConfig.setObjectWrapper(new BeansWrapper());
>>
>>
>>>
>>> Is this a defect in Freemarker,
>>
>> Arguably, it is, though the whole issue is a bit complex...
>>
>>> are we misusing the sequence syntax, or should we
>>> pass through the OrderedBidiMap's entry set and then call getKey and
>>> getValue on
>>> each bean?
>>
>> For the moment, the solution would be to explicitly use
>> freemarker.ext.beans.BeansWrapper.
>>
>> JR
>>
>>>
>>> Thanks in advance
>>>
>>> Stephen Smith
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/