javadependency-injectionguicedropwizard-guice

[Guice/MissingImplementation]: No implementation was bound


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 .


Solution

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