I've written a couple of posts about using @Alternative to achieve deployment-time polymorphism. What I've never really talked about is its role in CDI modularity.
Modularity and alternatives
From our point of view, support for modularity
in dependency management means that injection points of the same type, in different modules, can resolve to different beans. For example, suppose I have an interface Supplier, with two implementations. Let's say they are beans like BookSupplier and CameraSupplier, but they could easily be something more exotic. Now, in one module, bookshop.war, of my application, I have a BookShop:
class BookShop {
@Inject
BookShop(Supplier supplier) { ... }
...
}
In another module, camerashop.war, I have a CameraShop:
class CameraShop {
@Inject
CameraShop(Supplier supplier) { ... }
...
}
Now, how does the container tell that the Supplier in BookShop is a BookSupplier, but the Supplier in CameraShop is a CameraSupplier?
Well, there's two possibilities:
BookSupplier and CameraSupplier are deployed in different modules
Suppose that BookSupplier and CameraSupplier are deployed in separate modules, books.jar and cameras.jar respectively. Then the solution is easy. Just declare that bookshop.war depends on books.jar and that camerashop.war has a dependency to cameras.jar, and we're done. That's enough information for CDI to know what to inject where.
So bookshop.war would contain the following line in MANIFEST.MF:
Class-Path: books.jar
Meanwhile, camerashop.war would contain this line in its MANIFEST.MF:
Class-Path: cameras.jar
BookSupplier and CameraSupplier are deployed in the same module
But what if BookSupplier and CameraSupplier are both deployed in suppliers.jar? Well, there's a solution in this case, too.
First we need to add the @Alternative annotation to BookSupplier and CameraSupplier. @Alternative tells CDI not to inject a bean into a module that does not explicitly declare its dependency to the bean.
Next, we need to declare the appropriate alternative in each module. In bookshop.war, we specify:
<beans>
<alternatives>
<class>org.mydomain.supplier.BookSupplier</class>
</alternatives>
</beans>
In camerashop.war, we specify:
<beans>
<alternatives>
<class>org.mydomain.supplier.CameraSupplier</class>
</alternatives>
</beans>
And now each module has it's own, private, implementation of Supplier.
What if BookShop and CameraShop are deployed in the same module?
I suppose, at this point, you're wondering what happens if the clients, BookShop and CameraShop are deployed in the same module. Well, in this case we need to look for another solution. CDI doesn't support more granular alternative activation. There are no bean-level or package-level alternatives. (At least not in this release of CDI.)
Instead we need to add a qualifier, for example:
class BookShop {
@Inject
BookShop(@Supplies(Book.class) Supplier supplier) { ... }
...
}
or, more likely, add a generic type parameter to Supplier:
class BookShop {
@Inject
BookShop(Supplier<Book> supplier) { ... }
...
}
Unified EL
The example we've worked with involves Java classes using injection to obtain their dependencies. But what about JSP or JSF pages, which use Unified EL expressions to interact with beans. Well, happily, exactly the same rules apply during EL name resolution.
Modularity beyond Java EE
I've given examples from the Java EE environment. In this environment, a module
is a Java EE module like a war, EJB jar or rar, or a library jar. But what about other module architectures like OSGi or a future Java language-level module system?
Well, the CDI spec is slightly future-proof in this respect. This functionality is defined for an abstract notion of a module in an abstract module architecture
. So it's more or less well-defined what a CDI implementation should do in an OSGi architecture, if it wanted to support OSGi.
Isn't this already done? Or how is GlassFish running/using these things?
GlassFish uses OSGi to build the app server, but provides the well known Java EE application/module layer on top (what Gavin describes in the blog). So what they have working and tested in GlassFish is using Weld as an OSGi bundle, not at the application using CDI as OSGi bundles.
Just as the 299 spec supports an abstract modular architecture, so does Weld, allowing the container to describe the module structure to Weld on bootstrap.
Hi,
this comment is little bit related a previous Blog from Gavin that he see CDI/Weld/Seam providing contexts for event driven programming....
When you say to me contexts and event driven programming, I would understand something like Apaches SCXML with statemachine implementation...
So what I like to ask, is there more then conversation context inside of the Seam or any of other above mentioned frameworks or what Gavin is mentioning the conversation context..
Or this sort of statemachine context exist under the Seam also. If yes, under which topic, I programmed little bit Seam but I didn't see that sort of functionality....
Aha, OK. I though they already had something .
Hmmm, I think I should know that, since afair I wrote that piece in Weld-int. :-)
nonono, you're supposed to think more about traditional event models like in component-based GUI frameworks.