Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guice: Using @Named to create object

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;
like image 266
Ali Shakiba Avatar asked Sep 05 '12 21:09

Ali Shakiba


People also ask

What does @named do Guice?

Guice provides another way also to map bindings without creating a custom annoation. It allows so using @Named annotation.

What is @named annotation in Java?

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.

What does @inject do in Guice?

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.

What does @named do in Java?

@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.


2 Answers

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
}
like image 145
smjZPkYjps Avatar answered Sep 28 '22 11:09

smjZPkYjps


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;
    }
}
like image 25
John Ericksen Avatar answered Sep 28 '22 11:09

John Ericksen