CanardMoussant CanardMoussant - 1 year ago 72
Scala Question

Scala Graph JSON with Play Framework

I am trying to pass in a POST request to a REST API developped with Play! (2.5) an object that I would like to use a Scala Graph (from the graph-core dependency).
It looks like the graph already has JSON serialization/deserialization methods based on lift-json, but I am not sure how to "plug" that into Play Json library. Until now I was using implicit converters (with Reads/Writes methods) but I would like to avoid having to write my own methods for the graph part since it is already part of the library itself.

For instance, let's say I have this code:

import java.util.UUID
import scalax.collection.Graph

case class Task(
id: UUID,
status: String)

case class Stuff(
id: UUID = UUID.randomUUID(),
name: String,
tasks: Option[Graph[Task, DiEdge]])

implicit val stuffWrites: Writes[Stuff] = (
(JsPath \ "id").write[UUID] and
(JsPath \ "name").write[String]

implicit val stuffReads: Reads[Stuff] = (
(JsPath \ "id").read[UUID] and
(JsPath \ "name").read[String]
)(Stuff.apply _)

implicit val taskWrite: Writes[Task] = (
(JsPath \ "id").write[UUID] and
(JsPath \ "status").write[String]

implicit val taskReads: Reads[Task] = (
(JsPath \ "id").read[UUID] and
(JsPath \ "status").read[String]
)(Task.apply _)

I miss the part to serialize the graph and the parenting. Should I rewrite everything from scratch, or can I rely on methods toJson/fromJson from ?

Answer Source

Since I struggled a bit to get this working, I thought I would share the code:

class UUIDSerializer extends Serializer[UUID] {
  private val UUIDClass = classOf[UUID]

  def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), UUID] = {
    case (TypeInfo(UUIDClass, _), json) => json match {
      case JString(id) => UUID.fromString(id)
      case x => throw new MappingException("Can't convert " + x + " to UUID")
  def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
    case x: UUID => JString(x.toString)

val extraSerializers = new UUIDSerializer :: Nil
implicit val formats = Serialization.formats(NoTypeHints) ++ extraSerializers

val taskDescriptor = new NodeDescriptor[Task](typeId = "Tasks", customSerializers=extraSerializers) {
  def id(node: Any) = node match {
    case Task(id, _) => id.toString

val quickJson = new Descriptor[Task](
    defaultNodeDescriptor = taskDescriptor,
    defaultEdgeDescriptor = Di.descriptor[Task]()
implicit val tasksWrites = new Writes[Graph[Task, DiEdge]] {
  def writes(graph: Graph[Task, DiEdge]): JsValue = {
    val json = graph.toJson(quickJson)

implicit val tasksReads = new Reads[Graph[Task, DiEdge]] {
  def reads(json: JsValue): JsResult[Graph[Task, DiEdge]] = {
    try {
      val graph = Graph.fromJson[Task, DiEdge](json.toString, quickJson)
    catch {
      case e: Exception =>

implicit def stuffModelFormat = Jsonx.formatCaseClass[Stuff]