Skip to content

Commit

Permalink
fallout from reorg
Browse files Browse the repository at this point in the history
  • Loading branch information
Gavin King committed Nov 10, 2009
1 parent 173d38a commit 0eb7c9d
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 51 deletions.
41 changes: 39 additions & 2 deletions reference/en-US/injection.xml
Expand Up @@ -315,14 +315,51 @@ public @interface PayBy {
<programlisting role="JAVA"><![CDATA[@Synchronous @Reliable
public class SynchronousReliablePaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}]]></programlisting>
}]]></programlisting>

</section>

</section>

<section id="alternatives">
<title>Alternatives</title>

<para>Alternatives are beans whose implementation is specific to a particular client module or deployment
scenario. This alternative defines a mock implementation of both <literal>@Synchronous PaymentProcessor</literal>
and <literal>@Asynchronous PaymentProcessor</literal>, all in one:</para>

<programlisting role="JAVA"><![CDATA[@Alternative @Synchronous @Asynchronous
public class MockPaymentProcessor implements PaymentProcessor {
public void process(Payment payment) { ... }
}]]></programlisting>

<para>
By default, <literal>@Alternative</literal> beans are disabled. We need to <emphasis>enable</emphasis> an
alternative in the <literal>beans.xml</literal> descriptor of a bean archive to make it available for
instantiation and injection. This activation only applies to the beans in that archive.
</para>

<programlisting role="XML"><![CDATA[<beans
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>org.mycompany.mock.MockPaymentProcessor</class>
</alternatives>
</beans>]]></programlisting>

<para>
When an ambiguous dependency exists at an injection point, the container attempts to resolve the ambiguity
by looking for an enabled alternative among the beans that could be injected. If there is exactly one
enabled alternative, that's the bean that will be injected.
</para>

</section>

<section>
<title>Fixing unsatisfied dependencies</title>
<title>Fixing unsatisfied and ambiguous dependencies</title>

<para>
The typesafe resolution algorithm fails when, after considering the qualifier annotations on all beans that
Expand Down
92 changes: 43 additions & 49 deletions reference/en-US/specialization.xml
Expand Up @@ -47,68 +47,53 @@
alternatives and then show the guarantees that specialization adds.
</para>

<section id="alternatives">
<title>Alternatives</title>
<section id="alternativestereotypes">
<title>Using alternative stereotypes</title>

<para>
CDI lets you <emphasis>override</emphasis> the implementation of a bean type at deployment time using an
alternative. For example, the following bean provides an implementation of the
<literal>PaymentProcessor</literal> bean type in the default environment:
alternative. For example, the following bean provides a default implementation of the
<literal>PaymentProcessor</literal> interface:
</para>

<programlisting role="JAVA"><![CDATA[@CreditCard
public class CreditCardPaymentProcessor
<programlisting role="JAVA"><![CDATA[public class DefaultPaymentProcessor
implements PaymentProcessor {
...
}]]></programlisting>

<para>
But in our staging environment, we override that implementation of <literal>PaymentProcessor</literal> with a
different bean:
But in our staging environment, we don't really want to submit payments to the external system, so we override
that implementation of <literal>PaymentProcessor</literal> with a different bean:
</para>

<programlisting role="JAVA"><![CDATA[@CreditCard @Alternative
public class StagingCreditCardPaymentProcessor
<programlisting role="JAVA"><![CDATA[public @Alternative
class StagingPaymentProcessor
implements PaymentProcessor {
...
}]]></programlisting>

<para>or</para>

<programlisting role="JAVA"><![CDATA[@CreditCard @Alternative
public class StagingCreditCardPaymentProcessor
extends CreditCardPaymentProcessor {
<programlisting role="JAVA"><![CDATA[public @Alternative
class StagingPaymentProcessor
extends DefaultPaymentProcessor {
...
}]]></programlisting>

<para>
By default, <literal>@Alternative</literal> beans are disabled. We need to <emphasis>enable</emphasis> the
alternative&#8212;effectively replacing the bean implementation without the <literal>@Alternative</literal>
annotation&#8212;in the <literal>beans.xml</literal> descriptor of a bean archive by specifying the bean
class (or the class that contains the alternative producer method or field). This activation only applies
to the beans in that archive.
We've already seen how we can enable this alternative by listing its class in the <literal>beans.xml</literal>
descriptor.
</para>

<programlisting role="XML"><![CDATA[<beans
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>org.mycompany.myapp.StagingCreditCardProcessor</class>
</alternatives>
</beans>]]></programlisting>

<para>
Of course, if the goal is to enable all the alternatives for the staging environment, it would make much more
sense to make <literal>@Staging</literal> an <literal>@Alternative</literal> stereotype and annotate the
staging beans with this stereotype instead. You'll see how this level of indirection pays off. First, we create
the stereotype:
But suppose we have many alternatives in the staging environment. It would be much more convenient to be able
to enable them all at once. So let's make <literal>@Staging</literal> an <literal>@Alternative</literal> stereotype
and annotate the staging beans with this stereotype instead. You'll see how this level of indirection pays off.
First, we create the stereotype:
</para>

<programlisting role="JAVA"><![CDATA[@Stereotype
@Alternative
<programlisting role="JAVA"><![CDATA[@Alternative
@Stereotype
@Retention(RUNTIME)
@Target(TYPE)
public @interface Staging {}]]></programlisting>
Expand All @@ -117,14 +102,14 @@ public @interface Staging {}]]></programlisting>
Then we replace the <literal>@Alternative</literal> annotation on our bean with <literal>@Staging</literal>:
</para>

<programlisting role="JAVA"><![CDATA[@CreditCard @Staging
public class StagingCreditCardPaymentProcessor
extends CreditCardPaymentProcessor {
<programlisting role="JAVA"><![CDATA[@Staging
public class StagingPaymentProcessor
implements PaymentProcessor {
...
}]]></programlisting>

<para>
Finally, we activate the <literal>@Staging</literal> stereotype in the beans.xml descriptor:
Finally, we activate the <literal>@Staging</literal> stereotype in the <literal>beans.xml</literal> descriptor:
</para>

<programlisting role="XML"><![CDATA[<beans
Expand All @@ -139,27 +124,36 @@ public class StagingCreditCardPaymentProcessor
</beans>]]></programlisting>

<para>
Now, no matter how many staging beans we have, they will all be enabled at once. Does that mean the default
implementation is disabled? Well, not exactly. If the default implementation has a qualifier, for instance
<literal>@LargeTransaction</literal>, and the alternative does not, you could still inject the default
implementation.
Now, no matter how many staging beans we have, they will all be enabled at once.
</para>

</section>

<section>
<title>A minor problem with alternatives</title>

<para>
When we enable an alternative, does that mean the default implementation is disabled? Well, not exactly. If the
default implementation has a qualifier, for instance <literal>@LargeTransaction</literal>, and the alternative
does not, you could still inject the default implementation.
</para>

<programlisting role="JAVA"><![CDATA[@LargeTransaction @CreditCard PaymentProcessor paymentProcessor;]]></programlisting>
<programlisting role="JAVA"><![CDATA[@Inject @LargeTransaction PaymentProcessor paymentProcessor;]]></programlisting>

<para>
So we haven't completely replaced the default implementation in this deployment of the system. The only
way one bean can completely override a second bean at all injection points is if it implements all the bean
types and declares all the qualifiers of the second bean. However, if the second bean declares a producer
method or observer method, then even this is not enough to ensure that the second bean is never called! We need
something extra.
So we haven't completely replaced the default implementation in this deployment of the system. The only way one
bean can completely override a second bean at all injection points is if it implements all the bean types and
declares all the qualifiers of the second bean. However, if the second bean declares a producer method or
observer method, then even this is not enough to ensure that the second bean is never called! We need something
extra.
</para>

<para>
CDI provides a special feature, called <emphasis>specialization</emphasis>, that helps the developer avoid
these traps. Specialization is a way of informing the system of your intent to completely replace and disable
an implementation of a bean.
</para>

</section>

<section>
Expand Down

0 comments on commit 0eb7c9d

Please sign in to comment.