FYI, if you're looking to prevent injecting things that don't have a constructor annotated with @Inject, you want to use requireAtInjectOnConstructors (which I think is only available in the beta release). requireExplicitBindings requires that there's a bind statement for the binding, but the thing that is bound doesn't necessarily need an @Inject constructor (so long as there's a default no-args constructor).
sam On Sep 20, 2013 12:02 AM, "Nate Bauernfeind" <[email protected]> wrote: > Hmph, I was using a Module where I called 'requireExplicitBindings' under > the covers. But it turns out that parameterization does not apply to > Provider's and you can easily create a provider for something that has a > default constructor. So, you're right; that is not a viable solution. > > Ok, then instead of injecting a provider.. you can inject the injector and > explicitly grab it yourself. Or, you can construct a provider that takes > the injector. Here's (seriously) a working example: > > class TestModule extends PrivateModule with ScalaPrivateModule { > def configure() { > val injector = getProvider[Injector] > > bind[B].toProvider(new Provider[B]() { > def get() = { > new B(injector.get().instance[A]) > } > }) > > expose[B] > } > } > > object TestModule { > def main(args: Array[String]) { > val injector = Guice.createInjector(new TestModule) > println("Successfully created injector.") > injector.instance[B] > } > } > > This is the output when run: > Successfully created injector. > Exception in thread "main" com.google.inject.ProvisionException: Guice > provision errors: > > 1) Could not find a suitable constructor in A. Classes must have either > one (and only one) constructor annotated with @Inject or a zero-argument > constructor that is not private. > at A.class(TestModule.scala:9) > while locating A > at TestModule.bind(TestModule.scala:24) > while locating B > > And again, you can use an annotated @Provides on a method and pass in the > injector (instead of a provider) as well as inject the injector directly > into the class. > > > Also, at this point in time, with this solution, it feels very much like a > work-around than a natural fit for your system. So it's even more obvious > that you'll probably want to explicitly separate extending the historical > stuff separate from the broker stuff. > > Sorry for the wrong answer earlier. Guice was lying to me (and that became > more obvious when A didn't have a default constructor)! > Nate > > On Thu, Sep 19, 2013 at 10:13 PM, Eric Tschetter <[email protected]>wrote: > >> Hrm, the thing with the suggestion of switching to Providers is that the >> broker won't even have a binding to a provider, so I'm pretty sure (haven't >> tried yet) that it will fail out saying that it doesn't know how to create >> that Provider. >> >> I thought about creating separate methods for the different node types, >> but I'd rather not tie the API to the set of the nodes that exist. I'd >> prefer to have the system have the freedom to change around how it >> structures and thinks about nodes without the extensions having to worry >> about them. >> >> I'll try the Provider out tomorrow and see if that fixes it and if that >> doesn't work (and there aren't other suggestions), I'll start adjusting >> everything to be under one big injector. >> >> --Eric >> >> >> On Thu, Sep 19, 2013 at 9:12 PM, Nate Bauernfeind < >> [email protected]> wrote: >> >>> Also, I might recommend allowing your extensions to implement two >>> separate configuration methods -- one for the historical injector and the >>> other for your broker injector. >>> >>> Then, something like you're explaining would easily be "covered" or >>> explained as a bug in the contract between your design and the extension. >>> >>> >>> On Thu, Sep 19, 2013 at 9:10 PM, Nate Bauernfeind < >>> [email protected]> wrote: >>> >>>> I think this is the easiest way to do this (written in Scala purely for >>>> terseness): >>>> >>>> class A >>>> class B @Inject() (a: A) >>>> >>>> class TestModule extends PrivateModule { >>>> def configure() {} >>>> >>>> @Provides >>>> def createB(a: Provider[A]): B = { >>>> new B(a.get()) >>>> } >>>> } >>>> >>>> If you change Provider[A] to A you get the eager binding validation. >>>> Note, you can still annotate your provider method as a Singleton. >>>> >>>> Additionally, you can let your B take in a Provider and have the needed >>>> logic to error out if an instance of A is not available in your injected >>>> class' constructor. >>>> >>>> Nate >>>> >>>> >>>> On Thu, Sep 19, 2013 at 2:39 PM, Eric Tschetter <[email protected]>wrote: >>>> >>>>> Hello Guicers, >>>>> >>>>> I'm running into a bit of a problem that I was wondering if someone >>>>> from the Guice community might have some great insight into how to deal >>>>> with it. >>>>> >>>>> I have a project that is an open distributed analytical data store ( >>>>> http://www.druid.io) and I've been guicifying it in order to better >>>>> accommodate plugins. >>>>> >>>>> I'm basically using SPI to find instances of a "DruidModule" interface >>>>> that I created in the classpath of extensions, I then add those modules >>>>> into the main Guice injector and I'd added an external module to the >>>>> system. Or, at least, that's the theory. >>>>> >>>>> This is generally working, however, I have a number of different node >>>>> types that each have different object graph requirements. Right now, each >>>>> node type creates its own injector with modules that build up only the >>>>> object graph required by that node type. >>>>> >>>>> This is causing a problem for my extensions, because I'm only creating >>>>> a single module in the extension, which can get added to any of the >>>>> injectors on any of the processes. Specifically, I have a "broker" node >>>>> and a "historical" node. The extension I'm working with is meaningful in >>>>> both contexts, but only a subset of the classes are actually used on the >>>>> "broker" node, while all of them are relevant to the "historical" node. >>>>> >>>>> The problem is, the one class that is only used on the historical node >>>>> (i.e. it is bound by the module, but never instantiated on the broker >>>>> node), depends on something that the broker node does not have a binding >>>>> for. Even though the broker node never instantiates the thing that >>>>> requires the missing binding, Guice still fails because, if it did need >>>>> it, >>>>> it wouldn't be there. >>>>> >>>>> I've been wondering if there's a way to actively turn off the checking >>>>> there and force it to be lazy. I don't actually leverage Guice except in >>>>> the bootstrap phase of my application, so I don't gain any extra benefit >>>>> from how Guice enforces fail-fast behavior and thus the check right now is >>>>> only serving as an annoyance :). >>>>> >>>>> The only other work-around I can see for this is to basically build >>>>> one big Guice injector with full bindings for use across all node types. >>>>> The only differentiation between the node types being the set of objects >>>>> that actually get instantiated on startup. If I were to do that, I would >>>>> work around this, but it would also open the door to having weird things >>>>> accidentally instantiated at weird points, so I'm a little reluctant to do >>>>> it. If this is the only option, I will switch to this model, just hoping >>>>> there are other options as well. >>>>> >>>>> Does that all make sense? >>>>> >>>>> --Eric >>>>> >>>>> -- >>>>> 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 [email protected]. >>>>> To post to this group, send email to [email protected]. >>>>> Visit this group at http://groups.google.com/group/google-guice. >>>>> For more options, visit https://groups.google.com/groups/opt_out. >>>>> >>>> >>>> >>> -- >>> 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 [email protected]. >>> To post to this group, send email to [email protected]. >>> Visit this group at http://groups.google.com/group/google-guice. >>> For more options, visit https://groups.google.com/groups/opt_out. >>> >> >> -- >> 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 [email protected]. >> To post to this group, send email to [email protected]. >> Visit this group at http://groups.google.com/group/google-guice. >> For more options, visit https://groups.google.com/groups/opt_out. >> > > -- > 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 [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/google-guice. > For more options, visit https://groups.google.com/groups/opt_out. > -- 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 [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/google-guice. For more options, visit https://groups.google.com/groups/opt_out.
