Search
The JBoss Way

Leveraging CDI at lightspeed with JBoss and JRebel

 By now we’ve seen Contexts and Dependency Injection (CDI) is an essential part for modern Java application development and a core part of the Java EE 6 platform. To put it simply: without the benefits of CDI, the elements and functions of advanced applications would not be orchestrated or communicating well, and developing these apps would be a lot more time-consuming, more prone to bugs & errors and generally worse in a hundred ways.

In this article, we review CDI and have some fun deep-diving into the technical challenges of making complex, instantly-visible changes to Java applications using JBoss AS 7, JBoss Tools, JBoss Weld and JRebel.

As Java developers, whenever we make changes to the structure of our applications, each change to the application functionality is usually composed of several small discrete changes. Lets call them “scenarios” for the purpose of this article.

Here are a few example scenarios we might think of:

  • add new method to a class
  • add new class to the application
  • add new CDI bean
  • add new EJB

While working with CDI, as with any other framework, the developer has plenty of options to alter the application behavior just by adding a single annotation to some class or a method. In this way, you don’t need to write a ton of code in order to accomplish the same thing.

For instance, using qualifier annotations, we can affect the way injection of the beans is performed by the CDI container.

As CDI is the core technology behind Java EE 6, it is quite important for us to pay attention to JRebel behavior in such environment. JBoss Weld, the reference implementation of CDI, is embedded into Glassfish and JBoss, but it can also be successfully used with a servlet container like Tomcat.  JRebel integrates with Weld using a dedicated Weld “plugin”, which refreshes the framework metadata caches and wires changed dependencies once a relevant class is updated by JRebel

For this article, I used JBossAS 7.1.1.Final along with JBoss Tools, since they play well together. The JRebel-Eclipse plugin also seamlessly contributes to JBoss configuration screens, so the tooling support for this kind of experiment is quite smooth.

Before we begin, I’d like to point out that this article is not a yet another CDI tutorial nor an overview of CDI features. There are a lot of good CDI tutorial available already.

 

Start Your Engines!

We’ll start off with a simple example that consists of 3 classes and 1 interface:
1) HelloServlet class - the application entry point
2) HelloService class - a service which is injected into HelloServlet using @Inject annotation and it uses the World interface to hold the reference to the object of interest which we will use in our example further on to demonstrate the “change scenarios” (i.e. when making a discrete structural change that affects the behavior of the application)
3) Universe class - the factory which initializes World instance
4) World interface - used inside HelloService and produced (!) by the Universe 

@WebServlet(“/hello”)
public class HelloServlet {
   @Inject HelloService helloService;

}

public class HelloService {	
	World world = Universe.createWorld();

	String sayHello() {
		return "Hello " + world + "!";
	}
}

public class Universe {
	public World createWorld(){
		return new World(){
			@Override
			public String toString(){
				return "World";
			}
		};
	}
}
	

 So in this state HelloService#sayHello() returns “Hello World!” (No kidding, Sherlock!). The only place where CDI is used currently is the injection of HelloService instance into HelloServlet. We can also see that the World instance in HelloService is created by Universe. This is where we can start with the modifications, assuming that the application is already deployed to the container.

 We use the term “change scenarios” to refer to when we want to make a discrete structural change that affects the behavior of the application. How many of such scenarios can you think of in case of pure CDI application? How many of such scenarios can you think on in case if CDI is used to support other technologies, for instance, in conjunction with JAX-RS framework? A lot. We’ll review just some basic ones here.
Add @Inject & Producer Method

In regards to the example described above, where the World instance is created by Universe factory method, this is the first scenario that we could undertake for the demonstration. In the ideal CDI world, the World instance should have been injected rather than created explicitly.

So instead of World world = Universe.createWorld() we will use @Inject World world:

public class HelloService {	
	 @Inject World world;

	String sayHello() {
		return "Hello " + world + "!";
	}
  }
	

 As we do not have a default instance of the World in our application yet, but we do have a method that can produce the instances of World, we can mark it with @Produces annotation so it will be able to register World beans in CDI container.

public class Universe {

	@Produces
	public static World createWorld(){
		return new World(){
			@Override
			public String toString(){
				return "Injected World";
			}
		};
	}
}
	

Remember, that the application is already deployed and running. Therefore, we change the toString method to return “Injected World”, just to see if the new logic is applied and the World instance was injected correctly.

Now, HelloService#sayHello() returns “Hello Injected World!”. Wow! It worked!

In the console we could see the following messages:
 

	
17:28:34,181 INFO  [stdout] (http-localhost-127.0.0.1-8080-1) [2012-07-19 17:28:34] JRebel: Reloading class 'org.jboss.as.quickstarts.helloworld.HelloService'.

17:28:34,232 INFO  [stdout] (http-localhost-127.0.0.1-8080-1) [2012-07-19 17:28:34] JRebel-Weld: Reconfiguring bean with name 'null' [class org.jboss.as.quickstarts.helloworld.HelloService]

17:28:34,241 INFO  [stdout] (http-localhost-127.0.0.1-8080-1) [2012-07-19 17:28:34] JRebel: Reloading class 'org.jboss.as.quickstarts.helloworld.Universe'.

17:28:34,244 INFO  [stdout] (http-localhost-127.0.0.1-8080-1) [2012-07-19 17:28:34] JRebel: Reloading class 'org.jboss.as.quickstarts.helloworld.Universe$1'.

17:28:34,292 INFO  [stdout] (http-localhost-127.0.0.1-8080-1) [2012-07-19 17:28:34] JRebel-Weld: Reconfiguring bean with name 'null' [class org.jboss.as.quickstarts.helloworld.Universe]
	

First, JRebel will reload HelloService class since our request will hit it first by calling the sayHello() method, as this bean is reloaded, an internal JRebel even forces it to reconfigure the corresponding bean inside the Weld container, so we can see the “Reconfiguring bean...” message.

Next, while refreshing the metadata, the Universe class will be touched and reloaded as well as the corresponding bean metadata in the CDI container. Splendid! After all the actions World instance gets injected from producer method into the instance field

We just described a single JRebel test case for CDI - this is how we test every framework integration. We could also combine the scenarios to create more complicated tests which is sometimes also useful as CDI spawns across different parts for the platform and we need to ensure that JRebel would work fine in all situations. 

Qualifier Annotations

 Continuing with the same example, what if our Universe could produce different blends of World instances and we would like to select a particular one. This is where we can take a look at the qualifier annotations and make up a change scenario. We’ll add a new producer method which will also return an instance of World, but we’ll qualify it as a “Fantasy World” with @Fantasy annotation so that the CDI container can distinguish the sources of the produced World instances. To tell that, we now want to inject the fantasy World instance into HelloService we can also use the same annotation for the field declaration.

public class HelloService {	
	 @Inject @Fantasy World world;

	String sayHello() {
		return "Hello " + world + "!";
	}
     }


public class Universe {

	@Produces
	public static World createWorld(){
		return new World(){
			@Override
			public String toString(){
				return "Injected World";
			}
		};
	}
	
	@Produces @Fantasy World createFantasyWorld(){
		return new World(){
			@Override
			public String toString(){
				return "Fantasy World";
			}
		};
	}
	
	
}
	

 Voila! HelloService#sayHello returns “Hello Fantasy World!”

The examples above are really simple, but they provide a workflow example in which a developer might introduce changes to the application source code. If you can imagine, how many proxies the CDI container produces internally in order to create the cross-bean injections, you can project the scope of the integration JRebel has to cover.

Actually, it is bit harder than might think initially, as the programming model advocated with CDI is very loose. The added annotation for a method at one part of the application can affect the behavior of the application at the other side.

The Challenge: Annotation-Driven Programming Model

CDI is a static model - the beans, and where they are injected, is validated when the application starts. This is quite different from a programmatic approach, which is inherently lazy. This imposes a challenge on how JRebel should handle various combinations of changes.

CDI will detect ambiguities between candidate beans when injecting fields, methods and constructors. Imagine, we have a plain class without any annotations; now we change the source and put a qualifier on it. From the JRebel point of view, this annotation came from nowhere. To discover it, JRebel has to scan the classpath, and make sure that we can reconfigure the CDI container correctly.

This challenge isn’t one we face only for CDI. As CDI is at the very core of Java platform, it influences the whole of the programming model.
 

To Sum Up

Hopefully this tutorial has been able to push one thing through your forehead into your gray matter: If you aren’t using CDI for building modern Java apps, then you are not taking advantage of an important feature of the Java EE 6 spec.

Ultimately, using CDI with JRebel and your favorite tools from JBoss is going to give you the advanced capabilities you need for making modern Java apps without having to spend almost any time dealing with app server restarts. It’s like wrapping Charlie Sheen around a phoenix and adding into your technology stack. Crazy, fast and fiery :-) 

 This article was submitted to JBoss by Anton Arhipov, the technical mind behind JRebel.

Travel along the JBoss Way…

Learn

Get Going

Get Involved