Using Guice, if I have
@Inject @Named("light")
Color light;
I can use
bind(Color.class).annotatedWith(Names.named("light"))
.toInstance(new Color("white"));
to bind it to white color if Color constructor only requires color name.
But how can I do it if Color constructor also requires objects which are created by Guice? For example:
@Inject
public Color(ColorSet colorset, String colorName) {...}
where colorset is create at runtime by Guice and in not available in configure(){...}.
I would like to do it without:
ColorFactoy factory; factory.get("light");
instead of @Named("light") Color light;
Guice provides another way also to map bindings without creating a custom annoation. It allows so using @Named annotation.
This annotation indicates that the class is a named bean. You can specify a name to the named bean by adding an argument to the @Named annotation. For example, @Named("myBean") . If no name is specified, the Java class name is used as the name by default, with the first character converted to lowercase characters.
Note that the only Guice-specific code in the above is the @Inject annotation. This annotation marks an injection point. Guice will attempt to reconcile the dependencies implied by the annotated constructor, method, or field.
@Named annotation is used for giving names for classes which implements the interface, and it is optional. Otherwise, we can specify alternatives and a default bean by @Alternative , and @Default annotations.
The best way to do this is not with a factory but with @Provides
methods. My company uses Guice very, very extensively, and requestInjection
is always considered a bad idea because it can easily set up a very fragile graph of implicit dependencies.
Here's what it should look like:
public class FooModule extends AbstractModule {
protected void configure() {
// do configuration
}
@Provides
@Named("white")
Color provideWhiteColor(ColorSet colorSet) {
return colorSet.white(); // or whatever
}
@Provides
@Named("black")
Color provideBlackColor(ColorSet colorSet) {
return colorSet.black(); // or whatever
}
// etc
}
You could setup a factory within the module, and request injection on it to fill in the ColorSet.
Module:
ColorFactory colorFactory = new ColorFactory();
requestInjection(colorFactory);
bind(Color.class).annotatedWith(Names.named("light")).toInstance(colorFactory.buildColor("white"));
bind(Color.class).annotatedWith(Names.named("dark")).toInstance(colorFactory.buildColor("black"));
ColorFactory:
public class ColorFactory {
private ColorSet colorSet;
public Color buildColor(String color){
return new Color(colorSet, color);
}
@Inject
public void setColorSet(ColorSet colorSet) {
this.colorSet = colorSet;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With