case class Inner(foo: String, bar: Int)case class Outer(hello: String, world: Inner)object Application extends Controller {
def index = Action {
Logger.info("--------")val o = Outer("adam", Inner("eve", 4))Logger.info(o.toString)val oJson = com.codahale.jerkson.Json.generate(o)Logger.info(oJson)val o2 = com.codahale.jerkson.Json.parse[Outer](oJson)Logger.info(o2.toString)val o2Json = com.codahale.jerkson.Json.generate(o2)Logger.info(o2Json)Logger.info("--------")Ok("ok")
}}
2012-08-08 13:28:13,293 INFO application - --------2012-08-08 13:28:13,295 INFO application - Outer(adam,Inner(eve,4))2012-08-08 13:28:13,297 INFO application - {"hello":"adam","world":{"foo":"eve","bar":4}}2012-08-08 13:28:13,326 ERROR application -! @6ba4i1pig - Internal server error, for request [GET /] ->play.core.ActionInvoker$$anonfun$receive$1$$anon$1: Execution exception [[ParsingException: Unable to find a case accessor for controllers.Outer]]at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:134) [play_2.9.1.jar:2.0.2]at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:115) [play_2.9.1.jar:2.0.2]at akka.actor.Actor$class.apply(Actor.scala:318) [akka-actor.jar:2.0.2]at play.core.ActionInvoker.apply(Invoker.scala:113) [play_2.9.1.jar:2.0.2]at akka.actor.ActorCell.invoke(ActorCell.scala:626) [akka-actor.jar:2.0.2]at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:197) [akka-actor.jar:2.0.2]at akka.dispatch.Mailbox.run(Mailbox.scala:179) [akka-actor.jar:2.0.2]at akka.dispatch.ForkJoinExecutorConfigurator$MailboxExecutionTask.exec(AbstractDispatcher.scala:516) [akka-actor.jar:2.0.2]at akka.jsr166y.ForkJoinTask.doExec(ForkJoinTask.java:259) [akka-actor.jar:2.0.2]at akka.jsr166y.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975) [akka-actor.jar:2.0.2]at akka.jsr166y.ForkJoinPool.runWorker(ForkJoinPool.java:1479) [akka-actor.jar:2.0.2]at akka.jsr166y.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104) [akka-actor.jar:2.0.2]Caused by: com.codahale.jerkson.ParsingException: Unable to find a case accessor for controllers.Outerat com.codahale.jerkson.ParsingException$.apply(ParsingException.scala:17) ~[jerkson_2.9.1.jar:na]at com.codahale.jerkson.Parser$class.parse(Parser.scala:86) ~[jerkson_2.9.1.jar:na]at com.codahale.jerkson.Json$.parse(Json.scala:6) ~[jerkson_2.9.1.jar:na]at com.codahale.jerkson.Parser$class.parse(Parser.scala:14) ~[jerkson_2.9.1.jar:na]at com.codahale.jerkson.Json$.parse(Json.scala:6) ~[jerkson_2.9.1.jar:na]at controllers.Application$$anonfun$index$1.apply(Application.scala:24) ~[classes/:2.0.2]at controllers.Application$$anonfun$index$1.apply(Application.scala:18) ~[classes/:2.0.2]at play.api.mvc.Action$$anonfun$apply$4.apply(Action.scala:204) ~[play_2.9.1.jar:2.0.2]at play.api.mvc.Action$$anonfun$apply$4.apply(Action.scala:204) ~[play_2.9.1.jar:2.0.2]at play.api.mvc.Action$$anon$1.apply(Action.scala:170) ~[play_2.9.1.jar:2.0.2]at play.core.ActionInvoker$$anonfun$receive$1$$anonfun$6.apply(Invoker.scala:126) ~[play_2.9.1.jar:2.0.2]at play.core.ActionInvoker$$anonfun$receive$1$$anonfun$6.apply(Invoker.scala:126) ~[play_2.9.1.jar:2.0.2]at play.utils.Threads$.withContextClassLoader(Threads.scala:17) ~[play_2.9.1.jar:2.0.2]at play.core.ActionInvoker$$anonfun$receive$1.apply(Invoker.scala:125) [play_2.9.1.jar:2.0.2]... 11 common frames omittedCaused by: org.codehaus.jackson.map.JsonMappingException: Unable to find a case accessor for controllers.Outerat com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$4.apply(CaseClassDeserializer.scala:39) ~[jerkson_2.9.1.jar:na]at com.codahale.jerkson.deser.CaseClassDeserializer$$anonfun$4.apply(CaseClassDeserializer.scala:39) ~[jerkson_2.9.1.jar:na]at scala.Option.getOrElse(Option.scala:108) ~[scala-library.jar:0.11.3]at com.codahale.jerkson.deser.CaseClassDeserializer.<init>(CaseClassDeserializer.scala:39) ~[jerkson_2.9.1.jar:na]at com.codahale.jerkson.deser.ScalaDeserializers.findBeanDeserializer(ScalaDeserializers.scala:94) ~[jerkson_2.9.1.jar:na]at org.codehaus.jackson.map.deser.BeanDeserializerFactory._findCustomBeanDeserializer(BeanDeserializerFactory.java:482) ~[jackson-mapper-asl.jar:1.9.7]at org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:599) ~[jackson-mapper-asl.jar:1.9.7]at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:401)~[jackson-mapper-asl.jar:1.9.7]at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:310) ~[jackson-mapper-asl.jar:1.9.7]at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:290) ~[jackson-mapper-asl.jar:1.9.7]at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:159) ~[jackson-mapper-asl.jar:1.9.7]at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:180) ~[jackson-mapper-asl.jar:1.9.7]at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2829) ~[jackson-mapper-asl.jar:1.9.7]at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2699) ~[jackson-mapper-asl.jar:1.9.7]at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1315) ~[jackson-mapper-asl.jar:1.9.7]at com.codahale.jerkson.Parser$class.parse(Parser.scala:83) ~[jerkson_2.9.1.jar:na]... 23 common frames omitted
It seems to be an interaction issue between play and jerkson. On the first load in dev mode (from a fresh start) it works fine. If there is then a recompilation involving the nested classes, then it barfs on subsequent loads.
I suspect this is because the classes are effectively refreshed / updated, but jerkson keeps a static cache of the JavaTypes (see https://github.com/codahale/jerkson/blob/master/src/main/scala/com/codahale/jerkson/Types.scala#L9 ) and then presumably the matching done around https://github.com/codahale/jerkson/blob/master/src/main/scala/com/codahale/jerkson/deser/CaseClassDeserializer.scala#L21 fails, but I'm not sure.
If that is the case, then a potential fix could be to clear the Jerkson Types.cachedTypes on each reload in development. However, Types is private[jerkson] and Types.cachedTypes is private, so this is a little tricky to do.
Haven't found a workaround - right now I have to restart the dev server on each change to pretty much any part of the code. :(
This is biting me to, but just with sbt, not using play.I wrote some code to do what you described:val typesClass = Types.getClassval module = typesClass.getField("MODULE$").get(null)val cachedTypesField = module.getClass.getDeclaredField("cachedTypes")cachedTypesField.setAccessible(true)val cachedTypes = cachedTypesField.get(module).asInstanceOf[scala.collection.mutable.ConcurrentMap[_, _]]cachedTypes.clear()...but that didn't solve the issue.
Did you ever resolve it?
Can you share a bit more info on this? I’m currently writing a restful API which will be sitting on top of json, and I find myself wondering what the best way of validating the json is. the way Play does forms is rather elegant, so I was hoping something similar existed for json.
It sounds like your recent development is the closest thing there is?
Take care,
Sina
Website: www.SinaBahram.com
Twitter: @SinaBahram
--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/ijZGwzexPcQJ.
To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.