I am trying to implement a simple app using Guice for DI. The app has an interface Shape :
public interface Shape {
void draw();
}
that is implemented by a class Rectangle.
public class Rectangle implements Shape{
@Override
public void draw() {
System.out.printf("Shape is a rectangle");
}
}
Then there is a class ShapeRequest that would inject Shape bean at runtime based on the explicit bindings I provide.
@Singleton
public class ShapeRequest {
@AnnotatedRectangle
private final Shape shape;
@Inject
public ShapeRequest(Shape shape) {
System.out.println("Attempting injection");
this.shape = shape;
}
public Shape getShape() {
return shape;
}
public void action(){
System.out.println(shape.getClass());
shape.draw();
}
}
Binding class (implements AbstractModule) is as follows:
@Override
protected void configure(){
bind(Shape.class).annotatedWith(AnnotatedRectangle.class).to(Rectangle.class);
bind(String.class).annotatedWith(Color.class).toInstance("GREEN");
}
To support the above, I have created an annotation:
@BindingAnnotation
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotatedRectangle {
}
Now in the client class:
Injector injector = Guice.createInjector(new AppModule());
ShapeRequest request=injector.getInstance(ShapeRequest.class);
Error:
Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors:
1) [Guice/MissingImplementation]: No implementation for Shape was bound.
Did you mean?
* Shape annotated with interface AnnotatedRectangle bound at AppModule.configure(AppModule.java:18)
Requested by:
1 : ShapeRequest.<init>(ShapeRequest.java:19)
\_ for 1st parameter
while locating ShapeRequest
What could be the issue here? I believe that I am explicitly specifying that a dependency of type Shape and annotation AnnotatedRectangle must be injected with an object of type Rectangle .
Put the @AnnotatedRectangle
annotation to the constructor's parameter, not in the field:
private final Shape shape;
@Inject
public ShapeRequest(@AnnotatedRectangle Shape shape) {
System.out.println("Attempting injection");
this.shape = shape;
}
If you use contructor injection all the "metadata" of the injection must go to the construction. Guice attempts either constructor injection or field injection. Not both.
Also, I would replace @BindingAnnotation
with @Qualifier
as the JSR standard. Also according to Guice:
Guice's @BindingAnnotation is also used for this purpose in older code.