Announcement Announcement Module
Collapse
No announcement yet.
DI with Provider and Qualified interface implementations Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • DI with Provider and Qualified interface implementations

    When using the JSR 330 annotations, I came across the following use case: we have two different implementations of the same interface that are used interchangeably depending on the deployment environment.

    In order to implement this, we would like to use the Provider interface that knows which classes to use depending on a @Qualifier. It would be great if, someone could tell me how to make a provider of a certain type take precedence over an implementation of that same type. In other words: Provider<MyInterface> should take precedence over MyImplementation implements MyInterface when being injected as a dependency.

    For simplicity, I will use an example with a project stage qualifier that should model the well-known deployment-time differences (e.g. development, staging, production):

    Code:
    @Target( {ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface ProjectStage {
    
    	public enum Stage {
    		DEV,
    		PROD
    	}
    
    	Stage value() default Stage.PROD;
    }
    We can now annotate the two interfaces accordingly

    Code:
    @Repository
    @ProjectStage(Stage.DEV)
    public class MockRepository implements ContentRepository { ... }
    
    @Repository
    @ProjectStage(Stage.PROD)
    public class LegacyRepository implements ContentRepository { ... }
    Implementation of the Provider is straightforward and could even be generalized a little more

    Code:
    @Component
    public class RepositoryProvider implements Provider<ContentRepository> {
    
    	@Inject
    	@ProjectStage(Stage.PROD)
    	private ContentRepository production;
    
    	@Inject
    	@ProjectStage(Stage.DEV)
    	private ContentRepository development;
    
    	@Override
    	public ContentRepository get() {
    		String stage = System.getProperty("project.stage");
    		ContentRepository cs = selectRepository(stage); // omitting this
    		return cs;
    	}
    
    }
    The problem is now that injection into a consumer of the ContentRepository does not work, because more than one bean implementing this interface is defined.

    Code:
    public class RepositoryConsumer {
    
    	@Inject
    	ContentRepository repos; // ambiguous
    
    	...
    }
    Is there a way (except injecting Provider<ContentRepository>) to tell the IoC container that a provider should take precedence over other implementations of ContentRepository?

    I have tried putting a name on the provider implementation and add a corresponding @Named on the field injected in the consumer, but the lookup did not work with the Spring 3.0.0.RELEASE.

    Thank you very much for any pointers or even arguments why I should not do it this way.


    Cheers,
    Kariem
Working...
X