Re: t:grid coercing value when it shouldn't
On Sat, Jan 29, 2022 at 8:13 PM Jonathan Meijer wrote: > Thank you to both for your replies. > My pleasure to help! > After reading and rereading the documentation, I'm getting a much better > understanding of how (and how not) to use Tapestry. > Tapestry does have some concepts you need to understand well to use the framework well. > I'm trying to integrate with Cayenne without using the outdated integration > module, and so far it's going well and I figured out my way around the > coercion. Since my background is in WebObjects, I had to get used to this > completely different paradigm. > Interesting! As far as I remember, WebObjects was an inspiration for Tapestry in the beginning. > > Jonathan > > On Thu, Jan 27, 2022, 16:26 Thiago H. de Paula Figueiredo < > thiag...@gmail.com> wrote: > > > On Fri, Jan 21, 2022 at 12:56 AM Jonathan Meijer > > > wrote: > > > > > Hi, > > > > > > > Hi! > > > > > > > New Tapestry user here, started with a bootstrapped 5.7.3 and > > > experimenting. > > > > > > > Welcome to Tapestry! We just released 5.8.0, by the way. > > > > > > > Delete > > > > > > > I suggest using EventLink instead of ActionLink. Very similar, but easier > > and more elegant to use. > > > > Delete > > > > Object onDelete(...) { ... } > > > > > > > What am I doing wrong? There is really no room for error, the Blah > > class > > > is defined right there in the same class and the current row object has > > > absolutely no reason to be converted to String. > > > > > > > You passed an instance of Blah as the context of an ActionLink. This > > component needs to know how to convert Blah to a string to be put in the > > link's URL and how to do the conversion back so Tapestry can provide the > > Blah instance to be passed to the event handler method when you click the > > link. This is done by implementing the ValueEncoder instance for your > class > > then contributing it to the ValueEncoderSource service. Internally, when > a > > ValueEncoder isn't found for a given type, Tapestry tries to fallback on > > using a coercion from String to type and type to String from the > > TypeCoercer service. That's why I'm suggesting ValueEncoder and Voker is > > suggesting a coercion and both solutions are valid. :) I just prefer the > > ValueEncoder route in this case because it's specific for URLs (including > > page activation context, event handler parameters, etc) and TypeCoercer > is > > more general-purpose conversions, specially for component and page > > parameters (for example, Grid's source parameter receives a > GridDataSource > > but you can pass a List to it). > > > > Example of ValueEncoder usage: > > > > public class BlahValueEncoder implements ValueEncoder { > > public String toClient(Blah value) { > > (...) > > } > > > > public Blah toValue(String clientValue) > > { > > (...) > > } > > } > > > > In AppModule: > > > > public static void > > contributeValueEncoderSource(MappedConfiguration > > configuration) { > > configuration.add(Blah.class, new BlahValueEncoder()); // or, > with > > dependency injection: configuration.addInstance(Object.class, > > BlahValueEncoder.class); > > } > > > > > > > > > > > > Kindly help, > > > > > > Jonathan > > > > > > > > > -- > > Thiago > > > -- Thiago
Re: t:grid coercing value when it shouldn't
Thank you to both for your replies. After reading and rereading the documentation, I'm getting a much better understanding of how (and how not) to use Tapestry. I'm trying to integrate with Cayenne without using the outdated integration module, and so far it's going well and I figured out my way around the coercion. Since my background is in WebObjects, I had to get used to this completely different paradigm. Jonathan On Thu, Jan 27, 2022, 16:26 Thiago H. de Paula Figueiredo < thiag...@gmail.com> wrote: > On Fri, Jan 21, 2022 at 12:56 AM Jonathan Meijer > wrote: > > > Hi, > > > > Hi! > > > > New Tapestry user here, started with a bootstrapped 5.7.3 and > > experimenting. > > > > Welcome to Tapestry! We just released 5.8.0, by the way. > > > > Delete > > > > I suggest using EventLink instead of ActionLink. Very similar, but easier > and more elegant to use. > > Delete > > Object onDelete(...) { ... } > > > > What am I doing wrong? There is really no room for error, the Blah > class > > is defined right there in the same class and the current row object has > > absolutely no reason to be converted to String. > > > > You passed an instance of Blah as the context of an ActionLink. This > component needs to know how to convert Blah to a string to be put in the > link's URL and how to do the conversion back so Tapestry can provide the > Blah instance to be passed to the event handler method when you click the > link. This is done by implementing the ValueEncoder instance for your class > then contributing it to the ValueEncoderSource service. Internally, when a > ValueEncoder isn't found for a given type, Tapestry tries to fallback on > using a coercion from String to type and type to String from the > TypeCoercer service. That's why I'm suggesting ValueEncoder and Voker is > suggesting a coercion and both solutions are valid. :) I just prefer the > ValueEncoder route in this case because it's specific for URLs (including > page activation context, event handler parameters, etc) and TypeCoercer is > more general-purpose conversions, specially for component and page > parameters (for example, Grid's source parameter receives a GridDataSource > but you can pass a List to it). > > Example of ValueEncoder usage: > > public class BlahValueEncoder implements ValueEncoder { > public String toClient(Blah value) { > (...) > } > > public Blah toValue(String clientValue) > { > (...) > } > } > > In AppModule: > > public static void > contributeValueEncoderSource(MappedConfiguration > configuration) { > configuration.add(Blah.class, new BlahValueEncoder()); // or, with > dependency injection: configuration.addInstance(Object.class, > BlahValueEncoder.class); > } > > > > > > > Kindly help, > > > > Jonathan > > > > > -- > Thiago >
Re: t:grid coercing value when it shouldn't
On Fri, Jan 21, 2022 at 12:56 AM Jonathan Meijer wrote: > Hi, > Hi! > New Tapestry user here, started with a bootstrapped 5.7.3 and > experimenting. > Welcome to Tapestry! We just released 5.8.0, by the way. > Delete > I suggest using EventLink instead of ActionLink. Very similar, but easier and more elegant to use. Delete Object onDelete(...) { ... } > What am I doing wrong? There is really no room for error, the Blah class > is defined right there in the same class and the current row object has > absolutely no reason to be converted to String. > You passed an instance of Blah as the context of an ActionLink. This component needs to know how to convert Blah to a string to be put in the link's URL and how to do the conversion back so Tapestry can provide the Blah instance to be passed to the event handler method when you click the link. This is done by implementing the ValueEncoder instance for your class then contributing it to the ValueEncoderSource service. Internally, when a ValueEncoder isn't found for a given type, Tapestry tries to fallback on using a coercion from String to type and type to String from the TypeCoercer service. That's why I'm suggesting ValueEncoder and Voker is suggesting a coercion and both solutions are valid. :) I just prefer the ValueEncoder route in this case because it's specific for URLs (including page activation context, event handler parameters, etc) and TypeCoercer is more general-purpose conversions, specially for component and page parameters (for example, Grid's source parameter receives a GridDataSource but you can pass a List to it). Example of ValueEncoder usage: public class BlahValueEncoder implements ValueEncoder { public String toClient(Blah value) { (...) } public Blah toValue(String clientValue) { (...) } } In AppModule: public static void contributeValueEncoderSource(MappedConfiguration configuration) { configuration.add(Blah.class, new BlahValueEncoder()); // or, with dependency injection: configuration.addInstance(Object.class, BlahValueEncoder.class); } > > Kindly help, > > Jonathan > -- Thiago
Re: t:grid coercing value when it shouldn't
Hello Jonathan New Tapestry user here, started with a bootstrapped 5.7.3 and experimenting. > Welcome + enjoy! > What am I doing wrong? There is really no room for error, the Blah class > is defined right there in the same class and the current row object has > absolutely no reason to be converted to String. > Quite the opposite - the String contained in the link needs to be coerced back into a Blah object. Your code will render a useful link (e.g., http://localhost:8080/languages.delete/1). However, when the user clicks it, Tapestry will have to coerce back the context ("1", in my example) to a Blah object but doesn't know how, hence the error. The solution is to contribute a Coercion, defining how to coerce from a String value to a Blah object. Add the following to your AppModule: public static void contributeTypeCoercer(MappedConfiguration configuration) { Coercion coercion = new Coercion() { public Blah coerce(String input) { return new Blah(Integer.valueOf(input)); } }; CoercionTuple tuple = new CoercionTuple(String.class, Blah.class, coercion); configuration.add(tuple.getKey(), tuple); } Note Blah cannot be a static class within the Languages page class. Put Blah in its own package (not within pages, services, or components) and it will work. See https://tapestry.apache.org/type-coercion.html for more details on coercion. Cheers, Volker
t:grid coercing value when it shouldn't
Hi, New Tapestry user here, started with a bootstrapped 5.7.3 and experimenting. I tried to follow the grid example https://tapestry.apache.org/current/apidocs/org/apache/tapestry5/corelib/components/Grid.html quite literally, however I had issues with coercion, so I simplified to try to root out the issue. What I now have is the simplest of table with a column for Delete links. So the source is a List while the row is of course a Blah. onActionFromDelete only takes a Blah as argument. And regardless, I get org.apache.tapestry5.ioc.internal.OperationException Exception in method net.xytra.cirrus.pages.blog.admin.Languages.onActionFromDelete(net.xytra.cirrus.pages.blog.admin.Languages$Blah), parameter #1: org.apache.tapestry5.commons.util.UnknownValueException: Could not find a coercion from type java.lang.String to type net.xytra.cirrus.pages.blog.admin.Languages$Blah. Here's the grid in tml: http://tapestry.apache.org/schema/tapestry_5_4.xsd; xmlns:p="tapestry:parameter"> Available Languages Delete Add language And here's the class: public class Languages { @Property private Blah test; public List getLanguages() { List list = new ArrayList(); list.add(new Blah(1)); list.add(new Blah(2)); return list; } public void onActionFromDelete(Blah test) { System.err.println("--- onActionFromDelete: test.class="+test.getClass().getName()+" and test="+test); } public static class Blah { private int foo; public Blah(int bar) { foo = bar; } public String toString() { return Integer.toString(foo); } } } What am I doing wrong? There is really no room for error, the Blah class is defined right there in the same class and the current row object has absolutely no reason to be converted to String. Kindly help, Jonathan