Naming (JNDI) and dependency injection (CDI)

Practice for Week 7

The purpose of the exercise is to experiment with CDI and understand how it works.

Set Up

Create a new "Web Application" project named "Week7" that uses the "JavaServer Faces" framework. After creating the project, don't forget to add a reference to the Java EE 7 API Library (by right clicking on Libraries in the created project)!

In the project, create a Java class named "UniqueIdGenerator" in the package "au.edu.uts.aip.cdi".

Enter the following source code:

package au.edu.uts.aip.cdi;

public class UniqueIdGenerator {

    private static int counter = 0;

    public static synchronized int generate() {
        counter++;
        return counter;
    }

}

Next, create three Java classes, named "MyApplicationBean", "MyRequestBean" and "MyDependentBean", also in the same package:

MyApplicationBean:

package au.edu.uts.aip.cdi;

import javax.enterprise.context.*;
import javax.inject.*;

@Named
@ApplicationScoped
public class MyApplicationBean {

    private int uniqueId = UniqueIdGenerator.generate();

    public int getUniqueId() {
        return uniqueId;
    }

}

MyRequestBean:

package au.edu.uts.aip.cdi;

import javax.enterprise.context.*;
import javax.inject.*;

@Named
@RequestScoped
public class MyRequestBean {

    private int uniqueId = UniqueIdGenerator.generate();

    public int getUniqueId() {
        return uniqueId;
    }

}

MyDependentBean:

package au.edu.uts.aip.cdi;

import javax.enterprise.context.*;
import javax.inject.*;

@Named
@Dependent
public class MyDependentBean {

    private int uniqueId = UniqueIdGenerator.generate();

    public int getUniqueId() {
        return uniqueId;
    }

}

Finally, create a JSF Page named "cdi" (i.e., cdi.xhtml) with the following contents:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>CDI Testing</title>
    </h:head>
    <h:body>
        <p>myApplicationBean has id: #{myApplicationBean.uniqueId}.</p>
        <p>myApplicationBean has id: #{myApplicationBean.uniqueId}.</p>
        <p>myRequestBean has id:     #{myRequestBean.uniqueId}.</p>
        <p>myRequestBean has id:     #{myRequestBean.uniqueId}.</p>
        <p>myDependentBean has id:   #{myDependentBean.uniqueId}.</p>
        <p>myDependentBean has id:   #{myDependentBean.uniqueId}.</p>
    </h:body>
</html>

Run cdi.xhtml and look at the output.

Reflect

What does UniqueIdGenerator do?

What can we infer from the output of cdi.xhtml? What happens if you refresh the page? What does this tell us?

Create a new class called MySessionBean that is similar to the other beans but uses a @SessionScoped annotation.

Modify cdi.xhtml to show the id of the session bean.

Hint

SessionScoped beans should be made Serializable:

In other words, the class declaration should look like this:

import java.io.*;
...
public class MySessionBean implements Serializable {
...
}

If a class implements Serializable, it tells Java that the contents of the object can be saved to a file or a database. SessionScoped objects may be saved to a database or the filesystem so that if GlassFish crashes, it can still remember the details of the session.

The purpose of this exercise is to understand the important difference between using CDI injection and directly creating objects with "new".

Create Beans

Add two new Java classes to your project, MySimpleBean and MyComplexBean:

MySimpleBean.java:

package au.edu.uts.aip.cdi;

import java.io.*;
import javax.enterprise.context.*;

@Dependent
public class MySimpleBean implements Serializable {

    private int uniqueId = UniqueIdGenerator.generate();

    public int getUniqueId() {
        return uniqueId;
    }
}

MyComplexBean.java:

package au.edu.uts.aip.cdi;

import java.io.*;
import javax.enterprise.context.*;
import javax.inject.*;

@Dependent
public class MyComplexBean implements Serializable {

    @Inject
    private MySimpleBean simple;

    private int uniqueId = UniqueIdGenerator.generate();

    public int getUniqueId() {
        return uniqueId;
    }

    public MySimpleBean getSimple() {
        return simple;
    }
}

Create a View

Create a JavaServer Faces page called cdinew (i.e., cdinew.xhtml).

Enter the following code:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>CDI Testing</title>
    </h:head>
    <h:body>
        <p>simple has id:                   #{mySessionBean.simple.uniqueId}.</p>
        <p>complexByInject has id:          #{mySessionBean.complexByInject.uniqueId}.</p>
        <p>complexByNew has id:             #{mySessionBean.complexByNew.uniqueId}.</p>
        <p>complexByInject.simple is null?: #{mySessionBean.complexByInject.simple == null}.</p>
        <p>complexByInject.simple has id:   #{mySessionBean.complexByInject.simple.uniqueId}.</p>
        <p>complexByNew.simple is null?:    #{mySessionBean.complexByNew.simple == null}.</p>
        <p>complexByNew.simple has id:      #{mySessionBean.complexByNew.simple.uniqueId}.</p>
    </h:body>
</html>

Inject into MySessionBean

The JSF page we just created (cdinew.xhtml) makes use of two properties (i.e., get-methods) on MySessionBean. We need to implement them.

Add the following code to your session scoped bean, MySessionBean:

@Inject
MySimpleBean simple;

@Inject
MyComplexBean complexByInject;

MyComplexBean complexByNew = new MyComplexBean();

public MySimpleBean getSimple() {
    return simple;
}

public MyComplexBean getComplexByInject() {
    return complexByInject;
}

public MyComplexBean getComplexByNew() {
    return complexByNew;
}

Now run cdinew.xhtml and examine the output.

Reflect

Do you understand what this code does?

What does the output tell us?

What happens if you change the scopes of MyComplexBean and/or MySimpleBean?

Note: when you change the scopes, GlassFish does not always automatically detect the change in the scopes. Even clicking the green Play/Run button again may not work. The easiest way to solve this is to right click on the project, click on "Clean" and then run cdinew.xhtml again.

Challenge

This has been a short tutorial. I encourage you to attempt the challenge problem for the week.