Configuring Beans
To instantiate backing beans used in a JavaServer Faces application and store them in scope, you use the managed bean creation facility. This facility is configured in the application configuration resource file using
managed-beanXML elements to define each bean. This file is processed at application startup time. When a page references a bean, the JavaServer Faces implementation initializes it according to its configuration in the application configuration resource file.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 the bean's properties without any additional code.
- When a managed bean is created, customize the bean's property values directly from within the configuration file.
- Using
valueelements, set the property of one managed bean to be the result of evaluating another value-binding expression.This section shows you how to initialize backing beans using the managed bean creation facility. Writing Component Properties explains how to write backing bean properties. Writing Backing Bean Methods explains how to write backing bean methods. Binding Component Values and Instances to External Data Sources explains how to reference a managed bean from the component tags.
Using the managed-bean Element
You create a backing bean using a
managed-beanelement, which represents an instance of a bean class that must exist in the application. At runtime, the JavaServer Faces implementation processes themanaged-beanelement. If a page references the bean, the JavaServer Faces implementation instantiates the bean as specified by the element configuration if no instance exists.Here is an example managed bean configuration from the Duke's Bookstore application:
<managed-bean> <managed-bean-name> NA </managed-bean-name> <managed-bean-class> model.ImageArea </managed-bean-class> <managed-bean-scope> application </managed-bean-scope> <managed-property> <property-name>shape</property-name> <value>poly</value> </managed-property> ... </managed-bean-name> </managed-bean>The
managed-bean-nameelement defines the key under which the bean will be stored in a scope. For a component to map to this bean, the component tag'svalueattribute must match themanaged-bean-nameup to the first period. For example, thisvalueexpression maps to theshapeproperty of theImageAreainstance,NA:The part before the . matches the
managed-bean-nameofImageArea. Using the HTML Component Tags has more examples of usingvalueto bind components to bean properties.The
managed-bean-classelement defines the fully qualified name of the JavaBeans component class used to instantiate the bean. It is the application developer's responsibility to ensure that the class complies with the configuration of the bean in the application configuration resource file. For example, the property definitions must match those configured for the bean.The
managed-bean-scopeelement defines the scope in which the bean will be stored. The four acceptable scopes arenone,request,session, orapplication. If you define the bean with anonescope, the bean is instantiated anew each time it is referenced, and so it does not get saved in any scope. One reason to use a scope ofnoneis that a managed bean references another managed bean. The second bean should be innonescope if it is supposed to be created only when it is referenced. See Initializing Managed Bean Properties for an example of initializing a managed bean property.If you are configuring a backing bean that is referenced by a component tag's
bindingattribute, you should define the bean with a request scope. If you placed the bean in session or application scope instead, the bean would need to take precautions to ensure thread safety becauseUIComponentinstances depend on running inside of a single thread.The
managed-beanelement can contain zero or moremanaged-propertyelements, 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 amanaged-propertydefinition for it in your application configuration resource file.If a
managed-beanelement does not contain othermanaged-beanelements, it can contain onemap-entrieselement orlist-entrieselement. Themap-entrieselement configures a set of beans that are instances ofMap. Thelist-entrieselement configures a set of beans that are instances ofList.To map to a property defined by a
managed-propertyelement, you must ensure that the part of a component tag'svalueexpression after the . matches themanaged-propertyelement'sproperty-nameelement. In the earlier example, theshapeproperty is initialized with the valuepoly. The next section explains in more detail how to use themanaged-propertyelement.Initializing Properties using the managed-property Element
A
managed-propertyelement must contain aproperty-nameelement, which must match the name of the corresponding property in the bean. Amanaged-propertyelement must also contain one of a set of elements (listed in Table 21-1) 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 21-1 lists all the elements used to initialize a value.
Using the managed-bean Element includes an example of initializing
Stringproperties using thevaluesubelement. You also use thevaluesubelement to initialize primitive and other reference types. The rest of this section describes how to use thevaluesubelement and other subelements to initialize properties of typejava.util.Map,array, andCollection, as well as initialization parameters.Referencing an Initialization Parameter
Another powerful feature of the managed bean creation facility is the ability to reference implicit objects from a managed bean property.
Suppose that 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
initParamimplicit object by adding a context parameter to your web application and setting its value usingdeploytool. For example, to set a context parameter calleddefaultAreaCodeto650, launchdeploytool, open the web application, select the web application from the tree, select the Context tab, add a new context parameter, and enterdefaultAreaCodein the Coded Parameter field and650in the Value field.Next, you write a
managed-beandeclaration 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
areacomponent tag'svalueattribute:Retrieving values from other implicit objects is done in a similar way. See Table 18-9 for a list of implicit objects.
Initializing Map Properties
The
map-entrieselement is used to initialize the values of a bean property with a type ofjava.util.Mapif themap-entrieselement is used within amanaged-propertyelement. Here is the definition ofmap-entriesfrom theweb-facesconfig_1_0.dtd, located athttp://java.sun.com/dtd/web-facesconfig_1_0.dtdthat defines the application configuration resource file:As this definition shows, a
map-entrieselement contains an optionalkey-classelement, an optionalvalue-classelement, and zero or moremap-entryelements.Here is the definition of
map-entryfrom the DTD:According to this definition, each of the
map-entryelements must contain akeyelement and either anull-valueorvalueelement. Here is an example that uses themap-entrieselement:<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 that is created from this
map-entriestag contains two entries. By default, all the keys and values are converted tojava.lang.String. If you want to specify a different type for the keys in the map, embed thekey-classelement just inside themap-entrieselement: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 that you specify. The key from the example in this section cannot be converted to ajava.math.BigDecimalbecause it is aString.If you also want to specify a different type for all the values in the map, include the
value-classelement after thekey-classelement:<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
valuesubelements.The first
map-entryin the preceding example includes avaluesubelement. Thevaluesubelement defines a single value, which will be converted to the type specified in the bean.The second
map-entrydefines avalueelement, which references a property on another bean. Referencing another bean from within a bean property is useful for building a system from fine-grained objects. For example, a request-scoped form-handling object might have a pointer to an application-scoped database mapping object. Together the two can perform a form-handling task. Note that including a reference to another bean will initialize the bean if it does not already exist.Instead of using a
map-entrieselement, it is also possible to assign the entire map using avalueelement that specifies a map-typed expression.Initializing Array and List Properties
The
valueselement is used to initialize the values of anarrayorListproperty. Each individual value of the array orListis initialized using avalueornull-valueelement. Here is an example:<managed-bean> ... <managed-property> <property-name>books</property-name> <values> <value-type>java.lang.String</value-type> <value>Web Servers for Fun and Profit</value> <value>#{myBooks.bookId[3]}</value> <null-value/> </values> </managed-property> </managed-bean>This example initializes an
arrayor aList. The type of the corresponding property in the bean determines which data structure is created. Thevalueselement defines the list of values in thearrayorList. Thevalueelement specifies a single value in thearrayorListand can reference a property in another bean. Thenull-valueelement will cause thesetBooksmethod to be called with an argument ofnull. Anullproperty cannot be specified for a property whose data type is a Java primitive, such asintorboolean.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 that 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-beandeclarations create aCustomerBeaninstance that has twoAddressBeanproperties: one representing the mailing address, and the other representing the street address. This declaration results in a tree of beans withCustomerBeanas its root and the twoAddressBeanobjects as children.<managed-bean> <managed-bean-name>customer</managed-bean-name> <managed-bean-class> com.mycompany.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.mycompany.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
CustomerBeandeclaration (with themanaged-bean-nameofcustomer) creates aCustomerBeanin request scope. This bean has two properties:mailingAddressandstreetAddress. These properties use thevalueelement to reference a bean namedaddressBean.The second managed bean declaration defines an
AddressBeanbut does not create it because itsmanaged-bean-scopeelement defines a scope ofnone. Recall that a scope ofnonemeans that the bean is created only when something else references it. Because both themailingAddressand thestreetAddressproperties referenceaddressBeanusing thevalueelement, two instances ofAddressBeanare created whenCustomerBeanis 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
nonescope have no effective life span managed by the framework, so they can point only to othernonescoped objects. Table 21-2 outlines all of the allowed connections.
You should also not allow cyclical references between objects. For example, neither of the
AddressBeanobjects in the preceding example should point back to theCustomerBeanobject becauseCustomerBeanalready points to theAddressBeanobjects.Initializing Maps and Lists
In addition to configuring
MapandListproperties, you can also configure aMapand aListdirectly so that you can reference them from a tag rather than referencing a property that wraps aMapor aList.The Duke's Bookstore application configures a
Listto initialize the list of free newsletters, from which users can choose a set of newsletters to subscribe to on thebookcashier.jsppage:<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 configuration initializes a
Listcallednewsletters. This list is composed ofSelectIteminstances, which are also managed beans. See The UISelectItem, UISelectItems, and UISelectItemGroup Components for more information onSelectItem. Note that, unlike the example in Initializing Map Properties, the newsletters list is not a property on a managed bean. (It is not wrapped with amanaged-propertyelement.) Instead, the list is the managed bean.