Skip to main content

Contexts and Dependency Injection (JSR 299) and GlassFish

Posted by rogerk on September 4, 2009 at 12:34 PM PDT

Version 1.0.0.PREVIEW3 of Web Beans (the implementation for JSR 299 Contexts and Dependency Injection For Java EE) now uses the annotations from JSR 330 (Dependency Injection For Java) and it is available in GlassFish V3. 
In this entry, we'll look at a simple JSF 2 application that uses Web Beans and the JSR 330 annotations. There are other features available in this release of Web Beans which will be discussed in subsequent blog entries. This application is a simple "guess number" application which I'm sure we are probably all familiar with by now.  Let's start by taking a look at the application's UI markup.

Listing 1: User Interface Markup

 

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml"
  3.     xmlns:ui="http://java.sun.com/jsf/facelets"
  4.     xmlns:h="http://java.sun.com/jsf/html"
  5.     xmlns:f="http://java.sun.com/jsf/core">
  6.     <h:head>
  7.         <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  8.         <title>JSF 2.0 Web Beans Example</title>
  9.     </h:head>
  10.     <h:body>
  11.        <h:form id="NumberGuessMain">
  12.           <h:panelGrid styleClass="title-panel">
  13.              <h:outputText value="Guess Number" styleClass="title-panel-text"/>
  14.              <h:outputText value="Powered By JavaServer Faces 2.0 and Web Beans" styleClass="title-panel-subtext"/>
  15.           </h:panelGrid>
  16.           <div style="color: black; font-size: 24px;">
  17.              I'm thinking of a number between <span style="color: blue">#{game.smallest}</span> and <span style="color: blue">#{game.biggest}</span>. You have <span style="color: blue">#{game.remainingGuesses}</span> guesses.
  18.           </div>
  19.           <h:panelGrid border="1" columns="5" style="font-size: 18px;">
  20.              Number:
  21.              <h:inputText id="inputGuess" value="#{game.guess}" required="true" size="3" disabled="#{game.number eq game.guess}" validator="#{game.validateNumberRange}"/>
  22.              <h:commandButton id="GuessButton" value="Guess" action="#{game.check}" disabled="#{game.number eq game.guess}"/>
  23.              <h:commandButton id="RestartButton" value="Reset" action="#{game.reset}" immediate="true" />
  24.              <h:outputText id="Higher" value="Higher!" rendered="#{game.number gt game.guess and game.guess ne 0}" style="color: red"/>
  25.              <h:outputText id="Lower" value="Lower!" rendered="#{game.number lt game.guess and game.guess ne 0}" style="color: red"/>
  26.           </h:panelGrid>
  27.           <div style="color: red; font-size: 14px;">
  28.              <h:messages id="messages" globalOnly="false"/>
  29.           </div>
  30.           <h:outputStylesheet name="stylesheet.css" />
  31.        </h:form>
  32.     </h:body>
  33. </html>

Everything on this page is really just standard JSF 2.0 view markup.  I've emphasized  the  Expression Language  (EL) portions of the view, especially game because it refers to a contextual bean instance also known as a Web Bean.

  • Line 17: Binding to Web Bean properties
  • Line 21: Binding to Web Bean properties and validation method
  • Line 22, 23: Binding to Web Bean action method
  • Line 24, 25: Binding to Web Bean properties

As you can see, in JSF, binding to a Web Bean is no different than binding to a typical managed bean.

Supporting Classes And Annotations For The Applicaton

Let's take a look at some of the utility classes for the application, namely the classes that are used to generate a random number and some of the supporting annotations.

Listing 2: The "Random" Annotation

  1. package webbeansguess;
  2.  
  3. import static java.lang.annotation.ElementType.FIELD;
  4. import static java.lang.annotation.ElementType.METHOD;
  5. import static java.lang.annotation.ElementType.PARAMETER;
  6. import static java.lang.annotation.ElementType.TYPE;
  7. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  8. import java.lang.annotation.Documented;
  9. import java.lang.annotation.Retention;
  10. import javax.inject.Qualifier;
  11.  
  12. @Target( { TYPE, METHOD, PARAMETER, FIELD })
  13. @Retention(RUNTIME)
  14. @Documented
  15. @Qualifier
  16. public @interface Random {
  17. }

The JSR 330 @Qualifier annotation is used to make Random a binding type.   This will allow us to inject a random number into the application.

Listing 3: The "MaxNumber" Annotation

  1. package webbeansguess;
  2.  
  3. import static java.lang.annotation.ElementType.FIELD;
  4. import static java.lang.annotation.ElementType.METHOD;
  5. import static java.lang.annotation.ElementType.PARAMETER;
  6. import static java.lang.annotation.ElementType.TYPE;
  7. import static java.lang.annotation.RetentionPolicy.RUNTIME;
  8. import java.lang.annotation.Documented;
  9. import java.lang.annotation.Retention;
  10. import java.lang.annotation.Target;
  11. import javax.inject.Qualifier;
  12.  
  13. @Target( { TYPE, METHOD, PARAMETER, FIELD })
  14. @Retention(RUNTIME)
  15. @Documented
  16. @Qualifier
  17. public @interface MaxNumber {
  18. }


Likewise, the @Qualifier annotation is used to make MaxNumber a binding type that will allow us to inject the maximum number allowed (for a guess) in the application.

Listing 4: The "Generator" Class

  1. package webbeansguess;
  2.  
  3. import java.io.Serializable;
  4. import javax.enterprise.context.ApplicationScoped;
  5. import javax.enterprise.inject.Produces;
  6.  
  7. @ApplicationScoped
  8. public class Generator implements Serializable {
  9.     private static final long serialVersionUID = -7213673465118041882L;
  10.    private java.util.Random random = new java.util.Random( System.currentTimeMillis() );
  11.     private int maxNumber = 100;
  12.     java.util.Random getRandom() {
  13.         return random;
  14.     }
  15.     @Produces @Random int next() {
  16.         return getRandom().nextInt(maxNumber);
  17.     }
  18.     @Produces @MaxNumber int getMaxNumber() {
  19.         return maxNumber;
  20.     }
  21. }

 

  • Line 7: An instance of this class exists for the lifecycle of the application
  • Line 15: next() is a Web Beans producer method.  It will get called by the Web Beans Manager to obtain an instance of the next random number.
  • Line 18: getMaxNumber() is also a Web Beans producer method.  It will get called by the Web Beans Manager to obtain an instance of maxNumber - essentially returning the maximum number to "guess" in the application (in this case "100").

The Anatomy of a Simple Contextual Bean

Now that we have are utility classes and annotations in place, we can use them in our Web Bean.

Listing 5: The "Game" Contextual Bean

  1. package webbeansguess;
  2.  
  3. import java.io.Serializable;
  4. import javax.annotation.PostConstruct;
  5. import javax.enterprise.context.SessionScoped;
  6. import javax.enterprise.inject.Instance;
  7. import javax.inject.Inject;
  8. import javax.inject.Named;
  9. import javax.faces.application.FacesMessage;
  10. import javax.faces.component.UIComponent;
  11. import javax.faces.component.UIInput;
  12. import javax.faces.context.FacesContext;
  13.  
  14. @Named
  15. @SessionScoped
  16. public class Game implements Serializable {
  17.     private static final long serialVersionUID = 1L;
  18.  
  19.     private int number;
  20.     private int guess;
  21.     private int smallest;
  22.   
  23.     @MaxNumber @Inject
  24.     private int maxNumber;
  25.   
  26.     private int biggest;
  27.     private int remainingGuesses;
  28.   
  29.     @Random @Inject Instance<Integer> randomNumber;
  30.   
  31.     public Game() {
  32.     }
  33.  
  34.     public int getNumber() {
  35.          return number;
  36.     }
  37.   
  38.     public int getGuess() {
  39.          return guess;
  40.     }
  41.   
  42.     public void setGuess(int guess) {
  43.          this.guess = guess;
  44.     }
  45.   
  46.     public int getSmallest() {
  47.          return smallest;
  48.     }
  49.   
  50.     public int getBiggest() {
  51.         return biggest;
  52.     }
  53.   
  54.     public int getRemainingGuesses() {
  55.         return remainingGuesses;
  56.     }
  57.   
  58.     public String check() throws InterruptedException {
  59.         if (guess>number) {
  60.             biggest = guess - 1;
  61.         }
  62.         if (guess<number) {
  63.             smallest = guess + 1;
  64.        }
  65.        if (guess == number) {
  66.            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
  67.        }
  68.        remainingGuesses--;
  69.        return null;
  70.     }
  71.   
  72.     @PostConstruct
  73.     public void reset() {
  74.         this.smallest = 0;
  75.         this.guess = 0;
  76.         this.remainingGuesses = 10;
  77.         this.biggest = maxNumber;
  78.         this.number = randomNumber.get();
  79.     }
  80.   
  81.     public void validateNumberRange(FacesContext context,  UIComponent toValidate, Object value) {
  82.         if (remainingGuesses <= 0) {
  83.             FacesMessage message = new FacesMessage("No guesses left!");
  84.             context.addMessage(toValidate.getClientId(context), message);
  85.             ((UIInput)toValidate).setValid(false);
  86.             return;
  87.         }
  88.         int input = (Integer) value;
  89.         if (input < smallest || input > biggest) {
  90.             ((UIInput)toValidate).setValid(false);
  91.             FacesMessage message = new FacesMessage("Invalid guess");
  92.             context.addMessage(toValidate.getClientId(context), message);
  93.         }
  94.     }
  95. }

I've color coded the areas of interest in this class.  The blue areas are JSR 299 (Web Beans) implementation details.  The red areas are JSR 330 (Dependency Injection For Java) areas.  The purple areas are the binding types.

  • Line 14: We are using the Named annotation to associate a name with this bean.  Because there is no argument specified with the Named annotation, its name will be the name of the bean itself with the first letter lowercase (game).   This allows us to reference the bean by that name using the Expression Language in the view.
  • Line 15: We declare this bean as a session scoped bean, meaning it's lifecycle is the lifecycle of the session.
  • Line 23: The producer method in the Generator class (line 18) will service this injection point causing maxNumber to have a value of "100".
  • Line 29: The producer method in the Generator class (line 15) will service this injection point making a  randomNumber instance available for this Web Bean.
  • Line 72: We use a standard @PostConstruct annotation causing variable initialization (after this Web Bean is created).
  • Line 78: Our Web Bean has been created, so the randomNumber.get() call will cause the producer method in the Generator class (line 15) to get called.

Well, that's a quick overview of a simple JSF2 application that uses the Web Beans (JSR 299 implementation) and the Java Dependency Injection (JSR 330) annotations. You can find this version of Web Beans in any of the GlassFish V3 builds after September 2, 2009.

Related Topics >>

Comments

WebBeans activation needed?

Thanks for the example. I just tried it out and failed ;-) The Game bean got loaded but failed in @PostConstruct with a NullPointer on the injected randomNumber. Seems like the injection did not happen. I tried it with the nightly build glassfish-v3-b63-09_07_2009, netbeans and eclipse. Do I have to activate WebBeans or Dependency Injection support somehow (web.xml?) ? In the summary of your blog (aquarium) it says no, but the dependency injection spec says a beans.xml is needed. But even with beans.xml in place nothing happens. Did I miss something? Cheers

Sample

You can check out the sample from cvs:

cvs -d :pserver:@cvs.dev.java.net:/cvs co glassfish-samples

The location once checked out is:

glassfish-samples/ws/javaee6/webbeans/webbeans-guess

That would be: cvs -d

That would be: cvs -d :pserver:username:@cvs.dev.java.net:/cvs co glassfish-samples (where username is your java.net user name)

thank you very much. it's

thank you very much. it's working now. by the way, the beans.xml file has to be completely empty to work. if you put in a space or a line break by mistake you'll end up with an exception during deployment java.lang.NullPointerException at org.jboss.webbeans.bootstrap.WebBeansBootstrap.validateBeans(WebBeansBootstrap.java:267)

Thanks

Thanks - that's something we'll need to fix.

Hello, very good

Hello, very good example. Currently I do not use JSF as view technology and need to know how to inject into a servlet one webbeans. Thank you. Greetings.

Web Beas Injection Into Servlet

I've just posted an entry on this subject:
http://weblogs.java.net/blog/rogerk/archive/2009/09/09/context-and-depen...

Enjoy!