【问题标题】:Play JSON serialize/deserialize播放 JSON 序列化/反序列化
【发布时间】:2017-06-07 12:58:20
【问题描述】:

我正在尝试为此创建一些格式:

  case class Work[T](todo: Seq[T], failed: Seq[T], success: Seq[T])

  object Work {
    implicit def format[T](implicit r: Reads[T], w: Writes[T]): Format[Work[T]] = Json.format[Work[T]]
  }

  object InternalMessage {
    implicit def format[D, R](implicit
                              rD: Reads[D],
                              wD: Writes[D],
                              rR: Reads[R],
                              wR: Writes[R]
                             ): Format[InternalMessage[D, R]] = Json.format[InternalMessage[D, R]]

  }

  case class InternalMessage[D, R](
                                    download: List[Work[D]],
                                    refine: List[Work[R]],
                                    numberOfTries: Int
                                  )

这不起作用,我不明白为什么。错误是

[error] /home/oleber/develop/data-platform/modules/importerTemplate/src/main/scala/template/TemplateModel.scala:46: No apply function found matching unapply parameters
[error]     implicit def format[T](implicit r: Reads[T], w: Writes[T]): Format[Work[T]] = Json.format[Work[T]]
[error]                                                                                              ^
[error] /home/oleber/develop/data-platform/modules/importerTemplate/src/main/scala/template/TemplateModel.scala:55: No apply function found matching unapply parameters
[error]                              ): Format[InternalMessage[D, R]] = Json.format[InternalMessage[D, R]]

感谢您的帮助

【问题讨论】:

  • 您的代码似乎编译得很好。您是否在 Work 对象中添加了其他 applyunapply 方法?
  • @CyrilleCorpet,你使用什么 Scala/Play 版本?我可以确认,对于 Scala 2.11.11 上的 play-json 版本 2.5.15 上的 Work[T] 类,我得到了相同的错误,从 build.sbt 显式引用(即没有其他显式的 Play 依赖项)

标签: json scala playframework


【解决方案1】:

AFAIU 您无法使用 Play 2.5 宏为此类数据类型生成 JSON Format。限制你的是你使用Seq[T],即你想要一个泛型类的JSON序列化,它的字段使用从该泛型类型构建的一些复杂类型,而不仅仅是原始泛型T。相关代码似乎在JsMacroImpl lines 135-141 中。在maybeApply 计算的paramsMatch 内部方法中的这些行中,宏检查是否存在具有匹配(补码)签名的applyunapply 方法:

val maybeApply = applies.collectFirst {
  case (apply: MethodSymbol) if hasVarArgs && {
    // Option[List[c.universe.Type]]
    val someApplyTypes = apply.paramLists.headOption.map(_.map(_.asTerm.typeSignature))
    val someInitApply = someApplyTypes.map(_.init)
    val someApplyLast = someApplyTypes.map(_.last)
    val someInitUnapply = unapplyReturnTypes.map(_.init)
    val someUnapplyLast = unapplyReturnTypes.map(_.last)
    val initsMatch = someInitApply == someInitUnapply
    val lastMatch = (for {
      lastApply <- someApplyLast
      lastUnapply <- someUnapplyLast
    } yield lastApply <:< lastUnapply).getOrElse(false)
    initsMatch && lastMatch
  } => apply

  case (apply: MethodSymbol) if {
    val applyParams = apply.paramLists.headOption.
      toList.flatten.map(_.typeSignature)
    val unapplyParams = unapplyReturnTypes.toList.flatten

    def paramsMatch = (applyParams, unapplyParams).zipped.forall {
      case (TypeRef(NoPrefix, applyParam, _),
        TypeRef(NoPrefix, unapplyParam, _)) => // for generic parameter
        applyParam.fullName == unapplyParam.fullName

      case (applyParam, unapplyParam) => applyParam =:= unapplyParam
    }

    (applyParams.size == unapplyParams.size && paramsMatch)
  } => apply
}

正如您在相关(非hasVarArgs 分支)中看到的,此代码仅处理两种情况:applyunapply 中的类型完全匹配或使用相同的原始泛型类型。您的Seq[T](以及其他复杂的泛型类型)的情况在这里没有处理,当maybeApply 为空时,您得到的错误仅在几行之后生成:

val (tparams, params) = maybeApply match {
  case Some(apply) => {
    apply.typeParams -> apply.paramLists.head
    // assume there is a single parameter group
  }

  case None => c.abort(c.enclosingPosition, "No apply function found matching unapply parameters")
}

在 Play-JSON 2.6 中,此代码进行了重大修改,现在它似乎也支持您的情况(请参阅 conforms inner method)。

如果升级到(尚未发布)Play-JSON 2.6 是不可接受的,您可以使用 JSON Reads/Writes/Format Combinators doc 自己创建 Formats 对象。像这样的东西应该适合你:

  implicit def format[T](implicit r: Reads[T], w: Writes[T]): Format[Work[T]] = {
    val workReads = (
      (JsPath \ "todo").read[Seq[T]] and
        (JsPath \ "failed").read[Seq[T]] and
        (JsPath \ "success").read[Seq[T]]
      ) (Work.apply[T] _)

    val workWrites = (
      (JsPath \ "todo").write[Seq[T]] and
        (JsPath \ "failed").write[Seq[T]] and
        (JsPath \ "success").write[Seq[T]]
      ) (unlift(Work.unapply[T]))

    new Format[Work[T]] {
      override def reads(json: JsValue): JsResult[Work[T]] = workReads.reads(json)

      override def writes(o: Work[T]): JsValue = workWrites.writes(o)
    }
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-17
    • 2020-10-23
    • 2016-07-26
    • 2020-10-19
    • 2015-07-11
    • 1970-01-01
    相关资源
    最近更新 更多