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.


Reply via email to