how retrieve value from template in runtime

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

how retrieve value from template in runtime

shakedH
Hello , i'm new with FM
I have question.

I have implemented model, list and hash over my java classes
and it work perfectly.

My problem is with one of my hash implemented classes

----------------------------------------------------------------------
In my template code i have something like this

<#list physicalDevice.nodes as node>
    <#list wires as wire>
          <#assign secondPart = wire.getSecondPart>
          ${node.setSecondPart(secondPart)}
   </#list>
</#list>
----------------------------------------------------------------------
my model:
public class Wire implements TemplateHashModel {


    public TemplateModel get(String arg0) throws TemplateModelException {
              if(arg0.equals("getSecondPart")){
                    return .....(returnSomething)
                }
        }
}
------------
public class Node implements TemplateHashModel {

       public TemplateModel get(String arg0) throws TemplateModelException {
           ..........
       }
       public void setSecondPart(Object obj){
                if(obj instanceof Part){
                        .....(doSomething)
                }
        }
}
----------------------------------------------------------------------
As i said , i'm beeing able to access my node and wire classes.
but when i want to do the setSecondPart method, it accsses the node.get method (impement it)
and get error
so i want to know to things:
1. How can i get access to the node class methodes but not through the get method
    because i want to retrieve an object.
2. If i can't... how can i retrieve the object from template in runtime to the specific node in my nodeList    
    (gain access to my mhethods).

thanx.


Reply | Threaded
Open this post in threaded view
|

Re: how retrieve value from template in runtime

Daniel Dekany
Tuesday, August 3, 2010, 9:19:09 AM, shakedH wrote:

>
> Hello , i'm new with FM
> I have question.
>
> I have implemented model, list and hash over my java classes
> and it work perfectly.
>
> My problem is with one of my hash implemented classes
>
> ----------------------------------------------------------------------
> In my template code i have something like this
>
> <#list physicalDevice.nodes as node>
>     <#list wires as wire>
>           <#assign secondPart = wire.getSecondPart>
>           ${node.setSecondPart(secondPart)}
>    </#list>
> </#list>
> ----------------------------------------------------------------------
> my model:
> public class Wire implements TemplateHashModel {
>
>
>         public TemplateModel get(String arg0) throws TemplateModelException {
>                 if(arg0.equals("getSecondPart")){

(That's a quite unusual nomenclature. It should be just "secondPart",
so in the template you can write: wire.secondPart)

>                     return .....(returnSomething)
>                 }
>         }
> }
> ------------
> public class Node implements TemplateHashModel {
>
>        public TemplateModel get(String arg0) throws TemplateModelException {
>            ..........
>        }
>        public void setSecondPart(Object obj){
>                 if(obj instanceof Part){
>                         .....(doSomething)
>                 }
>         }
> }
> ----------------------------------------------------------------------
> As i said , i'm beeing able to access my node and wire classes.
> but when i want to do the setSecondPart method, it accsses the node.get
> method (impement it)
> and get error
> so i want to know to things:
> 1. How can i get access to the node class methodes but not through the get
> method
>     because i want to retrieve an object.
> 2. If i can't... how can i retrieve the object from template in runtime to
> the specific node in my nodeList    
>     (gain access to my mhethods).

When a class implements a TemplateModel interface (like Node in your
example does), FreeMarker will only use the methods of the implemented
TemplateModel interface(s). If you drop objects into the data-model
that don't implement any TemplateModel interfaces, then FreeMarker
will wrap them into TemplateModel-implementing classes automatically.
So that's the logic of this: if something implements TemplateModel
interfaces, then FreeMarker assumes it's already wrapped, hence, the
TemplateModel methods express how do you want to expose the object for
the templates. That's why you can't access setSecondPart from the
template.

OK, so what to do... Following the logic of what you did so far (which
is implementing TemplateModel interfaces directly) in Node.get you
could recognize the "setSecondPart" key, and return a TemplateModelEx
object for it. (Yes, in FTL methods and sub-variables are the same,
like ${foo.bar()} does the same as <#assing m = foo.bar>${m()}.)

But the more usual approach is that nor Node not Wire implements
TemplateHashModel, and you let FreeMarker wrap them automatically.
Thus your model classes (application-domain classes) are not bound to
FreeMarker at all; they are just POJO-s. However, the way FreeMarker
wraps your object automatically is sometimes not good enough, in which
case you are supposed to create custom ObjectWrapper class (usually be
extending BeansWrapper), and issue fmConfig.setObjectWrapper(new
MyObjectWrapper()) where you initialize(!) your whole application.

So, for starters you could just try:

  BeansWrapper myWrapper = new BeansWrapper();
  myWrapper.setSimpleMapWrapper(false);
  fmConfig.setObjectWrapper(myWrapper);

This will expose both the java.util.Map-entires and the public methods
of POJO-s. The catch is that this way if there is a method with the
same name as a Map key, you won't be able to get the Map entry, only
with node.get("theKey"), as the method with the same name "shadows" it
otherwise. Also node?keys will list a lot of junk (all the methods
names), not just the Map keys.


> thanx.

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Reply | Threaded
Open this post in threaded view
|

Re: how retrieve value from template in runtime

shakedH
First, thanx!

Sec, problem well explained!.

but didn't uderstand the solution

> OK, so what to do... Following the logic of what you did so far (which
> is implementing TemplateModel interfaces directly) in Node.get you
> could recognize the "setSecondPart" key, and return a TemplateModelEx
> object for it. (Yes, in FTL methods and sub-variables are the same,
> like ${foo.bar()} does the same as <#assing m = foo.bar>${m()}.)

you mean:

public class Node implements TemplateHashModel {
     
       private MyClass secondPart = null;
       public TemplateModel get(String arg0) throws TemplateModelException {
           if(arg0.equals("secondPart")){
                    return secondPart;
                }
       }
      // public void setSecondPart(Object obj){
      //          if(obj instanceof Part){
      //                  .....(doSomething)
      //          }
      //  }
}

but how do i connect those two objects  (the Wire secondPart and the Node secondPart )
Reply | Threaded
Open this post in threaded view
|

Re: how retrieve value from template in runtime

Daniel Dekany
Tuesday, August 3, 2010, 1:27:10 PM, shakedH wrote:

>
> First, thanx!
>
> Sec, problem well explained!.
>
> but didn't uderstand the solution
>
>> OK, so what to do... Following the logic of what you did so far (which
>> is implementing TemplateModel interfaces directly) in Node.get you
>> could recognize the "setSecondPart" key, and return a TemplateModelEx
>> object for it. (Yes, in FTL methods and sub-variables are the same,
>> like ${foo.bar()} does the same as <#assing m = foo.bar>${m()}.)
>
> you mean:
>
> public class Node implements TemplateHashModel {
>      
>        private MyClass secondPart = null;
>        public TemplateModel get(String arg0) throws TemplateModelException {
>            if(arg0.equals("secondPart")){
>                     return secondPart;
>                 }
>        }
>       // public void setSecondPart(Object obj){
>       //          if(obj instanceof Part){
>       //                  .....(doSomething)
>       //          }
>       //  }
> }
>
> but how do i connect those two objects  (the Wire secondPart and the Node
> secondPart )

With ${aNode.setSecondPart(whatever)}, which will print nothing, but
has the desired side-effect... Ugly, but works. What I explained was
that how to make that "setSecondPart" method visible in the templates.

I have to note however that it's not something that's normally done in
templates. Template should not build the data-model, just read it. So
FreeMarker was designed in read-only data-model in mind. You might
should do these things outside the template, and just do the things in
the template that it designed to do.

Personally, if this kind of thing is rare but can't be avoided, I
would go for a third solution: I would write a TemplateDirectiveModel
that can write Node and Wire objects, like <@setSecondPart
parent=aNode child=aPart />. This way I don't use a "hack" like a
${...} that prints nothing, also the data-model is not complicated
with the setter methods. Directive calls (<@...>) pretty much say that
"I have a side effect", so it's less confusing.

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Reply | Threaded
Open this post in threaded view
|

Re: how retrieve value from template in runtime

shakedH
hi
Ok, this one of the cases that cant be avoided(template change dataModel)

But now you lost me at the dataMode side...
If i use:  "${aNode.setSecondPart(whatever)}" in my template.
And in my dataMode at class Node (that implements TemplateMode)
I use: "setSecondPart" key (the implamented get method)
if replay the Object, you mean that i replay the Method setSecondPart, or the object secondPart itself.
 
 public class Node implements TemplateHashModel {
   
        private MyClass secondPart = null;
        public TemplateModel get(String arg0) throws TemplateModelException {
            if(arg0.equals("secondPart")){
                     return secondPart;
                 }
        }
}

Because i can't see how it will actualy going to set the new secondPart.
If setSecondPart return  the Object secondPart
Than i'll get something like this -> secondPart(whatever,or somthing undefined
Reply | Threaded
Open this post in threaded view
|

Re: how retrieve value from template in runtime

Daniel Dekany
Tuesday, August 3, 2010, 8:36:23 PM, shakedH wrote:

>
> hi
> Ok, this one of the cases that cant be avoided(template change dataModel)
>
> But now you lost me at the dataMode side...
> If i use:  "${aNode.setSecondPart(whatever)}" in my template.
> And in my dataMode at class Node (that implements TemplateMode)
> I use: "setSecondPart" key (the implamented get method)
> if replay the Object, you mean that i replay the Method setSecondPart, or
> the object secondPart itself.

The TemplateMethodEx object of course. Again, in the FreeMarker
Template Language methods are first-class values. So if you write
foo.setSecondPart(x), that first does foo.setSeconPart (and so
internally calls Node.get("setSeconPart")), and then it tries to call
the returned value as a method, like whateverYouReturned(x). If the
returned value is not something callable (like a TemplateMethod or
TemplateMethodEx), FreeMarker will throw a runtime error.

>  public class Node implements TemplateHashModel {
>    
>         private MyClass secondPart = null;
>         public TemplateModel get(String arg0) throws TemplateModelException
> {
>             if(arg0.equals("secondPart")){
>                      return secondPart;
>                  }
>         }
> }
>
> Because i can't see how it will actualy going to set the new secondPart.

You have to do it inside your TemplateMethodEx implementation. So you
need yet another class: "class NodeSecondPartSetter implements
TemplateMethodEx" etc. Yeah, too much classes... but at the places
where you don't want or can't to use automatic object wrapping, this
is unfortunately like that. BUT, if you are doing manual wrapping
anyway, you could just use a TemplateDirectiveModel instead of a
TemplateMethodEx. Then you could write something like this in the
templates:

  <@myNode.setSecondPart part=whatever />

Rather than a ${...} that actually prints nothing.

> If setSecondPart return  the Object secondPart
> Than i'll get something like this -> secondPart(whatever,or somthing
> undefined

--
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
The Palm PDK Hot Apps Program offers developers who use the
Plug-In Development Kit to bring their C/C++ apps to Palm for a share
of $1 Million in cash or HP Products. Visit us here for more details:
http://p.sf.net/sfu/dev2dev-palm
_______________________________________________
FreeMarker-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-devel
Reply | Threaded
Open this post in threaded view
|

Re: how retrieve value from template in runtime

shakedH
Daniel, thank you very much!!!