Guice: Using @Named to create object
Solution 1
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
}
Solution 2
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;
}
}
Solution 3
There are few code bases where I have seen the use of injector directly in order fetch certain object.
injector.getInstance(Color.class);
In this case, you can use the following:
injector.getInstance(Key.get(Color.class, Names.named("light")));
Comments
-
Ali Shakiba over 3 years
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:
- creating a class/subclass for each color that I need to inject (like WhiteColor)
- using reflection directly in my code
- changing my classes to use
ColorFactoy factory; factory.get("light");
instead of@Named("light") Color light;
-
John Ericksen over 11 yearsOh, I read that as you didn't want a subclass of each color (ie: WhiteColor). Are you looking to reference other colors as well?
-
John Ericksen over 11 yearsCan you clarify your usage of ColorSet?
-
Ali Shakiba over 11 yearsThat's just a simplified example of the real situation. There is not a colorset, there is a graph of objects created and connected by guice.
-
John Ericksen over 11 yearsAre your colors considered immutable?
-
Ali Shakiba over 11 yearsNo, but does it help if I make them immutable?
-
John Ericksen over 11 yearsIm not sure... just trying to figure out your architecture. I'll think about this usage of guice some more and let you know if I come up with anything.
-
Ali Shakiba over 11 yearsI doubt that, but your idea may still be helpful.
-
Ali Shakiba over 11 yearsThanks! They doesn't need to be immutable this way. I can bind named color to injected providers (instead of color instances).
-
John Ericksen over 11 yearsCool. Good luck on your project.
-
Ali Shakiba over 11 yearsThis is great idea, probably I can also mix it with Modules.override().with() to reuse them.
-
Galz over 9 yearsThat's helpful - any idea how you can use a Guice injector to get either of the instances? Looking for something like
Guice.createInjector(FooModule).getInstance(Color.class)
but with a specification of "white" or "black".. -
smjZPkYjps over 9 yearsI'm not sure how you would do it with @Named, but you should be using binding annotations (github.com/google/guice/wiki/BindingAnnotations) anyway. Then you could say injector.getInstance(Key.get(Color.class, Black.class)) (though I may be missing a generic type specification in there somewhere). getInstance(...) is overloaded to also take a Key (google.github.io/guice/api-docs/latest/javadoc/index.html?com/…), not just a class.