如何在 Scala 枚举(Play Framework 2.1)中编写 Reads[T] 和 Writes[T]?

25

对于Play Framework 2.1中的新ScalaJson功能,我有点迷惑。我想在我的枚举类型中编写Reads和Writes。

以下是我的代码:

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
    }
}}

有什么想法吗?

谢谢。

1个回答

42

简短回答:可以使用类似于Play Enumeration Utils的工具。

长话短说,不要将Reads放在枚举中,而是可以为枚举类型创建可重用的Reads:

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")
    }
  }
}

然后,当您想将某些内容解析为枚举时,请在作用域中创建一个特定的枚举类型的隐式读取器(Reads):

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

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

在Scala中使用null被认为是不好的做法。

将枚举写成JsValues更简单:

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

在尝试编写枚举(或将其显式地传递给 toJson 函数)之前,只需将其导入到作用域中:

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

您可以类似地创建一个函数,以创建一个同时包含读和写的格式化对象:

object EnumUtils {
  ....
  implicit def enumFormat[E <: Enumeration](enum: E): Format[E#Value] = {
    Format(EnumReader.enumReads(enum), EnumWriter.enumWrites)
  }
}

当我在REPL中尝试您的代码时,出现了以下错误:implicit val myEnumReads: Reads[EnumA#Value] = EnumUtils.enumReads(EnumA) 错误:未找到类型EnumA implicit val myEnumReads: Reads[EnumA#Value] = EnumUtils.enumReads(EnumA) ^ - smk
1
@smk:我发布的代码中已经包含了OPs的上下文。我现在已经更新了它以包含OPs的上下文。这是完整的gist链接 - Mikesname
@smk 谢谢,我修复了一个小错误:将 EnumA#Value 改为 EnumA.Value - Mikesname

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接