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
.