Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write Reads[T] and Writes[T] in scala Enumeration (play framework 2.1)

Tags:

I'm a little bit lost with the new ScalaJson Feature in Play Framework 2.1. I would like to write Reads and Writes in my Enumeration.

Here is my code :

object EnumA extends Enumeration {  type EnumA = Value  val VAL1, VAL2, VAL3 = Value  def parse(str:String) : EnumA = {     str.toUpperCase() match {          case "VAL1" => VAL1          case "VAL2" => VAL2          case "VAL3" => VAL3          case _ => null     } }} 

Any idea ?

Thanks.

like image 514
victorlambrt Avatar asked Mar 18 '13 23:03

victorlambrt


1 Answers

Short answer: use something like Play Enumeration Utils.

Long answer, instead of putting a Reads in your enum, you can create a re-useable Reads for Enumeration types:

object EnumA extends Enumeration {   type EnumA = Value   val VAL1, VAL2, VAL3 = Value }  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")     }   } } 

Then when you want to parse something to an enum, create an implicit Reads for your specific Enum type in scope:

import some.thing.EnumUtils implicit val myEnumReads: Reads[EnumA.Value] = EnumUtils.enumReads(EnumA)  val myValue: EnumA.Value = someJsonObject.as[EnumA.Value] 

or

val myValue: EnumA.Value = someJsonObject.asOpt[EnumA.Value].getOrElse(sys.error("Oh noes! Invalid value!")) 

(It's considered bad form to use null in Scala.)

Writing enums as JsValues is simpler:

object EnumUtils {   ...   implicit def enumWrites[E <: Enumeration]: Writes[E#Value] = new Writes[E#Value] {     def writes(v: E#Value): JsValue = JsString(v.toString)   } } 

Then just import that into scope before you attempt to write an enum (or pass it explicitly to the toJson function:

import EnumUtils.enumWrites val myEnumJson: JsValue = Json.toJson(EnumA.VAL1) 

You can similarly make a function to create a Format object combining both Reads and Writes:

object EnumUtils {   ....   implicit def enumFormat[E <: Enumeration](enum: E): Format[E#Value] = {     Format(EnumReader.enumReads(enum), EnumWriter.enumWrites)   } } 
like image 188
Mikesname Avatar answered Oct 25 '22 22:10

Mikesname