For those stumbling on this question in the future, I have found a solution 
that I am most pleased with:

Isolate the bindings of the Red and Blue Modules to their own injectors and 
create providers for only the exposed services you need / want in your 
application. My AwesomeService needs the Red and Blue Services, so I create 
2 provider methods for them; but the offending exposed ExecutorServices of 
these modules are isolated to their respective injectors not polluting my 
application's bindings:

public class MyAppModule extends PrivateModule {
  private static final Injector blueInjector = Guice.createInjector(new 
BlueModule());
  private static final Injector redInjector = Guice.createInjector(new 
RedModule());

  void configure() {
  
  bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor());
    bind(AwesomeService.class).to(AwesomeServiceImpl.class);
    expose(AwesomeService.class);
  }

  @Provides
  RedService getRedService() {
    return redInjector.getInstance(RedService.class);
  }

  @Provides
  BlueService getBlueService() {
    return blueInjector.getInstance(BlueService.class);
  }
}

Cheers!

On Friday, April 26, 2013 1:22:15 PM UTC-7, Matthew Madson wrote:
>
> Hi Marshall,
>
> Thanks for the reply, and I wholeheartedly agree with you, BlueModule's 
> author lacked foresight.
>
> I did consider using Modules.override, but I actually don't want to change 
> BlueModule's ExecutorService binding, you see BlueService actually uses 
> BlueModule's ExecutorService, and if I replace it with my application's 
> ExecutorService, BlueService will start kicking off threads in my 
> application's executor service and neither I nor BlueService want that.
>
> class BlueServiceImpl {
>   @Inject
>   BlueServiceImpl(ExecutorService executor) { ... }
> }
>
> Thanks,
> Matt
>
> On Friday, April 26, 2013 12:17:44 PM UTC-7, Marshall Pierce wrote:
>>
>> Looks like you could just use Modules.override [1]: 
>>
>> install(Modules.override(new BlueModule()).with(new 
>> MyExecutorServiceModule())); 
>>
>> [1] 
>> http://google-guice.googlecode.com/svn/trunk/javadoc/com/google/inject/util/Modules.html#override(com.google.inject.Module...)
>>  
>>
>>
>> Though, it would have been nice if BlueModule's author hadn't so rudely 
>> bound ExecutorService, since that makes it hard on users of his library. 
>> When releasing code externally I apply annotations to bindings of common 
>> classes from the JDK or other libraries so that users don't get these 
>> unpleasant surprises. 
>>
>> -Marshall 
>>
>> On Apr 26, 2013, at 11:54 AM, Matthew Madson <[email protected]> 
>> wrote: 
>>
>> > Let's say I'm developing an application which uses a service to do 
>> something totally awesome. 
>> > 
>> > public class MyAppModule extends PrivateModule { 
>> >   bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
>> >   expose(AwesomeService.class); 
>> > } 
>> > 
>> > Now the particular implementation of my AwesomeService needs a few 
>> things to be as awesome as it is: 
>> > 
>> > class AwesomeServiceImpl implements AwesomeService { 
>> >   @Inject 
>> >   AwesomeServiceImpl(BlueService blue, RedService red, ExecutorService 
>> executor) { ... } 
>> > } 
>> > 
>> > It just so happens that some upstanding internet denizen has created a 
>> standalone jar with guice modules that provide both Red and Blue Services. 
>> So I'll add the jar to my classpath and modify MyAppModule so that my 
>> AwesomeService can use the third pary Red and Blue Services: 
>> > 
>> > public class MyAppModule extends PrivateModule { 
>> >   install(new RedModule()); 
>> >   install(new BlueModule()); 
>> >   bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
>> >   expose(AwesomeService.class); 
>> > } 
>> > 
>> > I also need an ExecutorService for my AwesomeService, so I'll go ahead 
>> and bind to an explicit instance for now: 
>> > 
>> > public class MyAppModule extends PrivateModule { 
>> >   install(new RedModule()); 
>> >   install(new BlueModule()); 
>> >   
>> bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); 
>>
>> >   bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
>> >   expose(AwesomeService.class); 
>> > } 
>> > 
>> > Ah, but damn, apparently my good internet friend decided to expose not 
>> only the RedService and BlueService bindings that my AwesomeService needs, 
>> but also an ExecutorService that I don't want: 
>> > 
>> > public final class BlueModule extends PrivateModule { 
>> >   
>> bind(ExecutorService.class).toInstance(Executors.newCachedThreadPool()); 
>> >   bind(BlueService.class).to(BlueServiceImpl.class); 
>> > 
>> >   expose(ExecutorService.class); 
>> >   expose(BlueService.class); 
>> > } 
>> > 
>> > public final class RedModule extends PrivateModule { 
>> >   
>> bind(ExecutorService.class).toInstance(Executors.newCachedThreadPool()); 
>> >   bind(RedService.class).to(RedServiceImpl.class); 
>> > 
>> >   expose(ExecutorService.class); 
>> >   expose(RedService.class); 
>> > } 
>> > 
>> > No problem, I'll just wrap his modules in a private module and expose 
>> only the services I care about: 
>> > 
>> > public class MyAppModule extends PrivateModule { 
>> >   install(new PrivateModule() { 
>> >     install(new RedModule()); 
>> >     expose(RedService.class); 
>> >   }); 
>> >   install(new PrivateModule() { 
>> >     install(new BlueModule()); 
>> >     expose(BlueService.class); 
>> >   }); 
>> >   
>> bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); 
>>
>> >   bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
>> >   expose(AwesomeService.class); 
>> > } 
>> > 
>> > Ahh, but damn again, my ExecutorService binding is inherited by my 
>> private wrapper modules and is conflicting with the internal bindings 
>> defined in the RedModule and BlueModule. I guess I could annotate or Name 
>> my ExecutorService in my AwesomeService constructor, but what if I want 
>> that ExecutorService to be a singleton shared all over my app, by 20, 30 or 
>> 40 different services. I'll have to pollute all my ExecutorService 
>> injections with this annotation. 
>> > 
>> > Or I suppose I could do some trickery, staggering the bindings and 
>> hiding the ExecutorService so it doesn't conflict with the ExecutorService 
>> that RedModule and BlueModule need, but this just seems wrong: 
>> > 
>> > public class MyAppModule extends PrivateModule { 
>> >   install(new PrivateModule() { 
>> >     install(new RedModule()); 
>> >     expose(RedService.class); 
>> >   }); 
>> >   install(new PrivateModule() { 
>> >     install(new BlueModule()); 
>> >     expose(BlueService.class); 
>> >   }); 
>> > 
>> >   final Module myAppExecutorService = new PrivateModule() { 
>> >     
>> bind(ExecutorService.class).toInstance(Executors.newSingleThreadExecutor()); 
>>   
>> >     expose(ExecutorService.class); 
>> >   }; 
>> >   install(new PrivateModule() { 
>> >     install(myAppExecutorService); 
>> >     bind(AwesomeService.class).to(AwesomeServiceImpl.class); 
>> >     expose(AwesomeService.class); 
>> >   });   
>> >   expose(AwesomeService.class); 
>> > } 
>> > 
>> > This seems like a common problem one would have using guice. Am I 
>> missing something here? What is the best practice for this use case?   
>> > 
>> > Any assistance would be greatly appreciated! 
>> > 
>> > Minor Notes: 
>> > 
>> > - the configure method declaration was elided in all modules shown 
>> > - BlueModule and RedModule are intentionally marked final, so extending 
>> and overriding the expose method is not a viable solution to the problem 
>> > 
>> > 
>> > -- 
>> > 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?hl=en. 
>> > 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?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to