Jigsaw and CDI: A Perfect Fit
Over the last couple of weeks, I’ve been getting oriented with Jigsaw, seeing the progress they’re making and wondering how this work will affect our Java EE world. Though I still have a few questions remaining, I’ve found the high-level concepts to be very impressive. Moreover, the language-level approach that Jigsaw is taking is well-suited to integration with Java CDI. As you may know, Caucho is a major supporter of the Java CDI spec and we’re working on our own implementation, called CanDI. In this blog post, I’ll talk about the cool parts of Jigsaw and sketch a proposal for how Jigsaw and CDI might work together in the future.
Language support for modularity
Jigsaw supports modularity within the Java language. This is huge. You can define a module containing a set of packages and/or classes and specify module-level access protection. This one addition gives you much greater control over the visibility of classes you export from a library. What’s more, you can even control the methods visible in a library.
Let me give you an example based on the state pattern. Imagine we have a gearbox that has states: out of gear, reverse, and gears 1-3 (it’s an old gearbox :-)). We want the state objects to be an implementation detail and the gearbox itself to be a publicly accessible API object. We can put the GearBox in one package and the GearState in another. To hide the GearState from the consumer of the API, we’ll give it the module access modifier. Then it’s available from GearBox even though it’s in a different package, but not outside of our module.
Now you may also want GearBox to have some methods that are accessible only within the module, even though it is visible outside of your module as a whole. For example below, we have our state objects setting the next state on the GearBox. We can hide that method from the consumer by make it module private.
|
package com.example.gear;
public class GearBox { public GearBox() public void shiftUp() public void shiftDown() public void shiftOutOfGear() public void shiftReverse() module void setState(GearState nextState) _state = nextState; |
package com.example.gear.impl;
import com.example.gear.*; module enum GearState FIRST_GEAR { SECOND_GEAR { @Override THIRD_GEAR { module void shiftUp(GearBox gearBox) module void shiftDown(GearBox gearBox) module void shiftOutOfGear(GearBox gearBox) module void shiftReverse(GearBox gearBox) |
Contrasting with external metadata
Another approach to modularity might be to use external metadata to say what’s accessible outside of a module and what’s hidden. OSGi is one example of a system that takes this approach. The benefits to this style are that you don’t have to modify existing code and it’s backwards compatible with existing JVMs.
There are a number of drawbacks however. First, the enforcement of these rules is done using classloader techniques which completely throw out the classloader hierarchy. The problem with these techniques is granularity. Specifically, method-level hiding (e.g. GearBox.setState()) isn’t possible. All methods on public classes must be revealed.
Second, the Java community has decided that external metadata is difficult to maintain and generally undesirable compared to source-level information. If you’ve been following the dependency injection trends over the last few years, you know that annotation-based injection is by far the preferred configuration method over XML. The module keyword as an access modifier gives the coder, the compiler, and the JVM the information they need to understand the access rights. Moreover the information is exactly paired to the resource to which it refers.
(As a side benefit, think of how much better the module keyword will make Javadocs. It seems like a silly point, but in fact it will add a lot of clarity to consumers of an API to show what classes and methods are intended to be public versus what are really implementation details. We can effectively eliminate the type of Javadoc comments like “not intended to be invoked by the user.”)
Pairing Jigsaw with CDI
One of the most important aspects of an module system is inter-module connectivity. In most module systems, you can simply access the public classes in a module on which you have a dependency. While this is fine and a common use case, things get more complicated when you have multiple modules which provide objects which all implement the same interface. You might think of a plugin, filter, or interceptor system.
So far, Jigsaw doesn’t have much to say about this problem and I think that’s for a specific reason - they want to leave that issue up to higher levels of abstraction. OSGi does have a solution for this in services. OSGi services are a really nice architecture and especially useful for mobile and desktop applications where modules and services come and go. The main issue with OSGi services is that they need to go through manual registration and lookup steps instead of being injected/produced.
Using CDI, we can define a system using annotation based injection so that you get the right object, where you need it, from one of the modules on which you depend. Let’s look at an example to make this concrete.
Example application - Publishing News Items
Suppose you’re creating an application takes lets you create news items and publish them. You want to make the publishing mechanism pluggable so that you can distribute your news items to various outlets like blogs, wires, newspapers, magazines, et al. The mechanism for publishing to each of these different outlets is different, so you encapsulate the specific code for each in a plugin publisher module. Your top-level application then takes news items as you create them and publishes them with all registered publishing plugins. There’s a shared module that contains the API with interfaces for the publishers and the news items.
To summarize, you have several modules:
- Your publishing API module
- Your application module
- Any number of publisher plugin modules
Your application module and the publisher modules all depend on the the API module.
The API module is simple and has these two interfaces:
|
package publisher;
public interface NewsItem { |
package publisher;
public interface Publisher { |
Then your application uses CDI to inject all available Publishers that have been added as modules to the application:
import javax.enterprise.inject.*;
import publisher.*;
public class Distributor {
@Inject
private Instance<Publisher> _publishers;
public void publish(NewsItem newsItem)
{
int i = 0;
for (Publisher publisher : _publishers) {
publisher.publish(newsItem);
}
}
}
You might be asking what do I mean by “adding a module to an application.” Let’s get more specific by talking about enterprise (as in Java EE) applications. One application server may host several applications and each application may have a different module profile. Then you would need metadata to say which modules are configured in each application at runtime. This metadata would at the same level as a web.xml or ejb-jar.xml in the application. For required dependency modules, no explicit inclusion would be necessary (that would defeat much of the advantage of a runtime module system), but optional modules like those providing our Publisher plugins would. At the moment, CDI is technically only used for Java EE, but you might imagine that Java SE application could specify the additional modules on the command line of java.
Now let’s take a look at how the newspaper publisher is implemented:
|
package newspaper;
import javax.enterprise.inject.*; @Default public void publish(NewsItem item) |
package newspaper;
module class QueueFactory { |
|
package newspaper;
module class Auditor implements Runnable { public void run() |
package newspaper;
module class Printer implements Runnable { public void run() |
For the newpaper, we’re using a Queue to hold incoming NewsItems. This Queue is created by the QueueFactory and injected via CDI. We’re using CDI so that we can use the same Queue in various places throughout the module. In addition to using the Queue in the Publisher, we’re also injecting it in the Printer and an Auditor. (I’m ignoring concurrency issues here - the structure of the application is the main focus.)
You can imagine that if you had another Publisher such as a BlogPublisher, the internals might be pretty similar and use a Queue of NewsItems there as well. We can keep these Queues separate by enforcing module-level visibility in CDI. In particular, we would say that beans produced by methods with module scope are only injectable within the same module.
Proposals
We’ve implicitly made two proposals for how CDI and Jigsaw should fit together:
- An injectable bean that has module-level access or is produced by a @Producer method with module-level access may only be injected into the same module
- Modules for enterprise applications are specified in metadata at the web.xml or ejb-jar.xml levels
- Dependent modules will be added automatically by the application server
Conclusion
This post just discusses a few of the thoughts we had when looking at Jigsaw. So far, we really like the language-level module access qualifier. It’s one of those great, really clear concepts that makes you wonder how you got along without it before.
We’d love to hear from other folks interested in Jigsaw and/or CDI to see if this proposal makes sense and if you have any additions or other thoughts to extend the functionality.

March 5th, 2010 at 7:17 pm
OSGi services do not need to be manually registered and looked up; they can certainly be injected. The injection can be driven by source code annotations, and I think it should even be possible to adapt CDI’s annotations to inject OSGi services. The key challenge is that most existing DI frameworks (including e.g. Spring, Guice etc) do not support the dynamic re-wiring that is possible with OSGi services; there is no concept of having a dependency “uninjected” and then “reinjected” at runtime.
Nevertheless both Spring and Guice have been very successfully adapted to OSGi so I see no reason that CDI couldn’t be also.
Incidentally, method-level hiding is of course possible in OSGi. Java has supported the private and protected modifiers on methods since… well, forever
March 5th, 2010 at 7:29 pm
Hi Neil,
Thanks for the correction about the injected services. Actually, now that I think about it, it might be possible to do some interesting work with CDI scopes to solve the dynamic injection issue you mentioned.
I agree, CDI + OSGi would certainly work and I imagine there will be a melding at some point. In fact, I believe there was also some work to integrate Jigsaw (or at least JSR-294) and OSGi. I haven’t kept up with the current state of that.
The method-level hiding at the module level is completely new. Private, package, and protected access don’t really allow the kind of cross-package access that a module keyword can.
Thanks for the response,
Emil
March 5th, 2010 at 7:34 pm
Sorry my last comment was facetious. The point I really wish to make is that the new “module” access level keyword is being specified in JSR 294, which is separate from Jigsaw.
294 is the specification for module system support in the Java language, and is not tied to any specific module system. If the 294 Expert Group does its job properly then the “module” keyword will be understood by the javac compiler and usable in OSGi as well as within Jigsaw.
March 8th, 2010 at 11:08 am
Hmm. I think it would be more accurate to say that JSR-294 defines the module system, but leaves open the management of module repositories and their associated classloaders, like the current JDK leaves open management of the classloaders, jars and the classpath.
Maven and OSGi are both jar management systems (OSGi is also a classloader manager), but neither is really a module system.
March 9th, 2010 at 2:24 pm
@ferg
No, JSR 294 does NOT define the module system. In the words of Alex Buckley, the specification lead for JSR 294, it “provides language and VM features for the benefit of module systems such as OSGi and Jigsaw”. (http://blogs.sun.com/abuckley/en_US/entry/jsr_294_and_module_systems)
Maven is a modular build system, not a runtime module system. OSGi certainly IS a module system, as is Jigsaw (once released).