Scala-播放json特征序列化



在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:Entity,并返回类型T的实例。

例如,考虑以下内容:

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

给定类型T,我希望解析JSON字符串并生成类型T的实例,而该实例是trait Entity的派生。然而,关于反射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])
                                                                                           ^

因此,我将感谢您的帮助!

感谢

与使用某种工厂相比,您最好允许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}"""))

最新更新