NonEmptyList[A] 的自定义喷雾格式器
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
上进行模式匹配,如果它不是 JsString
,则返回 deserializationError
.
但是,由于 JsArray
可以有 0 个或多个 JsValue
元素,我必须求助于反射吗?基本上,我想定义另一个 (implicit ev2: JsValue => A)
without reflection.
我该怎么做?
编辑
我将 ev2
类型签名从 JsValue => Option[A]
更改为 JsValue => A
- 因为将抛出异常(据我所知,根据喷射约定)以指示反序列化失败。
我不确定您是否需要使用反射。您需要的是 A 的 JsonFormat 实例,并用它组成您的 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]]]
为 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))
}
我正在尝试为我的 NonEmptyList[A]
:
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
上进行模式匹配,如果它不是 JsString
,则返回 deserializationError
.
但是,由于 JsArray
可以有 0 个或多个 JsValue
元素,我必须求助于反射吗?基本上,我想定义另一个 (implicit ev2: JsValue => A)
without reflection.
我该怎么做?
编辑
我将 ev2
类型签名从 JsValue => Option[A]
更改为 JsValue => A
- 因为将抛出异常(据我所知,根据喷射约定)以指示反序列化失败。
我不确定您是否需要使用反射。您需要的是 A 的 JsonFormat 实例,并用它组成您的 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]]]
为 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))
}