You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Numa Schmeder <nu...@dfacto.ch> on 2021/05/26 10:00:13 UTC

method varargs and property expression

Hello,

It seems method with varargs doesn’t work with property expression. 
If I put the following property expression, I get an error: Message doesn’t have a public “format" method. 
${messages.format('priceFromPerGuest', travelMinPricePerGuest, displayedCurrency)}
But If I write it as follow is works:
messages.format('priceFromPerGuest', [travelMinPricePerGuest, displayedCurrency])

Is this a bug ?

Tapestry property expression is a bit limiting, particularly in conditions where you can’t have logical expression as:  test=“size > 10”

I know the rational is to keep property expression as simple as possible, but having some logic expressed in the template is not that bad, because it’s in context ans sometimes makes more sense than having everything in java code. 

Also if you work a lot with collection of objects, you have to create a property for each type of element in the collections, the “var” keyword is not powerful to be used in complex property expressions.
Exemple, this won’t work, but it would be very practical:
<t:loop source=“countries” value=“var:country”>
	${var:country.getName(locale)} - ${getPopulation(var:country)}
</t:loop>

And if you use a generic property tempValue that you could reuse in different places, it won’t work because all conduits will be based on the Object Type and not Country type. 

@Property
Object tempValue

<t:loop source=“countries” value=“var: tempValue”>
	${tempValue.getName(locale)} - ${getPopulation(tempValue)}
</t:loop>

Could we find a solution to avoir creating a lot of fields for all loops ?

Thank you for your help, 

Best! 


  <http://www.dfacto.ch/>	Numa Schmeder    www.dfacto.ch  <http://www.dfacto.ch/>
NUMA@DFACTO.CH <ma...@dfacto.ch>   |   M +41 79 538 30 01 

DIGITAL STRATEGY   |   DESIGN   |   DEVELOPMENT


 


Re: method varargs and property expression

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
On Mon, Jun 7, 2021 at 5:38 AM Numa Schmeder <nu...@dfacto.ch> wrote:

> Hi Thiago,
>

Hello!


> Thank you for your feedback, yes indeed, I have checked the code of the
> property binding and the antler syntax.
> Indeed it compiles byte code based on real method signature, so you can’t
> be to generic or it won’t find the method you have written.


And that's exactly how Tapestry voids runtime reflection so property access
is as fast as handwritten code. :)


> I was actually thinking of implementing Spring Expression Language (SpEL),
> OGNL is getting a bit outdated and is now longer evolving.


Interesting! Planning to opensource it when it's done? It would be nice.


> Although I figured out my language issue, if you don’t call
> PersistentLocale on first render, URL won’t contain the locale virtual
> folder in the path.
> I think this is a bug, the natural behavior seems to be if you define
> multiple locales, on first render without local (index page for example) it
> should select the appropriate locale from request, browser etc.. (this
> works) and set it with persistentLocale, so links should be written
> correctly with the locale virtual folder. What do you think ?
>

Hmm, I have to think about this one. No ready-made answers like the other
ones in this thread. :)


> Lastly I wanted to override a value encoder for specific hibernate objects
> to create SEO friendly urls , but it was discarded because there is already
> an hibernate value encoder registered with tapestry hibernate, how can I
> override it for specific objects ?
>

ValueEncoderSource is a service with a mapped configuration: key is the
class of the object being encoded/decoded, ValueEncoderFactory (which is
usually implemented together with ValueEncoder in most but not all cases),
so this should be a very straightforward Tapestry-IoC service contribution
override. I'm not sure how you tried to do your override.


> Your help is very much appreciated.


It's always nice to help people, doubly if it's about Tapestry. :D


>
>
> Thank you.
>
> Best regards,
>
> Numa
>
> > Le 6 juin 2021 à 21:09, Thiago H. de Paula Figueiredo <
> thiagohp@gmail.com> a écrit :
> >
> > On Wed, May 26, 2021 at 7:00 AM Numa Schmeder <numa@dfacto.ch <mailto:
> numa@dfacto.ch>> wrote:
> >
> >> Hello,
> >>
> >
> > Hello!
> >
> >
> >> It seems method with varargs doesn’t work with property expression.
> >> If I put the following property expression, I get an error: Message
> >> doesn’t have a public “format" method.
> >> ${messages.format('priceFromPerGuest', travelMinPricePerGuest,
> >> displayedCurrency)}
> >> But If I write it as follow is works:
> >> messages.format('priceFromPerGuest', [travelMinPricePerGuest,
> >> displayedCurrency])
> >>
> >> Is this a bug ?
> >>
> >
> > I don't think so. Varargs, as far as I know, are implemented in Java
> purely
> > as a compiler feature, and Tapestry prop binding expressions work at
> > runtime, so it only sees method(arg, Object[] varargs) for something
> > declared as method(arg1, Object... varargs).
> >
> >
> >> Tapestry property expression is a bit limiting, particularly in
> conditions
> >> where you can’t have logical expression as:  test=“size > 10”
> >>
> >
> > Let me be pedantic here. :) Yes, it's the prop binding, short for
> property.
> > Being based on properties, it can be very fast, since Tapestry-IoC and
> > Tapestry can create code that calls properties without using reflection.
> > This binding was never supposed to have logical expressions.
> >
> >
> >> I know the rational is to keep property expression as simple as
> possible,
> >> but having some logic expressed in the template is not that bad,
> >
> >
> > Having logic expressed in the template is completely against the way the
> > prop binding was created and implemented, so I suggest you to not try or
> > want to do something one given tool doesn't want.
> >
> >
> >> because it’s in context ans sometimes makes more sense than having
> >> everything in java code.
> >
> >
> > Here comes one of the beauties of Tapestry: it's incredibly flexible and
> > customizable. You can create your own bindings with any logic you want!
> If
> > you don't know how, please let us know and we'll show you how.
> >
> > By the way, ChenilleKit, a third-party Tapestry add-on library, provides
> an
> > OGNL binding that provides a lot of expression power (but uses reflection
> > at runtime).
> >
> >
> >> Also if you work a lot with collection of objects, you have to create a
> >> property for each type of element in the collections, the “var” keyword
> is
> >> not powerful to be used in complex property expressions.
> >> Exemple, this won’t work, but it would be very practical:
> >> <t:loop source=“countries” value=“var:country”>
> >>        ${var:country.getName(locale)} - ${getPopulation(var:country)}
> >> </t:loop>
> >>
> >> And if you use a generic property tempValue that you could reuse in
> >> different places, it won’t work because all conduits will be based on
> the
> >> Object Type and not Country type.
> >>
> >> @Property
> >> Object tempValue
> >>
> >> <t:loop source=“countries” value=“var: tempValue”>
> >>        ${tempValue.getName(locale)} - ${getPopulation(tempValue)}
> >> </t:loop>
> >>
> >> Could we find a solution to avoir creating a lot of fields for all
> loops ?
> >>
> >
> > The var binding only really accepts strings well because it doesn't use
> > reflection and being able to support arbitrary types would need
> reflection.
> >
> >
> >>
> >> Thank you for your help,
> >>
> >> Best!
> >>
> >>
> >>  <http://www.dfacto.ch/ <http://www.dfacto.ch/>>       Numa Schmeder
>   www.dfacto.ch <http://www.dfacto.ch/>  <
> >> http://www.dfacto.ch/ <http://www.dfacto.ch/>>
> >> NUMA@DFACTO.CH <ma...@DFACTO.CH> <mailto:numa@dfacto.ch <mailto:
> numa@dfacto.ch>>   |   M +41 79 538 30 01
> >>
> >> DIGITAL STRATEGY   |   DESIGN   |   DEVELOPMENT
> >>
> >>
> >>
> >>
> >>
> >
> > --
> > Thiago
>
>

-- 
Thiago

Re: method varargs and property expression

Posted by Numa Schmeder <nu...@dfacto.ch>.
Hi Thiago,

Thank you for your feedback, yes indeed, I have checked the code of the property binding and the antler syntax. 
Indeed it compiles byte code based on real method signature, so you can’t be to generic or it won’t find the method you have written. 
I will look into chenille kit for the OGNL binding, it’s interesting. I agree prop binding is cleaner in many way as it avoid logic inside template. But a bit of logic in the template avoids writing boiler plate code and declaring tons of variables in your class juste to create loop indexes or loop values. 
I was actually thinking of implementing Spring Expression Language (SpEL), OGNL is getting a bit outdated and is now longer evolving. 

Although I figured out my language issue, if you don’t call PersistentLocale on first render, URL won’t contain the locale virtual folder in the path. 
I think this is a bug, the natural behavior seems to be if you define multiple locales, on first render without local (index page for example) it should select the appropriate locale from request, browser etc.. (this works) and set it with persistentLocale, so links should be written correctly with the locale virtual folder. What do you think ?

Lastly I wanted to override a value encoder for specific hibernate objects to create SEO friendly urls , but it was discarded because there is already an hibernate value encoder registered with tapestry hibernate, how can I override it for specific objects ?

Your help is very much appreciated. 

Thank you. 

Best regards, 

Numa 

> Le 6 juin 2021 à 21:09, Thiago H. de Paula Figueiredo <th...@gmail.com> a écrit :
> 
> On Wed, May 26, 2021 at 7:00 AM Numa Schmeder <numa@dfacto.ch <ma...@dfacto.ch>> wrote:
> 
>> Hello,
>> 
> 
> Hello!
> 
> 
>> It seems method with varargs doesn’t work with property expression.
>> If I put the following property expression, I get an error: Message
>> doesn’t have a public “format" method.
>> ${messages.format('priceFromPerGuest', travelMinPricePerGuest,
>> displayedCurrency)}
>> But If I write it as follow is works:
>> messages.format('priceFromPerGuest', [travelMinPricePerGuest,
>> displayedCurrency])
>> 
>> Is this a bug ?
>> 
> 
> I don't think so. Varargs, as far as I know, are implemented in Java purely
> as a compiler feature, and Tapestry prop binding expressions work at
> runtime, so it only sees method(arg, Object[] varargs) for something
> declared as method(arg1, Object... varargs).
> 
> 
>> Tapestry property expression is a bit limiting, particularly in conditions
>> where you can’t have logical expression as:  test=“size > 10”
>> 
> 
> Let me be pedantic here. :) Yes, it's the prop binding, short for property.
> Being based on properties, it can be very fast, since Tapestry-IoC and
> Tapestry can create code that calls properties without using reflection.
> This binding was never supposed to have logical expressions.
> 
> 
>> I know the rational is to keep property expression as simple as possible,
>> but having some logic expressed in the template is not that bad,
> 
> 
> Having logic expressed in the template is completely against the way the
> prop binding was created and implemented, so I suggest you to not try or
> want to do something one given tool doesn't want.
> 
> 
>> because it’s in context ans sometimes makes more sense than having
>> everything in java code.
> 
> 
> Here comes one of the beauties of Tapestry: it's incredibly flexible and
> customizable. You can create your own bindings with any logic you want! If
> you don't know how, please let us know and we'll show you how.
> 
> By the way, ChenilleKit, a third-party Tapestry add-on library, provides an
> OGNL binding that provides a lot of expression power (but uses reflection
> at runtime).
> 
> 
>> Also if you work a lot with collection of objects, you have to create a
>> property for each type of element in the collections, the “var” keyword is
>> not powerful to be used in complex property expressions.
>> Exemple, this won’t work, but it would be very practical:
>> <t:loop source=“countries” value=“var:country”>
>>        ${var:country.getName(locale)} - ${getPopulation(var:country)}
>> </t:loop>
>> 
>> And if you use a generic property tempValue that you could reuse in
>> different places, it won’t work because all conduits will be based on the
>> Object Type and not Country type.
>> 
>> @Property
>> Object tempValue
>> 
>> <t:loop source=“countries” value=“var: tempValue”>
>>        ${tempValue.getName(locale)} - ${getPopulation(tempValue)}
>> </t:loop>
>> 
>> Could we find a solution to avoir creating a lot of fields for all loops ?
>> 
> 
> The var binding only really accepts strings well because it doesn't use
> reflection and being able to support arbitrary types would need reflection.
> 
> 
>> 
>> Thank you for your help,
>> 
>> Best!
>> 
>> 
>>  <http://www.dfacto.ch/ <http://www.dfacto.ch/>>       Numa Schmeder    www.dfacto.ch <http://www.dfacto.ch/>  <
>> http://www.dfacto.ch/ <http://www.dfacto.ch/>>
>> NUMA@DFACTO.CH <ma...@DFACTO.CH> <mailto:numa@dfacto.ch <ma...@dfacto.ch>>   |   M +41 79 538 30 01
>> 
>> DIGITAL STRATEGY   |   DESIGN   |   DEVELOPMENT
>> 
>> 
>> 
>> 
>> 
> 
> -- 
> Thiago


Re: method varargs and property expression

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
On Wed, May 26, 2021 at 7:00 AM Numa Schmeder <nu...@dfacto.ch> wrote:

> Hello,
>

Hello!


> It seems method with varargs doesn’t work with property expression.
> If I put the following property expression, I get an error: Message
> doesn’t have a public “format" method.
> ${messages.format('priceFromPerGuest', travelMinPricePerGuest,
> displayedCurrency)}
> But If I write it as follow is works:
> messages.format('priceFromPerGuest', [travelMinPricePerGuest,
> displayedCurrency])
>
> Is this a bug ?
>

I don't think so. Varargs, as far as I know, are implemented in Java purely
as a compiler feature, and Tapestry prop binding expressions work at
runtime, so it only sees method(arg, Object[] varargs) for something
declared as method(arg1, Object... varargs).


> Tapestry property expression is a bit limiting, particularly in conditions
> where you can’t have logical expression as:  test=“size > 10”
>

Let me be pedantic here. :) Yes, it's the prop binding, short for property.
Being based on properties, it can be very fast, since Tapestry-IoC and
Tapestry can create code that calls properties without using reflection.
This binding was never supposed to have logical expressions.


> I know the rational is to keep property expression as simple as possible,
> but having some logic expressed in the template is not that bad,


Having logic expressed in the template is completely against the way the
prop binding was created and implemented, so I suggest you to not try or
want to do something one given tool doesn't want.


> because it’s in context ans sometimes makes more sense than having
> everything in java code.


Here comes one of the beauties of Tapestry: it's incredibly flexible and
customizable. You can create your own bindings with any logic you want! If
you don't know how, please let us know and we'll show you how.

By the way, ChenilleKit, a third-party Tapestry add-on library, provides an
OGNL binding that provides a lot of expression power (but uses reflection
at runtime).


> Also if you work a lot with collection of objects, you have to create a
> property for each type of element in the collections, the “var” keyword is
> not powerful to be used in complex property expressions.
> Exemple, this won’t work, but it would be very practical:
> <t:loop source=“countries” value=“var:country”>
>         ${var:country.getName(locale)} - ${getPopulation(var:country)}
> </t:loop>
>
> And if you use a generic property tempValue that you could reuse in
> different places, it won’t work because all conduits will be based on the
> Object Type and not Country type.
>
> @Property
> Object tempValue
>
> <t:loop source=“countries” value=“var: tempValue”>
>         ${tempValue.getName(locale)} - ${getPopulation(tempValue)}
> </t:loop>
>
> Could we find a solution to avoir creating a lot of fields for all loops ?
>

The var binding only really accepts strings well because it doesn't use
reflection and being able to support arbitrary types would need reflection.


>
> Thank you for your help,
>
> Best!
>
>
>   <http://www.dfacto.ch/>       Numa Schmeder    www.dfacto.ch  <
> http://www.dfacto.ch/>
> NUMA@DFACTO.CH <ma...@dfacto.ch>   |   M +41 79 538 30 01
>
> DIGITAL STRATEGY   |   DESIGN   |   DEVELOPMENT
>
>
>
>
>

-- 
Thiago

Re: method varargs and property expression

Posted by Numa Schmeder <nu...@dfacto.ch>.
Hi,

Thank you. I know, I realized I made a typo. It should be:

@Property
Object tempValue

<t:loop source=“countries” value=“tempValue”>
	${tempValue.getName(locale)} - ${getPopulation(tempValue)}
</t:loop>

I think var prefix is a great addition, but it should be able to use var in property expression, and not only as single read write property storage. 

Numa
 

> Le 27 mai 2021 à 09:55, Chris Poulsen <ma...@nesluop.dk> a écrit :
> 
> We never really use much of the expression language, so I can't comment on
> that.
> 
> This is just a comment on the last example: I'm not sure that you need a
> @Property when using the "var:" prefix (if you have a backing property it
> ought to be a "prop:" binding, as far as I understand)
> 
> -- 
> Chris
> 
> 
> 
> On Wed, May 26, 2021 at 12:00 PM Numa Schmeder <numa@dfacto.ch <ma...@dfacto.ch>> wrote:
> 
>> Hello,
>> 
>> It seems method with varargs doesn’t work with property expression.
>> If I put the following property expression, I get an error: Message
>> doesn’t have a public “format" method.
>> ${messages.format('priceFromPerGuest', travelMinPricePerGuest,
>> displayedCurrency)}
>> But If I write it as follow is works:
>> messages.format('priceFromPerGuest', [travelMinPricePerGuest,
>> displayedCurrency])
>> 
>> Is this a bug ?
>> 
>> Tapestry property expression is a bit limiting, particularly in conditions
>> where you can’t have logical expression as:  test=“size > 10”
>> 
>> I know the rational is to keep property expression as simple as possible,
>> but having some logic expressed in the template is not that bad, because
>> it’s in context ans sometimes makes more sense than having everything in
>> java code.
>> 
>> Also if you work a lot with collection of objects, you have to create a
>> property for each type of element in the collections, the “var” keyword is
>> not powerful to be used in complex property expressions.
>> Exemple, this won’t work, but it would be very practical:
>> <t:loop source=“countries” value=“var:country”>
>>        ${var:country.getName(locale)} - ${getPopulation(var:country)}
>> </t:loop>
>> 
>> And if you use a generic property tempValue that you could reuse in
>> different places, it won’t work because all conduits will be based on the
>> Object Type and not Country type.
>> 
>> @Property
>> Object tempValue
>> 
>> <t:loop source=“countries” value=“var: tempValue”>
>>        ${tempValue.getName(locale)} - ${getPopulation(tempValue)}
>> </t:loop>
>> 
>> Could we find a solution to avoir creating a lot of fields for all loops ?
>> 
>> Thank you for your help,
>> 
>> Best!
>> 
>> 
>>  <http://www.dfacto.ch/ <http://www.dfacto.ch/>>       Numa Schmeder    www.dfacto.ch <http://www.dfacto.ch/>  <
>> http://www.dfacto.ch/ <http://www.dfacto.ch/>>
>> NUMA@DFACTO.CH <ma...@DFACTO.CH> <mailto:numa@dfacto.ch <ma...@dfacto.ch>>   |   M +41 79 538 30 01
>> 
>> DIGITAL STRATEGY   |   DESIGN   |   DEVELOPMENT


Re: method varargs and property expression

Posted by Chris Poulsen <ma...@nesluop.dk>.
We never really use much of the expression language, so I can't comment on
that.

This is just a comment on the last example: I'm not sure that you need a
@Property when using the "var:" prefix (if you have a backing property it
ought to be a "prop:" binding, as far as I understand)

-- 
Chris



On Wed, May 26, 2021 at 12:00 PM Numa Schmeder <nu...@dfacto.ch> wrote:

> Hello,
>
> It seems method with varargs doesn’t work with property expression.
> If I put the following property expression, I get an error: Message
> doesn’t have a public “format" method.
> ${messages.format('priceFromPerGuest', travelMinPricePerGuest,
> displayedCurrency)}
> But If I write it as follow is works:
> messages.format('priceFromPerGuest', [travelMinPricePerGuest,
> displayedCurrency])
>
> Is this a bug ?
>
> Tapestry property expression is a bit limiting, particularly in conditions
> where you can’t have logical expression as:  test=“size > 10”
>
> I know the rational is to keep property expression as simple as possible,
> but having some logic expressed in the template is not that bad, because
> it’s in context ans sometimes makes more sense than having everything in
> java code.
>
> Also if you work a lot with collection of objects, you have to create a
> property for each type of element in the collections, the “var” keyword is
> not powerful to be used in complex property expressions.
> Exemple, this won’t work, but it would be very practical:
> <t:loop source=“countries” value=“var:country”>
>         ${var:country.getName(locale)} - ${getPopulation(var:country)}
> </t:loop>
>
> And if you use a generic property tempValue that you could reuse in
> different places, it won’t work because all conduits will be based on the
> Object Type and not Country type.
>
> @Property
> Object tempValue
>
> <t:loop source=“countries” value=“var: tempValue”>
>         ${tempValue.getName(locale)} - ${getPopulation(tempValue)}
> </t:loop>
>
> Could we find a solution to avoir creating a lot of fields for all loops ?
>
> Thank you for your help,
>
> Best!
>
>
>   <http://www.dfacto.ch/>       Numa Schmeder    www.dfacto.ch  <
> http://www.dfacto.ch/>
> NUMA@DFACTO.CH <ma...@dfacto.ch>   |   M +41 79 538 30 01
>
> DIGITAL STRATEGY   |   DESIGN   |   DEVELOPMENT
>
>
>
>
>