Tricks and Problems with Servlets and JSPs

  1. BeanInfo doesn't work.
  2. How can BeanInfo be avoided?
  3. PopulateBean doesn't work.
  4. Accumulate output in a String instead of calling out.println
  5. Null Pointer exceptions for selections, radios and checkboxes
  6. Using if ..else if ... else if ... else to test for buttons.
  7. Putting validation routines in the Bean
  8. Putting error properties in the Bean
  9. Using setAttribute to send extra data to the JSP
  10. My servlet was working, but now it isn't.


BeanInfo Doesn't Work

Problem: The primary problem is that all properties that are defined in BeanInfo, must also be defined in the Bean.

Solution 1: Carefully inspect the BeanInfo and be sure that you have not defined property descriptors for properties that do not exist in the Bean.

Solution 2: See: Avoid BeanInfo


Avoid BeanInfo

Problem: Using complex Beans without using a BeanInfo class

Solution: Do not call populateBean. Do the initialization yourself. If you have a String[] for a multiple selection list or a checkbox, then you normally need to use populateBean and a BeanInfo class to initialize your Bean. It is possible to use request.getParameter and request.getParamterValues to initialize the Bean yourself.

Example: Using BidServlet with the complexBean BidInfo that has a String[] of options.

BidInfo bid = new BidInfo();
bid.setBidPrice( request.getParameter("bidPrice") );
bid.setItemName( request.getParameter("itemName") );
bid.setOptions( request.getParameterValues("options") );
etc.

Notice that the options property is filled using getParamterValues. You could actually use getParameterValues for all properties, since this method will return a single value or an array.


PopulateBean Doesn't Work

See: BeanInfo doesn't work.


Accumulate output in a String

Trick: Instead of displaying output when it is created, accumulate the output in a String, and display it later.

Advantage: This gives you more control over the appearance of the output. It is possible to create all of the output in different strings, and then to display them in any order you wish.

Example: Here is a method that generates its output as it is testing.

public void isValid(BidInfo bid) {
  if (bid.getPrice() < 1.0) {
    out.println("Price must be at least $1.0");
  }
  if (bid.getItemName().trim().indexOf(" ") >= 0) {
    out.println("ItemNames must be one word");
  }
}

Here is a more flexible version that stores the output in a String and returns it to the calling method. This gives the calling method more control over when the output will be displayed.

public String isValid(BidInfo bid) {
  String result = "";
  if (bid.getPrice() < 1.0) {
    result += "Price must be at least $1.0";
  }
  if (bid.getItemName().trim().indexOf(" ") >= 0) {
    result += "ItemNames must be one word";
  }
  return result;
}

It has the further advantage of being able to test if an error existed. If the return value is "", then no errors were generated, so the input data must be valid.


Null Pointer exceptions for selections, radios and checkboxes

Problem: If nothing is selected in a multiple selection list or checkbox, then a Null Pointer exception occurs.

Solution: If a radio, checkbox or option is not selected, then there is nothing in the Query String for these form elements. This means that getParamterValues will return null. It also means that a bean property for any of these will also return null. Any time you have a possiblity of a null, you must guard against it.

Example:

String[] options = bid.getOptions();
if (options != null) { for (i=0; i<options.length; i++) { .... } }

Without the explicit test for null, this code would crash if no options were selected.


Using if ..else if ... else if ... else to test for buttons

Trick: Using if .. else if insures that only one page is being called.

Suppose you have three buttons in your form

<input type="submit" name="edit"    value="Edit">
<input type="submit" name="confirm" value="Confirm">
<input type="submit" name="update"  value="Update">
The following code in your servlet would test which button was pressed
if (request.getParameter( "edit" ) != null) {
  //code for edit
} else if (request.getParameter( "confirm" ) != null) {
  //code for confirm
} else if (request.getParameter( "update" ) != null) {
  //code for update
} else {
  //default
}


Putting validation routines in the Bean

Trick: Place validation routines in the bean so that they can be accessed anywhere that the bean can be accessed

Advantage: All the variables and methods of the Bean are available.

Example:

public String validPrice() {
  String result = "";
  if (this.price < 1.00) {
    result += "Price must be at least $1.00";
  }
  return result;
}


Putting error methods in the Bean

Trick: For each property that is being validated, create error properties as well. They can be accessed anywhere that the bean can be accessed.

Advantage: All the variables and methods of the Bean are available. They can be incorporated with validation routines to simplify error processing.

Note: This does not have to be the actual error message that is displayed in the validataion routine. It could be anything (like a style?????).

Example:

private String priceError = "";
public void setPriceError(String error) {
priceError = error; } public String getPriceError() { return priceError; }

Example of a validation routine that uses this

public String validPrice() {
  String result = "";
  setPriceError("");
  if (this.price < 1.00) {
    setPriceError("Bad dog, no biscuit"); //or something more useful?????
    result += "Price must be at least $1.00";
  }
  return result;
}


Using setAttribute to send data to the JSP

Trick: Sometimes, it is easier to do all the logic in the servlet and then send output to the JSP.

Advantage: It is easier to write code in the servlet and the JSP is easier to read.

Example:

Code in servlet

String message = "";
if ( bid.isPartlyComplete() ) {
  message = "Please fill in all the data";
  address = "/Form.jsp";
} else {
  message = "Welcome to this site";
  address = "/Form.jsp";
}
request.setAttribute("message", message);
request.getRequestDispatcher(address).forward(request, response);

Code in JSP

<%= request.getAttribute("message") %>


My servlet was working, but now it isn't

Try renaming your servlet. The problem might be that Tomcat needs to be restarted. If you find that renaming the servlet fixes the problem, then restart your Tomcat, or ask me to reset your webapp if you are running your servlet off of otter. Usually the message you will see is that the INVOKER is not available for your servlet. There will not be a stack trace for an error, it will only state that the servlet is unavailable.

If you have the permissions wrong on your .class file, then Tomcat marks your servlet as unavailable. Even if you fix the permissions, Tomcat will still think that the servlet is unavailable. The only way to fix this is to restart Tomcat. If you are running your servlet from localhost, then you can restart Tomcat and the probem should be fixed. If you are running your servlet through my Tomcat on otter, then you will need to ask me to reset your webapp. In the meantime, you can work on your renamed servlet.

After you recompile your servlet, be sure that the permissions are correct before you access your servlet.