When a page references a managed bean for the first time, the JavaServer
Faces implementation initializes it either based on a @Named
annotation and scope annotation in the bean class or according to its
configuration in the application configuration resource file. For
information on using annotations to initialize beans, see
Using Annotations to Configure Managed
Beans.
You can use either annotations or the application configuration resource
file to instantiate managed beans that are used in a JavaServer Faces
application and to store them in scope. The managed bean creation
facility is configured in the application configuration resource file
using managed-bean XML elements to define each bean. This file is
processed at application startup time. For information on using this
facility, see Using the managed-bean Element.
Managed beans created in the application configuration resource file are
JavaServer Faces managed beans, not CDI managed beans.
With the managed bean creation facility, you can
-
Create beans in one centralized file that is available to the entire
application, rather than conditionally instantiate beans throughout the
application
-
Customize a bean’s properties without any additional code
-
Customize a bean’s property values directly from within the
configuration file so that it is initialized with these values when it
is created
-
Using value elements, set a property of one managed bean to be the
result of evaluating another value expression
Using the managed-bean Element
A managed bean is initiated in the application configuration resource
file using a managed-bean element, which represents an instance of a
bean class that must exist in the application. At runtime, the
JavaServer Faces implementation processes the managed-bean element. If
a page references the bean and no bean instance exists, the JavaServer
Faces implementation instantiates the bean as specified by the element
configuration.
Here is an example managed bean configuration from the Duke’s Bookstore
case study:
<managed-bean eager="true">
<managed-bean-name>Book201</managed-bean-name>
<managed-bean-class>dukesbookstore.model.ImageArea</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
<property-name>shape</property-name>
<value>rect</value>
</managed-property>
<managed-property>
<property-name>alt</property-name>
<value>Duke</value>
</managed-property>
<managed-property>
<property-name>coords</property-name>
<value>67,23,212,268</value>
</managed-property>
</managed-bean>
The managed-bean-name element defines the key under which the bean
will be stored in a scope. For a component’s value to map to this bean,
the component tag’s value attribute must match the managed-bean-name
up to the first period.
The managed-bean-class element defines the fully qualified name of the
JavaBeans component class used to instantiate the bean.
The managed-bean element can contain zero or more managed-property
elements, each corresponding to a property defined in the bean class.
These elements are used to initialize the values of the bean properties.
If you don’t want a particular property initialized with a value when
the bean is instantiated, do not include a managed-property definition
for it in your application configuration resource file.
If a managed-bean element does not contain other managed-bean
elements, it can contain one map-entries element or list-entries
element. The map-entries element configures a set of beans that are
instances of Map. The list-entries element configures a set of beans
that are instances of List.
In the following example, the newsletters managed bean, representing a
UISelectItems component, is configured as an ArrayList that
represents a set of SelectItem objects. Each SelectItem object is in
turn configured as a managed bean with properties:
<managed-bean>
<managed-bean-name>newsletters</managed-bean-name>
<managed-bean-class>java.util.ArrayList</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<list-entries>
<value-class>javax.faces.model.SelectItem</value-class>
<value>#{newsletter0}</value>
<value>#{newsletter1}</value>
<value>#{newsletter2}</value>
<value>#{newsletter3}</value>
</list-entries>
</managed-bean>
<managed-bean>
<managed-bean-name>newsletter0</managed-bean-name>
<managed-bean-class>javax.faces.model.SelectItem</managed-bean-class>
<managed-bean-scope>none</managed-bean-scope>
<managed-property>
<property-name>label</property-name>
<value>Duke's Quarterly</value>
</managed-property>
<managed-property>
<property-name>value</property-name>
<value>200</value>
</managed-property>
</managed-bean>
...
This approach may be useful for quick-and-dirty creation of selection
item lists before a development team has had time to create such lists
from the database. Note that each of the individual newsletter beans has
a managed-bean-scope setting of none so that they will not
themselves be placed into any scope.
Initializing Properties Using the managed-property Element
A managed-property element must contain a property-name element,
which must match the name of the corresponding property in the bean. A
managed-property element must also contain one of a set of elements
that defines the value of the property. This value must be of the same
type as that defined for the property in the corresponding bean. Which
element you use to define the value depends on the type of the property
defined in the bean. Table 16-1 lists all the elements that
are used to initialize a value.
Table 16-1 Subelements of managed-property Elements That Define Property
Values
Element |
Value It Defines |
list-entries
|
Defines the values in a list |
map-entries
|
Defines the values of a map |
null-value
|
Explicitly sets the property to null |
value
|
Defines a single value, such as a String, int, or
JavaServer Faces EL expression |
Using the managed-bean Element includes an example of
initializing an int property (a primitive type) using the value
subelement. You also use the value subelement to initialize String
and other reference types. The rest of this section describes how to use
the value subelement and other subelements to initialize properties of
Java Enum types, Map, array, and Collection, as well as
initialization parameters.
Referencing a Java Enum Type
A managed bean property can also be a Java Enum type (see
http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html). In this
case, the value element of the managed-property element must be a
String that matches one of the String constants of the Enum. In
other words, the String must be one of the valid values that can be
returned if you were to call valueOf(Class, String) on enum, where
Class is the Enum class and String is the contents of the value
subelement. For example, suppose the managed bean property is the
following:
public enum Suit { Hearts, Spades, Diamonds, Clubs }
...
public Suit getSuit() { ... return Suit.Hearts; }
Assuming you want to configure this property in the application
configuration resource file, the corresponding managed-property
element looks like this:
<managed-property>
<property-name>Suit</property-name>
<value>Hearts</value>
</managed-property>
When the system encounters this property, it iterates over each of the
members of the enum and calls toString() on each member until it
finds one that is exactly equal to the value from the value element.
Referencing a Context Initialization Parameter
Another powerful feature of the managed bean creation facility is the
ability to reference implicit objects from a managed bean property.
Suppose you have a page that accepts data from a customer, including the
customer’s address. Suppose also that most of your customers live in a
particular area code. You can make the area code component render this
area code by saving it in an implicit object and referencing it when the
page is rendered.
You can save the area code as an initial default value in the context
initParam implicit object by adding a context parameter to your web
application and setting its value in the deployment descriptor. For
example, to set a context parameter called defaultAreaCode to 650,
add a context-param element to the deployment descriptor and give the
parameter the name defaultAreaCode and the value 650.
Next, write a managed-bean declaration that configures a property that
references the parameter:
<managed-bean>
<managed-bean-name>customer</managed-bean-name>
<managed-bean-class>CustomerBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>areaCode</property-name>
<value>#{initParam.defaultAreaCode}</value>
</managed-property>
...
</managed-bean>
To access the area code at the time the page is rendered, refer to the
property from the area component tag’s value attribute:
<h:inputText id=area value="#{customer.areaCode}"
Values are retrieved from other implicit objects in a similar way.
Initializing Map Properties
The map-entries element is used to initialize the values of a bean
property with a type of Map if the map-entries element is used
within a managed-property element. A map-entries element contains an
optional key-class element, an optional value-class element, and
zero or more map-entry elements.
Each of the map-entry elements must contain a key element and either
a null-value or value element. Here is an example that uses the
map-entries element:
<managed-bean>
...
<managed-property>
<property-name>prices</property-name>
<map-entries>
<map-entry>
<key>My Early Years: Growing Up on *7</key>
<value>30.75</value>
</map-entry>
<map-entry>
<key>Web Servers for Fun and Profit</key>
<value>40.75</value>
</map-entry>
</map-entries>
</managed-property>
</managed-bean>
The map created from this map-entries tag contains two entries. By
default, all the keys and values are converted to String. If you want
to specify a different type for the keys in the map, embed the
key-class element just inside the map-entries element:
<map-entries>
<key-class>java.math.BigDecimal</key-class>
...
</map-entries>
This declaration will convert all the keys into java.math.BigDecimal.
Of course, you must make sure that the keys can be converted to the type
you specify. The key from the example in this section cannot be
converted to a BigDecimal, because it is a String.
If you want to specify a different type for all the values in the map,
include the value-class element after the key-class element:
<map-entries>
<key-class>int</key-class>
<value-class>java.math.BigDecimal</value-class>
...
</map-entries>
Note that this tag sets only the type of all the value subelements.
Each map-entry in the preceding example includes a value subelement.
The value subelement defines a single value, which will be converted
to the type specified in the bean.
Instead of using a map-entries element, it is also possible to assign
the entire map using a value element that specifies a map-typed
expression.
Initializing Array and List Properties
The list-entries element is used to initialize the values of an array
or List property. Each individual value of the array or List is
initialized using a value or null-value element. Here is an example:
<managed-bean>
...
<managed-property>
<property-name>books</property-name>
<list-entries>
<value-class>java.lang.String</value-class>
<value>Web Servers for Fun and Profit</value>
<value>#{myBooks.bookId[3]}</value>
<null-value/>
</list-entries>
</managed-property>
</managed-bean>
This example initializes an array or a List. The type of the
corresponding property in the bean determines which data structure is
created. The list-entries element defines the list of values in the
array or List. The value element specifies a single value in the
array or List and can reference a property in another bean. The
null-value element will cause the setBooks method to be called with
an argument of null. A null property cannot be specified for a
property whose data type is a Java primitive, such as int or
boolean.
Initializing Managed Bean Properties
Sometimes you might want to create a bean that also references other
managed beans so that you can construct a graph or a tree of beans. For
example, suppose you want to create a bean representing a customer’s
information, including the mailing address and street address, each of
which is also a bean. The following managed-bean declarations create a
CustomerBean instance that has two AddressBean properties: one
representing the mailing address and the other representing the street
address. This declaration results in a tree of beans with CustomerBean
as its root and the two AddressBean objects as children.
<managed-bean>
<managed-bean-name>customer</managed-bean-name>
<managed-bean-class>
com.example.mybeans.CustomerBean
</managed-bean-class>
<managed-bean-scope> request </managed-bean-scope>
<managed-property>
<property-name>mailingAddress</property-name>
<value>#{addressBean}</value>
</managed-property>
<managed-property>
<property-name>streetAddress</property-name>
<value>#{addressBean}</value>
</managed-property>
<managed-property>
<property-name>customerType</property-name>
<value>New</value>
</managed-property>
</managed-bean>
<managed-bean>
<managed-bean-name>addressBean</managed-bean-name>
<managed-bean-class>
com.example.mybeans.AddressBean
</managed-bean-class>
<managed-bean-scope> none </managed-bean-scope>
<managed-property>
<property-name>street</property-name>
<null-value/>
<managed-property>
...
</managed-bean>
The first CustomerBean declaration (with the managed-bean-name of
customer) creates a CustomerBean in request scope. This bean has two
properties, mailingAddress and streetAddress. These properties use
the value element to reference a bean named addressBean.
The second managed bean declaration defines an AddressBean but does
not create it, because its managed-bean-scope element defines a scope
of none. Recall that a scope of none means that the bean is created
only when something else references it. Because both the
mailingAddress and the streetAddress properties reference
addressBean using the value element, two instances of AddressBean
are created when CustomerBean is created.
When you create an object that points to other objects, do not try to
point to an object with a shorter life span, because it might be
impossible to recover that scope’s resources when it goes away. A
session-scoped object, for example, cannot point to a request-scoped
object. And objects with none scope have no effective life span
managed by the framework, so they can point only to other none-scoped
objects. Table 16-2 outlines all of the allowed
connections.
Table 16-2 Allowable Connections between Scoped Objects
An Object of This Scope |
May Point to an Object of This Scope |
none
|
none
|
application
|
none, application
|
session
|
none, application, session
|
request
|
none, application, session, request, view
|
view
|
none, application, session, view
|
Be sure not to allow cyclical references between objects. For example,
neither of the AddressBean objects in the preceding example should
point back to the CustomerBean object, because CustomerBean already
points to the AddressBean objects.
Initializing Maps and Lists
In addition to configuring Map and List properties, you can also
configure a Map and a List directly so that you can reference them
from a tag rather than referencing a property that wraps a Map or a
List.