繁体   English   中英

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 ,返回deserializationError如果它不是一个JsString

但是,由于JsArray可以有0个或更多JsValue元素,我必须求助于反射吗? 基本上,我想在没有反射的情况下定义另一个(implicit ev2: JsValue => A)

我怎样才能做到这一点?

编辑

我将ev2类型签名从JsValue => Option[A]更改为JsValue => A - 因为将抛出异常(按照我所理解的每个喷涂约定)来指示反序列化失败。

我不确定你是否需要使用反射。 你需要的是一个JsonFormat for A的实例,并用它组合你的NonEmptySeq格式。 然后你可以使用toJsonconvertTo[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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM