[英]Custom Spray Formatter for NonEmptyList[A]
我正在尝试为我的NonEmptyList[A]
编写自定义JSON格式化程序:
package net
import spray.json._
import Foo.NonEmptySeq
class NonEmptyCustomFormatter[A](implicit ev: A => JsValue)
extends JsonFormat[NonEmptySeq[A]] {
override def read(json: JsValue): NonEmptySeq[A] =
???
override def write(xs: NonEmptySeq[A]): JsValue = {
val values: Seq[JsValue] = Foo.toSeq[A](xs).map(ev(_))
JsArray( values: _* )
}
}
object Foo {
type NonEmptySeq[A] = (A, Seq[A])
def toSeq[A](neq: NonEmptySeq[A]): Seq[A] =
neq._1 +: neq._2
implicit def stringToJsValue(x: String): JsValue = JsString(x)
}
REPL示例:
scala> import spray.json._
import spray.json._
scala> import net._
import net._
scala> import net.Foo._
import net.Foo._
scala> implicit object NonEmptyStringList extends NonEmptyCustomFormatter[String]
defined object NonEmptyStringList
scala> val xs: NonEmptySeq[String] = ("foo", Nil)
xs: net.Foo.NonEmptySeq[String] = (foo,List())
scala> xs.toJson
res0: spray.json.JsValue = ["foo"]
接下来,我即将实现read
方法,目前定义为???
。
如果我有一个非通用的,即String-specific
格式化,那么我可以简单地在模式匹配JsString
,返回deserializationError
如果它不是一个JsString
。
但是,由于JsArray
可以有0个或更多JsValue
元素,我必须求助于反射吗? 基本上,我想在没有反射的情况下定义另一个(implicit ev2: JsValue => A)
。
我怎样才能做到这一点?
编辑
我将ev2
类型签名从JsValue => Option[A]
更改为JsValue => A
- 因为将抛出异常(按照我所理解的每个喷涂约定)来指示反序列化失败。
我不确定你是否需要使用反射。 你需要的是一个JsonFormat for A的实例,并用它组合你的NonEmptySeq格式。 然后你可以使用toJson
和convertTo[A]
例如:
class NonEmptyCustomFormatter[A : JsonFormat] extends JsonFormat[NonEmptySeq[A]] {
override def read(json: JsValue): NonEmptySeq[A] = json match {
case JsArray(Vector(value, values @ _*)) =>
(value.converTo[A], values.map(_.convertTo[A]))
}
override def write(xs: NonEmptySeq[A]): JsValue =
JsArray(Foo.toSeq[A](xs).map(_.toJson): _*)
}
我建议你使用spray的seq格式来继承已实现的功能,并将自己的逻辑置于其上。
首先implicitly[JsonFormat[Seq[A]]]
调用implicitly[JsonFormat[Seq[A]]]
来获取Seq[A]
json格式化程序。 编写NonEmptySeq[A]
是微不足道的,因为您知道如何编写Seq[A]
以及如何将NonEmptySeq[A]
转换为Seq[A]
。 读取NonEmptySeq[A]
,首先读取为Seq[A]
,然后验证它包含至少一个元素。 如果验证,则获得NonEmptySeq[A]
,如果不是,则给出DeserializationError。
class NonEmptySeqFormat[A : JsonFormat] extends JsonFormat[NonEmptySeq[A]] {
// this is implemented by spray developers
val seqFormat = implicitly[JsonFormat[Seq[A]]]
// read json as Seq[A] then check if it contains at least 1 element
def read(json: JsValue): NonEmptySeq[A] =
seqFormat.read(json) match {
case x +: xs => (x, xs)
case e => deserializationError("There should be at least one element, but got " + e)
}
// convert NonEmptySeq to Seq and then write it as json
def write(xs: NonEmptySeq[A]): JsValue =
seqFormat.write(Foo.toSeq(xs))
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.