Framework of the week: CDI

CDI meant Context dependency injection: this spec is derived from DI (Spring, Guice and JBoss Seam) to give an annotated driven programmation of your module.

Purpose

CDI uses the Dependency injection mechanism to loosely wire your beans together:

 
public interface IConsumer {
	String getHello();
}
public class Provider implements IProvider {
	@Override
	public String getMessage() {
		return "may I say hello?";
	}
}
 
public interface IProvider {
String getMessage();
}
public class Consumer implements IConsumer{
@Inject
private IProvider provider;
public String getHello() {
	return provider.getMessage();//Damn it works, it calls the Provider class !
}
}

We saw here how to wire The Provider implementation to the Consumer one without explicitely telling which (done with the @Default annotation (or nothing if it has only one Impl available))

With Cdi, you can now use a qualifier to define your injection specialization:

@Qualifier
@Retention(RUNTIME)
@Target({TYPE})//you can also make your annotations wire method params with Method target, attribute ones...
public @interface Informal {}
@Informal
public class Provider implements IProvider{...}
public class Consumer implements IConsumer{
@Inject @Informal
private IProvider provider;...}

And some other stuff, like contexts, extensions…

Concepts

Scope


You can have multiple contexts while you’re registering your beans: (@Request (an http request), Session, Application, Conversation) and the ability to make custom ones (DollarCurrencyInferiorToOneEuro :p). So that your beans will be used or reused depending this scope (created at the begining of the session, reused during its duration).

Extension

You can create CDI extensions to make annotations have some pre/post treatment.
In order to do this, just declare an extension module: create a src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension file containing your extension implementation: net.osgiliath.helpers.cdi.eager.extension.HelloExtension

And an Annotation:

@Qualifier
@Retention(RUNTIME)
@Target({TYPE})
public @interface Hello{}

Finally, you just have to create an interceptor (that you’ll use in your beans.xml mandatory file of your consumer’s module):

public <T> void processAnnotatedType(@Observes @WithAnnotations({
			Hello.class
	}) ProcessAnnotatedType<T> processAnnotatedTypeEvent) {
AnnotatedType<T> type = processAnnotatedTypeEvent.getAnnotatedType();
processAnnotatedTypeEvent.setAnnotatedType( type );
}
 
@Hello
@Interceptor
@Priority(4800)
public class HelloInterceptor implements Serializable {
 
	private static final long serialVersionUID = 604440259030722151L;
 
 
	@AroundInvoke
	public Object helloMethodInvocation(InvocationContext ctx) throws Exception {
		ExecutableValidator executableValidator = validator.forExecutables();
		Set<ConstraintViolation<Object>> violations = executableValidator.validateParameters(
				ctx.getTarget(),
				ctx.getMethod(),
				ctx.getParameters()
		);
 
		System.out.println("Said hello before proceed");
		Object result = ctx.proceed();
System.out.println("Said hello after proceed");
		return result;
	}

Finally you’ve got to reference the interceptor defined below in your modules beans.xml:

 
<beans
   xmlns="http://java.sun.com/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
	<interceptors>
      	<class>net.osgiliath.interceptor.HelloInterceptor</class>
	</interceptors>
</beans>

Isn’t it a nice way to make AOP without aspect programming? (or, if you prefer in pure Java programming).

Note that this isn’t a full CDI description and that you can have some more CDI Capabilities (for example, create beans from methods with @Produces, invoke post bean creation method with @PostConstruct… (see Cdi doc for many other capabilities).

Getting started

So now, in order to start, just create a new Maven Project and import these dependencies:

<dependency>
			<groupId>javax.enterprise</groupId>
			<artifactId>cdi-api</artifactId>
		</dependency>
		<dependency>
			<groupId>javax.interceptor</groupId>
			<artifactId>javax.interceptor-api</artifactId>
		</dependency>
<dependency>
			<groupId>org.apache.geronimo.specs</groupId>
			<artifactId>geronimo-atinject_1.0_spec</artifactId>
		</dependency>
<dependency>
			<groupId>org.jboss.logging</groupId>
			<artifactId>jboss-logging</artifactId>
		</dependency>
<dependency>
			<groupId>org.jboss.weld</groupId>
			<artifactId>weld-osgi-bundle</artifactId>
		</dependency><!-- note that weld osgi embeds all CDI 1.1 reference implemenation stuff (and more)-->

And Now let’s code some CDI Modules!

Share Button

Leave a Reply

Your email address will not be published. Required fields are marked *