Skip to content

Instantly share code, notes, and snippets.

@echojc
Last active August 29, 2015 14:00
Show Gist options
  • Save echojc/96d9fb9f04c7b7333b3a to your computer and use it in GitHub Desktop.
Save echojc/96d9fb9f04c7b7333b3a to your computer and use it in GitHub Desktop.
Fundep materialiser for spray-json's JsonFormat via superclass implicit (for Scala 2.10.3)
import scala.language.experimental.macros
import scala.reflect.macros.Context
import spray.json._
trait ImplicitJsonFormat
object ImplicitJsonFormat {
implicit def materializeJsonFormat[T]: JsonFormat[T] = macro jfImpl[T]
def jfImpl[T: c.WeakTypeTag](c: Context): c.Expr[JsonFormat[T]] = {
import c.universe._
val tpe = weakTypeOf[T]
val companion = tpe.typeSymbol.companionSymbol
val ctorParamsCounts = tpe.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor ⇒ m
} map (_.paramss.map(_.size).toSet)
ctorParamsCounts match {
case None ⇒
c.abort(c.enclosingPosition, "no ctor?")
case Some(paramsCountsSet) if paramsCountsSet.size > 1 ⇒
c.abort(c.enclosingPosition, "multiple primary ctors?")
case Some(paramsCountsSet) ⇒
val paramCount = paramsCountsSet.head
val importStmt =
Import(
Select(Select(Ident(newTermName("spray")), newTermName("json")), newTermName("DefaultJsonProtocol")),
List(
ImportSelector(newTermName("_"), -1, newTermName("_"), -1)
)
)
c.Expr[JsonFormat[T]](
Block(
List(
importStmt
),
Apply(
Ident(newTermName(s"jsonFormat$paramCount")),
List(
Select(
Ident(companion),
newTermName("apply")
)
)
)
)
)
}
}
}
object Main extends App {
case class Bar(name: String) extends ImplicitJsonFormat
case class Foo(id: Int, bar: Bar) extends ImplicitJsonFormat
assert(Foo(1, Bar("aoeu")).toJson == """{"id":1,"bar":{"name":"aoeu"}}""".asJson)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment