Re: Sharing constants in .java and .ftl files

Daniel Dekany <[email protected]>
Newsgroups gmane.comp.web.freemarker.user
Message-ID <[email protected]>
Sunday, November 16, 2008, 9:18:58 PM, Luther Baker wrote:

> I'd like to store something in the root hashmap and retrieve it in an
> FTL file.
>
> I'd like to avoid 'strings' as keys everywhere so I'd like to abstract
> that out - into a Constants class or something.
>
>
> CURRENT STYLE: notice the "projects" key in the class file ... and  
> rigid reference (not a string) in the FTL file.
>
> .class:
> root.put("projects", projectList);
>
> .ftl
> <#list projects[] as p>
> <li>${p.name}</li>
> </#list>
>
>
> NEW STYLE: I'd like to do this - but I don't know what to do at  
> the ???? below.
>
> Constants.java
> public class Constants
> {
>      public static final String PROJECTS = "projects";
> }
>
> .class:
> root.put(Constants.PROJECTS, projectList);
>
> .ftl
> <#list ?????[] as p>
> <li>${p.name}</li>
> </#list>

Er... but the java coded is equivalent with the previous one... so the
FTL should be <#list projects[] as p> again. Are you sure this is what
you wanted to ask?

> Furthermore, I'd like this Constants class available globally. Maybe
> I can assign it in an FTL I load at the beginning ... but since it
> is not a TemplateMethodModel or TemplateDirectiveModel, I'm not sure
> how to put it into the root scope permanently as a Java object. I
> guess - core this is the question - can I put POJOs into the root
> namespace ... and if so, how do I do that? Most of what I'm reading
> is more specific to the above named interfaces and their subsequent
> predefined methods.

You can put POJO-s into the data-model root, furthermore that's usual
way of doing that. Like, looking at
http://freemarker.org/docs/pgui_quickstart_all.html you see that there
are no TemplateXxxModel-s around at all, just POJO-s, yet we have
built a full data-model. Surely in that basic example we just add
String-s and simple stuff like that to the data-model, but you could
also add other kind of objects as well.

Regarding adding data-model entries globally, you can use
freemarker.core.Configurable.Configuration.setSharedVariable for that.
As you can is in the API, you can add both TemplateModel-s or POJO-s.
Or, you could use a custom-class TemplateHashModelEx as the data-model
root, which would act as an usual SimpleHash, only it would
automatically expose the static fields of a given class... BTW that's
one reason why one sometimes wants to deal with TemplateModel-s as
opposed to POJO-s. It gives you extra power, but if you don't need
that, just use POJO-s, like a java.util.Map as the data-model root.

> One the POJO is in the namespace, can I invoke arbitrary methods ...

Yes. Depends on the settings of the ObjectWrapper anyway, but be
default yes. See:
http://freemarker.org/docs/api/freemarker/ext/beans/BeansWrapper.html#setExposureLevel(int).

Although the default wrapper is
freemarker.template.DefaultObjectWrapper, not
freemarker.ext.beans.BeansWrapper, the only difference is that
DefaultObjectWrapper wraps String-s, Number-s, Date-s, List-s and
Map-s and few such basic classes specially, so you will not access
their methods (because you should use the FTL built-ins, like
myList?size, instead of myList.size()), but you will still access the
methods of other classes. (Oh, and it also treats org.w3c.dom.Node
specially, so you can process XML easily.)

> or look at arbitrary fields ....

Yes, but not be default. See:
http://freemarker.org/docs/api/freemarker/ext/beans/BeansWrapper.html#setExposeFields(boolean)

> and then finally, what syntax allows a string field serve as the
> 'list' parameter of the <#list macro ...

Such things are solved on the wrapping level, not on the FTL level.
FTL, the template language, only deals with TemplateModel-s; that's
what the native type-system of the template language is built from.
But behind the scenes there is (are) the ObjectWrapper(-s) that
translate POJO-s to TemplateModel-s. So if you have something that's a
String, and you want to expose that to the template as a sequence,
then the ObjectWrapper must translate (or as we call it: wrap) the
string into a TemplateSequenceModel or TemplateCollectionModel.
Actually, ObjectWrappers are not that much behind the scenes, as the
related API-s are public, and it's not rare that users fiddle with
them.

> Thanks for all your time parsing this :) Hope it is an easy answer.
>
> -Luther

-- 
Best regards,
 Daniel Dekany


-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.