I have a child module called ChildPlugin and I inject classes from main module as follows:
public class ChildPlugin {
private ExampleClass demo;
@Inject
public void setDemo(ExampleClass demo) {
this.demo = demo;
}
}
The problem is that I don't know whether the main module binds ExampleClass
and if it's not Guice throws an exception when creating the injector. What I want to do is to make Guice pass null
or Optional.empty
if ExampleClass is not binded.
I do not have access to the main module so I cannot change binder for ExampleClass
to OptionalBinder
, I tried @Nullable
and Optional<ExampleClass>
in ChildPlugin.setDemo
method but it didn't work.
there are 2 ways to do this.
Optional injection
Use the com.google.inject.Inject annotation. This one allows you to specify optional on the annotation. See this example:
public class GuiceInjectOptional extends AbstractModule {
@Override
protected void configure() {
// method 1:
bind(B.class).in(Singleton.class);
}
public static class A {
private String name;
// non null constructor so that A can't be instantiated automatically by guice
public A(String name) {
this.name = name;
}
@Override
public String toString() {
return "I am: " + name;
}
}
public static class B {
@Inject(optional=true)
A obj;
void run() {
System.out.println("Object is: " + obj);
}
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new GuiceInjectOptional());
injector.getInstance(B.class).run();;
}
}
The annotation on class B indicates that A is optional. It does not get injected. Running the snippet prints:
Object is: null
Method 2 (which is the way you'd do it after guice 4+). You can specify optional bindings. These bindings even allow you to define default values if you like. You can then inject an optional value like in this snippet I wrote up:
public class GuiceInjectOptional extends AbstractModule {
@Override
protected void configure() {
// set up optional binding for A.
OptionalBinder.newOptionalBinder(binder(), A.class);
bind(B.class).in(Singleton.class);
}
public static class A {
private String name;
// non null constructor so that A can't be instantiated automatically by guice
public A(String name) {
this.name = name;
}
@Override
public String toString() {
return "I am: " + name;
}
}
public static class B {
@Inject
Optional<A> obj;
void run() {
System.out.println("Object is present: " + obj.isPresent());
System.out.println("Object is: " + obj);
}
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new GuiceInjectOptional());
injector.getInstance(B.class).run();;
}
}
The Inject annotation is now non-optional, but guice is aware that class A may or may not have been bound. Running the snippet will print:
Object is present: false
Object is: Optional.empty
Finally, you can then just bind A normally and guice will inject it:
public class GuiceInjectOptional extends AbstractModule {
@Override
protected void configure() {
// set up optional binding for A.
OptionalBinder.newOptionalBinder(binder(), A.class);
bind(A.class).toInstance(new A("Pandaa!"));
bind(B.class).in(Singleton.class);
}
public static class A {
private String name;
// non null constructor so that A can't be instantiated automatically by guice
public A(String name) {
this.name = name;
}
@Override
public String toString() {
return "I am: " + name;
}
}
public static class B {
@Inject
Optional<A> obj;
void run() {
System.out.println("Object is present: " + obj.isPresent());
System.out.println("Object is: " + obj);
}
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new GuiceInjectOptional());
injector.getInstance(B.class).run();;
}
}
And the above will print:
Object is present: true
Object is: Optional[I am: Pandaa!]
And this is how you have fail safe optional bindings with guice :) I hope this helps.
Edit: I just saw the guice-3 tag, so you'll want to use the optional annotation method rather than the optional binder. With the optional annotation it will stay null instead of being an Optional value.
Artur