2017-07-19 3 views
0

J'essaie de créer un codeur implicite en utilisant Circé. Cependant ce codeur sera créé en utilisant une annotation donc j'utilise Scalameta. Voici mon code. Cependant, le compilateur se plaint d'avoir une instruction override dans les quasiquotes.Définition d'un codeur implicite en utilisant scala meta et 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) 
      } 
     } 
    """ 
    } 
} 

Le fichier de compilation est la suivante:

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) 

En conséquence, je reçois encore: annotation macro ne pouvait pas être étendue (la raison la plus courante pour ce que vous devez activer la macro plugin paradis, une autre possibilité est que vous essayez d'utiliser l'annotation macro dans la même série de compilation qui la définit)

Répondre

1

vous manquez juste new avant Encoder[$className] { (il peut y avoir d'autres erreurs, mais c'est l'erreur immédiate).

À cause de cela, le compilateur pense que vous essayez d'appeler une méthode générique Encoder avec le bloc

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

comme argument, et les méthodes locales ne peuvent pas être override.

+0

Merci @AlexeyRomanov, c'était une erreur stupide. Cependant j'ai toujours des problèmes quand j'essaye d'employer cette annotation sur une classe de cas obtenant l'erreur suivante: '[error] /Users/ibenardetelevis/Personal/annotation/src/main/scala/Mdsol.scala:25: l'annotation de macro pourrait ne pas être développé (la raison la plus fréquente est que vous devez activer le plugin macro paradise, une autre possibilité est que vous essayez d'utiliser l'annotation de macros dans la même compilation qui le définit) ' – igalbenardete

+0

En juger par le chemin,' Mdsol .scala' est dans le même projet. Si c'est le cas, c'est exactement la deuxième raison décrite dans le message d'erreur. Si vous essayez simplement de le tester, déplacez 'Mdsol' à' src/test/scala', si vous en avez besoin ailleurs, divisez votre projet en deux modules. –

+0

Juste au cas où vous avez aussi la raison 1, voir http://scalameta.org/tutorial/#Setupbuild. –