Weld tutorial – Part 3


In part 1 and part 2 of this series of articles I talked about how to use the simple injection provided by Weld. What I’ve done so far was to inject full blown beans which get instanciated by its constructor. But there is another way: a producer-consumer-relationship.

With this way of injection it is possible to really inject everything. POJOs, DB resoures like ResultSets even primitives can be injected.

The following two code listings show how to produce and how to consume. I’m going to explain what’s really happening here afterwards:

@Produces @Random int next() {
 return getRandom().nextInt(maxNumber);
}
@Inject @Random
private int number;

Okay, as promised here are some explanations:

@Produces tells Weld that something that might get injected somewhere is being produced here. What is specified by the next annotation. Although @Random might look like a built-in annotation it is not. I named it Random to point out that the int is generated (pseudo) randomly. This is a socalled qualifier annotation which tells the dependency injection framework where to look for the producer.

@Target( { TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface Random
{
}

The only new thing is the @Qualifier annotation which is contained in the javax.inject package and defines qualifier annotations. As you can see in the samples above it is really possible to inject everything. There thousands of scenarios in which this might be useful. Just imagine a producer which generates a unique ID fo every instance.

Event / Observer concept

So far I just talked about the DI features of JSR-299. Althought the official name of this JRS-299 might say otherwise Weld is not limited to dependecy injection. One thing I really love is the event “bus” which basically an implementation of the observer pattern with lots of tuning and simplification.

The greatest simplification ist that there is no need to explicitly register an observer and the observable knows nothing about its observers. If you look a the “standard” observer pattern used in Swing you’ll find a method JButton.addActionListener(ActionListener l). It’s clear what’s happening here: an ActionListener is explicitly registered at one button. That means that the Button knows its listeners and the listener knows exactly to what component he or she is listening to.

The following annotation defines an observable (Standard Java: implements Observable):

@Qualifier
@Target( { PARAMETER })
@Retention(RUNTIME)
public @interface Event {
 String source();
}

The next part might seem a litte strange since it implements an annotation but later it will be clear why this is done.

package de.publicstaticfinal.web.jsf;
import javax.enterprise.inject.AnnotationLiteral;
public abstract class EventImpl extends AnnotationLiteral<Event> implements Event
{
}

Next we declare the concrete event we’re listening to. This is just a simple POJO. IF you look at the Java API this Event is equivalent to the second argument of Observer.update(Oberservable o, Object argument). For better clarification I name it HelloWeldEvent.

package de.publicstaticfinal.web.jsf;
public class HelloWeldEvent
{
 private String source;

 public HelloWeldEvent(String source)
 {
 this.source = source;
 }

 public String getSource()
 {
 return source;
 }
}

A simple event which contains the name of its source. What’s left is the event listener itself but that’s not that many code:

public void handleEvent(@Observes @Any HelloWeldEvent hwe)
{
 System.out.println(hwe.getSource());
}

@Observes is the annotations which tells Weld that this method listens to ALL (@Any) HelloWeldEvent which are raised in this application. This might be useful in some circumstances (imagine a logging facility which gets called every time a button is clicked) but on other occasions this is to bloated. Therefore I added the “method” source() to the Event annotation. With that it is possible to just listen to a special HelloWeldEvent.

public void handleEvent(@Observes @Event("button1") HelloWeldEvent hwe)
{
 System.out.println(hwe.getSource());
}

This observer method just gets called when the raised event’s source is “button1″. So far so good but how do you raise an event? The famous BeanManager provides a method for doing this: public void fireEvent(Object event, Annotation… bindings).

The first argument is the event itself. It is of type Object since there is no special interface an event has to implement which means that every Object could be an event. The next arguments are the anootation bindings which are used to resolve the listeners. In this tutorial’s case this would be Event. And now it might be clear why we need an implementation if Event. I used @Event(“button1″) to specify on which concrete event the listener should be called. Weld needs a mechanism to read this information and to decide whether the method should be called or not.

Written in Java it looks like this:

private void fireEvent(){
 beanManager.fireEvent(new HelloWeldEvent("Test"), new EventImpl(){
 public String source()
 {
 return "button1";
 }});
 }

When calling fireEvent a concrete implementation of Event is provided and Weld can use the source() method to retrieve the source. After an check whith equals to the value of @Event(…) Weld knows what methods to call. Be aware that we talk about synchronous events here. JSR-299 does not define asynchronous events.

This was the last part of my tutorial series. As I stated before JSR-299 is way to extensive to be completely covered by a tutorial. I just wanted to give people who are interested in working with it a litte help to get started. I hope that I achieved this goal a little bit and the ones who read the article are goind to use Weld (or other implementations) since it will boost your application.

, ,

  1. No comments yet.
(will not be published)

Please leave these two fields as-is:

Protected by Invisible Defender. Showed 403 to 1,915 bad guys.