Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Last active July 29, 2019 07:51
Show Gist options
  • Save xuwei-k/ff9bc4eeba090bd6946d869790a16407 to your computer and use it in GitHub Desktop.
Save xuwei-k/ff9bc4eeba090bd6946d869790a16407 to your computer and use it in GitHub Desktop.
guice TypeLiteral macro in Scala

Licence: public domain

sbt.version=1.2.8
scalaVersion := "2.12.8"
libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value
libraryDependencies += "com.google.inject" % "guice" % "4.2.2"
package scala_guice_macro
import com.google.inject.Injector
import scala.reflect.macros.blackbox
import scala.language.experimental.macros
object InjectorOps {
implicit def toInjectorOps(i: Injector): InjectorOps = new InjectorOps(i)
}
class InjectorOps(val injector: Injector) extends AnyVal {
def instanceOf[A]: A = macro InjectorOpsImpl.instanceOf[A]
}
class InjectorOpsImpl(val c: blackbox.Context) {
def instanceOf[A: c.WeakTypeTag]: c.Tree = {
import c.universe._
c.prefix.tree match {
case Apply(_, injector :: Nil) =>
val t = q"new _root_.com.google.inject.TypeLiteral[${weakTypeOf[A]}]{}"
q"${injector}.getInstance(_root_.com.google.inject.Key.get(${t}))"
}
}
}
package example
import com.google.inject.{Guice, Module, Binder}
import scala_guice_macro.InjectorOps._
import scala_guice_macro.typeLiteral
trait Foo[A] {
def foo: A
}
class FooStringImpl extends Foo[String] {
override def foo = "foo string"
}
class FooListStringImpl extends Foo[List[String]] {
override def foo = List("list")
}
object Test {
def main(args: Array[String]): Unit = {
val injector = Guice.createInjector(new Module {
override def configure(binder: Binder): Unit = {
// TODO Intなどのプリミティブは、Scalaの制約上?うまくいかない気がする
binder.bind(typeLiteral[Foo[String]]).to(classOf[FooStringImpl])
binder.bind(typeLiteral[Foo[List[String]]]).to(classOf[FooListStringImpl])
}
})
println(injector.instanceOf[Foo[String]].foo)
println(injector.instanceOf[Foo[List[String]]].foo)
}
}
package scala_guice_macro
import com.google.inject.TypeLiteral
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object typeLiteral {
def apply[A]: TypeLiteral[A] = macro TypeLiteralImpl.apply[A]
}
class TypeLiteralImpl(val c: blackbox.Context) {
def apply[A: c.WeakTypeTag]: c.Tree = {
import c.universe._
q"new _root_.com.google.inject.TypeLiteral[${weakTypeOf[A]}]{}"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment