Play Framework JSON Format for Case Objects
Asked Answered
W

2

10

I have a set of case objects that inherits from a trait as below:

  sealed trait UserRole
  case object SuperAdmin extends UserRole
  case object Admin extends UserRole
  case object User extends UserRole

I want to serialize this as JSON and I just used the Format mechanism:

implicit val userRoleFormat: Format[UserRole] = Json.format[UserRole]

But unfortunately, the compiler is not happy and it says:

No unapply or unapplySeq function found

What is wrong in my case objects?

Weir answered 27/1, 2017 at 14:54 Comment(0)
H
5

Another option is to override def toString like this:

File: Status.scala

    package models

    trait Status
    case object Active extends Status {
      override def toString: String = this.productPrefix
    }
    case object InActive extends Status {
      override def toString: String = this.productPrefix
    }

this.productPrefix will give you case object name

File: Answer.scala

package models

import play.api.libs.json._

case class Answer(
    id: Int,
    label: String,
    status: Status
) {
  implicit val answerWrites = new Writes[Answer] {
    def writes(answer: Answer): JsObject = Json.obj(
      "id" -> answer.id,
      "label" -> answer.label,
      "status" -> answer.status.toString
    )
  }
  def toJson = {
    Json.toJson(this)
  }
}

File: Controller.scala

import models._
val jsonAnswer = Answer(1, "Blue", Active).toJson
println(jsonAnswer)

you get:

{"id":1,"label":"Blue","status":"Active"}

Hope this helps!

Hermaphrodite answered 22/11, 2018 at 18:57 Comment(0)
W
11

Ok I figured out what has to be done!

Here it is:

  implicit object UserRoleWrites extends Writes[UserRole] {
    def writes(role: UserRole) = role match {
      case Admin => Json.toJson("Admin")
      case SuperAdmin => Json.toJson("SuperAdmin")
      case User => Json.toJson("User")
    }
  }
Weir answered 27/1, 2017 at 14:57 Comment(2)
The point is not about case object, but about sealed trait/family which is not supported by macro in the latest release, but coming in the next one: github.com/playframework/play-json/pull/16Periodical
That pull request solves the issue for case classes but not for case objectsEnterpriser
H
5

Another option is to override def toString like this:

File: Status.scala

    package models

    trait Status
    case object Active extends Status {
      override def toString: String = this.productPrefix
    }
    case object InActive extends Status {
      override def toString: String = this.productPrefix
    }

this.productPrefix will give you case object name

File: Answer.scala

package models

import play.api.libs.json._

case class Answer(
    id: Int,
    label: String,
    status: Status
) {
  implicit val answerWrites = new Writes[Answer] {
    def writes(answer: Answer): JsObject = Json.obj(
      "id" -> answer.id,
      "label" -> answer.label,
      "status" -> answer.status.toString
    )
  }
  def toJson = {
    Json.toJson(this)
  }
}

File: Controller.scala

import models._
val jsonAnswer = Answer(1, "Blue", Active).toJson
println(jsonAnswer)

you get:

{"id":1,"label":"Blue","status":"Active"}

Hope this helps!

Hermaphrodite answered 22/11, 2018 at 18:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.