Vulpo Vulpo - 3 months ago 17
Java Question

CDI Inject Ambiguous Dependency "pick any, i don't care"

One of my classes has an attribute declared with the @EJB annotation.
Two beans are eligible, so I get a nice

org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies
.

I know this can be resolved with qualifiers. But that would make me select one EJB implementation over the other. But I don't really care which one is used. Is there a simple way to tell CDI "Pick any of the two eligible implementations, I don't care and both are fine" ?

Answer

... a simple way to tell CDI "Pick any of the two eligible implementations, I don't care and both are fine"

No there is not. That would be against what CDI tries to achieve. Here is a peak at why is that...

One case might be that your beans are for instance session beans. In such case, having two fitting beans for that injection points doesn't mean that both of them even exist within that given moment you request them. Needless to say they might not carry the data/state you expect them to have.

Another reason is that CDI has an underlying proxy system - each @Injected bean is in fact the proxy object of that bean. To avoid weird NPEs and exceptions during runtime, CDI needs to know, at boot time, what will be the one fitting bean for your injection point.

Another point might be the different lifecycle management of beans you could inject. That would yield you even weirder runtime errors.

Last but not least, imagine your app growing bigger. Someone adds third implementation of the type you are injection and that one is not fine for what you want to achieve. What would happen then?

That would be it from the top of my head. As for the way to go, you can use Instance<MyBean> or resolution via BeanManager. Below is a snippet with Instance which is probably a better way.

@Inject
private Instance<Foo> foo;

public void doStuff() {
  foo.isAmbiguous(); //you can check if there are more beans eligible for injection here
  foo.isResolvable(); //yet another useful check you might want

  // there are multiple selects you can use - based on type, annotation or both
  //select based on annotation (parameter is annotation INSTANCE), with this you require a Foo type with @Default qualifier
  foo.select(Default.Literal.INSTANCE).get();

  //select based on requested type, here you are asking for a Foo bean which also has a type MyType (implements interface or extends class with that type for instance)
  foo.select(MyType.class).get(); 

  // combined - type and annotation
  foo.select(MyType.class, Default.Literal.INSTANCE).get();
}

NOTE: When working with Instance<X> the method get() is what does the actual resolution and gives you the resulting bean.

Comments