Java EE CDI dependency disambiguation example

01 June 2013
By Gonçalo Marques
In this tutorial you will learn how to inject multiple interface implementations with Java EE CDI (dependency disambiguation) avoiding org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [...] with qualifiers [...] at injection point [...]

Introduction

In Java EE CDI it is possible to provide multiple implementations of a given interface - or service - to the service clients. The client should then be responsible for selecting the desired service implementation to be injected into a given injection point. In this tutorial we will see how to achieve this behaviour in detail.

This tutorial considers the following environment:

  1. JDK 1.7.0.21
  2. Weld 1.1.10

Weld is the CDI reference implementation


Note: When we provide multiple interface implementations with CDI and we don't specifically define any dependency disambiguation, the container will complain stating that it can not determine which implementation to inject at a given injection point.

Example exception:
org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [...] with qualifiers [...] at injection point [...]. Possible dependencies [...] with qualifiers [...], Managed Bean [...] with qualifiers [...]

The service

We start by defining a simple interface and a couple of interface implementations to serve as an example in this tutorial:

The interface

package com.byteslounge.service;

public interface NotificationService {

  void sendNotification();

}


EmailNotificationService implementation

package com.byteslounge.service.impl;

import com.byteslounge.service.NotificationService;

public class EmailNotificationService implements NotificationService {

  @Override
  public void sendNotification() {
    System.out.println("Sending email notification");
  }

}


SmsNotificationService implementation

package com.byteslounge.service.impl;

import com.byteslounge.service.NotificationService;

public class SmsNotificationService implements NotificationService {

  @Override
  public void sendNotification() {
    System.out.println("Sending SMS notification");
  }
	
}

What happens now when we inject the NotificationService bean?

NotificationService injection

@Inject
private NotificationService notificationService;

The container will not know which of the available implementations should be injected and will complain about it. We will see how to do dependency disambiguation in the next section.

Dependency disambiguation

One of the mechanisms provided by CDI to do dependency disambiguation is Qualifiers. Qualifiers are defined as Java annotations and are used by CDI to specify which dependency should be injected at a given injection point.

Let's define a Qualifier to be used in our NotificationService:

CDI qualifier

package com.byteslounge.service;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface NotificationServiceType {

  ServiceType value();
	
  public enum ServiceType{
    EMAIL, SMS;
  }

}

We defined a Java annotation that will be used to disambiguate between EmailNotificationService and SmsNotificationService service implementations. Also note that for convenience we defined an Enum which will be used as the value of our qualifier: EMAIL or SMS.

Now we go back to the service implementations and use the Qualifier annotation we just defined:

EmailNotificationService implementation

package com.byteslounge.service.impl;

import com.byteslounge.service.NotificationService;
import com.byteslounge.service.NotificationServiceType;
import com.byteslounge.service.NotificationServiceType.ServiceType;

@NotificationServiceType(ServiceType.EMAIL)
public class EmailNotificationService implements NotificationService {

  @Override
  public void sendNotification() {
    System.out.println("Sending email notification");
  }

}


SmsNotificationService implementation

package com.byteslounge.service.impl;

import com.byteslounge.service.NotificationService;
import com.byteslounge.service.NotificationServiceType;
import com.byteslounge.service.NotificationServiceType.ServiceType;

@NotificationServiceType(ServiceType.SMS)
public class SmsNotificationService implements NotificationService {

  @Override
  public void sendNotification() {
    System.out.println("Sending SMS notification");
  }
	
}

As you can see we used the Qualifier in each service implementation - @NotificationServiceType - where the value is EMAIL or SMS respectively.

Now when we inject the service we also use the Qualifier in order to specify which service implementation should be used:

NotificationService injection

@Inject
@NotificationServiceType(ServiceType.EMAIL)
private NotificationService notificationService;

By annotating the injection point with @NotificationServiceType(ServiceType.EMAIL) we will make possible for the container to know that it should inject the EmailNotificationService service implementation.

Dependency disambiguation in CDI Producer methods

It is also possible to do dependency disambiguation in CDI Producer methods. Please see Java EE CDI Producer methods tutorial.

Downloadable sample

You can find a downloadable sample at the end of this page showing CDI dependency disambiguation in action. The sample is configured to be run on Tomcat and the service is injected into a testing servlet.

Download source code from this article

Related Articles

Comments

About the author
Gonçalo Marques is a Software Engineer with several years of experience in software development and architecture definition. During this period his main focus was delivering software solutions in banking, telecommunications and governmental areas. He created the Bytes Lounge website with one ultimate goal: share his knowledge with the software development community. His main area of expertise is Java and open source.

GitHub profile: https://github.com/gonmarques

He is also the author of the WiFi File Browser Android application: