body.asJson throws JsonParseException exception

721 views
Skip to first unread message

ibsdevs

unread,
Jul 9, 2014, 4:37:12 AM7/9/14
to play-fr...@googlegroups.com
Hi,

the snippet
     
      request.body.asJson match {
        case Some(json) => ..
         case None => ...
      }

throws following exception if the request body containes an invalid json object:

com.fasterxml.jackson.core.JsonParseException: Unexpected character (''' (code 39)): was expecting double-quote to start field name

Why it doesn't catch the exception and match to the None case? 

Thanks 

ibsdevs

unread,
Jul 10, 2014, 8:25:41 AM7/10/14
to play-fr...@googlegroups.com
No ideas?

Erwan Loisant

unread,
Jul 10, 2014, 10:48:52 AM7/10/14
to play-framework
Basically "asJson" will just look at the request headers. It will only
be None if the headers are not text/json or application/json.

https://github.com/playframework/playframework/blob/92078f9cc751a5c19117dede18c7ca63aca73347/framework/src/play/src/main/scala/play/api/mvc/ContentTypes.scala#L55

https://github.com/playframework/playframework/blob/92078f9cc751a5c19117dede18c7ca63aca73347/framework/src/play/src/main/scala/play/api/mvc/ContentTypes.scala#L561
> --
> You received this message because you are subscribed to the Google Groups
> "play-framework" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to play-framewor...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.



--
Erwan Loisant

Yann Simon

unread,
Jul 10, 2014, 11:16:39 AM7/10/14
to play-fr...@googlegroups.com
Are you sure the exception does not come from the Some(json) branch?

ibsdevs

unread,
Jul 14, 2014, 11:25:51 AM7/14/14
to play-fr...@googlegroups.com
Here my code:

1.    Action.async { implicit request =>
2.     request.body.asJson match {
3.        case Some(json) =>

The exception is thrown on the first line. Is it the default body parser?

Should I try catch the whole Action.async?

I am sending following invalid Json (single quotes instead of double quotes) to trigger this exception:

{
    'email' : 'a...@example.de'
}

Thanks

ibsdevs

unread,
Jul 14, 2014, 11:32:17 AM7/14/14
to play-fr...@googlegroups.com
 
And here is the stacktrace:

2014-07-14 15:30:13,235 DEBUG play - Invalid Json
com.fasterxml.jackson.core.JsonParseException: Unexpected character (''' (code 39)): was expecting double-quote to start field name
 at [Source: [B@25e8d2d5; line: 2, column: 6]
        at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1369) ~[jackson-core.jar:2.2.2]
        at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:599) ~[jackson-core.jar:2.2.2]
        at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:520) ~[jackson-core.jar:2.2.2]
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._handleUnusualFieldName(UTF8StreamJsonParser.java:1716) ~[jackson-core.jar:2.2.2]
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._parseFieldName(UTF8StreamJsonParser.java:1406) ~[jackson-core.jar:2.2.2]
        at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:668) ~[jackson-core.jar:2.2.2]
        at play.api.libs.json.JsValueDeserializer.deserialize(JsValue.scala:406) ~[play-json_2.10.jar:2.2.2]
        at play.api.libs.json.JsValueDeserializer.deserialize(JsValue.scala:358) ~[play-json_2.10.jar:2.2.2]
        at play.api.libs.json.JsValueDeserializer.deserialize(JsValue.scala:353) ~[play-json_2.10.jar:2.2.2]
        at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:2860) ~[jackson-databind.jar:2.2.2]
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1569) ~[jackson-databind.jar:2.2.2]
        at play.api.libs.json.JacksonJson$.parseJsValue(JsValue.scala:480) ~[play-json_2.10.jar:2.2.2]
        at play.api.libs.json.Json$.parse(Json.scala:27) ~[play-json_2.10.jar:2.2.2]
        at play.api.mvc.BodyParsers$parse$$anonfun$tolerantJson$1.apply(ContentTypes.scala:361) ~[play_2.10.jar:2.2.2]
        at play.api.mvc.BodyParsers$parse$$anonfun$tolerantJson$1.apply(ContentTypes.scala:357) ~[play_2.10.jar:2.2.2]
        at play.api.mvc.BodyParsers$parse$$anonfun$tolerantBodyParser$1$$anonfun$27$$anonfun$apply$77.apply(ContentTypes.scala:836) ~[play_2.10.jar:2.2.2]
        at scala.util.control.Exception$Catch$$anonfun$either$1.apply(Exception.scala:124) ~[scala-library.jar:na]
        at scala.util.control.Exception$Catch$$anonfun$either$1.apply(Exception.scala:124) ~[scala-library.jar:na]
        at scala.util.control.Exception$Catch.apply(Exception.scala:102) ~[scala-library.jar:na]
        at scala.util.control.Exception$Catch.either(Exception.scala:124) ~[scala-library.jar:na]
        at play.api.mvc.BodyParsers$parse$$anonfun$tolerantBodyParser$1$$anonfun$27.apply(ContentTypes.scala:835) [play_2.10.jar:2.2.2]
        at play.api.mvc.BodyParsers$parse$$anonfun$tolerantBodyParser$1$$anonfun$27.apply(ContentTypes.scala:834) [play_2.10.jar:2.2.2]
        at play.api.libs.iteratee.Iteratee$$anonfun$map$1.apply(Iteratee.scala:469) ~[play-iteratees_2.10.jar:2.2.2]
        at play.api.libs.iteratee.Iteratee$$anonfun$map$1.apply(Iteratee.scala:469) ~[play-iteratees_2.10.jar:2.2.2]
        at play.api.libs.iteratee.Iteratee$$anonfun$flatMap$1$$anonfun$apply$14.apply(Iteratee.scala:494) ~[play-iteratees_2.10.jar:2.2.2]
        at play.api.libs.iteratee.Iteratee$$anonfun$flatMap$1$$anonfun$apply$14.apply(Iteratee.scala:494) ~[play-iteratees_2.10.jar:2.2.2]
        at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) ~[scala-library.jar:na]
        at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) ~[scala-library.jar:na]
        at play.api.libs.iteratee.Execution$$anon$1.execute(Execution.scala:43) ~[play-iteratees_2.10.jar:2.2.2]
        at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40) ~[scala-library.jar:na]
        at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248) ~[scala-library.jar:na]
        at scala.concurrent.impl.Promise$DefaultPromise.link(Promise.scala:304) ~[scala-library.jar:na]
        at scala.concurrent.impl.Promise$DefaultPromise.linkRootOf(Promise.scala:289) ~[scala-library.jar:na]
        at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:253) ~[scala-library.jar:na]
        at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249) ~[scala-library.jar:na]
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32) ~[scala-library.jar:na]
        at play.api.libs.iteratee.Execution$$anon$2.execute(Execution.scala:70) ~[play-iteratees_2.10.jar:2.2.2]
        at scala.concurrent.impl.CallbackRunnable.executeWithValue(Promise.scala:40) ~[scala-library.jar:na]
        at scala.concurrent.impl.Promise$DefaultPromise.tryComplete(Promise.scala:248) ~[scala-library.jar:na]
        at scala.concurrent.Promise$class.complete(Promise.scala:55) ~[scala-library.jar:na]
        at scala.concurrent.impl.Promise$DefaultPromise.complete(Promise.scala:153) ~[scala-library.jar:na]
        at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235) ~[scala-library.jar:na]
        at scala.concurrent.Future$$anonfun$map$1.apply(Future.scala:235) ~[scala-library.jar:na]
        at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32) ~[scala-library.jar:na]
        at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.processBatch$1(BatchingExecutor.scala:67) ~[akka-actor_2.10.jar:2.2.0]
        at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply$mcV$sp(BatchingExecutor.scala:82) ~[akka-actor_2.10.jar:2.2.0]
        at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply(BatchingExecutor.scala:59) ~[akka-actor_2.10.jar:2.2.0]
        at akka.dispatch.BatchingExecutor$Batch$$anonfun$run$1.apply(BatchingExecutor.scala:59) ~[akka-actor_2.10.jar:2.2.0]
        at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:72) ~[scala-library.jar:na]
        at akka.dispatch.BatchingExecutor$Batch.run(BatchingExecutor.scala:58) ~[akka-actor_2.10.jar:2.2.0]
        at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:42) ~[akka-actor_2.10.jar:2.2.0]
        at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386) ~[akka-actor_2.10.jar:2.2.0]
        at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) ~[scala-library.jar:na]
        at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) ~[scala-library.jar:na]
        at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) ~[scala-library.jar:na]
        at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) ~[scala-library.jar:na]
 

Yann Simon

unread,
Jul 30, 2014, 10:52:52 AM7/30/14
to play-fr...@googlegroups.com
You're right, it may be a bug. Can you report the issue.

The API would be better if request.body.asJson delivers a Try object instead of an Option IMO.
It would let a possibility for the application to handle different error cases.


 

--

James Roper

unread,
Jul 30, 2014, 10:58:56 PM7/30/14
to play-framework
It is catching the exception, what you're seeing there is just a debug message.  This is where it catches, logs and generates a 400 error to return to the client:


You'll notice that the error is logged at debug, also evidenced be the log message you posted:

2014-07-14 15:30:13,235 DEBUG play - Invalid Json

This is so that if you're not expecting it to be invalid JSON, at least you can turn on debug logging to find out what the error was and at what character it occurred, otherwise if it just discarded it, how would you debug what the problem was?

If you don't want to see this debug message, then turn debug logging off, by setting:

logger.play=INFO

in application.conf.
--
James Roper
Software Engineer

Typesafe – Build reactive apps!
Twitter: @jroper
Reply all
Reply to author
Forward
0 new messages