Skip to content

Instantly share code, notes, and snippets.

@mikesname
Last active December 15, 2021 23:10
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mikesname/5237809 to your computer and use it in GitHub Desktop.
Save mikesname/5237809 to your computer and use it in GitHub Desktop.
Example Play JSON Enum reading/writing
package enumtest
import play.api.libs.json._
object EnumUtils {
def enumReads[E <: Enumeration](enum: E): Reads[E#Value] = new Reads[E#Value] {
def reads(json: JsValue): JsResult[E#Value] = json match {
case JsString(s) => {
try {
JsSuccess(enum.withName(s))
} catch {
case _: NoSuchElementException => JsError(s"Enumeration expected of type: '${enum.getClass}', but it does not appear to contain the value: '$s'")
}
}
case _ => JsError("String value expected")
}
}
implicit def enumWrites[E <: Enumeration]: Writes[E#Value] = new Writes[E#Value] {
def writes(v: E#Value): JsValue = JsString(v.toString)
}
implicit def enumFormat[E <: Enumeration](enum: E): Format[E#Value] = {
Format(EnumReader.enumReads(enum), EnumWriter.enumWrites)
}
}
// Now let's test it
object EnumTest {
object EnumA extends Enumeration {
type EnumA = Value
val VAL1, VAL2, VAL3 = Value
}
implicit val enumAFormat = EnumUtils.enumFormat(EnumA)
val myEnumJson: JsValue = Json.toJson(EnumA.VAL1)
val myValue: EnumA.Value = myEnumJson.asOpt[EnumA.Value].getOrElse(sys.error("Oh noes! Invalid value!"))
def ok = EnumA.VAL1 == myValue
}
@mickeyvip
Copy link

Hi

line 26: EnumReader is not defined. I removed it and the error was gone

when i use it like so:

object Status extends Enumeration {
    type Status = Value
    val Enabled, Disabled = Value
}

case class Product(id: Option[Long], ean: Long, name: String, description: String, status: Status = Status.Enabled)

implicit val productWrites = (
        (__ \ "id").write[Option[Long]] ~
        (__ \ "ean").write[Long] ~ 
        (__ \ "name").write[String] ~
        (__ \ "description").write[String] ~
        (__ \ "status").write[Status]
    )(unlift(Product.unapply))

    implicit val productReads = (
        (__ \ "id").readNullable[Long] ~
        (__ \ "ean").read[Long] ~ 
        (__ \ "name").read[String] ~
        (__ \ "description").read[String] ~
        (__ \ "status").read[Status]  
    )(Product)

the (__ \ "status").write[Status] works ok, but (__ \ "status").read[Status] gives an error "Description Resource Path Location Type
No Json formatter found for type models.Status.Status. Try to implement an implicit Format for this type"

why doesn't it work for "read"?

Thank you

@fdz5
Copy link

fdz5 commented Oct 8, 2013

In line 26 just change the EnumReader to EnumUtils. After that you should be able to write something like this:

implicit val enumTypeFormat = EnumUtils.enumFormat(EnumClass)

At least for me it works.

@vega113
Copy link

vega113 commented Jan 22, 2015

Thanks, worked for me.

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