I am new to Google Guice and am trying to wrap my head around how to use it for my particular scenario. I am building a service client that is pretty complex and that (I believe) truly requires a Builder Pattern to be instantiated correctly. Because this client will ultimately get packaged up into its own JAR lib, I would like Guice to handle the DI under the hood. Below is a greatly simplified version of my code:
public interface MyClient {
public FizzResource getFizzResource();
public BuzzResource getBuzzResource();
public FooResource getFooResource();
}
public class MyClientImpl implements MyClient {
// See below
}
public class GetFizzCommand {
// omitted for brevity
}
public class GetBuzzCommand {
// omitted for brevity
}
public class GetFooCommand {
// omitted for brevity
}
public interface FizzResource {
Fizz getFizz(Long fizzId);
}
public class FizzResourceImpl implements FizzResource {
private GetFizzCommand getFizzCommand;
@Override
Fizz getFizz(Long fizzId) {
return getFizzCommand.doGetFizz(fizzId);
}
}
public interface BuzzResource {
Buzz getBuzz(Long buzzId);
}
public class BuzzResourceImpl implements BuzzResource {
private GetBuzzCommand getBuzzCommand;
@Override
Buzz getBuzz(Long buzzId) {
return getBuzzCommand.doGetBuzz(buzzId);
}
}
public interface FooResource {
Foo getFoo(Long fooId);
}
public class FooResourceImpl implements FooResource {
private GetFooCommand getFooCommand;
@Override
Foo getFoo(Long fooId) {
return getFooCommand.doGetFoo(fooId);
}
}
So as you can see the hierarchy/dep graph is as follows:
MyClient
should be injected with*ResourceImpl
s- Each
*ResourceImpl
should be injected with a*Command
instance
The intended use case is to make building a MyClient
impl as easy as:
MyClient myClient = MyClientImpl.Builder("myservice.example.org", 8080L, getWidget())
.withAuth("user", "password")
.withHttps()
.withFailureStrategy(someFailureStrategy)
// ...etc.
.build();
So here's my best attempt at the MyClientImpl
, its internal builder and my Guice module:
public class BaseClient {
private String uri;
private long port;
private Widget widget;
// ctor, getters and setters
}
public class MyClientImpl extends BaseClient implements MyClient {
@Inject
private FizzResource fizzResource;
@Inject
private BuzzResource buzzResource;
@Inject
private FooResource fooResource
public MyClientImpl(String uri, long port, Widget widget) {
super(uri, port, widget);
}
public static class Builder {
private String uri;
private long port;
private Widget widget;
Builder(String uri, long port, Widget widget) {
super();
setUri(uri);
setPort(port);
setWidget(widget);
}
// Lots of methods on the builder setting lots of MyClient-specific properties
// that I have omitted here for brevity.
MyClient build() {
Injector injector = Guice.createInjector(new MyClientModule(this));
return injector.getInstance(MyClient.class);
}
}
}
public class MyClientModule extends AbstractModule {
private MyClientImpl.Builder builder;
public MyClientModule(MyClientImpl.Builder builder) {
super();
setBuilder(builder);
}
@Override
protected void configure() {
MyClientImpl myClientImpl = new MyClientImpl(builder.getUri(), builder.getPort(), builder.getWidget());
bind(MyClient.class).toInstance(myClientImpl);
}
}
But for the life of me, I can't see how/where to:
- Bind the
*Command
s to the*ResourceImpl
s; and - Bind the
*ResourceImpl
s to theMyClientImpl
instance
Any ideas?
It's not clear entirely what you're trying to accomplish with your injections. You may be confusing the matter further by making it about builders and other aspects of your design. I suggest you strip your code down to a SSCCE that functions but does not include any injection, and then increment your design by injecting, for example, a single field. Right now all your code shows is the trimmed down skeleton of a complex design with injections that don't make sense, and there is no way to run the code and see what happens. Guice operates at runtime, so it's essential that we see your
main
method to see what your application code actually does.Below follows a very simple example of what I describe above.
An interface with two different impls:
A vanilla (non-Guice) user of this interface:
A Guicified user of this interface:
In the Guicified version, the impl definition is coded in a Guice module rather than in the runtime code. The only thing the runtime code includes is the usage of the module when creating the injector. You could make a new module for bar service and use that to create an injector instead, or you could change the binding in your primary service module.
Once you understand what is happening above, you should be able to solve any issues in your own code by repeating the concepts on every instance that you want to be injected by Guice.