Определение неявного кодировщика с использованием мета-кавычек и квази-кавычек
Я пытаюсь создать неявный кодер, используя Circe. Однако этот кодировщик будет создан с использованием аннотации, поэтому я использую Scalameta. Вот мой код Однако компилятор жалуется на наличие оператора переопределения в квазицитатах.
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)
В результате я по-прежнему получаю: аннотацию макроса нельзя расширить (наиболее распространенная причина этого заключается в том, что вам необходимо включить плагин macro paradise; другая возможность состоит в том, что вы пытаетесь использовать аннотацию макроса в том же прогоне компиляции, который его определяет)
1 ответ
Вы просто скучаете new
до Encoder[$className] {
(могут быть и другие ошибки, но это немедленная ошибка).
Из-за этого компилятор считает, что вы пытаетесь вызвать универсальный метод Encoder
с блоком
{
override def apply(a: $className): Json = ...
...
}
как аргумент, так и локальные методы не могут быть override
,