【问题标题】:Scala - play json trait serialisationScala - 播放 json 特征序列化
【发布时间】:2016-07-26 01:54:15
【问题描述】:

在 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 的实例,而该实例是 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])
                                                                                           ^

因此,我将不胜感激!

谢谢

【问题讨论】:

    标签: json scala serialization playframework


    【解决方案1】:

    你最好让隐式解决你的格式要求,而不是使用某种工厂:

    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)
    

    更新

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

      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}"""))
    

    【讨论】:

    • 虽然问题成立,但还剩下一点:每次需要解析Entity类型的实例,即无论是X还是Y实例,都需要显式提供格式或者读取,这正是我一直试图避免的事情。相反,我正在寻找以下内容:parse[X](jsonString),而序列化程序应在 parse 函数中确定。
    • @dsafa 请注意,您不需要明确提供格式。在第一个示例中,格式是隐式提供的,这就是关键字存在的原因
    • 上述使用反射获取类型标签并将格式映射到类型标签的解决方案完美运行!非常感谢!
    猜你喜欢
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    • 2013-04-29
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-22
    相关资源
    最近更新 更多