0

这并不编译:Playframeworks json写入隐式需要显式类型,为什么?

package model 

import play.api.libs.json._ 

case class Dog(id: Long, name: String, kind: String) { 

    def asJson() = Json.toJson(this) 
} 

object Dog { 
    implicit val writes = Json.writes[Dog] 
} 

错误:

53. Waiting for source changes... (press enter to interrupt) 
[info] Compiling 1 Scala source to /Users/pablo/projects/mvp/target/scala-2.10/classes... 
[error] /Users/pablo/projects/mvp/app/models/model2.scala:7: No Json deserializer found for type model.Dog. Try to implement an implicit Writes or Format for this type. 
[error] def asJson() = Json.toJson(this) 
[error]       ^
[error] one error found 
[error] (compile:compile) Compilation failed 

更改伴侣对象(注意明确的类型):

object Dog { 
    implicit val writes: Writes[Dog] = Json.writes[Dog] 
} 

修复该问题。这是为什么?

+0

请注意,'Json.writes'签名是'def writes [A]:写入[A]',因此类型完全是明确的。 –

+1

我对scala没有足够的了解来回答这个问题,但它可能很重要['Writes [-A]'](http://www.playframework.com/documentation/2.3.x/api/scala/index。 html#play.api.libs.json.Writes)是逆变的。我不知道斯卡拉是否可以处理这种情况下的暗示。 – Carsten

回答

1

这是不是一个真正的答案(但我需要一个很大的空间来贴我的代码!),但是这对我的作品:

package model 

import play.api.libs.json._ 

object Dog { 
    implicit val writes = Json.writes[Dog] 
} 

case class Dog(id: Long, name: String, kind: String) { 

    def asJson() = Json.toJson(this) 
} 

基本上我只是在上课前移动的对象声明。这可能是由于Json.writes使用宏,因此必须在使用构造的Write实例之前发生。

+0

upvoted,感谢您的信息。我真的希望有一个不同于声明顺序的解释。 –

1

Json.toJson是一个宏观的,这是在编译时执行。在那个阶段,类型分析尚未发生,这意味着方法参数的类型(this)不能被自动推断(或者如果宏实现了这样做所需的额外功能,可能会推断出来,但我会假设这是相当困难的)。这就是为什么你需要提供一个类型参数,比如Json.toJson [Dog]。

在声明像这样一个同伴对象:

object Dog { 
    implicit val writes: Writes[Dog] = Json.writes[Dog] 
} 

声明的类型隐式的作家。鉴于Scala的隐式解析规则,当您尝试将案例类实例转换为JSON时,将会在范围内找到作者。所以它是有效的,但不是因为你的类中的asJson()方法,而是因为隐式解析已经找到了在伴随对象中定义的写入器。

相关问题