I think I'm starting to 'get' it. Having just one Module with the
'configuration' sure is a lot simpler. In cases where I need to map to a
specific implementation I used this approach:
@Named("MyImpl")
&
bind(IMyInterface.class).annotatedWith(Names.named("MyImpl")).to(MyImpl.class);
That seems pretty simple. I still think/hope the IDE can be smart and make
sure that if I annotate with @Inject it will let me know and/or help me make
sure all the parameters have been specified in the 'configuration'.
Thanks for the explanations it really helps.
-Dave
On Tue, May 10, 2011 at 12:53 PM, Thomas Broyer <[email protected]> wrote:
>
>
> On Tuesday, May 10, 2011 10:47:51 AM UTC+2, dhoffer wrote:
>>
>> 1. Hum, perhaps I'm doing more work than I need to...perhaps just out
>> of habit of previously using manual factories...but I think I got this
>> from the Guice online docs. Here is what I do:
>>
>> Class A takes 4 parameters where all are interfaces of course. I add
>> @Inject annotation to the constructor and optionally scope annotation
>> to the class. I then create a module for this class that extends from
>> AbstractModule that implements configure. In this method I create and
>> maintain 4 bind() method calls that map the interface to the actual
>> class. I assume the order of these bind statements much match the
>> order in the constructor. Repeat for every IoC class in the
>> application.
>>
>
> You're doing it wrong. Modules are not factories, they're configuration.
>
> 1. the bind() order is not significant
> 2. using a module per "class requiring injection", you'll probably have
> duplicate bindings (classes Foo and Bar have a dependency on Baz, following
> your "rule", both FooModule and BarModule will
> bind(Baz.class).to(BazImpl.class), this will cause an error) or conflicts
> (FooModule binds Baz to BazImpl whereas BarModule binds Baz to AnotherBaz).
> If you want to make very fine-grained modules (really not sure that's a
> best practice), you'd rather have one per "interface some other class
> depends on" (i.e. interface Baz), but then you could in simple cases just as
> easily use an @ImplementedBy annotation.
>
> You have to think at a wider level than "one class", think "module" instead
> (I'm not talking about Guice modules, but application/feature modules).
> As an example, we have "api modules" (Maven modules, think of them as JARs
> or Eclipse projects if you prefer) comprised mostly of interfaces (we have
> one for managing entities in a simple datastore, one for indexing and
> searching them, one for validating them, one for dispatching events on a
> bus, etc.) Then we have "implementation modules" where the storage is
> implemented using Morphia/MongoDB, the indexing/searching backed by Solr,
> validation by Hibernate Validator and JSR303, and the event bus by HornetQ.
> In each of these "implementation modules", we have only a single Guice
> module that binds each interface from the "api module" to the concrete
> implementation of the "implementation module" (Indexer to a SolrIndexer
> backed by a SolrServer, EntityManager to a MorphiaEntityManager backed by a
> Morphia Datastore, etc.)
> Then we have several applications (a webapp and a bunch or "executables")
> that make use of these modules, each one creates a Guice Injector installing
> the required modules; the code only depends on the interfaces from the "api
> modules" though.
>
> I guess I just don't get your comment 'bind()ings are about *what* to
>> inject, not *where* to inject them.'
>>
> It's not where I use an EntityManager that I decide which one I'll use
> (i.e. it's not in a FooModule along side a Foo class with an "@Inject
> EntityManager em" field, that I bind(EntityManager.class)), it's at the
> application level that I instead decide which modules I'll install, those
> modules providing the bindings (some classes need an EntityManager, and the
> bootstrap code for the app chooses to use the MorphiaStorageModule that
> binds EntityManager to an implementation based on Morphia).
>
> It seems you need some way to
>> specify the *where* too.
>>
> If you need several implementations of a given interface to be injected at
> different places in your app, then you have to annotate those places. For
> instance, we have several Solr indexes –Solr cores–, one used for "suggest
> as you type" and one for "advanced search", because they need different Solr
> configurations. In our app, both are accessed through a Searcher interface.
> We created a "binding annotation" (or you could use @Named if your prefer)
> so that anywhere I need a "searcher for suggest-as-you-type" I declare a
> "@ForIndex(Index.Suggest) Searcher" field or constructor argument, and
> anywhere I need a "searcher for advanced search" I declare a
> "@ForIndex(Index.AdvancedSearch) Searcher" field or constructor argument.
> In the SolrSearchModule, we then have two bindings (in the form of
> @Provides methods):
> @Provides @ForIndex(Index.Suggest) Searcher provideSuggestSearcher(...other
> dependencies...) { ... }
> @Provides @ForIndex(Index.AdvancedSearch) Searcher
> provideAdvancedSearchSearcher(...other dependencies...) { ... }
>
> See, it's about *what* you depend on/inject, not about *where* you inject
> it.
>
> --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/google-guice?hl=en.
>
--
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice?hl=en.