【问题标题】:Defining implicit encoder using scala meta and quasiquotes使用 scala meta 和 quasiquotes 定义隐式编码器
【发布时间】:2017-07-20 23:05:54
【问题描述】:

我正在尝试使用 Circe 创建一个隐式编码器。然而,这个编码器将使用注释创建,因此我使用的是 Scalameta。这是我的代码。但是,编译器抱怨在 quasiquotes 中有一个覆盖语句。

class HalResource extends StaticAnnotation {
  inline def apply(defn: Any): Any = meta {
    val q"..$mods class $tName (..$params) extends $template {..$stats}" = defn

    q"object $tName {${createApply(tName)}}"
  }


  private def createApply(className: Type.Name): Defn.Def = {
    q"""
       import _root_.io.circe.Json
       import _root_.io.circe.syntax._
       import _root_.io.circe.Encoder


       implicit def encoder = Encoder[$className] {
          override def apply(a: $className): Json = {
           val (simpleFields: Seq[Term.Param], nonSimpleFields: Seq[Term.Param]) =
             params.partition(field => field.decltpe.fold(false) {
               case _: Type.Name => true
               case _ => false
             })

           val embedded: Seq[(String, Json)] = nonSimpleFields.map(field => field.name.syntax -> field.name.value.asJson)
           val simpleJsonFields: Seq[(String, Json)] = simpleFields.map(field => field.name.syntax -> field.name.value.asJson)

           val baseSeq: Seq[(String, Json)] = Seq(
             "_links" -> Json.obj(
               "href" -> Json.obj(
                 "self" -> Json.fromString("self_reference")
               )
             ),
             "_embedded" -> Json.fromFields(embedded),
           ) ++ simpleJsonFields

           val result: Seq[(String, Json)] = baseSeq ++ simpleJsonFields
           Json.fromFields(result)
          }
       }
     """
  }
}

构建文件如下:

import sbt.Keys.{scalaVersion, scalacOptions}

val circeVersion = "0.8.0"

lazy val circeDependencies = Seq(
  "io.circe" %% "circe-core",
  "io.circe" %% "circe-generic",
  "io.circe" %% "circe-parser"
).map(_ % circeVersion)

lazy val commonSettings = Seq(
  name := "Annotation",
  version := "1.0",
  scalaVersion := "2.12.2",
  scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature"),
  resolvers += Resolver.sonatypeRepo("releases")
)

lazy val macroAnnotationSettings = Seq(
  addCompilerPlugin("org.scalameta" % "paradise" % "3.0.0-M9" cross CrossVersion.full),
  scalacOptions += "-Xplugin-require:macroparadise",
  scalacOptions in (Compile, console) ~= (_ filterNot (_ contains "paradise"))
)

lazy val projectThatDefinesMacroAnnotations = project.in(file("annotation-definition"))
  .settings(commonSettings)
  .settings(
    name := "HalResource",
    libraryDependencies += "org.scalameta" %% "scalameta" % "1.8.0" % Provided,
    macroAnnotationSettings)

lazy val annotation = project.in(file("."))
  .settings(commonSettings)
  .settings(macroAnnotationSettings)
  .settings(
    libraryDependencies ++= circeDependencies
  ).dependsOn(projectThatDefinesMacroAnnotations)

结果我仍然得到: 无法扩展宏注解(最常见的原因是您需要启用宏天堂插件;另一种可能是您尝试在定义它的同一编译运行中使用宏注解)

【问题讨论】:

    标签: scala annotations circe scala-quasiquotes scalameta


    【解决方案1】:

    您只是在Encoder[$className] { 之前缺少new(可能还有其他错误,但这是最直接的错误)。

    因此,编译器认为您正在尝试使用块调用泛型方法Encoder

    {
      override def apply(a: $className): Json = ...
      ...
    }
    

    作为参数,本地方法不能为override

    【讨论】:

    • 谢谢@AlexeyRomanov,这是一个愚蠢的错误。但是,当我尝试在出现以下错误的案例类上使用该注释时,我仍然遇到问题:[error] /Users/ibenardetelevis/Personal/annotation/src/main/scala/Mdsol.scala:25: macro annotation could not be expanded (the most common reason for that is that you need to enable the macro paradise plugin; another possibility is that you try to use macro annotation in the same compilation run that defines it)
    • 从路径来看,Mdsol.scala在同一个项目中。如果是这样,这正是错误消息中描述的第二个原因。如果您只是想测试它,请将Mdsol 移动到src/test/scala,如果您在其他地方需要它,请将您的项目分成两个模块。
    • 以防万一您也有原因1,请参阅scalameta.org/tutorial/#Setupbuild
    • 我在开始任务时遵循了相同的链接,这里是我的 build.sbt 的一个示例:`lazy val macroAnnotationSettings = Seq( addCompilerPlugin("org.scalameta" % "paradise" % " 3.0.0-M9" cross CrossVersion.full), scalacOptions += "-Xplugin-require:macroparadise", scalacOptions in (Compile, console) ~= (_ filterNot (_ contains "paradise")) )`
    • 我在开始任务时遵循了相同的链接,这里是我的 build.sbt 文件的示例,作为原始问题的一部分。我已经将它们分成不同的子模块。 @AlexeyRomanov
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    • 2018-04-24
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    • 1970-01-01
    相关资源
    最近更新 更多