21

Maybe I am just blind, but I do not see how to use Guice (just starting with it) to replace the new call in this method:

public boolean myMethod(String anInputValue) {
    Processor proc = new ProcessorImpl(anInputValue);
    return proc.isEnabled();
}

For testing there might be a different implementation of the Processor, so I'd like to avoid the new call and in the course of that get rid of the dependency on the implementation.

If my class could just remember an instance of Processor I could inject it via the constructor, but as the Processors are designed to be immutable I need a new one every time.

How would I go about and achieve that with Guice (2.0) ?

Daniel Schneller
  • 13,728
  • 5
  • 43
  • 72

3 Answers3

27

There is some time since I used Guice now, but I remember something called "assisted injection". It allows you to define a factory method where some parameters are supplied and some are injected. Instead of injecting the Processor you inject a processor factory, that has a factory method that takes the anInputValue parameter.

I point you to the javadoc of the FactoryProvider. I believe it should be usable for you.

waxwing
  • 18,547
  • 8
  • 66
  • 82
  • 7
    Yup, AssistedInject is the best solution. http://code.google.com/p/google-guice/wiki/AssistedInject – Jesse Wilson Jun 16 '09 at 06:57
  • 1
    Here is a short post I wrote about it. Assisted Injection is a wonderful tool for some problems, and I believe that it's not that well known. Good work spreading the knowledge. http://ripper234.com/p/assisted-injection-in-guice/ – ripper234 Aug 04 '11 at 01:51
  • Where can I get the .jar for assisted inject? It's not available as a download at http://code.google.com/p/google-guice/downloads/list. – Julian A. Feb 13 '12 at 03:28
  • For anyone else looking, it's available in http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.google.inject.extensions%22%20AND%20a%3A%22guice-assistedinject%22 – Charles Munger Apr 28 '13 at 02:04
11

You can get the effect you want by injecting a "Provider", which can by asked at runtime to give you a Processor. Providers provide a way to defer the construction of an object until requested.

They're covered in the Guice Docs here and here.

The provider will look something like

public class ProcessorProvider implements Provider<Processor> {
    public Processor get() {
        // construct and return a Processor
    }
}

Since Providers are constructed and injected by Guice, they can themselves have bits injected.

Your code will look something like

@Inject
public MyClass(ProcessorProvider processorProvider) {
    this.processorProvider = processorProvider;
}

public boolean myMethod(String anInputValue) {
    return processorProvider.get().isEnabled(anInputValue);
}
Dave W. Smith
  • 24,318
  • 4
  • 40
  • 46
  • Thanks a lot, this seems to be what I was looking for. Sometimes you don't see the forest for all the trees. – Daniel Schneller Jun 15 '09 at 16:05
  • And you'll want to bind a DebugProcessorProvider from your debug Modules, but if you've been using Guice, you've probably already figured that out. – Dave W. Smith Jun 15 '09 at 16:52
  • 1
    Seeing as the API has now changed to Process.isEnabled(anInputValue) (the same as in my response), why bother include a Provider now? Why not just have a single Processor and skip the Provider completely? – tddmonkey Jun 16 '09 at 09:38
  • MrWiggles: Sorry for my first comment. You are right of course. What I failed to recognize here in the example is that the provider does not have any parameters either. @Assisted is the way to go, even though the example is not correct in that regard. I now inject a ProcessorFactory. Changed the accepted answer accordingly. – Daniel Schneller Jun 16 '09 at 22:02
  • Corrected a bug in the example. And agree that @Assisted is the way to go. – Dave W. Smith Jun 17 '09 at 17:44
2

Does your Processor need access to anInputValue for its entire lifecycle? If not, could the value be passed in for the method call you're using, something like:

@Inject
public MyClass(Processor processor) {
    this.processor = processor;
}

public boolean myMethod(String anInputValue) {
    return processor.isEnabled(anInputValue);
}
thSoft
  • 21,755
  • 5
  • 88
  • 103
tddmonkey
  • 20,798
  • 10
  • 58
  • 67
  • The Processor implementations are designed to be immutable, creating them once with all the data they need, then only ask them for stuff. – Daniel Schneller Jun 15 '09 at 16:04