Avoid injector deeps in code and lack of provided bindings.

54 views
Skip to first unread message

Kevin Burton

unread,
Oct 2, 2014, 12:33:42 AM10/2/14
to google...@googlegroups.com
I'm curious what the best practice is here.

Let's say that deep in your code you wanted to create a new instance of MyObject and pass it a FooService...

One could use an injector to do this.. but what if we actually forgot to bind anything to FooService?

You would deploy your application, it would be running just fine for months, then all of a sudden you would need FooService and your app would fail.

How does one avoid that scenario?

If you used explicitly provided dependencies, your app would fail at compilation time.

Now we've postponed to fail at run time.. which is not fun.

Any solutions here?

Nate Bauernfeind

unread,
Oct 2, 2014, 8:52:38 AM10/2/14
to google...@googlegroups.com
I did a tiny code test, and it seems like this is already going to fail at initial start time (note: not compilation time).

object Test {
  import net.codingwell.scalaguice.InjectorExtensions._

  class FooService
  class MyObject @Inject() (foo: FooService)

  class InjectionTest @Inject() (inj: Injector) {
    def doTest() = inj.instance[MyObject]
  }

  def main(args: Array[String]): Unit = {
    val injector = Guice.createInjector(new ScalaModule() {
      override def configure(): Unit = {
        binder().requireExplicitBindings()
        bind[MyObject]
        bind[InjectionTest].asEagerSingleton()
      }
    })

    injector.instance[InjectionTest].doTest()
  }
}

The error is this (rightly so):
Exception in thread "main" com.google.inject.CreationException: Guice creation errors:

1) Explicit bindings are required and Test$FooService is not explicitly bound.
  while locating Test$FooService
    for parameter 0 at Test$MyObject.<init>(Test.scala:22)
  at Test$$anon$1.bind(Test.scala:27)


Did you test the behavior already, or were you just curious of the behavior? It seems to work the way you want it to.


--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.
To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-guice/b138aea2-f477-414b-8b36-f3e306ca12d2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Nate Bauernfeind

unread,
Oct 2, 2014, 8:56:20 AM10/2/14
to google...@googlegroups.com
Forgot to mention, my recommendation would be to inject a Provider[MyObject] instead of the injector as I did in my example. I injected the injector just in case the results were different (i.e. delayed exception); turned out it failed at injector construction time (so it shouldn't matter which you do).

Nate

Kevin Burton

unread,
Oct 2, 2014, 12:41:13 PM10/2/14
to google...@googlegroups.com
I think I answered my own question :-P

I think the strategy is to always inject in the constructor.  This way the entire application won't startup.

Even if it's rarely used, having it from the start of the application will fix these problems and your app won't compile without this object in the constructor.

Nate Bauernfeind

unread,
Oct 2, 2014, 2:35:30 PM10/2/14
to google...@googlegroups.com
I'm going to point you in the direction of a Guice best-practice guideline which strongly suggests not doing what you've chosen to do.


Specifically, months down the road what if MyObject also needs a BarService? And then a BazService? Now you're going to have a bunch of hand-written specific code to do exactly what Guice is supposed to do for you for free. When does the madness end?! =)

Good luck,
Nate

--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.
To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice.

Nate Bauernfeind

unread,
Oct 2, 2014, 2:38:23 PM10/2/14
to google...@googlegroups.com
I should've read the example more closely, I guess the example is the other way around (injecting a B into A so that A can get access to C through B). Either way, I'm sure that assisted inject is a better practice ;).

Kevin Burton

unread,
Oct 2, 2014, 2:39:10 PM10/2/14
to google...@googlegroups.com
Yes... totally agree. I don't really think that's what I was referring too.

What I was saying was that you should just have all your services ahead of time, that you need.

The object that's needed in the hypothetical 'if' block that I was talking about would be created by the injector ahead of time.

It's a direct dependency... 

Nate Bauernfeind

unread,
Oct 2, 2014, 2:41:36 PM10/2/14
to google...@googlegroups.com
Ahh awesome. I misunderstood what you meant.

Happy Guicing =),
Nate

Reply all
Reply to author
Forward
0 new messages