Scala - 播放json特征序列化

时间:2016-04-05 22:10:07

标签: json scala serialization playframework

在scala中,我定义了以下特征和类(名称仅用于说明目的):

trait Entity {
  def x() : Collection
}

case class X(x : Int, y : Int) extends Entity {
  def x() : Collection = XCollection()
}

case class Y(x : Int, y : Int) extends Entity {
  def x() : Collection = YCollection()
}

虽然通过解析来自Web服务REST API的响应来创建类实例。

虽然使用play-json库的方法适用于解析响应的情况,并返回响应的类表示,但我一直在努力解决以下问题:使用泛型函数获取类型参数,而T:实体,并返回类型为T的实例。

例如,请考虑以下事项:

def parse[T <: Entity](json : String) : Option[T] = Json.parse(json).asOpt[T](Variants.format[T])

给定类型T,我想解析JSON字符串并生成类型为T的实例,而实例是特征实体的派生。但是,我不断收到有关反射API的编译错误:

Error:(25, 96) exception during macro expansion: 
scala.ScalaReflectionException: type T is not a class
at scala.reflect.api.Symbols$SymbolApi$class.asClass(Symbols.scala:323)
at scala.reflect.internal.Symbols$SymbolContextApiImpl.asClass(Symbols.scala:73)
at julienrf.variants.Variants$Impl$.baseAndVariants(Variants.scala:132)
at julienrf.variants.Variants$Impl$.formatDiscriminator(Variants.scala:99)
at julienrf.variants.Variants$Impl$.format(Variants.scala:94)
def parse[T <: Entity](json : String) : Option[T] =     Json.parse(json).asOpt[T](Variants.format[T])
                                                                                           ^

因此,我希望得到一些帮助!

由于

1 个答案:

答案 0 :(得分:2)

您最好允许implicits解决您的格式要求,而不是使用某种工厂:

def parse[T <: Entity](json: String)(implicit r: Reads[T]): Option[T] = 
     Json.parse(json).asOpt[T]

然后,如果您在隐式定义的当前上下文中使用了格式,parse将起作用:

implicit val XFormat = Json.format[X]

parse[X](Json.stringify(Json.toJson(X(1, 2))) // returns X(1, 2)

<强>更新

如果你真的想要它,你可以把它作为工厂。我会质疑它是否值得这样做,但从理论上讲,我可以想象一些你不想使用隐式机制的不同情况。我仍然认为如果implicits对您不起作用,您的代码中可能存在架构问题

  import play.api.libs.json.{Json, Reads}

  import scala.reflect.runtime.universe._

  trait Entity
  case class X(x : Int, y : Int) extends Entity
  case class Y(x : Int, y : Int) extends Entity


  val mapping = Map[Type, Reads[_]](typeOf[X] -> Json.format[X], typeOf[Y] -> Json.format[Y])
  def getFormat[T](tpe: Type): Reads[T] =
    mapping(tpe).asInstanceOf[Reads[T]]

  def parse[T : TypeTag](json: String): Option[T] = {
    val map = mapping(implicitly[TypeTag[T]].tpe)
    Json.parse(json).asOpt[T](getFormat(implicitly[TypeTag[T]].tpe))
  }

  println(parse[X]("""{"x": 5, "y": 6}"""))
  println(parse[Y]("""{"x": 5, "y": 6}"""))