2016-12-30 139 views
0

我嘗試寫隱含物化播放格式化實例在需要時宏:編譯錯誤泛型類型

class FormattableImpl(override val c: whitebox.Context) extends Utils(c) { 
    import c.universe._ 

    def materializeFormatImpl[T : c.WeakTypeTag]: c.Expr[play.api.libs.json.Format[T]] = { 
     val tpe = implicitly[c.WeakTypeTag[T]].tpe 
     val x = c.Expr[play.api.libs.json.Format[T]](q" com.ubookr.macros.Json.format[$tpe] ") 
     println(show(x)) 
     x 
    } 
} 

object Format { 
    implicit def materializeFormat[T]: play.api.libs.json.Format[T] = macro FormattableImpl.materializeFormatImpl[T] 
} 

這只是正常的非參數化類型(例如

case class Apple(id: Long, name: String) 
val x = materializeFormat[Apple] 

)。

它也適用於集合

val xx = materializeFormat[Seq[Apple]] 

當我試圖用我自己的參數化類型,但是,它失去了類型參數的值:與

響應

case class Proxy[+T](id: Long, name: String) 
val xxx = materializeFormat[Proxy[Apple]] 

[error] package.scala:112: type mismatch; 
[error] found : play.api.libs.json.OFormat[com.ubookr.macros.Proxy[Nothing]] 
[error] required: play.api.libs.json.Format[com.ubookr.macros.Proxy[Apple]] 
[error] Note: com.ubookr.macros.Proxy[Nothing] <: com.ubookr.macros.Proxy[Apple], but trait Format is invariant in type A. 
[error] You may wish to define A as +A instead. (SLS 4.5) 
[error]  val xxx: Any = com.ubookr.macros.Format.materializeFormat[Proxy[Apple]] 
[error] 

這是有道理的,因爲WeakTypeTag不知道T.我的第一個問題是爲什麼這與Seq正確工作?

不過,我想出了什麼,我覺得應該是一個可行的解決方法:

def materializeProxy[T]: play.api.libs.json.Format[Proxy[T] = macro FormattableImpl.materializeProxyImpl[T] 

其中materializeProxyImpl實現是

def materializeProxyImpl[T : c.WeakTypeTag]: c.Expr[play.api.libs.json.Format[Proxy[T]]] = materializeFormatImpl[Proxy[T]] 

printlnmaterializeFormatImpl現在正確顯示參數類型t的實際值:

Expr[play.api.libs.json.Format[com.ubookr.macros.Proxy[Apple]]](com.ubookr.macros.Json.format[com.ubookr.macros.Proxy[Apple]]) 

,但我仍然後,立即得到了同樣的錯誤:

[error] package.scala:112: type mismatch; 
[error] found : play.api.libs.json.OFormat[com.ubookr.macros.Proxy[Nothing]] 
[error] required: play.api.libs.json.Format[com.ubookr.macros.Proxy[Apple]] 
[error] Note: com.ubookr.macros.Proxy[Nothing] <: com.ubookr.macros.Proxy[Apple], but trait Format is invariant in type A. 
[error] You may wish to define A as +A instead. (SLS 4.5) 
[error]  val xxx: Any = Format.materializeProxy[Apple] 
[error] 

我試圖改變對兩者分別materializeProxymaterializeProxyImplAnyTree類型標註,但語法錯誤仍然出現,反映走勢將轉我發現類型不匹配發生在宏引擎的內部。

我做錯了什麼?或者這是宏引擎中的一個錯誤?

+0

嗯,我認爲它對Seq正確工作的事實是一個線索。 JsMacroImpl代碼具有Seq參數的顯式幫助器。我懷疑發生錯誤是因爲播放宏忽略了我的類型參數。 –

+0

這是一個已知的限制,現在已修復:https://github.com/playframework/playframework/pull/5384 – cchantep

回答

0

看來,玩JSON宏的實現並不期望泛型案例類。它輸出

(
    (JsPath \ "id").format[Long] and 
    (JsPath \ "name").format[String] 
)(Proxy.apply, unlift(Proxy.unapply) 

我修改了遊戲宏,以便它輸出

(
    (JsPath \ "id").format[Long] and 
    (JsPath \ "name").format[String] 
)(Proxy.apply[Apple], unlift(Proxy.unapply[Apple]) 

,現在它按預期工作。