My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

joi, 2 iunie 2016

CDI-JSF: Avoid common mistakes that causes ambiguous dependencies errors

After you start using CDI, sooner or later, you will get an error of type: "Ambiguous dependencies for type...". Without too many words, this errors means that CDI should inject a bean into another bean, but it cannot decide what bean to inject.

In CDI, a bean can have multiple beans types (user-defined class or interface) - is important to keep this in mind. For example:

public class Foo extends Buzz implements Bizz {
   ...
}

The bean types are: Foo, Buzz,  Bizz and java.lang.Object.

 If you never saw this error before then probably you are in one of the two most common scenarios from below:

·         a bean type doesn't provide enough information to the container to point out that it should be injected
·         you have multiple beans that "share" bean types, so the container cannot determine the bean type that you are referring

Multiple implementations of the same interface
One of the most common mistakes that result in an ambiguity case consist in injecting an interface that has multiple implementations. For example, let's suppose that you have an interface named FooI:

public interface FooI {
 public void fooify();
}

Furthermore, we have a simple implementation of this interface named Foo1:

public class Foo1 implements FooI {  

 @Override
 public void fooify() {
  ...
 }
}

Now, we can easily inject the Foo1 bean into another bean like this:

@Inject
private FooI foo;

Further, let's suppose that we write another implementation of FooI named, Foo2:

public class Foo2 implements FooI {  

 @Override
 public void fooify() {
  ...
 }
}

At this point, you will see an "Ambiguous dependencies for type..." error. This is happening because the container cannot determine if you want to inject the Foo1 bean or the Foo2 bean.

You can easily solve this problem (and similar problems) via CDI qualifiers. Basically, a qualifier is a user-defined annotation that is itself annotated with @Qualifier. For example, we can write a qualifier like below:

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

The next thing to do is to annotate the desired bean with this qualifier. For example, let's annotate the Foo1 bean:

@F1
public class Foo1 implements FooI {
 ...
}

Once we have done this the application works again, but pay attention that the container will inject an instance of Foo2 bean, NOT Foo1 bean. This is happening because we did not used our qualifier at the injection point! So, if we want to inject an instance of Foo1, we need to do this:

@Inject @F1
private FooI foo;

Now, we can easily inject an instance of Foo1  and Foo2 in the same bean:

@Inject @F1
private FooI foo1;
   
@Inject
private FooI foo2;

Done! The complete application is available here.

Ambiguous dependencies caused by extension
Furthermore, let's see another common case that causes an ambiguous dependency error. For example, let's suppose that we have a simple bean Foo:

public class Foo {
 ...
}

Now, we know that this can be easily injected as:

@Inject
private Foo foo;

Later, in development stage, you extend this bean like this:

public class Buzz extends Foo {
 ...
}

Suddenly the application stop working! Again, you can notice an "Ambiguous dependencies for type..." error. The problem is that our Foo bean has the bean types Foo and java.lang.Object, while the Buzz bean has the Foo, Buzz and java.lang.Object bean types. Even if we can successfully use @Inject Buzz buzz, we cannot use @Inject Foo foo. In first case (@Inject Buzz buzz) the container can uniquely identify the Buzz bean, while in the second case (@Inject Foo foo) the container observe that the Foo and Buzz beans have in common the bean type Foo, and it doesn't know what to inject, a Foo or the Buzz instance. And this is the cause of the ambiguity.

We can solve this problem using a qualifier as in the previous case, or we can use the @Typed annotation. This annotation allows us to restrict the bean types to an explicit set of classes. For example, we can instruct the container that the Buzz bean has the bean type Buzz, BUT not Foo:

@Typed(Buzz.class)
public class Buzz extends Foo {
 ...
}

Now, the container knows that you want to inject an instance of Foo bean.

The complete application is available here.

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors