SeamFramework.orgCommunity Documentation
We've already seen how the Web Beans dependency injection model lets
us override the implementation of an API at deployment
time. For example, the following enterprise Web Bean provides an implementation
of the API PaymentProcessor
in production:
@CreditCard @Stateless
public class CreditCardPaymentProcessor
implements PaymentProcessor {
...
}
But in our staging environment, we override that implementation of
PaymentProcessor
with a different Web Bean:
@CreditCard @Stateless @Staging
public class StagingCreditCardPaymentProcessor
implements PaymentProcessor {
...
}
What we've tried to do with StagingCreditCardPaymentProcessor
is to completely replace AsyncPaymentProcessor
in a particular
deployment of the system. In that deployment, the deployment type @Staging
would have a higher priority than the default deployment type @Production
,
and therefore clients with the following injection point:
@CreditCard PaymentProcessor ccpp
Would receive an instance of StagingCreditCardPaymentProcessor
.
Unfortunately, there are several traps we can easily fall into:
the higher-priority Web Bean may not implement all the API types of the Web Bean that it attempts to override,
the higher-priority Web Bean may not declare all the binding types of the Web Bean that it attempts to override,
the higher-priority Web Bean might not have the same name as the Web Bean that it attempts to override, or
the Web Bean that it attempts to override might declare a producer method, disposal method or observer method.
In each of these cases, the Web Bean that we tried to override could still be called at runtime. Therefore, overriding is somewhat prone to developer error.
Web Beans provides a special feature, called specialization, that helps the developer avoid these traps. Specialization looks a little esoteric at first, but it's easy to use in practice, and you'll really appreciate the extra security it provides.
Specialization is a feature that is specific to simple and enterprise Web Beans. To make use of specialization, the higher-priority Web Bean must:
be a direct subclass of the Web Bean it overrides, and
be a simple Web Bean if the Web Bean it overrides is a simple Web Bean or an enterprise Web Bean if the Web Bean it overrides is an enterprise Web Bean, and
be annotated @Specializes
.
@Stateless @Staging @Specializes
public class StagingCreditCardPaymentProcessor
extends CreditCardPaymentProcessor {
...
}
We say that the higher-priority Web Bean specializes its superclass.
When specialization is used:
the binding types of the superclass are automatically inherited by the
Web Bean annotated @Specializes
, and
the Web Bean name of the superclass is automatically inherited by the
Web Bean annotated @Specializes
, and
producer methods, disposal methods and observer methods declared by the
superclass are called upon an instance of the Web Bean annotated
@Specializes
.
In our example, the binding type @CreditCard
of
CreditCardPaymentProcessor
is inherited by
StagingCreditCardPaymentProcessor
.
Furthermore, the Web Bean manager will validate that:
all API types of the superclass are API types of the Web Bean
annotated @Specializes
(all local interfaces
of the superclass enterprise bean are also local interfaces of the
subclass),
the deployment type of the Web Bean annotated
@Specializes
has a higher precedence than the
deployment type of the superclass, and
there is no other enabled Web Bean that also specializes the superclass.
If any of these conditions are violated, the Web Bean manager throws an exception at initialization time.
Therefore, we can be certain that the superclass with never
be called in any deployment of the system where the Web Bean annotated
@Specializes
is deployed and enabled.