Java EE 6 – CDI: Using InjectionPoint to resolve ambiguous dependencies at run-time

This is an advanced usage of the CDI specification of Java EE 6 that assumes the reader is already familiar with the Dependency Injection patterns provided by it.

The problem:

We have a service which is dependent of certain type of object to perform its actions. If we only have one implementation of the dependency, then we can use the regular injection methods to get a reference of it.

In our case, we need to find out which of the implementations the client of our service wants to be used. We would like this configuration to be made as easy as possible for the client, so we need to assure our dependency can be easily changed with minor modifications to the code.

  • First, we need to create an annotation to be able to allow the client to specify the type of the dependency that he would like to use. The following snippet of code shows an example of it:
    @Retention(RUNTIME)
    @Target({ TYPE, METHOD, FIELD, PARAMETER })
    public @interface DependentAnnotation {
        public Class<? extends DependencyType> type();
    }
  • Our dependency is specified by an interface which the implementations should extend:
    public interface DependencyType{
        public void performSomeAction(Object arg);
    }
  • These are sample implementations of our dependency interface:
    1. public class DependencyTypeImplOne implements DependencyType{
      
          @Inject
          public DependencyType() {
              // Constructs the object
              ...
          }
      
          public void performSomeAction(Object arg) {
              // Perform some action with arg
              ...
              System.out.println("One received argument: " + arg.toString());
          }
      }
    2. public class DependencyTypeImplTwo implements DependencyType{
      
          @Inject
          public DependencyType() {
              // Constructs the object
              ...
          }
      
          public void performSomeAction(Object arg) {
              // Perform some action with arg
              ...
              System.out.println("Two received argument: " + arg.toString());
          }
      }
  • And the following code shows how an implementation of the service would find out which of the implementations to use.
    public class Dependent {
    
        private DependencyType dependency;    
    
        @Inject
        public Dependent(@Any Instance‹DependencyType› depInstance,
                        InjectionPoint ip) {
            // Get the class passed in at injection point
            Annotated annotated = ip.getAnnotated();
            DependentAnnotation annotation = 
                 annotated.getAnnotation(DependentAnnotation.class);
            if (annotation == null) {
                 throw new RuntimeException("Needs to be annotated");
            }
            Class<? extends DependencyType> dependencyClass = 
                     annotation.type();
            /* 
            * Find the actual implementation at run-time
            * using the class passed in at injection point
            */
            dependency = depInstance.select(dependencyClass).get();
        }    
    
        public void someAction() {
            dependency.performSomeAction("pass some argument to it");
        }
     }
  • The next three options show how the service could be injected, so that it would be able to find the correct implementation of its dependency. That’s also how the client indicates which implementation he expects to be used as dependency for the service.
    1. Using field injection:
      @Inject 
      @DependentAnnotation(type = DependencyTypeImplOne.class)
      private Dependent dependentService;
    2. Using constructor injection:
      @Inject 
      public SomeClass(
         @DependentAnnotation(type = DependencyTypeImplOne.class)
         DependentService dependentService) {
          ...
      }
    3. Using setter injection:
      @Inject 
      public setDependentService(
          @DependentAnnotation(type = DependencyTypeImplOne.class) 
          DependentService dependentService) {
          ...
      }

    We can see from above that the only thing the client needs to do now to change the implementation used, would be to change the type given to the annotation. To use the second implementation he could for example write this:

    @DependentAnnotation(type = DependencyTypeImplTwo.class)
  • After obtaining a reference to it through injection, the only thing left for the client is to use it somewhere:
    public void someMethod() { 
        dependentService.someAction(); 
    }

The code snippets above were not tested and thus probably contain errors, but I hope they serve their purpose of illuminating the intended solution.

If you have any suggestions on how to solve the same problem in a better way, feel free to express yourself.

Find me on Google+

About Jonas Hartmann

A flying mind. I develop software that gives wings to human imagination.
This entry was posted in CDI, Java, Java EE 6, Technologien and tagged , , , , , , , , . Bookmark the permalink.

2 Responses to Java EE 6 – CDI: Using InjectionPoint to resolve ambiguous dependencies at run-time

  1. Gaurav says:

    Thank you. That was quick and easy.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s