Forms 播放如何为包含枚举的案例类实现隐式写入或格式
下面显示了如何使用case类将枚举绑定到表单 但是,在第2.7.3重头戏中,该代码在以下情况下失效: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
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
..
}