WELD-001409 – Ambiguous dependencies


Weld/CDI resolves bean injection mainly based on type or name. This is sufficient for most cases and works like a charm. You can either specify a name yourself or inject it by simply letting CDI resolve the type for you. The following snippet shows how easy it is.


@Named("yourName")
public class SomeClass implements SomeInterface {
 //Your class implementation
}

public class YourImplementation {

 @Inject
 SomeInterface someClass;
 
 //Or
 @Inject
 @Named("yourName")
 SomeClass someClass;
}

Now in my case I had multiple classes that all implemented the same signature. Based on the name I wanted to inject one or another class. However, when letting CDI resolve the injection by type or name I got an error stating that the bean could not be injected because multiple options exist. The error message looked something like this:

org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type AuthorizationInterface with qualifiers @Default
  at injection point [BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] @Inject @Named public nl.janssen.my.class[SomeInterface]
  at nl.janssen.theClassInWhichYouTryTheInjection
  Possible dependencies: 
  - Managed Bean [ class nl.janssen.interfaceBasedClassOne] with qualifiers [@Default @Named @Any],
  - Managed Bean [ class nl.janssen.interfaceBasedClassTwo] with qualifiers [@Default @Named @Any],

It states that CDI cannot inject the class because it has more then one dependency. It cannot decide which one to pick. The solution is to create your own qualifiers. CDI already has some default qualifiers (default, any etc.) which you can see in the error but they are not sufficient in this case. You have to create a custom qualifier for each implementation of the interface that you want to inject. With these qualifiers you can tell CDI that you want inject a bean of type X and it has to have a qualifier y. By adding a custom qualifier to each interfaced object I can tell CDI to inject a specific class. A custom qualifier looks like this:

import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, PARAMETER})
public @interface One {
}

The @Target indicates the location in which you can use the qualifier. This qualifier you can use when injecting a parameter or a type.

Now you have to specify your implementations with the correct qualifiers:

import javax.enterprise.inject.Default;

//Interface implementation with the custom qualifiers

@One
public class SomeClassOne implements SomeInterface {
 //Your class implementation
}

@Two
@Default
public class SomeClassTwo implements SomeInterface {
 //Your class implementation
}


//Injection of the 
public class YourImplementation {

 @Inject
 @One
 SomeInterface classOne;

 @Inject
 @Two
 SomeInterface classTwo;
 
 @Inject
 SomeInterface classTwoIsDefault;


CDI will now resolve the correct implementation and no longer complain about ambiguous dependencies. When you do not provide a qualifier CDI will raise the same ambiguous error again. This because it doesn’t know which implementation is the default. You can specify this by adding the “@Default” annotation to one of your classes.

ActiveMQ connection pooling using Weld

Last week I, again, had to create a connection pool for a camel route that was sending messages to an ActiveMQ broker. This time I had to specify it in a project that uses Weld as an injection framework. I based my configuration on the ActiveMQ documentation.

The amount of connections and concurrent consumers is based on the standard documentation. The documentation states that you can easily set those numbers without any major impact. Increasing the amount is of course possible, it will however have impact on your memory usage. Before changing it make sure it is required for your application. I decided to go for the “standard” settings and change it whenever the application usage exceeds my expectations.

The documentation also states that a connectionFactory needs to be started and stopped for it to work correctly. Because I was using CDI I had to look for a solution to do this on startup / shutdown of the application. I found the “Initialized/Destroyed” annotations in combination with the “Observes” annotation. The “Observer” will make sure that the method is called whenever the the application scope is ether initialized or destroyed.


package nl.janssen.coolproject.mq;

import io.fabric8.annotations.ServiceName;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.camel.component.ActiveMQComponent;
import org.apache.activemq.jms.pool.PooledConnectionFactory;
import org.apache.camel.component.jms.JmsConfiguration;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Destroyed;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Produces;
import javax.inject.Named;

public class ActiveMQComponentFactory {

  public void init(@Observes @Initialized(ApplicationScoped.class) Object init, @Named("pooledConnectionFactory") PooledConnectionFactory pooledConnectionFactory){
    pooledConnectionFactory.start();
  }

  public void destroy(@Observes @Destroyed(ApplicationScoped.class) Object init, @Named("pooledConnectionFactory") PooledConnectionFactory pooledConnectionFactory){
    pooledConnectionFactory.stop();
  }

 @Produces
  @Named("connectionFactory")
  @ApplicationScoped
  public ActiveMQConnectionFactory jmsConnectionFactory(){
    ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
    factory.setUserName("admin");
    factory.setPassword("admin");

    return factory;
  }

  @Produces
  @Named("pooledConnectionFactory")
  @ApplicationScoped
  public PooledConnectionFactory createPooledConnectionFactory(@Named("connectionFactory") ActiveMQConnectionFactory factory){
    PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory();
    pooledConnectionFactory.setMaxConnections(8);
    pooledConnectionFactory.setConnectionFactory(factory);
    return pooledConnectionFactory;
  }

  @Produces
  @Named("jmsConfiguration")
  @ApplicationScoped
  public JmsConfiguration createJmsConfiguration(@Named("pooledConnectionFactory") PooledConnectionFactory pooledConnectionFactory){
    JmsConfiguration jmsConfiguration =  new JmsConfiguration();
    jmsConfiguration.setConnectionFactory(pooledConnectionFactory);
    jmsConfiguration.setConcurrentConsumers(10);
    return  jmsConfiguration;
  }

  @Produces
  @Named
  @Alias("jms")
  @ApplicationScoped
  public ActiveMQComponent createActiveMQComponent(@Named("jmsConfiguration") JmsConfiguration jmsConfiguration){
    ActiveMQComponent component = new ActiveMQComponent();
    component.setConfiguration(jmsConfiguration);
    return component;
  }

}

And of course to use the connection pool in your route you have to refer to the ActiveMQComponent. In my case I refered to the alias “jms”.


public class IndexerApi extends RouteBuilder {

  @Override
  public void configure() throws Exception {

    from("direct:somewhere")
        .to("jms:queue:randomQueueName")
  }
}

DeltaSpike with CDI and Camel

Last week I was looking for a easy way to inject property values into my code. In my project I was using Camel in combination with Weld (CDI). One of the main requirements was that properties could be injected from multiple “locations”. From a property file or a system / environment property.

Because we are using Openshift to run our applications it is easy to use environment variables to inject your configuration. I did not want to write my own code to resolve the properties so I started looking. Eventually I found DeltaSpike, with DeltaSpike you can easily inject properties in your code and it works seamlessly with CDI.

You can inject properties from the following four locations:

  • System properties (ordinal = 400)
  • Environment properties (ordinal = 300)
  • JNDI values (ordinal = 200, the base name is “java:comp/env/deltaspike/”)
  • Properties file values (apache-deltaspike.properties) (ordinal = 100, default filename is “META-INF/apache-deltaspike.properties”)

When the same property is configured in two or more locations the value of the highest ordinal is used. So System properties will overwrite any configuration done in the property file.

Because I did not want to use the default property filename I implemented the following class in order to load my own property file:


import org.apache.deltaspike.core.api.config.PropertyFileConfig;

import javax.inject.Named;

@Named
public class MyCustomPropertyConfig implements PropertyFileConfig {

    @Override public String getPropertyFileName() {
      return "badasspropertyFile.properties";
    }

    @Override public boolean isOptional() {
      return true;
    }
}

There are three ways to load a property in your class.

  • ConfigResolver methods for easy programmatic access to values
  • TypedResolver API for typed configuration values and precise control over resolution
  • @ConfigProperty for injection of configured values into beans
  • interface based configuration

When using DeltaSpike in combination with CDI you can inject property values in a similar way you are used to when injecting beans. For this you can use the “@ConfigProperty” annotation:


@Inject
@ConfigProperty(name = "loglevel", defaultValue = "INFO")
  private String logLevel;

Alternative class in Weld

In a Camel project with Weld I faced an issue while trying to unit test a route that called a remote system (Elasticsearch). This was done with the help of a custom bean. The bean handles the connection and the actual calls to the system. I did not want to call the actual system during my Unit Test, so I created a stub. However, to create the context and start the route I used CamelCdiRunner. This meant that the original client bean was being loaded. So I had to replace the actual bean with my stub. Luckily Weld supports the use of alternative beans. In essence you can replace a bean with an alternative, in my case a stub.

The first thing you need to do is to make sure that your class is based on a interface. This enables Weld to successfully replace your bean with a alternative. Inject the bean based on the interface and not on the class itself.

@Inject
@Named("elasticsearchCamelClient")
ElasticsearchCamelClientInterface client;

Next create your mock and make sure that it implements the interface of the bean you want to replace. Add the Alternative annotation.

@Alternative
@Named("elasticsearchCamelClient")
public class MockElasticsearchCamelClient implements ElasticsearchCamelClientInterface {

  public MockElasticsearchCamelClient() {
  }

  Stub code.....

Most of the documentation I found shows you how to use an alternative bean using the beans.xml file. However it is not possible to simply add a beans.xml file to the test resources. You can only specify one for your project. You could replace it dynamically with your build tool. This however is, imho, not a nice solution. Luckily you can also specify an alternative class in your test class. By adding the “@Beans” annotation. This allows you to specify one or more alternative beans.

@RunWith(CamelCdiRunner.class)
@Beans(
  alternatives = {MockElasticsearchCamelClient.class}
)
public class RouteTest { ...

The alternatives indicates that you want to run the CamelCdiRunner with the stub. When you now start the Unit Test you will see that both beans are being loaded but that the mock is used to run your tests.

Happy testing!