2017-07-19 81 views
0

我正嘗試使用Circe創建一個隱式編碼器。然而,這個編碼器將使用註釋創建,因此我使用了Scalameta。這是我的代碼。然而,編譯器抱怨在quasiquotes中有一個覆蓋語句。使用scala meta和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) 

因此,我仍然得到: 宏註釋不能擴展(對於最常見的原因是,你需要啓用宏觀天堂插件;另一種可能性是,您嘗試在定義它的同一編譯運行中使用宏註釋)

回答

1

您只是在缺少new之前Encoder[$className] {(可能還有其他錯誤,但這是直接的錯誤)。

正因爲如此,編譯器會認爲你試圖調用一個泛型方法Encoder與塊

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

作爲參數,和當地的方法不能override

+0

謝謝@AlexeyRomanov,這是一個愚蠢的錯誤。但是,當我嘗試在case類上使用該註釋時,我仍然遇到問題,出現以下錯誤:[error] /Users/ibenardetelevis/Personal/annotation/src/main/scala/Mdsol.scala:25:宏註釋可能(最常見的原因是您需要啓用宏觀天堂插件;另一種可能性是您嘗試在定義它的同一編譯運行中使用宏註釋) ' – igalbenardete

+0

通過路徑判斷,Mdsol .scala'在同一個項目中。如果是這樣,這正是錯誤消息中描述的第二個原因。如果你只是想測試它,將Mdsol移動到src/test/scala中,如果你在其他地方需要它,將你的項目分成兩個模塊。 –

+0

爲防萬一您也有理由1,請參閱http://scalameta.org/tutorial/#Setupbuild。 –