繁体   English   中英

play-json格式的宏对于具有通用类型属性的案例类失败

[英]play-json format macro fails for case classes with genericly typed properties

我无法弄清楚为什么play-json的Json.format[]宏无法处理以下案例类构造。 更具体地说,编译器引发的错误并不能给我任何有关问题是什么以及如何解决的线索。

给出以下定义:

trait Evt[T <: Evt[T]] {
  def meta: Meta[T]
}
case class Meta[T <: Evt[T]](value: String)
case class X(meta: Meta[X], data: String) extends Evt[X]

我试图实现如下的JSON格式。 Meta[X]的格式只是初步的尝试。 我在这里更加关注使用Json.format[X]的标准方法和下面描述的编译错误。

import play.api.libs.json._

object Formats {
  implicit val metaFormat = new Format[Meta[X]] {
    override def writes(o: Meta[X]): JsValue = JsString(o.value)
    override def reads(json: JsValue): JsResult[Meta[X]] = json.validate[String] match {
      case JsSuccess(value, path) => JsSuccess(Meta[X](value), path)
      case error: JsError => error
    }
  }
  implicit val xFormat: Format[X] = Json.format[X]
}

尝试对此进行编译会产生以下错误:

[error] ...: type mismatch;
[error]  found   : X
[error]  required: Meta[X]
[error]   implicit val xFormat: Format[X] = Json.format[X]
[error]                                                ^

我想了解为什么会发生这种情况,并且可能了解解决此问题的方法的一些线索,以便我可以格式化上面的结构。

运用

  • 斯卡拉2.11.4
  • 玩-json_2.11-2.3.6

更新

经过更多的思考和挖掘,我怀疑由编译器宏生成的代码会导致此编译错误,因为至少对于我来说,该错误消息对于打印的代码行没有任何意义。 我试图用scalac选项-Ymacro-debug-lite检查代码,这就是我得到的:

{
  import play.api.libs.functional.syntax._;
  final class $anon extends play.api.libs.json.util.LazyHelper[Format, X] {
    def <init>() = {
      super.<init>();
      ()
    };
    override lazy val lazyStuff: Format[X] = play.api.libs.json.JsPath.$bslash("meta").lazyFormat(this.lazyStuff).and(play.api.libs.json.JsPath.$bslash("data").format(json.this.Format.GenericFormat[String](json.this.Reads.StringReads, json.this.Writes.StringWrites))).apply(((meta, data) => X.apply(meta, data)), play.api.libs.functional.syntax.unlift(X.unapply))
  };
  new $anon()
}.lazyStuff

我认为$bslash("meta").lazyFormat(this.lazyStuff)可能会导致编译错误,因为this.lazyStuff返回Format[X]而在此位置(对于path meta )是Format[Meta[X]]

通过这种分析,它看起来像是format宏的缺点。 但是,我不确定此分析是否正确,因此仍希望进行一些澄清。

更新2

更多的实验表明,此问题不仅限于递归定义的类型。 尝试对此format使用format宏也会失败,并出现相同的错误:

trait Evt[T] { 
  def meta: Meta[T]
}
case class Meta[T](value: String, anotherValue: String)
case class X(meta: Meta[X], data: String) extends Evt[X]

我在这里在宏上找到了一些可能相关的工作。 但是使用2.4.0-M1的播放框架仍然显示出相同的问题。

Json.format[A]是一个宏,用于序列化简单案例类。 我相信在文档中的某处会警告不要将其与递归定义的类型一起使用。 似乎可以使用json组合器工作:

import play.api.libs.json._
import play.api.libs.functional.syntax._

implicit val XFormat: Format[X] = (
    (__ \ "meta").format[Meta[X]] and 
    (__ \ "data").format[String]
)(X.apply _, unlift(X.unapply))


scala> val x = X(Meta[X]("meta"), "data")
x: X = X(Meta(meta),data)

scala> Json.toJson(x)
res1: play.api.libs.json.JsValue = {"meta":"meta","data":"data"}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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