如何解决Scala |如何将此代码放入宏注释中?
我有很多包装器类,它们所做的就是添加类型安全性和格式化。除了ClassName之外,每个包装器类基本上都是相同的。
import com.helpers.buildFormatter
import spray.json.JsonFormat
final case class ClassName(value: String)
object ClassName {
implicit val jsonFormatter: JsonFormat[ClassName] =
buildFormatter[ClassName]("ClassName",_.value,this.apply)
}
有没有办法进一步缩短?我想知道批注,宏或继承是否可行。
编辑:buildFormatter
提供自定义json解析,这就是为什么我想将其保留在结果答案中的原因
def buildStringFormatter[A](className: String,serializer: A => String,deserializer: String => A): JsonFormat[A]
来自评论:
问:包装箱类将始终为单参数,参数类型将始终为String
,参数名称将始终为value
吗?
答:您是正确的,将只有1个参数,参数名称为value
。我可以限制那些限制
解决方法
您可以搜索spray json derivation
https://github.com/driver-oss/spray-json-derivation
https://github.com/milessabin/spray-json-shapeless
https://github.com/zackangelo/spray-json-macros
https://github.com/ExNexu/spray-json-annotation
等
由于buildFormatter
的签名是
def buildFormatter[T](str: String,value: T => String,apply: String => T): JsonFormat[T] = ???
(您说包装箱类始终是单参数,参数类型始终为String
,参数名称始终为value
),您可以尝试Shapeless
import shapeless.{::,Generic,HList,HNil,Typeable}
object caseClassJsonFormats {
implicit def caseClassJsonFormat[A <: Product,L <: HList](implicit
gen: Generic.Aux[A,String :: HNil],typeable: Typeable[A]
): JsonFormat[A] =
buildFormatter[A](typeable.describe,gen.to(_).head,s => gen.from(s :: HNil))
}
因此,您可以为所有案例类定义一个隐式(而不是每个案例类都隐式)。
测试:
final case class ClassName(value: String)
import caseClassJsonFormats._
implicitly[JsonFormat[ClassName]] // compiles
替代方法是macro annotation(对于宏项目,是sbt settings)
import scala.annotation.{StaticAnnotation,compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
@compileTimeOnly("enable macro annotations")
class jsonFormat extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro JsonFormatMacro.impl
}
object JsonFormatMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
def jsonFormatImplicit(tpname: TypeName) =
q"""implicit val jsonFormatter: _root_.spray.json.JsonFormat[$tpname] =
buildFormatter[$tpname](${tpname.toString},_.value,this.apply)"""
annottees match {
// if there is companion object,modify it
case (clazz@q"$_ class $tpname[..$_] $_(...$_) extends { ..$_ } with ..$_ { $_ => ..$_ }") ::
q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" :: Nil =>
q"""
$clazz
$mods object $tname extends { ..$earlydefns } with ..$parents { $self =>
..$body
${jsonFormatImplicit(tpname)}
}"""
// if there is no companion object,create it
case (clazz@q"$_ class $tpname[..$_] $_(...$_) extends { ..$_ } with ..$_ { $_ => ..$_ }") :: Nil =>
q"""
$clazz
object ${tpname.toTermName} {
${jsonFormatImplicit(tpname)}
}"""
}
}
}
因此,您需要为每个带注释的案例类在同伴对象中定义一个隐式对象。
测试:
@jsonFormat
final case class ClassName(value: String)
implicitly[JsonFormat[ClassName]] // compiles
// scalacOptions += "-Ymacro-debug-lite"
//scalac: {
// final case class ClassName extends scala.Product with scala.Serializable {
// <caseaccessor> <paramaccessor> val value: String = _;
// def <init>(value: String) = {
// super.<init>();
// ()
// }
// };
// object ClassName extends scala.AnyRef {
// def <init>() = {
// super.<init>();
// ()
// };
// implicit val jsonFormatter: _root_.spray.json.JsonFormat[ClassName] = buildFormatter[ClassName]("ClassName",((x$1) => x$1.value),this.apply)
// };
// ()
//}
,
您可以使用此选项:
import spray.json.DefaultJsonProtocol._
implicit val format = jsonFormat1(ClassName.apply)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。