【发布时间】:2014-11-20 11:20:38
【问题描述】:
我不明白为什么 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] ^
我想了解为什么会发生这种情况,并可能提供一些有关解决此问题的方法的线索,以便我可以格式化上述构造。
使用
- Scala 2.11.4
- play-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],而在这个地方(对于路径meta)需要Format[Meta[X]]。
通过这个分析,它看起来像是 format 宏的一个缺点。不过,我不确定这个分析是否正确,所以仍然希望得到一些澄清。
更新 2
更多的实验表明,这个问题不仅限于递归定义的类型。尝试对此构造使用 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]
我发现了一些可能与宏 here 相关的工作。但是同样使用2.4.0-M1的play框架还是会出现同样的问题。
【问题讨论】:
标签: json scala playframework playframework-2.3