How do I make an optional binding in Guice?
Here is my client:
class Client {
@Inject(optional=true) Service service;
}
Sometimes that Service isn't needed, and we know that information when the JVM starts (i.e before the binder is run). How do I make the binding optional? If I don't specify a binding at all it tries to new the Service (and fails because there is no zero-argument constructor: "Error while injecting at package.Client.service(Service.java:40): Could not find a suitable constructor in package.Service."), and I can开发者_StackOverflow社区't do:
binder.bind(Service.class).toInstance(null);
because Guice seems to disallow nulls. Any ideas?
Are you using Guice 2.0? I've tried this both with Service
being an interface (service field is always null
) and with it being a class (null
if it can't create a new instance with a JIT binding, an instance if it can). Both seem like what you'd expect.
In neither case did I use a binding like bind(Service.class).toInstance(null)
. If you do this, then you need to make sure that all injection points for Service
specify that they allow it to be null
. This can be done by annotating the injection point with any annotation called @Nullable
(you can make your own or use an existing one):
class Client {
@Inject @Nullable Service service;
}
If you want to make the existence of a binding optional you can use @Inject(optional = true)
for field and method injections. For contructor and other parameter type injections, you must use a helper class, for example:
class Foo {
public String hello(Helper helper) {
return Helper.string;
}
private static final class Helper {
@Inject(optional = true) public String string = "";
}
}
Note that the above doesn't allow null
to be injected, so Foo#hello will never return null
. If you do want to allow null
, simply add the @Nullable
annotation. Keep in mind that code like the following will fail unless you've provided a binding (to null, if nothing else) for String:
class Bar {
@Inject @Nullable public String hello(@Nullable String string) {
return string;
}
}
I couldn't reproduce this behavior. When I run this example code, the injector creates and the optional injection is left unsatisfied. The program prints null
:
public class OptionalInjections {
static class Service {
public Service(Void v) {} // not injectable
}
static class Client {
@Inject(optional = true) Service service;
}
public static void main(String[] args) {
Injector i = Guice.createInjector();
Client client = i.getInstance(Client.class);
System.out.println(client.service);
}
}
Could you reproduce this in a JUnit test case and submit it to the Guice issue tracker?
精彩评论