宏展开时异常:类型T不是类,玩json

问题描述 投票:0回答:1

我面临这个错误:

exception during macro expansion: 
scala.ScalaReflectionException: type T is not a class
    at scala.reflect.api.Symbols$SymbolApi.asClass(Symbols.scala:284)
    at scala.reflect.api.Symbols$SymbolApi.asClass$(Symbols.scala:284)
    at scala.reflect.internal.Symbols$SymbolContextApiImpl.asClass(Symbols.scala:99)
    at play.api.libs.json.JsMacroImpl.directKnownSubclasses$1(JsMacroImpl.scala:527)
    at play.api.libs.json.JsMacroImpl.macroImpl(JsMacroImpl.scala:850)
    at play.api.libs.json.JsMacroImpl.implicitConfigWritesImpl(JsMacroImpl.scala:44)

当尝试声明一个方法来为给定的泛型类型创建编写器时:

def makeWriter[T]: Writes[T] = Json.writes[T]

现在

Json.writes
的实现只是一个宏,它不需要任何类型的上下文边界或其他东西:

def writes[A]: OWrites[A] = macro JsMacroImpl.withOptionsWritesImpl[A]

有人知道这是怎么回事吗?我不太擅长宏,所以如果有人能解释这一点,我将不胜感激,任何解决方案都会受到赞赏。

scala scala-macros play-json
1个回答
0
投票

是的,这是可能的。

堆栈跟踪

scala.ScalaReflectionException: type T is not a class
    at scala.reflect.api.Symbols$SymbolApi.asClass(Symbols.scala:284)
    at scala.reflect.api.Symbols$SymbolApi.asClass$(Symbols.scala:284)
    at scala.reflect.internal.Symbols$SymbolContextApiImpl.asClass(Symbols.scala:99)
    at play.api.libs.json.JsMacroImpl.directKnownSubclasses$1(JsMacroImpl.scala:555)
    at play.api.libs.json.JsMacroImpl.macroImpl(JsMacroImpl.scala:869)
    at play.api.libs.json.JsMacroImpl.implicitConfigWritesImpl(JsMacroImpl.scala:44)

提示问题所在:

    def directKnownSubclasses: Option[List[Type]] = {
      // Workaround for SI-7046: https://issues.scala-lang.org/browse/SI-7046
      val tpeSym = atag.tpe.typeSymbol.asClass
      ...

https://github.com/playframework/play-json/blob/main/play-json/shared/src/main/scala-2/play/api/libs/json/JsMacroImpl.scala#L555

.asClass
只能在类符号上调用,否则会抛出异常(宏的运行时异常是主代码的编译错误)

def asClass: ClassSymbol = throw new ScalaReflectionException(s"$this is not a class")

https://github.com/scala/scala/blob/2.13.x/src/reflect/scala/reflect/api/Symbols.scala#L284

定义的问题

def makeWriter[T]: Writes[T] = Json.writes[T]

是宏

Json.writes[T]
在这里扩展,其中
T
还不是一个类,而只是一个类型参数。如果您也将
makeWriter
设为宏,则可以推迟宏扩展

import play.api.libs.json.Writes
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

def makeWriter[T]: Writes[T] = macro makeWriterImpl[T]

def makeWriterImpl[T: c.WeakTypeTag](c: blackbox.Context): c.Tree = {
  import c.universe._
  val typeT = weakTypeOf[T]
  q"_root_.play.api.libs.json.Json.writes[$typeT]"
}
// in a different subproject

case class A(i: Int)

makeWriter[A] // compiles
© www.soinside.com 2019 - 2024. All rights reserved.