Local usage of Json4s with entity in directive - parsing error

428 views
Skip to first unread message

Bruno Freschi

unread,
Apr 23, 2014, 9:02:20 AM4/23/14
to spray...@googlegroups.com
Hi

Sorry for the basic question, as I am a spray.io beginner and did not find any solutions posted so far regarding my issue. I am using Version 1.3.1 with Scala 2.10.4.

In my project I use spray.io to return json data to a web application (yui3 based) from various sources like cloud services and database services that already return json data (so no need to parse or convert). So in these cases I am just forwarding the JSON data with respondWithMediaType(`application/json`). This all works fine so far.

As a next step in my project I want to provide a service to the web application based on an HTTP POST request and JSON data.
In a first attempt I used Json4s with Json4sSupport with a case class. Unfortunately this approach breaks my spray.io application as it parses and modifies all strings I return in a complete directive including the JSON data I am returning (with the effect that all " are turned into \"). So the problem is similar to this post: https://groups.google.com/forum/#!searchin/spray-user/json4s/spray-user/wdcaLvNVj0A/x3O27wmTAIkJ.

To solve my problem I am using Json4s locally in my directive where I actually need it, so my other directives json data is not affected when returned with complete.
My first attempt to use Json4s locally is like this:

import org.json4s.Formats
import org.json4s.DefaultFormats
import org.json4s.JsonAST.JObject

/* We need an implicit formatter to be mixed in to our trait to be used locally in a directive */
object Json4sProtocol extends Json4sSupport {
  implicit def json4sFormats: Formats = DefaultFormats
}
.
.
.
    path("delperson") {
       post {
       import Json4sProtocol._
        entity(as[JObject]) { adrObject =>
          complete {
            val address = adrObject.extract[TTAddress]
            address.firstname + ' ' + address.famname
          }
        }
      }
    }

I get the following error returned as a string to the web application:
The request content was malformed: unknown token j Near: js

This is the HTTP Request that is sent from the web application:

HttpRequest(POST,http://localhost:9090/delperson,List(Cache-Control: no-cache, Pragma: no-cache, Connection: keep-alive, Content-Length: 419, Referer: http://localhost:9090/, Content-Type: application/json; charset=UTF-8, X-Requested-With: XMLHttpRequest, Accept-Encoding: gzip, deflate, Accept-Language: en-US, en, User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0, Host: localhost:9090),HttpEntity(application/json; charset=UTF-8,json=%7B%22famname%22%3A%22Indonesian1%22%2C%22maidenname%22%3A%22M%C3%BCller%22%2C%22firstname%22%3A%22Maku%22%2C%22phone%22%3A%22061%22%2C%22dnc%22%3Atrue%2C%22orgtype%22%3A%22person%22%2C%22langname%22%3A%22Indonesian%22%2C%22street%22%3A%22Erlenstrasse%22%2C%22streetnum%22%3A%2259%22%2C%22postcode%22%3A%224058%22%2C%22city%22%3A%22Basel%22%2C%22canton%22%3A%22Basel-Stadt%22%2C%22country%22%3A%22Switzerland%22%7D),HTTP/1.1)

I am not sure where the error is, as the Request seems to be well formed. Am I missing something regarding how I obtain the entity (internal parsing/unmarshalling)?

Thank you for any help and king regards

Bruno

Bruno Freschi

unread,
Apr 23, 2014, 10:24:39 AM4/23/14
to spray...@googlegroups.com
With further modification of removing json to contain the JSON string and sending the JSON as array, the JSON data is now being parsed. But I now run into the following error:
The request content was malformed: Do not know how to convert JArray(List(JObject(List((famname,JString(Indonesian1)), (maidenname,JString(Müller)), (firstname,JString(Maku)), (phone,JString(061)), (dnc,JBool(true)), (orgtype,JString(person)), (langname,JString(Indonesian)), (street,JString(Erlenstrasse)), (streetnum,JString(59)), (postcode,JString(4058)), (city,JString(Basel)), (canton,JString(Basel-Stadt)), (country,JString(Switzerland)))))) into class org.json4s.JsonAST$JObject

If I am sending the JSON data not as an Array I get the following error:
a.a.RepointableActorRef - Error during processing of request HttpRequest(POST,http://localhost:9090/delperson,List(Cache-Control: no-cache, Pragma: no-cache, Connection: keep-alive, Content-Length: 256, Referer: http://localhost:9090/, Content-Type: application/json; charset=UTF-8, X-Requested-With: XMLHttpRequest, Accept-Encoding: gzip, deflate, Accept-Language: en-US, en, User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0, Host: localhost:9090),HttpEntity(application/json; charset=UTF-8,{"famname":"Indonesian1","maidenname":"Müller","firstname":"Maku","phone":"061","dnc":true,"orgtype":"person","langname":"Indonesian","street":"Erlenstrasse","streetnum":"59","postcode":"4058","city":"Basel","canton":"Basel-Stadt","country":"Switzerland"}),HTTP/1.1)
ttapp org.json4s.package$MappingException: unknown error

Marek Żebrowski

unread,
Apr 23, 2014, 10:39:04 AM4/23/14
to spray...@googlegroups.com
Hi,
 try this
path("delperson") {
       post {
       import Json4sProtocol._
        entity(as[JValue]) { adrObject =>
          complete {
            val address = adrObject.extract[TTAddress]
            address.firstname + ' ' + address.famname
          }
        } 
      }
    }

or extract straight to TTAddress

path("delperson") {
       post {
       import Json4sProtocol._
        entity(as[TTAddress]) { address =>
          complete {
            address.firstname + ' ' + address.famname
          }
        } 
      }
    }

Marek Żebrowski

unread,
Apr 23, 2014, 10:40:59 AM4/23/14
to spray...@googlegroups.com
Explanation:
You are trying to extract JObject, but got JArray.
JValue is superclass of both JArray and JObject - see json4s guide

Bruno Freschi

unread,
Apr 23, 2014, 11:16:26 AM4/23/14
to spray...@googlegroups.com
Hi Marek

Thank you for your solution! The following one works perfectly and I also do not need to send the JSON as an array anymore:

path("delperson") {
       post {
       import Json4sProtocol._
        entity(as[TTAddress]) { address =>
          complete {
            address.firstname + ' ' + address.famname
          }
        } 
      }
    }

Kind Regards
Bruno

Bruno Freschi

unread,
Apr 23, 2014, 11:19:30 AM4/23/14
to spray...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages