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()方法,而是因爲隱式解析已經找到了在伴隨對象中定義的寫入器。

相關問題