Guice: Using @Named to create object

33,451

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")));
Share:
33,451
Ali Shakiba
Author by

Ali Shakiba

github.com/shakiba

Updated on December 14, 2020

Comments

  • Ali Shakiba
    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
    John Ericksen over 11 years
    Oh, 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
    John Ericksen over 11 years
    Can you clarify your usage of ColorSet?
  • Ali Shakiba
    Ali Shakiba over 11 years
    That'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
    John Ericksen over 11 years
    Are your colors considered immutable?
  • Ali Shakiba
    Ali Shakiba over 11 years
    No, but does it help if I make them immutable?
  • John Ericksen
    John Ericksen over 11 years
    Im 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
    Ali Shakiba over 11 years
    I doubt that, but your idea may still be helpful.
  • Ali Shakiba
    Ali Shakiba over 11 years
    Thanks! They doesn't need to be immutable this way. I can bind named color to injected providers (instead of color instances).
  • John Ericksen
    John Ericksen over 11 years
    Cool. Good luck on your project.
  • Ali Shakiba
    Ali Shakiba over 11 years
    This is great idea, probably I can also mix it with Modules.override().with() to reuse them.
  • Galz
    Galz over 9 years
    That'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
    smjZPkYjps over 9 years
    I'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?c‌​om/…), not just a class.