Skip to content

Instantly share code, notes, and snippets.

@loicknuchel
Created May 23, 2017 16:37
Show Gist options
  • Select an option

  • Save loicknuchel/df25679afaf202420e02c8fdafc06682 to your computer and use it in GitHub Desktop.

Select an option

Save loicknuchel/df25679afaf202420e02c8fdafc06682 to your computer and use it in GitHub Desktop.
Decoding json

I've got a JSON with a list of events :

[
  {"id":"1","kind":"start"},
  {"id":"2","kind":"start"},
  {"id":"1","kind":"stop"},
  {"id":"4","kind":"start"},
  {"id":"4","kind":"stop"}
]

I encoded them as an ADT :

sealed trait Event {
  val kind: String
}
case class Start(id: String) extends Event {
  val kind = "start"
}
case class Stop(id: String) extends Event {
  val kind = "stop"
}

How to decode them ?

I tried with json4s :

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.scalatest.{FunSpec, Matchers}
import org.json4s.DefaultFormats

sealed trait Event {
  val kind: String
}
case class Start(id: String) extends Event {
  val kind = "start"
}
case class Stop(id: String) extends Event {
  val kind = "stop"
}

class Main extends FunSpec with Matchers {
  it("json4s") {
    implicit val formats = DefaultFormats
    def decode(json: String): List[Event] = parse(json).extract[List[Event]]
    val json =
      """[
        |  {"id":"1","kind":"start"},
        |  {"id":"2","kind":"start"},
        |  {"id":"1","kind":"stop"},
        |  {"id":"4","kind":"start"},
        |  {"id":"4","kind":"stop"}
        |]
      """.stripMargin
    println("result: "+decode(json))

    true shouldBe true
  }
}

But I got :

No constructor for type Event, JObject(List((id,JString(1)), (kind,JString(start))))
org.json4s.package$MappingException: No constructor for type Event, JObject(List((id,JString(1)), (kind,JString(start))))

Any ideas ?

@loicknuchel
Copy link
Copy Markdown
Author

So, the solution I found (thanks Loïc Descotte) was using play-json with play-json-derived-codecs

Here is my final code :

import julienrf.json.derived
import org.scalatest.{FunSpec, Matchers}
import play.api.libs.json.{Json, Reads, __}

sealed trait Event
case class Start(id: String, kind: String) extends Event
case class Payload(name: String)
case class Stop(id: String, kind: String, payload: Payload) extends Event

class Test extends FunSpec with Matchers {
  implicit val formatPayload: Reads[Payload] = Json.format[Payload]
  implicit val formatEvent: Reads[Event] = derived.flat.reads((__ \ "kind").read[String])

  it("play-json") {
    val events = Json.parse(
      """[
        |  {"id":"1","kind":"Start"},
        |  {"id":"2","kind":"Start"},
        |  {"id":"1","kind":"Stop","payload":{"name":"toto"}},
        |  {"id":"4","kind":"Start"},
        |  {"id":"4","kind":"Stop","payload":{"name":"tata"}}
        |]
      """.stripMargin).as[List[Event]]
    println("events: "+events)
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment