Forms 播放如何为包含枚举的案例类实现隐式写入或格式

Forms 播放如何为包含枚举的案例类实现隐式写入或格式,forms,scala,enums,playframework,Forms,Scala,Enums,Playframework,下面显示了如何使用case类将枚举绑定到表单 但是,在第2.7.3重头戏中,该代码在以下情况下失效: No Json serializer found for type jura.SearchRequest. Try to implement an implicit Writes or Format for this type. 当我实现格式化程序时: object SearchRequest { implicit val searchRequestFormat: OFormat[Sear

下面显示了如何使用case类将枚举绑定到表单

但是,在第2.7.3重头戏中,该代码在以下情况下失效:

No Json serializer found for type jura.SearchRequest. Try to implement an implicit Writes or Format for this type.
当我实现格式化程序时:

object SearchRequest {
  implicit val searchRequestFormat: OFormat[SearchRequest] = Json.format[SearchRequest]
}
我明白了

没有play.api.libs.json.Format的实例可用于 隐式范围中的scala.Enumeration.Value

我是否应该尝试为系统scala.Enumeration类型编写格式化程序?
或者,当涉及枚举时,是否有其他方法实现格式化程序


测试用例。

要将枚举作为字符串写入,正如cchantep所说,您可以使用写入。enumNameWrites,我们专门用于读取和写入ID。因此,我们在enums的全局包中有EnumFormat:

package object enums {

  implicit def reads[E <: Enumeration](enum: E): Reads[E#Value] = new Reads[E#Value] {
    def reads(json: JsValue): JsResult[E#Value] = json match {
      case JsNumber(s) =>
        try {
          JsSuccess(enum.apply(s.toInt))
        } catch {
          case _: NoSuchElementException => JsError(s"Enumeration expected of type: '${enum.getClass}', but it does not appear to contain the value: '$s'")
        }
      case _ => JsError("Number value expected")
    }
  }

  implicit def writes[E <: Enumeration]: Writes[E#Value] = new Writes[E#Value] {
    def writes(v: E#Value): JsValue = JsNumber(v.id)
  }

  implicit def formatID[E <: Enumeration](enum: E): Format[E#Value] =
    Format(reads(enum), writes)


  def readsString[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 writesString[E <: Enumeration]: Writes[E#Value] = new Writes[E#Value] {
    def writes(v: E#Value): JsValue = JsString(v.toString)
  }

  implicit def formatString[E <: Enumeration](enum: E): Format[E#Value] =
    Format(readsString(enum), writesString)
}

将以下内容添加到枚举对象中

implicit object MatchFilterTypeFormatter extends Formatter[MatchFilterType.Value] {
    override val format = Some(("format.enum", Nil))
    override def bind(key: String, data: Map[String, String]) = {
      try {
        Right(MatchFilterType.withName(data.get(key).head))
      } catch {
        case e:NoSuchElementException =>  Left(Seq(play.api.data.FormError(key, "Invalid MatchFilterType Enumeration")))
      }
    }
    override def unbind(key: String, value: MatchFilterType.Value) = {
      Map(key -> value.toString)
    }
  }
  implicit val matchFilterTypeFormat = new Format[MatchFilterType.MatchFilterType] {
    def reads(json: JsValue) = JsSuccess(MatchFilterType.withName(json.as[String]))
    def writes(myEnum: MatchFilterType.MatchFilterType) = JsString(myEnum.toString)
  }
然后问题中给出的格式化程序/控制器就可以工作了


工作测试用例是。

我用于此库的任何枚举:

使用Dotty将有大量的枚举,但在此之前,我认为使用enumeratum是在Scala中处理枚举的最佳方法。另见

另外还有一个
播放json
扩展,请参阅

使用此选项,您的代码将如下所示:

import enumeratum.{ PlayJsonEnum, Enum, EnumEntry }

sealed trait SearchRequest extends EnumEntry

object SearchRequest extends Enum[SearchRequest] with PlayJsonEnum[SearchRequest] {

  val values = findValues

  case object SuperRequest  extends SearchRequest
  case object SimpleRequest extends SearchRequest
  ..
}

本质上,
PlayJsonEnum[SearchRequest]
完成了所有工作。

写入。提供了enumNameWrites
。没有case类定义,我发现将
scala.Enumeration.Value
作为属性类型而不是
E#Value
(对于一些
E,您是否控制
SearchRequest
,它是否不被其他库使用?@pme是的,控制中。它将与Slick一起使用。谢谢!您是否也对完全替换
scala.Enumeration
的解决方案感兴趣?@pme是的。据我所知,我们应该使用枚举类还是只使用我们自己的类还没有定论。)e case classes..任何提供类似枚举功能的方法都可以工作-但首选最佳实践方法,我认为这意味着使用实际枚举。这不应该是必需的,并且当使用
Json.Writes/format
宏时,应该从隐式范围解析此通用
Writes
o“generate”/“派生”案例类的实例。谢谢,不幸的是,这段代码似乎给出了一个类型不匹配,我们的格式是
play.api.libs.json.format[models.MatchFilterType.Value]
但是play需要
play.api.data.format.Formatter[models.MatchFilterType.Value]“mft”->Forms.of[MatchFilterType](matchFilterTypeFormat)
。我在这里制作了一个测试用例,感谢您的进一步帮助!注意SearchRequest是case类,它使用enum MatchFilterType。一个改进是使其成为泛型,这样就不需要为您希望使用的每个enum复制。非常好,谢谢!这看起来比标准枚举要好得多。一个小的更改是使用PlayEnum而不是PlayJsonEnum,因为它包括JSON和表单支持。在表单映射中,您可以使用
“myEnum”->myEnum.formField,
import enumeratum.{ PlayJsonEnum, Enum, EnumEntry }

sealed trait SearchRequest extends EnumEntry

object SearchRequest extends Enum[SearchRequest] with PlayJsonEnum[SearchRequest] {

  val values = findValues

  case object SuperRequest  extends SearchRequest
  case object SimpleRequest extends SearchRequest
  ..
}