[MAGNOLIA-3287] freemarker MagnoliaObjectWrapper should wrap any Content instance info.magnolia.freemarker.models.ContentModel, also if the given Content also implements Map Created: 01/Sep/10  Updated: 04/Nov/15  Resolved: 04/Nov/15

Status: Closed
Project: Magnolia
Component/s: freemarker, rendering, templating
Affects Version/s: 4.3.6
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Fabrizio Giustina Assignee: Fabrizio Giustina
Resolution: Won't Do Votes: 0
Labels: quickwin
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Template:
Acceptance criteria:
Empty
Task DoD:
[ ]* Doc/release notes changes? Comment present?
[ ]* Downstream builds green?
[ ]* Solution information and context easily available?
[ ]* Tests
[ ]* FixVersion filled and not yet released
[ ]  Architecture Decision Record (ADR)
Date of First Response:

 Description   

If you try to use a Content object which also implements Map in a freemarker template (e.g. if the object is not DefaultContent but info.magnolia.cms.util.NodeMapWrapper) it gets not wrapped properly using info.magnolia.freemarker.models.ContentModel as expected.

This is due to the fact that the custom wrapper only gets used if standard freemarker adapters are not available, so implementing Map is enough to make freemarker skip the Magnolia factories...
This is the same issue we had in the past with the "Context" object, and we already have a specific check in the wrap() method of MagnoliaObjectWrapper:

    public TemplateModel wrap(Object obj) throws TemplateModelException {
        if (obj instanceof Context) {
            // bypass the default SimpleHash wrapping, we need a MapModel.
            // handleUnknownType() will relay to our ContextModelFactory.
            return handleUnknownType(obj);
        }
        return super.wrap(obj);
    }

the proposed change is to also add "Content" to the list of objects that should always we wrapped using Magnolia-specific adapters:

    public TemplateModel wrap(Object obj) throws TemplateModelException {
        if (obj instanceof Context || obj instanceof Content) {
            // bypass the default SimpleHash wrapping, we need a MapModel.
            // handleUnknownType() will relay to our ContextModelFactory.
            return handleUnknownType(obj);
        }
        return super.wrap(obj);
    }


 Comments   
Comment by Magnolia International [ 14/Sep/10 ]

This if() statement should then check if we have a known model factory for the given object, instead of re-hardcoding the list of objects we want to wrap specifically (which would defeat the whole purpose of these factories); since getModelFactory is fairly heavy , it might be good idea to cache the results. (Perhaps simply a Map<Class concrete, Boolean hasFactory> ?).

Alternatively, you could write a custom MagnoliaModelFactory (in your case for AdvancedResult? - see info.magnolia.module.templating.freemarker.RenderableDefinitionModel for an example) and register it under /server/rendering/freemarker/modelFactories.

Comment by Michael Mühlebach [ 04/Nov/15 ]

Given the thousands of other issues we have open that are more highly requested, we won't be able to address this issue in the foreseeable future. Instead we will focus on issues with a higher impact, and more votes.
Thanks for taking the time to raise this issue. As you are no doubt aware this issue has been on our backlog for some time now with very little movement.
I'm going to close this to set expectations so the issue doesn't stay open for years with few updates. If the issue is still relevant please feel free to reopen it or create a new issue.

Generated at Mon Feb 12 03:45:01 CET 2024 using Jira 9.4.2#940002-sha1:46d1a51de284217efdcb32434eab47a99af2938b.