Created
April 23, 2015 11:33
-
-
Save anonymous/608a88aca413d853f980 to your computer and use it in GitHub Desktop.
Type class materializer macro
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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") | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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