Creating an ADF Databound Check Box in JSP

Written By Duncan Mills, Oracle Corporation
February 2005

Introduction

Oracle JDeveloper 10g, using the Oracle Application Development Framework (ADF), provides the JSP page developer with simple ways to produce various UI artifacts such as drop-down lists and radio groups which are bound to the business service in use. I have documented the steps to do this in previous How To documents, for example:
Creating a Databound Drop Down List in Oracle JDeveloper 10g). In this article though I'll be looking a a slightly different scenario, that of binding a checkbox.

Traditionally in an Oracle database, the kind of boolean choice that you want to expose through a checkbox has been defined as a simple character column on the table for instance VARCHAR2(1), using the valid values "Y" or "N" to indicate the boolean state. The technique outlined in this paper is based on this scenario, but will work just as well with any kind of boolean storage, for instance a CHAR or NUMBER. In this example we'll be working with an employee record that has an addition field called CONTRACTOR. In the database schema this is defined as being NOT NULL, and has a check constraint to enforce valid values of "Y" or "N". Before we proceed I'll assume that you've already defined your business service and the relevant data control is available in the Data Control Palette.

Creating the UI

The simplest way to create both the model binding and the UI for the checkbox is to drag and drop the field in question into your input form as normal input field. If you created the input form by dragging and dropping the whole collection as an "Input Form" from the Data Control Palette then of course this will have already been done. To convert the field from a normal text input to a checkbox, switch to Source view in the JSP editor and look for the relevant column name. So in my example I'll just search for the String
<html:text property="Contractor"/>. To convert the UI to a checkbox you'll need to change the
html:text to
html:checkbox. You also need to tell the tag what the
checked value is, in this case "Y", using the
value attribute. The altered tag will now look like this:

<html:checkbox property="Contractor" value="Y"/>

If you go ahead and run the page at this point, everything will appear to work correctly, existing rows in the collection will be shown either checked or unchecked as expected. However, if you start to test a little you'll begin to see some problems:

If you create a new record with the checkbox unchecked, then you'll get a constraint violation error when you commit.

If you update an existing record by un-checking the box, that change will apparently get ignored and when the screen is refreshed the box will show as checked again.

What's going on here?

The problem we're encountering here is down to a peculiarity of checkboxes in HTML UIs. The value of a checkbox is only sent to the server if it is checked, so for an unchecked checkbox no value is sent. As such, the two problems highlighted above happen because the ADF model layer is simply not been notified of the checkbox status at all.

Handling an Unchecked Checkbox

So let's look at what you have to do to handle this behavior. Fortunately it's a simple thing to detect, if you know it's likely to happen on a particular page:

In the Struts Page flow diagram, right mouse click on the DataPage in question and choose
Go To Code to create a DataForwardAction subclass.

In the Java code editor for the code, choose
Tools > Override Methods and select the
processUpdateModel() method to implement. This method maps the contents of the Struts Form Bean used by ADF back into the underlying business service. The processModelUpdate() code will initially just have a call to the superclass to process the mapping in the normal way.

Now we have to check to see if the checkbox is actually included in the request parameters. If it is included, then we know it's checked in the UI and we have to do nothing. If it is not included then we have to explicitly set the unchecked case into the ADF Form Bean for the normal update process to handle.
Here's the code for the sample scenario:

//We only need to do anything if it was not submitted
if (cbInRequest == null)
{
// Get hold of the Form Bean containing the record
BindingContainerActionForm updateForm
= (BindingContainerActionForm)ctx.getActionForm();
//Get the binding for our particular column
JUCtrlAttrsBinding checkBoxBinding
= (JUCtrlAttrsBinding)updateForm.get("Contractor");
//Reset that explicitly to the *unchecked* value (N in this case)
checkBoxBinding.setAttribute(0,"N");
}

//Now let the model update progress using the data in updateForm as normal
super.processUpdateModel(ctx);
}

The above code will need some import statements added to the class for BindingContainerActionForm and so on. JDeveloper will prompt you for these as the type is entered, press Alt-Enter to action the auto-import when prompted.
The above code can usefully be refactored into a small utility method that just takes the name of the field and the unchecked value. If you already have your own framework subclass of DataForwardAction (something I'd generally recommend) then this utility method would be a good candidate for storing in that class for reuse.

Finally, note that the code shown above is deliberately simplified for clarity.Your own code should be defensive and check for things like checkBoxBinding being not null and so forth.