how to make freeMarker simply call toString?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

how to make freeMarker simply call toString?

Vitaliy Semochkin
Hello,

I want to configure Freemarker
in order to make it replace

every ${object}, ${object.someField}, ${object.someMethod()}
in my template with a toString value for the returned object.
Even if it is an array, list, map or collection.

How to configure freemarkert in order to do so?

Regards,
Vitaliy


------------------------------------------------------------------------------

_______________________________________________
FreeMarker-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-user
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: how to make freeMarker simply call toString?

Daniel Dekany
Hello,

The way it works currently is that if FreeMarker doesn't know how to
make string out of a value (an FTL sequence or FTL hash in your case),
it will check if the *wrapped* value (which is made by the
ObjectWrapper from the plain Java object) implements
TemplateScalarModel, and if it does, it will use that to generate the
text to print. So, everything is possible with a custom ObjectWrapper.

As of how to achieve this with an out-of-the box object wrapper...
BeansWrapper does this if you don't
beansWrapper.setSimpleMapWrapper(true) it, except for arrays, but the
toString output of arrays is useless anyway. However, I wouldn't
recommend setSimpleMapWrapper(false), because it mixes the method
names with the keys in the map, which can get quite confusing.

But maybe I can give a better answer (or an RFE...) if I know why is
this needed. So why?

--
Thanks,
 Daniel Dekany


Sunday, March 30, 2014, 12:16:07 PM, Vitaliy Semochkin wrote:

> Hello,
>
> I want to configure Freemarker
> in order to make it replace
>
> every ${object}, ${object.someField}, ${object.someMethod()}
> in my template with a toString value for the returned object.
> Even if it is an array, list, map or collection.
>
> How to configure freemarkert in order to do so?
>
> Regards,
> Vitaliy
>


------------------------------------------------------------------------------
_______________________________________________
FreeMarker-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-user
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: how to make freeMarker simply call toString?

Vitaliy Semochkin
Hello Dánie,

You advise works great, thank you very much for the fast response!

As for your question, I need it because I do not know the types of  variablles that arrive to my template.

My only option to display it is to follow the rule:
When I have an expression ${someObject.someFieldOrPropertOrMethod} to be displayed
in case it returns a primitive i want it to be cast to String via it's Wrapper class (Boolean, Float, etc)
in case it is an object that overrides Object's toString() I want it to be displayed as a result of toString() execution.
in case it is a sequence that does not override toString() (e.g array, list, set) I want it to be displayed as [value1.toString,...,valueN.toString]
in case it is a Map that does not override toString I want it to be displayed as [{key1.toString(),value1.toString()..., ]

Am I right that all I need to do, is to override BeansWrapper?

Once again, thank you very much for supporting this great project and for a lighting fast response on Sunday :-)

Regards,
Vitaliy






On Sun, Mar 30, 2014 at 6:35 PM, Daniel Dekany <[hidden email]> wrote:
Hello,

The way it works currently is that if FreeMarker doesn't know how to
make string out of a value (an FTL sequence or FTL hash in your case),
it will check if the *wrapped* value (which is made by the
ObjectWrapper from the plain Java object) implements
TemplateScalarModel, and if it does, it will use that to generate the
text to print. So, everything is possible with a custom ObjectWrapper.

As of how to achieve this with an out-of-the box object wrapper...
BeansWrapper does this if you don't
beansWrapper.setSimpleMapWrapper(true) it, except for arrays, but the
toString output of arrays is useless anyway. However, I wouldn't
recommend setSimpleMapWrapper(false), because it mixes the method
names with the keys in the map, which can get quite confusing.

But maybe I can give a better answer (or an RFE...) if I know why is
this needed. So why?

--
Thanks,
 Daniel Dekany


Sunday, March 30, 2014, 12:16:07 PM, Vitaliy Semochkin wrote:

> Hello,
>
> I want to configure Freemarker
> in order to make it replace
>
> every ${object}, ${object.someField}, ${object.someMethod()}
> in my template with a toString value for the returned object.
> Even if it is an array, list, map or collection.
>
> How to configure freemarkert in order to do so?
>
> Regards,
> Vitaliy
>



------------------------------------------------------------------------------

_______________________________________________
FreeMarker-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-user
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: how to make freeMarker simply call toString?

Daniel Dekany
Sunday, March 30, 2014, 9:38:35 PM, Vitaliy Semochkin wrote:

> Hello Dánie,
>
> You advise works great, thank you very much for the fast response!
>
> As for your question, I need it because I do not know the types of
> variablles that arrive to my template.

What will consume that template output? The toString() of arbitrary
objects is meaningless for users (non-developer human beings) for
sure. It's also useless for other programs, as it's not even possible
to write code that reliably extracts data from the toString() of
standard collections and maps, as they don't quote the items or
anything like that. It's only good for debugging. Do you need this for
debugging maybe?

> My only option to display it is to follow the rule:
> When I have an expression ${someObject.someFieldOrPropertOrMethod} to be displayed
> in case it returns a primitive i want it to be cast to String via
> it's Wrapper class (Boolean, Float, etc)
> in case it is an object that overrides Object's toString() I want
> it to be displayed as a result of toString() execution.
> in case it is a sequence that does not override toString() (e.g
> array, list, set) I want it to be displayed as
> [value1.toString,...,valueN.toString]
> in case it is a Map that does not override toString I want it to be
> displayed as [{key1.toString(),value1.toString()..., ]
>
> Am I right that all I need to do, is to override BeansWrapper?

Yes, to ensure that all wrapped values that you want to print and
isn't a TemplateNumberModel or TemplateBooleanModel or
TemplateDateModel implements TemplateScalarModel, in the way that you
prefer, you will have to do that. Now, BeansWrapper is a quite complex
beast, so I'm not sure if it will be easy or not...

> Once again, thank you very much for supporting this great project
> and for a lighting fast response on Sunday  
>
> Regards,
> Vitaliy
>
>
>
>
>
>
> On Sun, Mar 30, 2014 at 6:35 PM, Daniel Dekany <[hidden email]> wrote:
> Hello,
>
> The way it works currently is that if FreeMarker doesn't know how to
> make string out of a value (an FTL sequence or FTL hash in your case),
> it will check if the *wrapped* value (which is made by the
> ObjectWrapper from the plain Java object) implements
> TemplateScalarModel, and if it does, it will use that to generate the
> text to print. So, everything is possible with a custom ObjectWrapper.
>
> As of how to achieve this with an out-of-the box object wrapper...
> BeansWrapper does this if you don't
> beansWrapper.setSimpleMapWrapper(true) it, except for arrays, but the
> toString output of arrays is useless anyway. However, I wouldn't
> recommend setSimpleMapWrapper(false), because it mixes the method
> names with the keys in the map, which can get quite confusing.
>
> But maybe I can give a better answer (or an RFE...) if I know why is
> this needed. So why?
>
> --
> Thanks,
>  Daniel Dekany
>
>
> Sunday, March 30, 2014, 12:16:07 PM, Vitaliy Semochkin wrote:
>
>> Hello,
>>
>> I want to configure Freemarker
>> in order to make it replace
>>
>> every ${object}, ${object.someField}, ${object.someMethod()}
>> in my template with a toString value for the returned object.
>> Even if it is an array, list, map or collection.
>>
>> How to configure freemarkert in order to do so?
>>
>> Regards,
>> Vitaliy
>>
>
>

--
Thanks,
 Daniel Dekany


------------------------------------------------------------------------------
_______________________________________________
FreeMarker-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-user
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: how to make freeMarker simply call toString?

Vitaliy Semochkin
Thank you for fast reply, Daniel!

>What will consume that template output? The toString() of arbitrary
>objects is meaningless for users (non-developer human beings) for
>sure. It's also useless for other programs, as it's not even possible
>to write code that reliably extracts data from the toString() of
>standard collections and maps, as they don't quote the items or
>anything like that. It's only good for debugging. Do you need this for
>debugging maybe?

I forgot to mention one case in my displaying algorithm (i marked it with bold below)

When I have an expression ${someObject.someFieldOrPropertOrMethod} to be displayed
in case it returns a primitive i want it to be cast to String via it's Wrapper class (Boolean, Float, etc)
in case it is an object that overrides Object's toString() I want it to be displayed as a result of toString() execution.
in case it is a sequence that does not override toString() (e.g array, list, set) I want it to be displayed as [value1.toString,...,valueN.toString]
in case it is a Map that does not override toString I want it to be displayed as [{key1.toString(),value1.toString()..., ]
in case it is an object that doesn't override toString() and none of the above(not a collection, array,map) it will be displayed as "¿"


I'm already digging in BeansWrapper
am I right that in I want objects that do not override toString methods return a "¿", i need to provide a StringModel for them
instantiated as  modelCache.getInstance(object, StringModel.FACTORY)?

Do I need to override public Object unwrap(TemplateModel model, Class hint)?

Regards,
Vitaliy










On Mon, Mar 31, 2014 at 1:59 AM, Daniel Dekany <[hidden email]> wrote:
Sunday, March 30, 2014, 9:38:35 PM, Vitaliy Semochkin wrote:

> Hello Dánie,
>
> You advise works great, thank you very much for the fast response!
>
> As for your question, I need it because I do not know the types of
> variablles that arrive to my template.

What will consume that template output? The toString() of arbitrary
objects is meaningless for users (non-developer human beings) for
sure. It's also useless for other programs, as it's not even possible
to write code that reliably extracts data from the toString() of
standard collections and maps, as they don't quote the items or
anything like that. It's only good for debugging. Do you need this for
debugging maybe?

> My only option to display it is to follow the rule:
> When I have an expression ${someObject.someFieldOrPropertOrMethod} to be displayed
> in case it returns a primitive i want it to be cast to String via
> it's Wrapper class (Boolean, Float, etc)
> in case it is an object that overrides Object's toString() I want
> it to be displayed as a result of toString() execution.
> in case it is a sequence that does not override toString() (e.g
> array, list, set) I want it to be displayed as
> [value1.toString,...,valueN.toString]
> in case it is a Map that does not override toString I want it to be
> displayed as [{key1.toString(),value1.toString()..., ]
>
> Am I right that all I need to do, is to override BeansWrapper?

Yes, to ensure that all wrapped values that you want to print and
isn't a TemplateNumberModel or TemplateBooleanModel or
TemplateDateModel implements TemplateScalarModel, in the way that you
prefer, you will have to do that. Now, BeansWrapper is a quite complex
beast, so I'm not sure if it will be easy or not...

> Once again, thank you very much for supporting this great project
> and for a lighting fast response on Sunday
>
> Regards,
> Vitaliy
>
>
>
>
>
>
> On Sun, Mar 30, 2014 at 6:35 PM, Daniel Dekany <[hidden email]> wrote:
> Hello,
>
> The way it works currently is that if FreeMarker doesn't know how to
> make string out of a value (an FTL sequence or FTL hash in your case),
> it will check if the *wrapped* value (which is made by the
> ObjectWrapper from the plain Java object) implements
> TemplateScalarModel, and if it does, it will use that to generate the
> text to print. So, everything is possible with a custom ObjectWrapper.
>
> As of how to achieve this with an out-of-the box object wrapper...
> BeansWrapper does this if you don't
> beansWrapper.setSimpleMapWrapper(true) it, except for arrays, but the
> toString output of arrays is useless anyway. However, I wouldn't
> recommend setSimpleMapWrapper(false), because it mixes the method
> names with the keys in the map, which can get quite confusing.
>
> But maybe I can give a better answer (or an RFE...) if I know why is
> this needed. So why?
>
> --
> Thanks,
>  Daniel Dekany
>
>
> Sunday, March 30, 2014, 12:16:07 PM, Vitaliy Semochkin wrote:
>
>> Hello,
>>
>> I want to configure Freemarker
>> in order to make it replace
>>
>> every ${object}, ${object.someField}, ${object.someMethod()}
>> in my template with a toString value for the returned object.
>> Even if it is an array, list, map or collection.
>>
>> How to configure freemarkert in order to do so?
>>
>> Regards,
>> Vitaliy
>>
>
>

--
Thanks,
 Daniel Dekany



------------------------------------------------------------------------------

_______________________________________________
FreeMarker-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-user
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: how to make freeMarker simply call toString?

Daniel Dekany
Monday, March 31, 2014, 9:34:34 AM, Vitaliy Semochkin wrote:

> Thank you for fast reply, Daniel!
>
> I'm already digging in BeansWrapper
> am I right that in I want objects that do not override toString
> methods return a "¿", i need to provide a StringModel for them
> instantiated as  modelCache.getInstance(object, StringModel.FACTORY)?

Most certainly you should override BeansWrapper.getModelFactory. And
then, instead of MapModel, CollectionModel, etc, you had to create
sub-classes of those where getAsString (inherited from StringModel) is
overridden.

Of course, it's quite awkward that you can't just override getAsString
in StringModel, but that's just one of the many cases where
inheritance is not flexible enough. I wonder if
StringModel.gasAsString should call back into BeansWrapper so that
there's a single point where you can control its behavior. Then you
don't even need to override getModelFactory. I just wonder if it's
useful enough in general to introduce the (small) overhead that the
indirection means.

> Do I need to override public Object unwrap(TemplateModel model, Class hint)?

Nope.

--
Thanks,
 Daniel Dekany


------------------------------------------------------------------------------
_______________________________________________
FreeMarker-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/freemarker-user
Loading...