I get a problem using Scala and trying to do a renderJSON on a list
I get all contacts and then try to render the list as JSON
> var contacts = asScala[Contact].findAll
> renderJSON(contacts)
I get this exception
Execution exception (In /app/controllers/Contacts.scala around line
48)
UnsupportedOperationException occured : Expecting parameterized type,
got class scala.collection.immutable.$colon$colon. Are you missing
the use of TypeToken idiom? See
http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and...
play.exceptions.JavaExecutionException: Expecting parameterized type,
got class scala.collection.immutable.$colon$colon.
Are you missing the use of TypeToken idiom?
See http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and... at play.mvc.ActionInvoker.invoke(ActionInvoker.java:259)
at Invocation.HTTP Request(Play!)
Caused by: java.lang.UnsupportedOperationException: Expecting
parameterized type, got class scala.collection.immutable.$colon$colon.
Are you missing the use of TypeToken idiom?
See http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and... at com.google.gson.TypeInfoFactory.getActualType(TypeInfoFactory.java:
97)
at
com.google.gson.TypeInfoFactory.extractRealTypes(TypeInfoFactory.java:
116)
at com.google.gson.TypeInfoFactory.getActualType(TypeInfoFactory.java:
65)
at
com.google.gson.TypeInfoFactory.getTypeInfoForField(TypeInfoFactory.java:
54)
at
com.google.gson.ObjectNavigator.navigateClassFields(ObjectNavigator.java:
148)
at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:123)
at
com.google.gson.JsonSerializationContextDefault.serialize(JsonSerialization ContextDefault.java:
56)
at com.google.gson.Gson.toJsonTree(Gson.java:230)
at com.google.gson.Gson.toJson(Gson.java:315)
at com.google.gson.Gson.toJson(Gson.java:270)
at com.google.gson.Gson.toJson(Gson.java:250)
at play.mvc.results.RenderJson.<init>(RenderJson.java:20)
at play.mvc.Controller.renderJSON(Controller.java:280)
at play.mvc.ControllerDelegate.renderJSON(ControllerDelegate.java:58)
at controllers.Contacts$.getContacts(/app/controllers/Contacts.scala:
48)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:
374)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:
357)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:162)
... 1 more
it's work when i render only one contact
> var contacts = asScala[Contact].findAll
> renderJSON(contacts(0))
According to the gson document , you need to define a TypeToken if the object that your are serializing/deserializing is a ParameterizedType (i.e. contains at least one type parameter and may be an array) then you must use the toJson(Object, Type)<file:///E:/libary/google-gson-1.4-release/google-gson-1.4/gson-1.4-ja vadoc/com/google/gson/Gson.html#toJson(java.lang.Object, java.lang.reflect.Type)> or fromJson(String, Type)<file:///E:/libary/google-gson-1.4-release/google-gson-1.4/gson-1.4-ja vadoc/com/google/gson/Gson.html#fromJson(java.lang.String, java.lang.reflect.Type)> method.
Here is an example for serializing and deserialing a ParameterizedType picked from gson docs:
Type listType = new TypeToken<List<String>>() {}.getType(); List<String> target = new LinkedList<String>(); target.add("blah");
But it does not work properly in scala.collection.immutable.List, so you can only use array instead - it seams the array in Scala is the same as the one in Java
On Thu, Jul 15, 2010 at 11:52 PM, Vincent Buzzano <vincent.buzz...@gmail.com
> I get a problem using Scala and trying to do a renderJSON on a list
> I get all contacts and then try to render the list as JSON > > var contacts = asScala[Contact].findAll > > renderJSON(contacts)
> I get this exception
> Execution exception (In /app/controllers/Contacts.scala around line > 48) > UnsupportedOperationException occured : Expecting parameterized type, > got class scala.collection.immutable.$colon$colon. Are you missing > the use of TypeToken idiom? See
> play.exceptions.JavaExecutionException: Expecting parameterized type, > got class scala.collection.immutable.$colon$colon. > Are you missing the use of TypeToken idiom? > See > http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and... > at play.mvc.ActionInvoker.invoke(ActionInvoker.java:259) > at Invocation.HTTP Request(Play!) > Caused by: java.lang.UnsupportedOperationException: Expecting > parameterized type, got class scala.collection.immutable.$colon$colon. > Are you missing the use of TypeToken idiom? > See > http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and... > at > com.google.gson.TypeInfoFactory.getActualType(TypeInfoFactory.java: > 97) > at > com.google.gson.TypeInfoFactory.extractRealTypes(TypeInfoFactory.java: > 116) > at > com.google.gson.TypeInfoFactory.getActualType(TypeInfoFactory.java: > 65) > at > com.google.gson.TypeInfoFactory.getTypeInfoForField(TypeInfoFactory.java: > 54) > at > com.google.gson.ObjectNavigator.navigateClassFields(ObjectNavigator.java: > 148) > at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:123) > at
> com.google.gson.JsonSerializationContextDefault.serialize(JsonSerialization ContextDefault.java: > 56) > at com.google.gson.Gson.toJsonTree(Gson.java:230) > at com.google.gson.Gson.toJson(Gson.java:315) > at com.google.gson.Gson.toJson(Gson.java:270) > at com.google.gson.Gson.toJson(Gson.java:250) > at play.mvc.results.RenderJson.<init>(RenderJson.java:20) > at play.mvc.Controller.renderJSON(Controller.java:280) > at > play.mvc.ControllerDelegate.renderJSON(ControllerDelegate.java:58) > at > controllers.Contacts$.getContacts(/app/controllers/Contacts.scala: > 48) > at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java: > 374) > at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java: > 357) > at play.mvc.ActionInvoker.invoke(ActionInvoker.java:162) > ... 1 more
> it's work when i render only one contact > > var contacts = asScala[Contact].findAll > > renderJSON(contacts(0))
> Do you have any idea ?
> -- > You received this message because you are subscribed to the Google Groups > "play-framework" group. > To post to this group, send email to play-framework@googlegroups.com. > To unsubscribe from this group, send email to > play-framework+unsubscribe@googlegroups.com<play-framework%2Bunsubscribe@go oglegroups.com> > . > For more options, visit this group at > http://groups.google.com/group/play-framework?hl=en.
> UnsupportedOperationException occured : Expecting parameterized type, > got class scala.collection.immutable.$colon$colon. Are you missing > the use of TypeToken idiom?
Here's a solution to the problem using a custom serializer:
// Your action def search(query: String) = Json(MySerializer.toJson(User.find("name like ?", query)))
object MySerializer { val builder = new GsonBuilder()
builder.registerTypeAdapter(classOf[scala.collection.immutable.$colon$colon [_]], new CollectionSerializer) val gson = builder.create
On Tue, Apr 12, 2011 at 9:09 AM, Loic <loic.desco...@gmail.com> wrote: > I have this problem too, maybe we should open a bug
> -- > You received this message because you are subscribed to the Google Groups > "play-framework" group. > To post to this group, send email to play-framework@googlegroups.com. > To unsubscribe from this group, send email to > play-framework+unsubscribe@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/play-framework?hl=en.
On Wed, Apr 13, 2011 at 9:49 AM, Loic <loic.desco...@gmail.com> wrote: > There is a method for that in the play scala API, no need to use lift-json > I think.
> According to the Scala module documentation, I guess this should work > without error :
> -- > You received this message because you are subscribed to the Google Groups > "play-framework" group. > To post to this group, send email to play-framework@googlegroups.com. > To unsubscribe from this group, send email to > play-framework+unsubscribe@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/play-framework?hl=en.
> On Tue, Apr 12, 2011 at 9:09 AM, Loic <loic.desco...@gmail.com> wrote:
> > I have this problem too, maybe we should open a bug
> > --
> > You received this message because you are subscribed to the Google Groups
> > "play-framework" group.
> > To post to this group, send email to play-framework@googlegroups.com.
> > To unsubscribe from this group, send email to
> > play-framework+unsubscribe@googlegroups.com.
> > For more options, visit this group at
> >http://groups.google.com/group/play-framework?hl=en.
We really need Lift-JSON working with Play Scala as GSON won't work for most Scala specific structure. If you have a working version, please send us a pull request.
> > On Tue, Apr 12, 2011 at 9:09 AM, Loic <loic.desco...@gmail.com> wrote: > > > I have this problem too, maybe we should open a bug
> > > -- > > > You received this message because you are subscribed to the Google > Groups > > > "play-framework" group. > > > To post to this group, send email to play-framework@googlegroups.com. > > > To unsubscribe from this group, send email to > > > play-framework+unsubscribe@googlegroups.com. > > > For more options, visit this group at > > >http://groups.google.com/group/play-framework?hl=en.
> -- > You received this message because you are subscribed to the Google Groups > "play-framework" group. > To post to this group, send email to play-framework@googlegroups.com. > To unsubscribe from this group, send email to > play-framework+unsubscribe@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/play-framework?hl=en.
> We really need Lift-JSON working with Play Scala as GSON won't work for > most Scala specific structure. If you have a working version, please send us > a pull request.
> On Wed, Apr 13, 2011 at 10:23 PM, v6ak <v...@volny.cz> wrote:
>> > On Tue, Apr 12, 2011 at 9:09 AM, Loic <loic.desco...@gmail.com> wrote: >> > > I have this problem too, maybe we should open a bug
>> > > -- >> > > You received this message because you are subscribed to the Google >> Groups >> > > "play-framework" group. >> > > To post to this group, send email to play-framework@googlegroups.com. >> > > To unsubscribe from this group, send email to >> > > play-framework+unsubscribe@googlegroups.com. >> > > For more options, visit this group at >> > >http://groups.google.com/group/play-framework?hl=en.
>> -- >> You received this message because you are subscribed to the Google Groups >> "play-framework" group. >> To post to this group, send email to play-framework@googlegroups.com. >> To unsubscribe from this group, send email to >> play-framework+unsubscribe@googlegroups.com. >> For more options, visit this group at >> http://groups.google.com/group/play-framework?hl=en.
> -- > You received this message because you are subscribed to the Google Groups > "play-framework" group. > To post to this group, send email to play-framework@googlegroups.com. > To unsubscribe from this group, send email to > play-framework+unsubscribe@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/play-framework?hl=en.
In fact, I don't have integrated it well. I just have solved the issue with loading parameter names according to a dicsussion thread. The problem was probably that Lift JSON expects serialized classes to be on classpath (unless you provide a custom ParameterNameReader), but Play! uses a different classloading mechanism. (This is possibly not true in the production mode.)
I'm not sure about the right Play integration. Like any advanced (de)serializer, Lift suports some configuration. (In fact, you can handle polymorphism, of you configure it.) The configuration is described in an instance of net.liftweb.json.Formats.
* Constructor parameter vs. method: Constructor parameter seems to be a cleaner way for me.
* It is possible to use constructor overloading for convenience. So, Controller can have constructors that accepts both of variants (either net.liftweb.json.Formats or something like play.json.JsonAdapter).
* Combining availbility of constructor parameter and protected method seems to be odd for me. Parameters could be overriden in such case by a trait. A similar API design fail have been done in java.lang.Thread, which implements java.lang.Runnable. Although there is a different issue (you can accidentaly call run() instead of start()), both of these designs are crazy.
* Should Play! "defensively" force an instance of PlayParameterReader? There are some advantages and disadvantages on both sides:
* * If Play! does not force the PlayParameterReader (or PlayParameterNameReader), it can lead to some serialization issues (the result of the serialization is "{}") if the user speciffies some non-default Formats and does not choose to use PlayParameterReader.
* * If Play! forces the PlayParameterReader, it can lead to similar iussues if user uses a specific ParameterNameReader on purpose. Fortunately, it is an edge case. However, this seems to be a magic for me.
* * It is also possible to use one of these ParameterNameReader-s by default and the other as a fallback, but there is still some magic.
* * It is also possible to allow user to switch overriding ParameterNameReader off, which can be the best way.
The reason they added the configuration option to use another parameter name reader is because I asked for it so that lift-json could be used with play: http://groups.google.com/group/liftweb/browse_thread/thread/b6d5a0060... So we simply define a play ParameterNameReader that uses play's classloading mechanism. I'll do this within the scala plugin itself so that play users don't need to worry about it. I'm currently working on it, but as I mentioned in my last post I'm just waiting for them iron out a couple of problems with the serialization: http://groups.google.com/group/liftweb/browse_thread/thread/96d3bd870...
On Sat, Apr 16, 2011 at 1:49 PM, v6ak <v...@volny.cz> wrote: > In fact, I don't have integrated it well. I just have solved the issue with > loading parameter names according to a dicsussion thread. The problem was > probably that Lift JSON expects serialized classes to be on classpath > (unless you provide a custom ParameterNameReader), but Play! uses a > different classloading mechanism. (This is possibly not true in the > production mode.)
> I'm not sure about the right Play integration. Like any advanced > (de)serializer, Lift suports some configuration. (In fact, you can handle > polymorphism, of you configure it.) The configuration is described in an > instance of net.liftweb.json.Formats.
> * Constructor parameter vs. method: Constructor parameter seems to be a > cleaner way for me. > * It is possible to use constructor overloading for convenience. So, > Controller can have constructors that accepts both of variants (either > net.liftweb.json.Formats or something like play.json.JsonAdapter). > * Combining availbility of constructor parameter and protected method seems > to be odd for me. Parameters could be overriden in such case by a trait. A > similar API design fail have been done in java.lang.Thread, which implements > java.lang.Runnable. Although there is a different issue (you can accidentaly > call run() instead of start()), both of these designs are crazy. > * Should Play! "defensively" force an instance of PlayParameterReader? > There are some advantages and disadvantages on both sides: > * * If Play! does not force the PlayParameterReader (or > PlayParameterNameReader), it can lead to some serialization issues (the > result of the serialization is "{}") if the user speciffies some non-default > Formats and does not choose to use PlayParameterReader. > * * If Play! forces the PlayParameterReader, it can lead to similar iussues > if user uses a specific ParameterNameReader on purpose. Fortunately, it is > an edge case. However, this seems to be a magic for me. > * * It is also possible to use one of these ParameterNameReader-s by > default and the other as a fallback, but there is still some magic. > * * It is also possible to allow user to switch overriding > ParameterNameReader off, which can be the best way.
> What do you think about it?
> Regards > Vít Šesták 'v6ak'
> -- > You received this message because you are subscribed to the Google Groups > "play-framework" group. > To post to this group, send email to play-framework@googlegroups.com. > To unsubscribe from this group, send email to > play-framework+unsubscribe@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/play-framework?hl=en.
RI understand that Play users don't need to worry about it in simple cases. However, one may need a custom Formats (for typeHinth etc.). In such case, the behavior is a tradeoff between simplicity and magic.
Yes you're right the developer should be allowed to override the default behaviour. I will make the Play ParameterNameReader object public so that it can be re-used. In the case that the developer wants to use a completely different library, he can produce the required json as a string and pass that to Json()
On Sun, Apr 17, 2011 at 9:06 AM, v6ak <v...@volny.cz> wrote:
> RI understand that Play users don't need to worry about it in simple cases. > However, one may need a custom Formats (for typeHinth etc.). In such case, > the behavior is a tradeoff between simplicity and magic.
> Regards, > Vít Šesták 'v6ak'
> -- > You received this message because you are subscribed to the Google Groups > "play-framework" group. > To post to this group, send email to play-framework@googlegroups.com. > To unsubscribe from this group, send email to > play-framework+unsubscribe@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/play-framework?hl=en.