Spray-Json: unmarshing of only a part of a Json document?

1,464 views
Skip to first unread message

Markus Jais

unread,
Nov 14, 2012, 9:18:20 AM11/14/12
to spray...@googlegroups.com
Hello,

I have a question about unmarshalling a part of a json document.
Let's assume I have the following document

{"ecosystem": { "location" : "Africa",
                          "mammals" : { "mammal" : "tiger" } ,
          "birds" : { "bird" :  "Golden Eagle", "bird" : "Harpy Eagle"}
                        }
} // sorry for formatting errors

Let's assume I have this Scala code:

case class Bird(name: String)

object BirdJsonProtocol extends DefaultJsonProtocol {
  implicit val BirdFormat = jsonFormat(Bird)
}

I would like to do something like this:

// result is the spray.http.HttpResponse I get from my future when successfully calling a REST service
val res = result.entity.as[List[Bird]]

Is there a way to tell spray to unmarshall only the "birds" section and just ignoring the rest of the JSON document?
I can easily write an JsonProtocol that contains all the stuff in this Json document but my actual document is a lot bigger
and I am only interested in a small part of it.

Cheers,

Markus

Age Mooij

unread,
Nov 14, 2012, 11:53:03 AM11/14/12
to spray...@googlegroups.com
One possible solution would be to:

- parse the JSOS string into the spray-json JsValue domain (using "…".asJson or JsonParser("…"))
- extract the part you care about using the JsValue api
- convert the JSON fragment into your case class using the standard spray-json convertTo[T] function


The SprayJsonSupport unmarshallers in spray-http are just a very thin layer over the spray-json JsonFormat and for this kind of stuff it's better to use spray-json directly.

Age


--
 
 

Johannes Rudolph

unread,
Nov 15, 2012, 4:39:24 AM11/15/12
to spray...@googlegroups.com
Hi Markus,

you could use json-lenses for this. Then your read line would look like this:

result.entity.as[JsValue].extract[Bird]('ecosystem / 'birds / *)

Here's the complete example (I fixed a few bugs in your example):

https://gist.github.com/4077644
> --
>
>



--
Johannes

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net

Age Mooij

unread,
Nov 15, 2012, 5:45:31 AM11/15/12
to spray...@googlegroups.com
That looks great!

Any plans for folding json-lenses into spray-json in the foreseeable future? The package names seem to indicate something like that.

Age

PS
The spray-json README contains a link to the javadocs and that link is currently broken (404). I keep forgetting to mention this so I'll grab this opportunity ;)
> --
>
>

Markus Jais

unread,
Nov 15, 2012, 8:15:26 AM11/15/12
to spray...@googlegroups.com
Hi Johannes,

that looks great. It works. I hope this get's integrated in spray-json. Very cool stuff.

I also need a solution that works with just spray-json at the moment and I also have to convert the whole JSON document.

Is there a way to convert the whole document with all the nested objects? I tried several different things but just can't get it running.

One solution I found was this:

But I can't find the DefaultJsonFormat trait anywhere with the latest spray-json.

This is the current JSON I have for playing (similar to the old legacy format I have to use but cannot change):

{
  "ecoSystem": "garden",
  "birds": {
    "german": "Voegel",
    "bird": [{
      "name": "Amsel",
      "color": "black"
    }, {
      "name": "Bussard",
      "color": "brown"
 }

I want to map it to  classes like this:

case class Bird(name:  String, color:  String)
case class Birds(german:  String, birds: List[Bird)
case class Ecosytem (ecoSystem: String, birds:  Birds)

If anywhere has a solution for this it would be fantastic. Maybe I am just too blind to see it.

Cheers,

Markus




Von: Johannes Rudolph <johannes...@googlemail.com>
An: spray...@googlegroups.com
Gesendet: 10:39 Donnerstag, 15.November 2012
Betreff: Re: [spray-user] Spray-Json: unmarshing of only a part of a Json document?
--




Johannes Rudolph

unread,
Nov 15, 2012, 8:28:34 AM11/15/12
to spray...@googlegroups.com
Hi Markus,

On Thu, Nov 15, 2012 at 2:15 PM, Markus Jais <marku...@yahoo.de> wrote:
> that looks great. It works. I hope this get's integrated in spray-json.

It will be integrated.

> I also have to convert the whole JSON document.
> Is there a way to convert the whole document with all the nested objects? I
> tried several different things but just can't get it running.

Ok, that's reasonable and possible. Btw. it would help if you would
post exact error messages and/or compiling code.

> But I can't find the DefaultJsonFormat trait anywhere with the latest
> spray-json.

Strange. It's hasn't moved.

I updated the example [1] to extract the complete structure. You can
clone the complete gist and run it with sbt as a starting point.

HTH

--
Johannes

[1] https://gist.github.com/4077644

Markus Jais

unread,
Nov 15, 2012, 8:53:32 AM11/15/12
to spray...@googlegroups.com

Hi,


>________________________________
> Von: Johannes Rudolph <johannes...@googlemail.com>
>An: spray...@googlegroups.com

>Gesendet: 14:28 Donnerstag, 15.November 2012


>Betreff: Re: [spray-user] Spray-Json: unmarshing of only a part of a Json document?
>

>Hi Markus,
>
>On Thu, Nov 15, 2012 at 2:15 PM, Markus Jais <marku...@yahoo.de> wrote:
>> that looks great. It works. I hope this get's integrated in spray-json.
>
>It will be integrated.

cool!


>
>> I also have to convert the whole JSON document.
>> Is there a way to convert the whole document with all the nested objects? I
>> tried several different things but just can't get it running.
>
>Ok, that's reasonable and possible. Btw. it would help if you would
>post exact error messages and/or compiling code.

Sorry, forgot that:

Here is my attempt. Don't  know how to implement the read/write methods.


object bird extends App {

  case class Bird(name: String, color: String)

  case class Birds(german: String, birds: List[Bird])
  case class Ecosystem(ecoSystem: String, birds: Birds)

  object MyJsonProtocol extends DefaultJsonProtocol {
    implicit object EcosystemJsonFormat extends RootJsonFormat[Ecosystem] {
      implicit val birdFormat = jsonFormat2(Bird)
      implicit val birdsFormat = jsonFormat2(Birds)
      implicit val ecosystemFormat = jsonFormat2(Ecosystem)

      def write(es: Ecosystem) = {
        //JsArray(JsString(es.ecoSystem), JsObject(es.birds))
        // ??? how to work with the nested objects like Birds and Bird?
      }

        def read(value: JsValue) = {
          // ????
          }
      }
    }
  }

  import MyJsonProtocol._

  val b1 = Bird("amsel", "braun")
  val b2 = Bird("Bussard", "gelb")
  val birds = Birds("vogel", List(b1, b2))
  val es = Ecosystem("garden", birds)

  val json = es.toJson   
  println(json)

}

>
>> But I can't find the DefaultJsonFormat trait anywhere with the latest
>> spray-json.
>
>Strange. It's hasn't moved.

Can't find it in the latest code on github. Yes, this is strange :-)


>
>I updated the example [1] to extract the complete structure. You can
>clone the complete gist and run it with sbt as a starting point.

Looks great but I cannot compile it in my project. I use Scala 2.10 RC2. Is this a problem?

sbt cannot download the json-lenses jar. Do I need an additional repository to add to my resolvers in the sbt file?

Markus


>
>HTH
>
>--
>Johannes
>
>[1] https://gist.github.com/4077644
>
>-----------------------------------------------
>Johannes Rudolph
>http://virtual-void.net
>

>--
>
>
>
>
>

Johannes Rudolph

unread,
Nov 15, 2012, 8:59:28 AM11/15/12
to spray...@googlegroups.com
On Thu, Nov 15, 2012 at 2:53 PM, Markus Jais <marku...@yahoo.de> wrote:
> Here is my attempt. Don't know how to implement the read/write methods.

Have you looked at the gist? You don't need that `implicit object
EcosystemJsonFormat` block and implement read/write manually. This
line:

> implicit val ecosystemFormat = jsonFormat2(Ecosystem)

already provides a `RootJsonFormat[Ecosystem]`.

>>> But I can't find the DefaultJsonFormat trait anywhere with the latest
>>> spray-json.
>>
>>Strange. It's hasn't moved.
>
> Can't find it in the latest code on github. Yes, this is strange :-)

https://github.com/spray/spray-json/blob/master/src/main/scala/spray/json/DefaultJsonProtocol.scala

>>I updated the example [1] to extract the complete structure. You can
>>clone the complete gist and run it with sbt as a starting point.
>
> Looks great but I cannot compile it in my project. I use Scala 2.10 RC2. Is this a problem?

There's no artifact for json-lenses for 2.10.0-RC2 yet, maybe that's
the problem. Otherwise it should work as before.

--
Johannes

Markus Jais

unread,
Nov 15, 2012, 9:07:56 AM11/15/12
to spray...@googlegroups.com
Hi Johannes,

thanks for the really quick answer.

I got it working now. I mixed up something while copying the gist.

All I had to change was
val ecosystem = json.as[Ecosystem]
to
val ecosystem = json.convertTo[Ecosystem]

I think "as" is part of the json-lenses project (?).

And you are of course right about the DefaultJsonProtocol.scala.
I confused it with DefaultJsonFormat (not "Protocol").

I just read the whole json-lenses docs. Really an awesome small library. I am sure I will use it in all my
projects where I need json stuff once it works with 2.10 RC2 or newer (I can't use an older Scala version at the moment).

Cheers,

Markus

----- Ursprüngliche Message -----

> CC:
> Gesendet: 14:59 Donnerstag, 15.November 2012


> Betreff: Re: [spray-user] Spray-Json: unmarshing of only a part of a Json document?
>

> --
>

Reply all
Reply to author
Forward
0 new messages