1

I have a requirement to Inject the same instance of an ApplicationScoped bean into several places of my application and have created the following factory class which uses the @PostConstruct annotation to initialize the bean and the @Produces annotation to return the same instance of the bean.

@ApplicationScoped
public class CommandBusFactory implements Serializable {

    private static final long serialVersionUID = 1L;

    private CommandBus commandBus;

    @PostConstruct
    public void init() {
        commandBus = new BasicCommandBus();
        // Do some stuff to configure the command bus
    }

    @Produces
    public CommandBus produceCommandBus() {
        return commandBus;
    }

}

The problem I've got is when I deploy the application GlassFish returns the following error message:

Exception while loading the app : CDI deployment failure:WELD-001409 Ambiguous dependencies for type [CommandBus] with qualifiers [@Default] at injection point [[BackedAnnotatedField] @Inject private myapp.web.ToDoItemCommandController.commandBus]. Possible dependencies [[Producer Method [CommandBus] with qualifiers [@Any @Default] declared as [[BackedAnnotatedMethod] @Produces public myapp.core.cdi.CommandBusFactory.produceCommandBus()], Managed Bean [class myapp.core.commandhandling.BasicCommandBus] with qualifiers [@Any @Default]]]

I can overcome this exception by adding the @Alternative annotation to the BasicCommandBus class, however this doesn't seem to be the best way of solving the problem.

I don't want to add a qualifier everywhere that I inject CommandBus into my application as using a different implementation of CommandBus would require changing the code in multiple places. The intention is that a later version of the factory will read a configuration file and depending upon a value in the configuration file it may create a different type of CommandBus.

I have read the answer to this question (https://stackoverflow.com/a/18782027/1274662) and understand why the Ambiguous dependencies exception is being thrown but what I don't know is the best way to deal with the fact that there are two possible beans that could be injected given that I want to decide which implementation is used and how it is initialised in a central location.

The questions I've got are:

  1. Is using the @Alternative annotation on the BasicCommandBus class the right approach?

  2. Is there a better approach that I should be using to Inject the same instance of an ApplicationScoped bean (i.e. CommandBus) into several places of my application whilst controlling which implementation created (i.e. BasicCommandBus or EnhancedCommandBus) and how it is initialised in a central location?

Community
  • 1
  • 1
Paul H
  • 2,104
  • 7
  • 39
  • 53
  • Are you sure that your CommandBusFactory does not appear multiple times in your deployed application? Say both in the EAR/lib directory and a WAR/WEB-INF/lib directory? – Steve C Apr 05 '15 at 01:20

1 Answers1

3

If you want your bean to be injectable only by the producer you can annotate BasicCommandBus and EnhancedCommandBus with @Vetoed this way you'll not have the ambiguity between the bean it self and the producer method and at every injection point it's the producer that will inject the instance.

faissalb
  • 1,739
  • 1
  • 12
  • 14