2016-12-30 115 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]) 

,现在它按预期工作。