Internet Programming with Java Course

1.    Using JavaBeans with JSP

 

he JavaBeans API provides a standard format for Java classes. Visual manipulation tools and other programs can automatically discover information about classes that follow this format and can then create and manipulate the classes without the user having to explicitly write any code.

 

1. A bean class must have a zero-argument (empty) constructor.

You can satisfy this requirement either by explicitly defining such a constructor or by omitting all constructors, which results in an empty constructor being created automatically. The empty constructor will be called when JSP elements create beans.

 

2. A bean class should have no public instance variables

(fields). I hope you already follow this practice and use accessor methods instead of allowing direct access to the instance variables. Use of accessor methods lets you impose constraints on

variable values (e.g., have the setSpeed method of your Car class disallow negative speeds), allows you to change your internal data structures without changing the class interface (e.g., change from English units to metric units internally, but still have getSpeedInMPH and getSpeedInKPH methods), and automatically perform side effects when values change (e.g., update the user interface when setPosition is called).

 

3. Persistent values should be accessed through methods

called getXxx and setXxx. For example, if your Car class stores the current number of passengers, you might have methods named getNumPassengers (which takes no arguments and returns an int) and setNumPassengers (which takes an int and has a void return type). In such a case, the Car class is said to have a property named numPassengers (notice the lowercase n in the property name, but the uppercase N in the method names). If the class has a getXxx method but no corresponding setXxx, the class is said to have a read-only property named xxx.

The one exception to this naming convention is with Boolean properties: they use a method called isXxx to look up their values. So, for example, your Car class might have methods called isLeased (which takes no arguments and returns a boolean) and setLeased (which takes a boolean and has a void return type), and would be said to have a boolean property named leased (again, notice the lowercase leading letter in the property name). Although you can use JSP scriptlets or expressions to access arbitrary methods of a class, standard JSP actions for accessing beans can only make use of methods that use the getXxx/setXxx or isXxx/setXxx design pattern.

Basic Bean Use

The jsp:useBean action lets you load a bean to be used in the JSP page. Beans provide a very useful capability because they let you exploit the reusability of Java classes without sacrificing the convenience that JSP adds over servlets alone. The simplest syntax for specifying that a bean should be used is:

<jsp:useBean id="name" class="package.Class" />

This usually means “instantiate an object of the class specified by Class, and bind it to a variable with the name specified by id.” So, for example, the JSP action <jsp:useBean id="book1" class="coreservlets.Book" />

can normally be thought of as equivalent to the scriptlet <% coreservlets.Book book1 = new coreservlets.Book(); %>

Although it is convenient to think of jsp:useBean as being equivalent to building an object, jsp:useBean has additional options that make it more powerful. You can specify a scope attribute that makes the bean associated with more than just the current page. If beans can be shared, it is useful to obtain references to existing beans, so the jsp:useBean action specifies that a new object is instantiated only if there is no existing one with the same id and scope. Rather than using the class attribute, you are permitted to use beanName instead. The difference is that beanName can refer either to a class or to a file containing a serialized bean object. The value of the beanName attribute is passed to the instantiate method of java.beans.Bean. In most cases, you want the local variable to have the same type as the object being created. In a few cases, however, you might want the variable to be declared to have a type that is a superclass of the actual bean type or is an interface that the bean implements. Use the type attribute to control this, as in the following example:

 

<jsp:useBean id="thread1" class="MyClass" type="Runnable" />

 

This use results in code similar to the following being inserted into the _jspService method:

 

Runnable thread1 = new MyClass();

 

Note that since jsp:useBean uses XML syntax, the format differs in three ways from HTML syntax: the attribute names are case sensitive, either single or double quotes can be used (but one or the other must be used), and the end of the tag is marked with />, not just >. The first two syntactic differences apply to all JSP elements that look like jsp:xxx. The third difference applies unless the element is a container with a separate start and end tag.

 

There are also a few character sequences that require special handling in order to appear inside attribute values:

• To get within an attribute value, use \’.

• To get " within an attribute value, use \".

• To get \ within an attribute value, use \\.

• To get %> within an attribute value, use %\>.

• To get <% within an attribute value, use <\%.

Accessing Bean Properties

Once you have a bean, you can access its properties with jsp:getProperty, which takes a name attribute that should match the id given in jsp:useBean and a property attribute that names the property of interest. Alternatively, you could use a JSP expression and explicitly call a method on the object that has the variable name specified with the id attribute. For example, assuming that the Book class has a String property called title and that you’ve created an instance called book1 by using the jsp:useBean example just given, you could insert the value of the title property into the JSP page in either  of the following two ways:

 

<jsp:getProperty name="book1" property="title" />

<%= book1.getTitle() %>

 

The first approach is preferable in this case, since the syntax is more accessible to Web page designers who are not familiar with the Java programming language. However, direct access to the variable is useful when you are using loops, conditional statements, and methods not represented as properties. If you are not familiar with the concept of bean properties, the standard interpretation of the statement “this bean has a property of type T called foo” is “this class has a method called getFoo that returns something of type T and has another method called setFoo that takes a T as an argument and stores it for later access by getFoo.”

Setting Bean Properties: Simple Case

To modify bean properties, you normally use jsp:setProperty. This action has several different forms, but with the simplest form you just supply three  attributes: name (which should match the id given by jsp:useBean), property (the name of the property to change), and value (the new value). That section also explains how to supply values that are computed at request time (rather than fixed strings) and discusses the type conversion conventions that let you supply string values for parameters that expect numbers, characters, or boolean values. An alternative to using the jsp:setProperty action is to use a scriptlet that explicitly calls methods on the bean object. For example, given the book1 object shown earlier in this section, you could use either of the following two forms to modify the title property:

 

<jsp:setProperty name="book1" property="title"

    value="Core Servlets and JavaServer Pages" />

<% book1.setTitle("Core Servlets and JavaServer Pages"); %>

 

Using jsp:setProperty has the advantage that it is more accessible to the nonprogrammer, but direct access to the object lets you perform more complex operations such as setting the value conditionally or calling methods other than getXxx or setXxx on the object.

Setting Bean Properties

You normally use jsp:setProperty to set bean properties. The simplest form of this action takes three attributes: name (which should match the id given by jsp:useBean), property (the name of the property to change), and value (the new value). For example, the SaleEntry class shown in Listing has an itemID property (a String), a numItems property (an int), a discountCode property (a double), and two read-only properties itemCost and totalCost (each of type double). Listing 13.4 shows a JSP file that builds an instance of the SaleEntry class by means of:

<jsp:useBean id="entry" class="coreservlets.SaleEntry" />

Once the bean is instantiated, using an input parameter to set the itemID is straightforward, as shown below:

 

<jsp:setProperty

name="entry"

property="itemID"

value='<%= request.getParameter("itemID") %>' />

 

Notice that I used a JSP expression for the value parameter. Most JSP attribute values have to be fixed strings, but the value and name attributes of jsp:setProperty are permitted to be request-time expressions. If the expression uses double quotes internally, recall that single quotes can be used instead of double quotes around attribute values and that \’ and \" can be used to represent single or double quotes within an attribute value.

 

Result of StringBean.jsp.

 

Listing 1 - SaleEntry.java

 

package coreservlets;

 

/**

* Simple bean to illustrate the various forms

* of jsp:setProperty.

*/

public class SaleEntry {

    private String itemID = "unknown";

    private double discountCode = 1.0;

    private int numItems = 0;

 

    public String getItemID() {

        return(itemID);

    }

 

    public void setItemID(String itemID) {

        if (itemID != null) {

            this.itemID = itemID;

        } else {

            this.itemID = "unknown";

        }

    }

 

    public double getDiscountCode() {

        return(discountCode);

    }

 

    public void setDiscountCode(double discountCode) {

        this.discountCode = discountCode;

    }

 

    public int getNumItems() {

        return(numItems);

    }

 

    public void setNumItems(int numItems) {

        this.numItems = numItems;

    }

 

    // Replace this with real database lookup.

    public double getItemCost() {

        double cost;

        if (itemID.equals("a1234")) {

            cost = 12.99*getDiscountCode();

        } else {

            cost = -9999;

        }

        return(roundToPennies(cost));

    }

 

    private double roundToPennies(double cost) {

        return(Math.floor(cost*100)/100.0);

    }

 

    public double getTotalCost() {

        return(getItemCost() * getNumItems());

    }

}

 

Listing 2 - SaleEntry1.jsp

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML>

    <HEAD>

        <TITLE>Using jsp:setProperty</TITLE>

        <LINK REL=STYLESHEET HREF="JSP-Styles.css" TYPE="text/css">

    </HEAD>

<BODY>

    <TABLE BORDER=5 ALIGN="CENTER">

        <TR><TH CLASS="TITLE">

            Using jsp:setProperty</TABLE>

            <jsp:useBean id="entry" class="coreservlets.SaleEntry" />

            <jsp:setProperty name="entry" property="itemID"

            value='<%= request.getParameter("itemID") %>' />

            <%

                int numItemsOrdered = 1;

                try {

                    numItemsOrdered =

                    Integer.parseInt(request.getParameter("numItems"));

                } catch(NumberFormatException nfe) {}

            %>

            <jsp:setProperty name="entry" property="numItems"

            value="<%= numItemsOrdered %>" />

            <%

                double discountCode = 1.0;

                try {

                    String discountString =

                        request.getParameter("discountCode");

                    // Double.parseDouble not available in JDK 1.1.

                    discountCode =

                        Double.valueOf(discountString).doubleValue();

                } catch(NumberFormatException nfe) {}

            %>

            <jsp:setProperty name="entry" property="discountCode"

            value="<%= discountCode %>" />

            <BR>

            <TABLE ALIGN="CENTER" BORDER=1>

                <TR CLASS="COLORED">

                <TH>Item ID<TH>Unit Price<TH>Number Ordered<TH>Total Price

                <TR ALIGN="RIGHT">

                    <TD><jsp:getProperty name="entry" property="itemID" />

                    <TD>$<jsp:getProperty name="entry" property="itemCost" />

                    <TD><jsp:getProperty name="entry" property="numItems" />

                    <TD>$<jsp:getProperty name="entry" property="totalCost" />

            </TABLE>

    </TABLE>

</BODY>

</HTML>

Associating Individual Properties with Input Parameters

Setting the itemID property was easy since its value is a String. Setting the numItems and discountCode properties is a bit more problematic since their values must be numbers and getParameter returns a String. Here is the somewhat cumbersome code required to set numItems:

 

<%

    int numItemsOrdered = 1;

    try {

        numItemsOrdered =

        Integer.parseInt(request.getParameter("numItems"));

    } catch(NumberFormatException nfe) {}

%>

<jsp:setProperty

name="entry"

property="numItems"

value="<%= numItemsOrdered %>" />

 

Fortunately, JSP has a nice solution to this problem that lets you associate a property with a request parameter and that automatically performs type conversion from strings to numbers, characters, and boolean values. Instead of using the value attribute, you use param to name an input parameter. The value of this parameter is automatically used as the value of the property, and simple type conversions are performed automatically. If the specified input parameter is missing from the request, no action is taken (the system does not pass null to the associated property). So, for example, setting the numItems property can be simplified to:

 

<jsp:setProperty

name="entry"

property="numItems"

param="numItems" />

 

The listing shows the entire JSP page reworked in this manner.

 

Result of SaleEntry1.jsp.

 

Listing 3 - SaleEntry2.jsp

 

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<HTML>

    <HEAD>

        <TITLE>Using jsp:setProperty</TITLE>

        <LINK REL=STYLESHEET HREF="JSP-Styles.css" TYPE="text/css">

    </HEAD>

<BODY>

    <TABLE BORDER=5 ALIGN="CENTER">

        <TR><TH CLASS="TITLE">

            Using jsp:setProperty</TABLE>

            <jsp:useBean id="entry" class="coreservlets.SaleEntry" />

            <jsp:setProperty

            name="entry"

            property="itemID"

            param="itemID" />

            <jsp:setProperty

            name="entry"

            property="numItems"

            param="numItems" />

            <%-- WARNING! Both the JSWDK 1.0.1 and the Java Web Server

            have a bug that makes them fail on double

            type conversions of the following sort.

            --%>

            <jsp:setProperty

            name="entry"

            property="discountCode"

            param="discountCode" />

            <BR>

            <TABLE ALIGN="CENTER" BORDER=1>

                <TR CLASS="COLORED">

                    <TH>Item ID<TH>Unit Price<TH>Number Ordered<TH>Total Price

                <TR ALIGN="RIGHT">

                    <TD><jsp:getProperty name="entry" property="itemID" />

                    <TD>$<jsp:getProperty name="entry" property="itemCost" />

                    <TD><jsp:getProperty name="entry" property="numItems" />

                    <TD>$<jsp:getProperty name="entry" property="totalCost" />

            </TABLE>

    </BODY>

</HTML>

Associating All Properties with Input Parameters

Associating a property with an input parameter saves you the bother of performing conversions for many of the simple built-in types. JSP lets you take the process one step further by associating all properties with identically named input parameters. All you have to do is to supply "*" for the property parameter. So, for example, all three of the jsp:setProperty statements of Listing 13.5 can be replaced by the following simple line. Listing 13.6 shows the complete page.

 

<jsp:setProperty name="entry" property="*" />

 

Although this approach is simple, four small warnings are in order. First, as with individually associated properties, no action is taken when an input parameter is missing. In particular, the system does not supply null as the property value. Second, the JSWDK and the Java Web Server both fail for conversions to properties that expect double values. Third, automatic type conversion does not guard against illegal values as effectively as does manual type conversion. So you might consider error pages when using automatic type conversion. Fourth, since both property names and input parameters are case sensitive, the property name and input parameter must match exactly.