EzDevInfo.com

spray-json

A lightweight, clean and simple JSON implementation in Scala

How to represent optional fields in spray-json?

I have an optional field on my requests:

case class SearchRequest(url: String, nextAt: Option[Date])

My protocol is:

object SearchRequestJsonProtocol extends DefaultJsonProtocol {
    implicit val searchRequestFormat = jsonFormat(SearchRequest, "url", "nextAt")
}

How do I mark the nextAt field optional, such that the following JSON objects will be correctly read and accepted:

{"url":"..."}
{"url":"...", "nextAt":null}
{"url":"...", "nextAt":"2012-05-30T15:23Z"}

I actually don't really care about the null case, but if you have details, it would be nice. I'm using spray-json, and was under the impression that using an Option would skip the field if it was absent on the original JSON object.


Source: (StackOverflow)

how to serialize case classes with traits with jsonspray

I understand that if I have:

case class Person(name: String)

I can use

object PersonJsonImplicits extends DefaultJsonProtocol {
  implicit val impPerson = jsonFormat1(Person)
}

and thus serialize it with:

import com.example.PersonJsonImplicits._
import spray.json._
new Person("somename").toJson

however what If i have

trait Animal
case class Person(name: String) extends Animal

and I have somewhere in my code

val animal = ???

and I need to serialize it and I want to use json spray

which serializer should I add I was hoping to have something like:

object AnimalJsonImplicits extends DefaultJsonProtocol {
  implicit val impAnimal = jsonFormat???(Animal)
}

where maybe I needed to add some matcher in order to check of what type is Animal so that if its a person I would direct it to person but found nothing... was reading https://github.com/spray/spray-json and don't understand how to do that..

so how can I serialize the set of

trait Animal
case class Person(name: String) extends Animal

with json spray?


Source: (StackOverflow)

Advertisements

Convert polymorphic case classes to json and back

I am trying to use spray-json in scala to recognize the choice between Ec2Provider and OpenstackProvider when converting to Json and back. I would like to be able to give choices in "Provider", and if those choices don't fit the ones available then it should not validate.

My attempt at this can be seen in the following code:

import spray.json._
import DefaultJsonProtocol._ 

case class Credentials(username: String, password: String)
abstract class Provider
case class Ec2Provider(endpoint: String,credentials: Credentials) extends Provider
case class OpenstackProvider(credentials: Credentials) extends Provider
case class Infrastructure(name: String, provider: Provider, availableInstanceTypes: List[String])
case class InfrastructuresList(infrastructures: List[Infrastructure])

object Infrastructures extends App with DefaultJsonProtocol {
   implicit val credFormat = jsonFormat2(Credentials)
   implicit val ec2Provider = jsonFormat2(Ec2Provider)
   implicit val novaProvider = jsonFormat1(OpenstackProvider)
   implicit val infraFormat = jsonFormat3(Infrastructure)
   implicit val infrasFormat = jsonFormat1(InfrastructuresList)

  println(
    InfrastructuresList(
      List(
        Infrastructure("test", Ec2Provider("nova", Credentials("user","pass")), List("1", "2")) 
      )
    ).toJson
  )
}

Unfortunately, it fails because it can not find a formatter for Provider abstract class.

test.scala:19: could not find implicit value for evidence parameter of type Infrastructures.JF[Provider]

Anyone have any solution for this?


Source: (StackOverflow)

spray-json and list marshalling

I'm using spray-json to marshal lists of custom objects into JSON. I have the following case class and its JsonProtocol.

case class ElementResponse(name: String, symbol: String, code: String, pkwiu: String, remarks: String, priceNetto: BigDecimal, priceBrutto: BigDecimal, vat: Int, minInStock:Int,                        maxInStock: Int)

object JollyJsonProtocol extends DefaultJsonProtocol with SprayJsonSupport  {
 implicit val elementFormat = jsonFormat10(ElementResponse)
}

When I try to put in in a route like this one:

get {
      complete {
        List(new ElementResponse(...), new ElementResponse(...))
      }
    }

I get an error saying that:

 could not find implicit value for evidence parameter of type spray.httpx.marshalling.Marshaller[List[pl.ftang.scala.polka.rest.ElementResponse]]

Perhaps you know what is the problem?

I'm using Scala 2.10.1 with spray 1.1-M7 and spray-json 1.2.5


Source: (StackOverflow)

spray-json cannot marshal Map[String,String]

I have the following route setup, but when my map is returned in the first complete block I get an error:

could not find implicit value for evidence parameter of type spray.httpx.marshalling.Marshaller[scala.collection.immutable.Map[String,String]]

import spray.routing.HttpService
import akka.actor.Actor
import spray.http.HttpRequest
import spray.routing.RequestContext
import spray.json.DefaultJsonProtocol._


class UserServiceActor extends Actor with RestUserService {
  def actorRefFactory = context
  def receive = runRoute(linkRoute)

}

trait RestUserService extends HttpService {

  val userService = new LinkUserService

  def linkRoute = 
    pathPrefix("user" / Segment) {
      userId =>
        path("link") {
          parameters('service ! "YT") {
            complete {
              Map("status"-> "OK", "auth_url" -> "http://mydomain.com/auth")
            }
          }
        }
    }
}

According to this test I should be able to convert a Map to json when DefaultJsonProtocol._ is imported but even that's failing:

val map:Map[String, String] = Map("hi"->"bye")
map.toJson

Cannot find JsonWriter or JsonFormat type class for scala.collection.mutable.Map[String,String]

Not sure what's wrong :(


Source: (StackOverflow)

spray-json for normal classes (non case) on a List

I'm finding myself in a situation in which I need to serialize into JSON a non case class.

Having a class as:

class MyClass(val name: String) {
  def SaySomething() : String = {
    return "Saying something... "
  }
}

I've created a JsonProtocol for this class:

object MyClassJsonProtocol extends DefaultJsonProtocol {

  implicit object MyClassJsonFormat extends JsonWriter[MyClass] {
  override def write(obj: MyClass): JsValue =
    JsObject(
      "name" -> JsString(obj.name)
    )
  }
}

Later on in the code I import the protocol..

val aListOfMyClasses = List[MyClass]() ... // lets assume that has items and not an empty list
import spray.json._
import MyClassJsonProtocol._

val json = aListOfMyClasses.toJson

When trying to build the project I get the following error:

Cannot find JsonWriter or JsonFormat for type class List[MyClass]

spray-json has already a format for generic list and I'm providing a format for my class, what would be the problem?

Thanks in advance...!!!


Source: (StackOverflow)

How does Scala use explicit types when resolving implicits?

I have the following code which uses spray-json to deserialise some JSON into a case class, via the parseJson method.

Depending on where the implicit JsonFormat[MyCaseClass] is defined (in-line or imported from companion object), and whether there is an explicit type provided when it is defined, the code may not compile.

I don't understand why importing the implicit from the companion object requires it to have an explicit type when it is defined, but if I put it inline, this is not the case?

Interestingly, IntelliJ correctly locates the implicit parameters (via cmd-shift-p) in all cases.

I'm using Scala 2.11.7.

Broken Code - Wildcard import from companion object, inferred type:

import SampleApp._
import spray.json._

class SampleApp {
  import MyJsonProtocol._
  val inputJson = """{"children":["a", "b", "c"]}"""
  println(s"Deserialise: ${inputJson.parseJson.convertTo[MyCaseClass]}")
}

object SampleApp {
  case class MyCaseClass(children: List[String])

  object MyJsonProtocol extends DefaultJsonProtocol {
    implicit val myCaseClassSchemaFormat = jsonFormat1(MyCaseClass)
  }
}

Results in:

Cannot find JsonReader or JsonFormat type class for SampleAppObject.MyCaseClass

Note that the same thing happens with an explicit import of the myCaseClassSchemaFormat implicit.

Working Code #1 - Wildcard import from companion object, explicit type:

Adding an explicit type to the JsonFormat in the companion object causes the code to compile:

import SampleApp._
import spray.json._

class SampleApp {
  import MyJsonProtocol._
  val inputJson = """{"children":["a", "b", "c"]}"""
  println(s"Deserialise: ${inputJson.parseJson.convertTo[MyCaseClass]}")
}

object SampleApp {
  case class MyCaseClass(children: List[String])

  object MyJsonProtocol extends DefaultJsonProtocol {
    //Explicit type added here now
    implicit val myCaseClassSchemaFormat: JsonFormat[MyCaseClass] = jsonFormat1(MyCaseClass)
  }
}

Working Code #2 - Implicits inline, inferred type:

However, putting the implicit parameters in-line where they are used, without the explicit type, also works!

import SampleApp._
import spray.json._

class SampleApp {
  import DefaultJsonProtocol._

  //Now in-line custom JsonFormat rather than imported
  implicit val myCaseClassSchemaFormat = jsonFormat1(MyCaseClass)

  val inputJson = """{"children":["a", "b", "c"]}"""
  println(s"Deserialise: ${inputJson.parseJson.convertTo[MyCaseClass]}")
}

object SampleApp {
  case class MyCaseClass(children: List[String])
}

Source: (StackOverflow)

Spray-json deserializing nested object

How to deserialize nested objects correctly in spray-json?

    import spray.json._

    case class Person(name: String)

    case class Color(n: String, r: Int, g: Int, b: Int, p: Person)

    object MyJsonProtocol extends DefaultJsonProtocol {

      implicit object ColorJsonFormat extends RootJsonFormat[Color] {
        def write(c: Color) = JsObject(
          "color-name" -> JsString(c.n),
          "Green" -> JsNumber(c.g),
          "Red" -> JsNumber(c.r),
          "Blue" -> JsNumber(c.b),
          "person-field" -> JsObject("p-name" -> JsString(c.p.name))
        )

        def read(value: JsValue) = {
          value.asJsObject.getFields("color-name", "Red", "Green", "Blue", "person-field") match {
            case Seq(JsString(name), JsNumber(red), JsNumber(green), JsNumber(blue), JsObject(person)) =>
              Color(name, red.toInt, green.toInt, blue.toInt, null) //gotta replace null with correct deserializer
            case _ => throw new DeserializationException("Color expected")
          }
        }
      }

    }

    import MyJsonProtocol._

    val jsValue = Color("CadetBlue", 95, 158, 160, Person("guest")).toJson

    jsValue.prettyPrint

    val color = jsValue.convertTo[Color] //person is missing of course

On a side-note, how to spray-json help serializing to a map of fields (with nested map for nested objects)?


Source: (StackOverflow)

How to unmarshal POST params and JSON body in a single route?

I have this route:

val routes =
    pathPrefix("api") {
      path("ElevationService" / DoubleNumber / DoubleNumber) { (long, lat) =>
        post {
          requestContext =>
            println(long, lat)
        }
      }
    }

This works nicely, I can call my ElevationService as:

http://localhost:8080/api/ElevationService/39/80

The problem is, I also want to parse the body sent to me in the request as JSON. It looks as follows:

{
  "first": "test",
  "second": 0.50
}

I've managed to get it to work in a separate route following the documentation on the entity directive:

path("test") {
   import scrive.actors.ScriveJsonProtocol
   import spray.httpx.SprayJsonSupport._
   post {
      entity(as[ScriveRequest]) { scrive =>
        complete(scrive)
      }
   }
}

But I don't know how to merge these two routes into one. Since they're wrapped in functions, I can't call the params long, lat from within the entity function, they doesn't exist in that scope I suppose. The same goes or the other way around.

I want to be able to access both my params and my POST body, and then call a service passing all the data:

val elevationService = actorRefFactory.actorOf(Props(new ElevationService(requestContext)))
elevationService ! ElevationService.Process(long, lat, bodyParams)

Source: (StackOverflow)

Get Json Object using spray.json

I'm using spray and I need to return a json object through a method.

val route = 

path("all-modules") {
        get {
          respondWithMediaType(`text/html`) {
            complete( configViewer.findAllModules.toString)
          }
        }
      }

This prints ConfigResults(S1000,Success,List(testDataTypes, mandate, sdp))

But I need get this as the json object. how can I do it?

I tried in this way

 val route =

    path("all-modules") {
      get {
        respondWithMediaType(`application/json`) {
          complete{
            configViewer.findAllModules
          }
        }
      }
    }

It gives an compilation error could not find implicit value for parameter marshaller: spray.httpx.marshalling.ToResponseMarshaller


Source: (StackOverflow)

Can't convert unicode symbols to cyrillic

I have a bunch of documents persisted in Apache Lucene with some names in russian, and when I'm trying to print them out it looks like this "\u0410\u0441\u043f\u0430\u0440", but not in cyrillic symbols. The project is in Scala. I've tried to fix this with Apache Commons unescapeJava method, but it didn't help. Are there any other options?

Updated: Project is writen with Spray framework and returns json like this.

{
  "id" : 0,
  "name" : "\u0410\u0441\u043f\u0430\u0440"
}

Source: (StackOverflow)

Serialize Map[String, Any] with spray json

How do I serialize Map[String, Any] with spray-json? I try

val data = Map("name" -> "John", "age" -> 42)
import spray.json._
import DefaultJsonProtocol._
data.toJson

It says Cannot find JsonWriter or JsonFormat type class for scala.collection.immutable.Map[String,Any].


Source: (StackOverflow)

What is a good way to handle default values with spray-json

In some cases default values make more sense than optionals in case classes:

case class Car(numberOfWheels:Int = 4, color:String)

case class Car(numbeOfWheels:Option[Int], color:String) //silly

In the first case I'd expect to be able to easily convert the following json to an instance:

{"color":"red"}

But with a standard jsonFormat2(Car), spray-json complains about missing value for numberOfWheels.

How do I work around this most cleanly?


Source: (StackOverflow)

Spray-Json: How to parse a Json Array?

I'm new to the Spray-Json API and I'm trying to parse a Json response from the Docker REST API.

There is a clean example of the usage of Spray-Json to parse this Google Map Json response :

{
   "results" : [
      {
         "elevation" : 8815.7158203125,
         "location" : {
            "lat" : 27.988056,
            "lng" : 86.92527800000001
         },
         "resolution" : 152.7032318115234
      }
   ],
   "status" : "OK"
}

In the above example the outermost level is an Object. However, I need to directly parse a Json response whose outermost level is an Array composed of containers information as shown below :

[
     {
       "Id": "8dfafdbc3a40",
       "Image": "base:latest",
       "Command": "echo 1",
       "Created": 1367854155,
       "Status": "Exit 0",
       "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}],
       "SizeRw":12288,
       "SizeRootFs":0
     },
     { ... },
     { ... }
]

Here is a code that I adapted from the Google map example :

package main

import ...

case class Container(id: String, image: String, command: String, created: Long, status: String, ports: List[Port], sizeRW: Long, sizeRootFs: Long)
case class Port(privatePort: Long, publicPort: Long, portType: String)
case class DockerApiResult[T](results: List[T])

object ContainerListJsonProtocol extends DefaultJsonProtocol {
  implicit val portFormat = jsonFormat3(Port)
  implicit val containerFormat = jsonFormat8(Container)
  implicit def dockerApiResultFormat[T :JsonFormat] = jsonFormat1(DockerApiResult.apply[T])
}

object Main extends App {

  implicit val system = ActorSystem("simple-spray-client")
  import system.dispatcher // execution context for futures below
  val log = Logging(system, getClass)

  log.info("Requesting containers info...")

  import ContainerListJsonProtocol._
  import SprayJsonSupport._
  val pipeline = sendReceive ~> unmarshal[DockerApiResult[Container]]

  val responseFuture = pipeline {
    Get("http://<ip-address>:4243/containers/json")
  }

  responseFuture onComplete {
    case Success(DockerApiResult(Container(_,_,_,_,_,_,_,_) :: _)) =>
      log.info("Id of the found image: {} ")
      shutdown()

    case Success(somethingUnexpected) =>
      log.warning("The Docker API call was successful but returned something unexpected: '{}'.", somethingUnexpected)
      shutdown()

    case Failure(error) =>
      log.error(error, "Couldn't get containers information")
      shutdown()
  }

  def shutdown(): Unit = {
    IO(Http).ask(Http.CloseAll)(1.second).await
    system.shutdown()
  }
}

And below is the exception I get (Object expected) :

spray.httpx.PipelineException: MalformedContent(Object expected,Some(spray.json.DeserializationException: Object expected))

I certainly miss something obvious but How to parse a Json Array using Spray-Json?

Also, is there a simple way to do this without having to deal with custom JsonFormat or RootJsonFormat?


Source: (StackOverflow)

Spray won't convert my case class to json and expect a spray.httpx.marshalling.ToResponseMarshallable

I'm trying to reprocude this or this, but I keep getting an error I am not able to fix...

First of all, here are my dependencies:

compile 'io.spray:spray-can_2.11:1.3.1'
compile 'io.spray:spray-routing_2.11:1.3.1',
compile 'io.spray:spray-json_2.11:1.2.6'

Now what I'm trying to do is:

class WHttpService extends Actor with HttpService with ActorLogging {

  implicit def actorRefFactory = context

  def receive = runRoute(route)

  lazy val route = logRequest(showReq _) {
    // Way too much imports but I tried all I could find
    import spray.json._
    import DefaultJsonProtocol._
    import MasterJsonProtocol._
    import spray.httpx.SprayJsonSupport._
    path("server" / Segment / DoubleNumber / DoubleNumber) { (login, first, second) =>
      get {
          complete {
            Answer(1, "test")
          }
      }
    }
  }

  private def showReq(req : HttpRequest) = LogEntry(req.uri, InfoLevel)
}

With:

case object MasterJsonProtocol extends DefaultJsonProtocol with SprayJsonSupport {
  import spray.json._

  case class Answer(code: Int, content: String)
  implicit val anwserFormat: JsonFormat[Answer] = jsonFormat2(Answer)
}

Now I get this error:

Error:(42, 19) type mismatch;
 found   : MasterJsonProtocol.Answer
 required: spray.httpx.marshalling.ToResponseMarshallable
            Answer(1, "test")
                  ^

I tried a lot of things but can't manage to make it works. I tried with

Answer(1, "test").toJson
Answer(1, "test").toJson.asJsObject

Finally what I did was

complete {
    Answer(1, "test").toJson.compactPrint
}

This works but it is sent to the client as Content-Type: text/plain when I need application/json.

Anyone see what the problem is here?

Edit: I added a sample project on github https://github.com/ydemartino/spray-test


Source: (StackOverflow)