Mastering Java EE Development with WildFly
上QQ阅读APP看书,第一时间看更新

Enabled and disabled beans

In WildFly, injection is enabled by the XML descriptor. For example if you are in a web application, you deploy web.xml, and in EJB, ejb-jar.xml. Considering that these descriptors are now optional, the same thing is not true for the CDI. If you don’t deploy an almost empty XML descriptor, CDI doesn’t work because the CDI engine is not started. For a simple CDI injection you must also deploy the standard beans descriptor, the beans.xml. Here is an empty sample of beans.xml that lets the CDI engine to start:

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" bean-discovery-mode="all">
</beans>

The bean-discovery-mode tag lets us identify implicit and explicit archives. An implicit archive defining as annotation tells that only the annotated classes will manage beans. When we said earlier that all POJO is a managed bean, that is because the all value is used. The all value identifies an explicit archive, so the not annotated classes will also be managed beans. The none value will not accept the annotated beans but only beans declared in the XML descriptor.

A bean is said to be enabled if:

  • It is deployed in a bean archive
  • It is not a producer method or field of a disabled bean
  • It is not specialized for any other enabled bean, and either
  • It is not an alternative, or it is a selected alternative of at least one bean archive

Let's now see an alternative bean.

Here's a simple bean interface:

public interface Coder {
String codeString(String s, int tval);
Bean<Coder> getBean();
}

And here is its implementation:

public class CoderImpl implements Coder {
@Override
public String codeString(String s, int tval) {
return "hi";
}
@Override
public Bean<Coder> getBean() {
return null;
}
}

We can inject the Coder in any bean through the following code:

@Inject
private Coder coder;

Executing the codeString method:

coder.codeString("Hello", 3);

We get hi.

Presuming we don’t want this implementation, we can write an alternative implementation:

@Alternative
public class CoderBrutalImpl implements Coder {
@Override
public String codeString(String s, int tval) {
return "hiiiiiiiii";
}
@Override
public Bean<Coder> getBean() {
return null;
}
}

We want to ensure that when the codeString method is executed, this new implementation is executed. To do this, we need to add the script in beans.xml:

<alternatives>
<class> it.vige.businesscomponents.injection.alternative.CoderBrutalImpl
</class>
</alternatives>

Now we will view as a result the value hiiiiiiiii.

To an alternative bean (and only to it), the @Specializes annotation can be added.

@Specializes indicates that a bean directly specializes another bean. This may be applied to a bean class or producer method. If a bean directly specializes a second bean, it inherits:

  • All qualifiers of the second bean
  • The name, if any, of the second bean

To use it, we need to modify CoderBrutalImpl:

@Specializes
@Alternative
public class CoderBrutalImpl extends CoderImpl

And add some annotation to the CoderImpl class. For example:

@Named
public class CoderImpl implements Coder...

The specialized class using the @Specializes annotation needs to extend another class so it can inherit its properties.

Now execute this code:

@Inject
private BeanManager beanManager;
...
Bean<?> bean = beanManager.getBeans(CoderBrutalImpl.class).iterator().next();
bean.getQualifiers();

We will see that this class has imported the qualifier @Named. In the next section, we will see this annotation in detail.

Another good annotation is @Stereotype.

The @Stereotype establishes a role for the annotated beans. It can contain other annotations to define a set of achievements.

Here is a @Stereotype annotation sample:

@Stereotype
@Alternative
@Audit
@Logging
@Retention(RUNTIME)
@Target(TYPE)
public @interface ServiceStereotype {
}

In an alternative use, bean is very useful to switch according to the used annotation instead of the class as seen before. We can have two different beans annotated with two different stereotypes and switch, thanks to the beans.xml that annotated beans use:

   <alternatives>
<stereotype> it.vige.businesscomponents.injection.alternative.stereotype.ServiceStereotype
</stereotype>
</alternatives>

CDI 1.1 introduces a new annotation to disable beans so that they cannot be injectable. It is @Vetoed. This annotation was done for the first time in the Seam project called @Veto. Now it is introduced in Java EE 7.

@Vetoed can hide a class by the injection, a method with a simple annotation, or even a whole package. See now how to hide a package.

Create two simple beans in the package it.vige.businesscomponents.injection.inject.veto:

public class MockBean {
}
public class TestBean {
}

Now, in the same package, add the package-info.java package descriptor:

@Vetoed
package it.vige.businesscomponents.injection.inject.veto;
import javax.enterprise.inject.Vetoed;

Now try a manual injection through the beanManager:

beanManager.getBeans(MockBean.class).iterator().next();
beanManager.getBeans(TestBean.class).iterator().next();

Both the invocations will fail, throwing a NoSuchElementException!

If you need the objects for injection, simply delete package-info.java from the package.