Help

/This is the second installment of a series of articles describing the current status of the Web Beans specification. You can find the first installment here./

Web Beans supports three primary mechanisms for dependency injection:

Direct field injection:

@Component
public class Checkout {

    @In ShoppingCart cart;
    
}

Method injection:

@Component
public class Checkout {
        
    private ShoppingCart cart;

    @In void setShoppingCart(ShoppingCart cart) {
        this.cart = cart;
    }
    
}

And constructor injection:

@Component
public class Checkout {
        
    private final ShoppingCart cart;

    public Checkout(ShoppingCart cart) {
        this.cart = cart;
    }

}

In addition, resolver methods support parameter injection:

@Resolves Checkout createCheckout(ShoppingCart cart) {
    return new Checkout(cart);
}

Dependency injection always occurs when the component instance is first instantiated.

The Web Beans specification defines a procedure, called the /typesafe resolution algorithm/, that the Web Beans container follows when identifying the component to inject to an injection point. This algorithm looks complex at first, but once you understand it, it's really quite intuitive. Typesafe resolution is performed at system initialization time, which means that the container will inform the user immediately if a component's dependencies cannot be satisfied.

The purpose of this algorithm is to allow multiple components to implement the same API type and either:

  • allow the client to select which implementation it requires using /binding annotations/, or
  • allow one implementation of an API to override another implementation of the same API at deployment time, without changes to the client, using /component type precedence/.

Let's explore how the Web Beans container determines a component to be injected.

Binding annotations

If we have more than one component that implements a particular API type, the injection point can specify exactly which component should be injected using a binding annotation. For example, there might be two implementations of PaymentProcessor:

@Component @PayByCheque
public class ChequePaymentProcessor implements PaymentProcessor {
    public void process(Payment payment) { ... }
}

@Component @PayByCreditCard
public class CreditCardPaymentProcessor implements PaymentProcessor {
    public void process(Payment payment) { ... }
}

Where @PayByCheque and @PayByCreditCard are binding annotations:

@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD})
@BindingType
public @interface PayByCheque {}
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD})
@BindingType
public @interface PayByCreditCard {}

A client component developer uses the binding annotation to specify exactly which component should be injected:

@In @PayByCheque PaymentProcessor chequePaymentProcessor;
@In @PayByCreditCard PaymentProcessor creditCardPaymentProcessor;

Equivalently, using constructor injection:

public Checkout(@PayByCheque PaymentProcessor chequePaymentProcessor, 
                 @PayByCreditCard PaymentProcessor creditCardPaymentProcessor) {
   this.chequePaymentProcessor = chequePaymentProcessor;
   this.creditCardPaymentProcessor = creditCardPaymentProcessor;
}

Binding annotations with members

Binding annotations may have members:

@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD})
@BindingType
public @interface PayBy {
    PaymentType value();
}

In which case, the member value is significant:

@In @PayBy(CHEQUE) PaymentProcessor chequePaymentProcessor;
@In @PayBy(CREDIT_CARD) PaymentProcessor creditCardPaymentProcessor;

Combinations of binding annnotations

An injection point may even specify multiple binding annotations:

@In @Asynchronous @PayByCheque paymentProcessor

In this case, only a component which supports /both/ binding annotation would be eligable for injection.

Binding annotations and resolver methods

Of course, even resolver methods may specify binding annotations:

@Resolves 
@Asynchronous @PayByCheque 
PaymentProcessorService createAsyncPaymentProcessor(@PayByCheque PaymentProcessor processor) {
    return new AsynchronousPaymentProcessorService(processor);
}

This method would be called to create an instance for injection to the following injection point:

@In @Asynchronous @PayByCheque PaymentProcessorService service;

Component types

All Web Bean components have a /component type/. Each component type identifies a set of components that should be conditionally installed in some deployments of the system.

For example, we could define a component type named @Mock, which would identify components that should only be installed when the system executes inside an integration testing environment:

@Retention(RUNTIME)
@Target({TYPE, METHOD})
@ComponentType
public @interface Mock {}

Suppose we had some component that interacted with an external system to process payments:

@Component
public class PaymentProcessor {
        
    public void process(Payment p) {
        ...
    }
    
}

For integration or unit testing, the external system is slow or unavailable. So we would create a mock object:

@Mock 
public class MockPaymentProcessor extends PaymentProcessor {

    @Override
    public void process(Payment p) {
        p.setSuccessful(true);
    }

}

Installing component types

Web Beans defines two built-in component types: @Component and @Standard. By default, only components with the built-in component types are installed when the system is deployed. We can identify additional component types to be installed in a particular deployment by listing them in web-beans.xml.

Going back to our example, when we deploy our integration tests, we want all our @Mock objects to be installed:

<web-beans>
    <component-types>
        <component-type>javax.webbeans.Standard</component-type>
        <component-type>javax.webbeans.Component</component-type>
        <component-type>org.jboss.test.Mock</component-type>
    </component-types>
</web-beans>

Now the Web Beans container will identify and install all components annotated @Component, @Standard or @Mock at deployment time.

(Note that a component with no component type annotation will never be discovered by the Web Beans container; the container searches for classes with component type annotations when scanning the classpath to discover components.)

It's interesting to compare this facility to today's popular container architectures. Various lightweight containers also allow conditional deployment of components that exist in the classpath, but the components that are to be deployed must be explicity, individually, listed in configuration code or in some XML configuration file. Web Beans does support component definition and configuration via XML, but in the common case where no complex configuration is required, component types allow a whole set of components to be enabled with a single line of XML. Meanwhile, a developer browsing the code can easily identify what context the component will be used in.

Component type precedence

If you've been paying attention, you're probably wondering how the container decides which implementation - PaymentProcessor or MockPaymentProcessor - to choose. Consider what happens when the container encounters this injection point:

@In PaymentProcessor pp;

There are now two components which satisfy the PaymentProcessor contract. Of course, we can't use a binding annotation to disambiguate, since binding annotations are hardcoded into the source at the injection point, and we want the container to be able to decide at deployment time!

The solution to this problem is that each component type has a different /precedence/. The precedence of the component types is determined by the order in which they appear in web-beans.xml. In our example, @Mock appears later than @Component so it has a higher precedence.

Whenever the container discovers that more than one component could satisfy the contract (API type plus binding annotations) specified by an injection point, it considers the relative precedence of the components. If one has a higher precedence than the others, it chooses the higher precedence component to inject. So, in our example, the container will inject MockPaymentProcessor when executing in the integration testing environment, and PaymentProcessor when executing in production (which is exactly what we want).

Example component types

Component types are useful for all kinds of things, some more examples:

  • @Mock and @Staging component types for testing
  • @AustralianTaxLaw for site-specific components
  • @SeamFramework, @Guice for third-party frameworks which build on Web Beans
  • @Standard for standard components defined by the Web Beans specification

I'm sure you can think of more applications...

Two more rules to remember?

As we've seen, the typesafe resolution algorith considers:

  1. API type
  2. binding annotations
  3. component type precedence

when resolving a component to be injected. If these rules fail to produce a unique component (if there are multiple components which all have the same high precedence, implement the required API type and support the required binding annotations), an exception will be thrown by the container at system initialization time.

The Web Beans group has discussed the possibility of introducing two additional rules to be used only when the rules above fail to narrow the list of components to a unique component. On balance, I'm in favor of these rules, since I think they're useful. However, the group as a whole is concerned that the additional complexity is confusing to developers. Therefore, we're seeking feedback from the community on the following ideas.

/Note:/ If you're not used to thinking in terms of binding annotations and component precendence, you're probably thinking that component resolution is already complex enough! But I'm confident that once you get used to it, the resolution algorithm is extremely robust and will grow to become totally intuitive.

Rule 1: The /least-derived implementation/ rule

This proposed rule states that if the algorithm above fails to result in a unique component, and if there is a /least-derived/ component in the set of candidates - one candidate that the other candidates all (directly or indirectly) extend, then the least-derived component will be chosen.

This rule is designed to ensure that it is easy to introduce new components into the system using implementation inheritance from pre-existing components, without breaking or changing the behavior of pre-existing clients.

For example, if I have this pre-existing component:

@Component @PayByCheque
ChequePaymentProcessor implements PaymentProcessor { ... }

and I introduce a new component that extends this one:

@Component @PayByCheque
AsynchronousChequePaymentProcessor 
    extends ChequePaymentProcessor 
    implements AsynchronousPaymentProcessor { ... }

Then the following injection point would continue to resolve to the base ChequePaymentProcessor component:

@In @PayByCheque PaymentProcessor processor;

While this new injection point would of course receive an instance of AsynchronousChequePaymentProcessor:

@In @PayByCheque AsynchronousPaymentProcessor processor;

Rule 2: The /least-specific bindings/ rule

This proposed rule is analogous to the previous rule, but refers to binding annotations rather than API types. It could be adopted either in addition to, or as an alternative to, Rule 1. It states that if the algorithm above fails to result in a unique component, and if there is exactly one component in the set of candidates that has /exactly/ the same binding annotations specified at the injection point, then this least-specific component will be chosen.

For example, if I have this pre-existing component:

@Component @PayByCheque 
ChequePaymentProcessor implements PaymentProcessor { ... }

and I introduce a new component that also supports the @PayByCheque binding annotation:

@Component @PayByCheque @Asynchronous
AsynchronousChequePaymentProcessor 
    extends ChequePaymentProcessor { ... }

Then the following injection point would continue to resolve to the base ChequePaymentProcessor component:

@In @PayByCheque PaymentProcessor paymentProcessor;

While this new injection point would of course receive an instance of AsynchronousPaymentProcessor:

@In @PayByCheque @Asynchronous PaymentProcessor paymentProcessor;

Are you scared yet?

Phew, we started to get a bit esoteric there! Don't worry, this is as complex as it gets, and if we get too much negative feedback about the two proposed rules above, it won't even get /that/ complex.

24 comments:
22. Sep 2007, 12:05 CET | Link

My mistaken impression was that web-beans would standardize Seam. But after reading the bit about @SeamFramework, I'm thinking that Seam would instead ultimately rely on web-beans for it's component plumbing. Is this correct?

As far as the two extra rules go, they don't seem that complex. However, perhaps something like a command line switch that activates the additional rules would satisfy everyone. Or an annotation(s) that can be applied to specific components and which turns the rules on for it and its subclasses (maybe this is making it too complex--but that way you'd always get an exception unless you enabled it so you wouldn't accidentally be relying on them).

23. Sep 2007, 00:17 CET | Link

Interesting - the tie in to Seam is obvious, but this is the first I've seen of any involvement from the Guice team... I can't help but wonder if the term 'Web Beans' is accurate, though -- after all, the only thing in these first two articles that relates to the web at all is a brief example of using the Unified EL... I certainly see possibilities here beyond the standard 'web' environment - perhaps a renaming is in order :)

Looks like some good work, guys!

M

23. Sep 2007, 00:49 CET | Link
David Churavy

This looks really great! It also seems to me that such specification would be very useful in JSE environment also.

23. Sep 2007, 01:43 CET | Link
My mistaken impression was that web-beans would standardize Seam. But after reading the bit about @SeamFramework, I'm thinking that Seam would instead ultimately rely on web-beans for it's component plumbing. Is this correct?

Probably, Seam will eventually be split into two layers:

  1. the core component engine, which will evolve into the Web Beans RI
  2. the framework layer which will provide all the built-in components, JSF components, etc.

Does that make sense?

As far as the two extra rules go, they don't seem that complex. However, perhaps something like a command line switch that activates the additional rules would satisfy everyone. Or an annotation(s) that can be applied to specific components and which turns the rules on for it and its subclasses (maybe this is making it too complex--but that way you'd always get an exception unless you enabled it so you wouldn't accidentally be relying on them).

I think that's too complex :-) I want to settle on rules which are so natural that no-one would ever feel the need to change them.

Interesting - the tie in to Seam is obvious, but this is the first I've seen of any involvement from the Guice team

Bob has contributed a huge amount of effort and ideas to the specification.

I can't help but wonder if the term 'Web Beans' is accurate, though -- after all, the only thing in these first two articles that relates to the web at all is a brief example of using the Unified EL... I certainly see possibilities here beyond the standard 'web' environment - perhaps a renaming is in order :)

I already have a revolt on my hands of Web Beans EG members who agree with you :-) However, I'm can't lead us down the path of considering non-EE environments unless there is pressure from the community and the JCP leadership to do so.

24. Sep 2007, 07:08 CET | Link
<web-beans>
    <component-types>
        <component-type>javax.webbeans.Standard</component-type>
        <component-type>javax.webbeans.Application</component-type>
        <component-type>org.jboss.test.Mock</component-type>
    </component-types>
</web-beans>
Now the Web Beans container will identify and install all components annotated @Component, @Standard or @Mock at deployment time.

Is this a typo, or does @Component somehow relate to javax.webbeans.Application?

24. Sep 2007, 07:14 CET | Link
Dependency injection always occurs when the component instance is first instantiated.

This is radically different than the way it's done in Seam, right? In Seam, injection occurs before every method invocation, which is what allows short-running (eg request) scoped components to be injected into long-running (eg session) scoped components. Will this sort of thing be possible in Web Beans?

24. Sep 2007, 12:37 CET | Link
Is this a typo, or does @Component somehow relate to javax.webbeans.Application?

Yes, a typo. Fixed now.

24. Sep 2007, 12:38 CET | Link
This is radically different than the way it's done in Seam, right? In Seam, injection occurs before every method invocation, which is what allows short-running (eg request) scoped components to be injected into long-running (eg session) scoped components. Will this sort of thing be possible in Web Beans?

Yes, it will be possible, but the implementation must use proxying of the injected object or bytecode enhancement of the injected field instead.

25. Sep 2007, 01:09 CET | Link

my 2 cents of feedback on the 2 additional component resolution rules:

1. i think the least-derived implementation rule is a relatively safe bet - it just expresses that the closer a component is in the inheritance tree to the type stated at the injection point the more similar it is to what the injection point asks for. however, it also means that i can not override all uses of an existing component just by sub-classing from that component. to do that i would need to either remove the @Component annotation from the base component or change all injection points to refer to the derived component.

2. the least-specific bindings rule is a different beast: it seems to me that not specifying a binding annotation at the injection point means that the injection point does not care whether that annotation is present on a component or not. for instance, the binding annotation may relate to a property (such as security) that is irrelevant for the injection point. the least-specific bindings rule however re-defines the absence of a binding annotation on an injection point to mean that the injection point would prefer the binding annotation to not be on the injected component. although, it has to be said that without this rule it is possible to break a working system just by adding a component that shares the set of binding annotations used at one or more injection points with another component (that is already part of the system).

good luck with this very interesting spec!!, gerald

 
25. Sep 2007, 10:01 CET | Link
I already have a revolt on my hands of Web Beans EG members who agree with you :-) However, I'm can't lead us down the path of considering non-EE environments unless there is pressure from the community and the JCP leadership to do so.

Actually, I wasn't referring to a change in project scope (although perhaps applicable) -- I was just referring to the name itself... after all, it appears that I could build an enterprise application with Web Beans that doesn't have a web interface at all -- perhaps an integration of two existing systems, or an application that has EJB's as a facade that communicate with a remote application client, etc...

Seems like a minor issue compared to making this available to JSE, but just ask anyone who works in product marketing -- giving it the wrong name could pigeon hole it to just the web for many people...

M

 
25. Sep 2007, 13:40 CET | Link
Actually, I wasn't referring to a change in project scope (although perhaps applicable) -- I was just referring to the name itself... after all, it appears that I could build an enterprise application with Web Beans that doesn't have a web interface at all -- perhaps an integration of two existing systems, or an application that has EJB's as a facade that communicate with a remote application client, etc...

Yes, this is certainly possible with Web Beans today and I consider it to be within the scope of the JSR.

 
26. Sep 2007, 19:24 CET | Link

How is the scope taken into account during resolution? Say I have a PaymentProcessor bean in

- application scope as global default

- in http session as provided by a resolver method reading the users preferred payment method from his profile

- in the conversation scope provided by a jsf ui selection where the user is able to overwrite the payment method for a certain order

Will there be any kind of scope precedence taking place during resolution?

@In @PayBy PaymentProcessor relevantOrderPaymentProcesser;

 
27. Sep 2007, 12:06 CET | Link
Ben Hutchison | ben_hutchison(AT)yahoo.com

There is a challenge that's previously been leveled at Guice that seems similarly relevant to WebBeans:

How can WebBeans model inject two different instances of a class into two different instances of a dependent class?

Example: I have two different instances of the same business component class, in the same scope, that each depend upon a DataSource. I want to pass DataSource (a) to component instance (A), and DataSource (b) to component instance (B). How can I achieve this in WebBeans?

The model outlined infers runtime wiring purely from metadata on classes. Therefore, it seems unable to distinguish different instances of the same class, if they have differing dependencies.

Surely we all would agree there are some aspects of a software system's runtime object graph that cannot be specified or inferred from static class-based metadata? I cannot see how the proposed dependency injection mechanism can assist in such cases.

 
27. Sep 2007, 17:15 CET | Link
Simon Gunzenreiner | simon.gunzenreiner(AT)axa-tech.com

So as opposed to in Seam, where injection happens every time a component is invoked, in WebBeans injection would only happen at initialization time? If so - how will I deal with changing context values in WebBeans - holder components?

27. Sep 2007, 23:21 CET | Link

How is suppose to include new implementations at deploy time? We have to add a line to the 'web-beans.xml' and wait that the container take the last line included? I'm confussed

 
03. Oct 2007, 01:22 CET | Link
How is the scope taken into account during resolution?

It's not. If you want components with the same API and different scopes, they /must/ have different binding annotations.

I'm pretty sure this is a Good Thing.

 
03. Oct 2007, 01:24 CET | Link
How can WebBeans model inject two different instances of a class into two different instances of a dependent class? Example: I have two different instances of the same business component class, in the same scope, that each depend upon a DataSource. I want to pass DataSource (a) to component instance (A), and DataSource (b) to component instance (B). How can I achieve this in WebBeans?

You have two options:

  • define two components for the same business component class, using XML
  • define two subclasses of the business component class, each of with different annotations

IMO, the second option is usually the best.

 
03. Oct 2007, 01:27 CET | Link
So as opposed to in Seam, where injection happens every time a component is invoked, in WebBeans injection would only happen at initialization time? If so - how will I deal with changing context values in WebBeans - holder components?

The container will proxy the reference to a component in a narrower scope.

 
03. Oct 2007, 01:28 CET | Link
How is suppose to include new implementations at deploy time? We have to add a line to the 'web-beans.xml' and wait that the container take the last line included?

Approximately, yes.

I would say: you declare the overriding component to have a component type with a higher precedence than the one it overrides. (Where precedence is determined by the order of component types declared in web-beans.xml.)

 
03. Oct 2007, 15:29 CET | Link
Ben Hutchison

After rereading, I have a decent picture of how the two proposed extra binding resolution rules would work (ie least-derived, least-specific).

I think their both worthy and should be included. As you mention, they will tend to prevent existing binding from breaking as side-effects of new work.

 
05. Oct 2007, 15:45 CET | Link

Hello,

about the two last rules: they certainly have logic in them, but I think that keeping things simple is better. I would rather think that having two components to choose from, when injecting, should produce a warning or error: as it very often may be a programmers error. Without that, people will spend hours searching for the problem.

Also, these rules would be necessary if web beans didn't provide mechanisms to clearly specify which component should be injected - but they do (annotations and web component types). Isn't it enough, to be able to easily write applications without amigious component injections?

Regards, Adam

 
09. Nov 2007, 18:47 CET | Link
Mohammad Norouzi

regarding two rules, I think it's much better to use simple since it prevents many unexpected exceptions and logical mistakes, but as I think about the other rules it also seems they are useful in some way, so my idea is to change the rules by config files, for example, in web-beans.xml we can define something like this:

 
09. Nov 2007, 18:54 CET | Link
Mohammad Norouzi

regarding two rules, I think it's much better to use simple since it prevents many unexpected exceptions and logical mistakes, but as I think about the other rules it also seems they are useful in some way, so my idea is to change the rules by config files, for example, in web-beans.xml we can define something like this: injection-precedency: rule-name: least-derived

and if it's not declared the default and simplest one can be used

 
12. Jan 2008, 05:22 CET | Link
Torakiki

What's the difference between @BindingType and @ComponentType annotations? Looking at the examples they seem to be used for the same purpose...