I have three classes CircleBuilder
, SquareBuilder
, and TriangleBuilder
implementing the ShapeBuilder
interface.
I need to initialize my FormBuilder
and notably a BuilderList
(extending List<ShapeBuilder>
) with one instance of each class with google-guice.
What is the best way?
I know about the provider methods and stuff like this:
@Provides
FormBuilder provideFormBuilder() {
DatabaseTransactionLog instance = new FormBuilder ( <numerous parameters> );
ShapeBuilder builder = null ;
builder = new CircleBuilder( <numerous parameters> ) ;
instance.addBuilder( builder ) ;
builder = new SquareBuilder( <numerous parameters> ) ;
instance.addBuilder( builder ) ;
// And so on
return instance;
}
but it would mean that I have to create my FormBuilder
manually which defeats the purpose of using guice (because FormBuilder
is the top element in my object graph).
I'd love to be able to write something like this:
bind(BuilderList.class).to(CircleBuilder.class);
bind(BuilderList.class).to(TriangleBuilder.class);
bind(BuilderList.class).to(SquareBuilder.class);
Any idea?
To use it, annotate the constructor with the @Inject annotation. This constructor should accept class dependencies as parameters. Most constructors will then assign the parameters to final fields. If your class has no @Inject -annotated constructor, Guice will use a public, no-arguments constructor if it exists.
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.
@Target(value={METHOD,CONSTRUCTOR,FIELD}) @Retention(value=RUNTIME) @Documented public @interface Inject. Annotates members of your implementation class (constructors, methods and fields) into which the Injector should inject values. The Injector fulfills injection requests for: Every instance it constructs.
Consider Multibindings, which will collect bindings very much like your code snippet. There is no provision for lists through Multibinder, because Multibinder is designed for binding to the same collection in multiple modules, and the element order of a Multibinder list would depend on the order that your Modules were evaluated.
Multibinder<ShapeBuilder> shapeBinder =
Multibinder.newSetBinder(binder(), ShapeBuilder.class);
shapeBinder.addBinding().to(CircleBuilder.class);
shapeBinder.addBinding().to(TriangleBuilder.class);
shapeBinder.addBinding().to(SquareBuilder.class);
// Now you can inject Set<ShapeBuilder>.
Alternatively, your @Provides
method can take in parameters (e.g. CircleBuilder
or Provider<CircleBuilder>
) so you can have Guice create everything except the List itself. Not only will Guice bind Providers of all bound types automatically, but it will also inject every parameter in any @Provides
method.
@Provides List<ShapeBuilder> provideShapeBuilders(
CircleBuilder circleBuilder,
SquareBuilder squareBuilder,
TriangleBuilder triangleBuilder,
Provider<TrapezoidBuilder> trapezoidBuilderProvider) {
return new ArrayList<ShapeBuilder>(
circleBuilder,
squareBuilder,
triangleBuilder,
trapezoidBuilderProvider.get(),
trapezoidBuilderProvider.get());
}
We can do something like this:-
@Override
protected void configure() {
bind(ShapeBuilder.class).annotatedWith(Names.named("Circle")).to(CircleBuilder.class);
bind(ShapeBuilder.class).annotatedWith(Names.named("Triangle")).to(TriangleBuilder.class);
bind(ShapeBuilder.class).annotatedWith(Names.named("Square")).to(SquareBuilder.class);
}
In your FormBuilder Class:-
class FormBuilder{
List<ShapeBuilder> shapeBuilderList;
@Inject
public FormBuilder(@Named("Circle")ShapeBuilder circle, @Named("Triangle")ShapeBuilder triangle,@Named("Square")ShapeBuilder square){
shapeBuilderList = new ArrayList<>();
//add all of them
shapeBuilderList.add(circle);
}
}
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