Skip to content

Instantly share code, notes, and snippets.

Created April 23, 2015 11:33
Show Gist options
  • Select an option

  • Save anonymous/608a88aca413d853f980 to your computer and use it in GitHub Desktop.

Select an option

Save anonymous/608a88aca413d853f980 to your computer and use it in GitHub Desktop.
Type class materializer macro
import hoconspring.HoconType
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object BigMac {
def materializeHoconType[T]: HoconType[T] = macro materializeHoconType_impl[T]
def materializeHoconType_impl[T: c.WeakTypeTag](c: blackbox.Context): c.Expr[HoconType[T]] = {
import c.universe._
val sym = symbolOf[T]
if (sym.isClass && sym.asClass.isCaseClass) {
val tpe = weakTypeOf[T]
val primaryConstructor = tpe.member(termNames.CONSTRUCTOR).alternatives
.collectFirst({ case m: MethodSymbol if m.isPrimaryConstructor => m })
.getOrElse(c.abort(c.enclosingPosition, s"No primary constructor found for $sym"))
val constructorArgs = primaryConstructor.paramLists match {
case List(params) => params.map { param =>
q"implicitly[HoconType[${param.typeSignature}]].get(configObject.get(${param.name.decodedName.toString}))"
}
case _ => c.abort(c.enclosingPosition, s"Primary constructor of $sym takes more than one list of parameters")
}
// @formatter:off
val result =
q"""
{
import _root_.hoconspring.HoconType
import _root_.com.typesafe.config.{ConfigValue, ConfigObject, ConfigValueType}
new HoconType[$tpe] {
def get(value: ConfigValue): $tpe = {
require(value.valueType == ConfigValueType.OBJECT, s"Required object at $${value.origin} but got $${value.valueType}")
val configObject = value.asInstanceOf[ConfigObject]
${sym.companion}(..$constructorArgs)
}
}
}
"""
// @formatter:on
c.Expr[HoconType[T]](result)
} else {
c.abort(c.enclosingPosition, s"${sym.fullName} is not a case class")
}
}
}
case class Something(a: String, b: Int)
val sthHoconType = util.BigMac.materializeHoconType[Something]
val sth: Something = sthHoconType.get(ConfigFactory.parseString("{a: stuff, b: 123}").root)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment