Reputation: 687
This was going to be a question about how to get the binding to work, but in cleaning up my example ready to post I've actually managed to get it working - the problem is I have no idea why this works:
import org.specs2.mutable._
import com.google.inject.{ Inject, Module, Binder, Guice }
import net.codingwell.scalaguice.ScalaModule
object InjectorSpec extends Specification {
val injector = Guice.createInjector(new ScalaModule() {
def configure() {
bind[Message].toInstance(MessageImpl)
bind[MessageService.type].toInstance(MessageService) // This line makes it work?
}
})
trait Message {
val body: String
}
object MessageImpl extends Message {
val body: String = "Hello!"
}
object MessageService {
@Inject
val message: Message = null
def get = message.body
}
"MessageService" should {
"Inject Message Implementation" in {
MessageService.get mustEqual "Hello!"
}
}
}
Initially I was just binding the type to be injected (inject MessageImpl for Message). Somewhere along the way I picked up the second bind which is for the service, that isn't injected (so I don't understand the bind being required). Can anyone explain what's happening here and if this is the correct way to proceed?
Upvotes: 5
Views: 5543
Reputation: 23548
So the thing is that guice won't search through your program and find all the @Inject
points that are in any class that you load anywhere. Instead, it needs to be given some path to find objects that you want it to inject stuff into. Generally, this is taken care of by the way you use Guice, since the standard pattern is:
val injector = Guice.createInjector(/* stuff */)
val main = injector.getInstance(classOf[Main])
main.mainMethod()
Guice performs injection on the instance of Main
that you ask it to make/get, and recursively performs injection on all the things @Inject
ed into main
.
In your case, one of these statements would also have worked; I say "one of", because though I could tell you exactly how to inject into java I'm not entirely clear on how the scala compiler compiles scala companion objects into java classes. (that is, I don't know if message
ends up being at the java level a static variable on the class called MessageService$
or an instance variable, with MessageService$
being instantiated only once through some threadsafe singleton pattern)
requestInjection(MessageService)
requestStaticInjection(MessageService.type)
The reason the toInstance
statement worked is that Guice automatically performs injection on all onjects passed to toInstance
as the injector is created. (something bound .asEagerSingleton
will also have injection performed on it as the injector is coming up, as will all things bound as singletons if you create a "production mode" injector)
Upvotes: 3