Write a custom JSF tag for enhancing radio button behavior JavaServer Faces is a server-side user interface component framework for Java-based Web applications and is now officially part of Java Platform, Enterprise Edition 5. One of the major advantages of JSF is its flexible component architecture.Though JSF provides standard user interface components, sometimes the standard tags supplied by JSF are insufficient for easily representing complex user interface controls or certain behaviors of some GUI controls. Thus, a JSF developer must often write complex logic and the corresponding Java class in each page. In addition, implementing some special behaviors sometimes requires JavaScript. One such scenario arises while embedding a radio button inside the JSF dataTable tag. A radio button is generally required when we need to select only one option from a set of options. Let’s consider two radio button scenarios for a JSF application:Our first scenario is often employed while using a single selection of a row in a table (dataTable). Here, when the page is submitted to the server side, our intention is to receive the row index selected in the table. In addition, all the radio buttons inside that particular column of the table should behave like a radio group (such as when one is selected, the others are unselected). This simple functionality is pretty difficult to achieve using JSF technology without JavaScript or third-party custom tag libraries. Figure 1 describes the scenario.The first scenario deals with grouping the radio button within a column. Our second scenario handles just the opposite: we must group the radio buttons inside a row. Say we need a feedback application where a manager rates different employees by selecting a single radio button from different column headers such as excellent or good. As shown in Figure 2, we group the radio buttons within a single row. Again, achieving this functionality using standard JSF tags without JavaScript can prove quite difficult.The problem with standard JSF tagsLet’s analyze why standard JSF tags are difficult to implement in our two scenarios. The following JSF page fragment shows the usage of the h:selectOneRadio tag: <h:selectOneRadio id="myRadio" value="#{myBackingBean.myRadioValue}"> <f:selectItems value="#{myBackingBean.myRadioPossibleOptions}"/> </h:selectOneRadio> Alternatively, instead of using f:selectItems, you can use multiple f:selectItems: <h:selectOneRadio id="myRadio" value="#{myBackingBean.myRadioValue}"> <f:selectItem itemValue="0" itemLabel="#{myBackingBean.myRadioPossibleLabel1}"/> <f:selectItem itemValue="1" itemLabel="#{myBackingBean.myRadioPossibleLabel2}"/> <f:selectItem itemValue="2" itemLabel="#{myBackingBean.myRadioPossibleLabel3}"/> </h:selectOneRadio> Note that itemValue property’s value can also be taken from the backing bean as value-binding instead of hard-coding.Both of the two syntaxes mandate that the f:selectItems tag or the f:selectItem tag (which are actually responsible for individual radio items) must be nested inside the h:selectOneRadio tag. All the radio buttons behave as if they were residing under a radio button group. We cannot put this radio button inside a JSF dataTable tag and span the radio button group behavior across rows or across columns because h:selectOneRadio cannot contain the h:column element, which represents a column inside an h:dataTable. When each column is rendered, the name generated by the JSF containers differs for each cell. As a result, individual radio buttons receive different names and create separate radio groups (with only one radio) in each group. The important point to note is, if we use h:selectOneRadio and f:selectItems or f:selectItem inside dataTable, the radio buttons render properly; that is, when the page renders, the page displays a table that contains the right radio buttons. But the problem is all the radio buttons inside each cell (inside each <tr> and <td> tag) fall under different radio button groups, because each radio button’s name attribute is generated uniquely by the JSF container.SolutionsSolutions are available for overcoming this problem, but they require either some JavaScript (along with a valueChangeListener) or third-party custom tags. If you are OK with using JavaScript to control your radio-click behavior, then go ahead with valueChangeListener and the JavaScript solution. Using a third-party custom tag is a good option if you are already using that third-party library for some other purpose. But if you do not want to use any other component from a third-party library, you can build your own custom tag to solve this issue with minimal effort.JSF quick tourBefore diving into our custom component, let’s quickly review JSF technology. When JSF is used with vanilla Java, the values for the user interface component are set with Java, not the custom tag class, because the JSF APIs are coded on top of the servlet layer, not the JavaServer Pages layer. But JSP, as the rendering technology for JSF, and HTML, as the target client, is currently the most widely used scenario.In JSF’s JSP pages, developers use the custom tags as defined by JSF along with any other user-defined custom tags. Let’s use a simple example to see how a JSF page works. Figure 3 shows a diagram of a JSF sample application. As illustrated, the JSF page contains several JSF tags. The value and action of these tags can bind to a JavaBean property and method at the Web-container level. One JSF page can map to multiple JavaBeans. These JavaBeans are generally called backing beans or managed beans. From a backing bean, you can call the middle-tier business logic using any other favorite framework or technology. Between the client and the JavaBean are the JSF implementation classes, which consist of a controller servlet (FacesServlet), components, renderers and XML configuration.The main configuration file used to control different aspects of JSF programming is faces-config.xml. This file contains the managed bean declaration, navigational flow, locale declaration, phase-listener declarations, any custom components and custom renderer declarations (registration). Let’s look into the JSF user interface component architecture. To achieve decoupling between the presentation (rendering) and the behavior of the component, JSF has introduced separate interfaces. The part that deals with the user interface data’s behavior is called a component. The part that deals with the presentation (rendering) is called a renderer. Though the rendering logic can also be coded inside the component, if the same behavioral component must be displayed in a different form, then separation is must.By delegating the operations to the renderer, we have the option of associating our custom component with different renderers so we can represent the component in different ways on the page. If we don’t want to render a particular component differently, it’s OK to let the component class handle the rendering.To use the JSF custom component in a JSP page, we need a custom tag (along with the component and renderer). Thus, to build a custom user interface component in JSF, developers need to write three different Java classes, which we will also write for our custom radio button: A component classA renderer classA custom tag classCustom component creation for the radio buttonLet’s first concentrate on writing the component class. The radio button value displays the content to front-end users, plus the submitted value needs to traverse to the server side, so we need to extend our custom tag from the javax.faces.component.UIInput class. Note that if we need to write a component used only for display purpose (say, h:outputText), then we need to extend our component class from javax.faces.component.UIOutput: public class UICustomSelectOneRadio extends UIInput { //Other codes //... } For simplicity, we take all the attributes of our custom tags as strings. Let’s consider the attributes below for our custom tag. You can add any other relevant attributes later.Also, for each of the above attributes, we provide the option of value-binding instead of hard-coding; such as the value of each property can also be taken using value-binding, say, from a backing bean’s attribute. So, inside our custom component, we need a utility method such as the following: public String returnValueBindingAsString(String attr) { ValueBinding valueBinding = getValueBinding(attr); if (valueBinding != null) return (String)valueBinding.getValue(this.getFacesContext()); else return null; } Note: The getValueBinding() method inside the returnValueBindingAsString() method is available in the super class hierarchy for javax.faces.component.UIComponentBase (javax.faces.component.UIInput extends javax.faces.component.UIOutput, which extends javax.faces.component.UIComponentBase). Value-bindings are stored in a map associated with the component, though usually a property (setter/getter method) of the same name is defined on the component itself, which evaluates the value-binding when called. getFacesContext() also exists in the javax.faces.component.UIComponentBase class, which returns the FacesContext instance. FacesContext contains all of the per-request state information related to the processing of a single JSF request and the rendering of the corresponding response. It is passed to, and potentially modified by, each phase of the request-processing life cycle.Our component class now looks like the following: public class UICustomSelectOneRadio extends UIInput { public String returnValueBindingAsString(String attr) { ValueBinding valueBinding = getValueBinding(attr); if (valueBinding != null) return (String)valueBinding.getValue(this.getFacesContext()); else return null; } private String name = null; private String overrideName = null; private String styleClass = null; private String style = null; private String disabled = null; private String itemLabel = null; private String itemValue = null; private String onClick = null; private String onMouseOver = null; private String onMouseOut = null; private String onFocus = null; private String onBlur = null; //Other codes //... } Now, for each attribute, we need accessor and mutator methods like the following: public String getName() { if (null != name) { return name; } return returnValueBindingAsString("name"); } public void setName(String string) { name = string; } The same code repeats for other attributes, such as overrideName or styleClass. We also need to override two important methods from the super class: public Object saveState(FacesContext context) and public void restoreState(FacesContext context, Object state). The JSF container uses these methods to save and restore the JSF tree state: public Object saveState(FacesContext context) { Object[] values = new Object[13]; values[0] = super.saveState(context); values[1] = styleClass; values[2] = style; values[3] = disabled; values[4] = itemLabel; values[5] = itemValue; values[6] = onClick; values[7] = onMouseOver; values[8] = onMouseOut; values[9] = onFocus; values[11] = name; values[12] = overrideName; return (values); } public void restoreState(FacesContext context, Object state) { Object[] values = (Object[]) state; super.restoreState(context, values[0]); styleClass = (String) values[1]; style = (String) values[2]; disabled = (String) values[3]; itemLabel = (String) values[4]; itemValue = (String) values[5]; onClick = (String) values[6]; onMouseOver = (String) values[7]; onMouseOut = (String) values[8]; onFocus = (String) values[9]; onBlur = (String) values[10]; name = (String) values[11]; overrideName = (String) values[12]; } Last, but not least, another method is also important for our component class: getFamily(), illustrated below. The value returned from getFamily() is referenced in the faces-config.xml file. public String getFamily() { return ("CustomSelectOneRadio"); } Look at the code available for download from Resources for the full source of the UICustomSelectOneRadio.java file.Now let’s concentrate on writing our custom radio button’s renderer. It extends the javax.faces.render.Renderer class: public class HTMLCustomSelectOneRadioRenderer extends Renderer { //Other codes //... } The important methods in any renderer class are the following: public void decode(FacesContext context, UIComponent component)public void encodeBegin(FacesContext context, UIComponent component)public void encodeChildren(FacesContext context, UIComponent component)public void encodeEnd(FacesContext context, UIComponent component)The decode() method is used in the JSF life cycle’s “apply request values” phase. In this phase, the values submitted from the frontend (GUI) are taken from the request object and updated in the JSF component tree.Note that JSF has six distinct phases in its life cycle, the discussion of which reaches beyond this article’s scope. For more details, consult the links in Resources.Our decode() method, and other methods used inside decode(), looks like the following: public void decode(FacesContext context, UIComponent component) { if ((context == null) || (component == null)) { throw new NullPointerException(); } UICustomSelectOneRadio aUICustomSelectOneRadio = null; if(component instanceof UICustomSelectOneRadio) { aUICustomSelectOneRadio = (UICustomSelectOneRadio)component; } else { return; } Map map = context.getExternalContext().getRequestParameterMap(); String name = getName(aUICustomSelectOneRadio, context); if ( map.containsKey(name) ) { String value = (String)map.get(name); if ( value != null ) { setSubmittedValue(component, value); } } } public void setSubmittedValue(UIComponent component, Object obj) { if(component instanceof UIInput) { ((UIInput)component).setSubmittedValue(obj); } } private String getName(UICustomSelectOneRadio aUICustomSelectOneRadio, FacesContext context) { UIComponent parentUIComponent = getParentDataTableFromHierarchy(aUICustomSelectOneRadio); if ( parentUIComponent == null ) { return aUICustomSelectOneRadio.getClientId(context); } else { if ( aUICustomSelectOneRadio.getOverrideName() != null && aUICustomSelectOneRadio.getOverrideName().equals("true")) { return aUICustomSelectOneRadio.getName(); } else { String id = aUICustomSelectOneRadio.getClientId(context); int lastIndexOfColon = id.lastIndexOf(":"); String partName = ""; if ( lastIndexOfColon != -1 ) { partName = id.substring(0, lastIndexOfColon + 1); if ( aUICustomSelectOneRadio.getName() == null ) { partName = partName + "generatedRad"; } else partName = partName + aUICustomSelectOneRadio.getName(); } return partName; } } } private UIComponent getParentDataTableFromHierarchy(UIComponent uiComponent) { if ( uiComponent == null ) { return null; } if ( uiComponent instanceof UIData ) { return uiComponent; } else { //try to find recursively in the Component tree hierarchy return getParentDataTableFromHierarchy(uiComponent.getParent()); } } As mentioned earlier, the decode() method retrieves the client-submitted value from the request object and sets the value in the component residing in the JSF component tree. The context.getExternalContext().getRequestParameterMap() statement inside decode() retrieves a Map object. This Map contains all the submitted values from the frontend as name-value pairs.The most interesting method in our renderer is getName(), which is where the magic happens. The first line checks whether the radio button resides inside a JSF dataTable. If not, the method returns with the JSF container-generated ID. Now, if we want to group all the radio buttons in a particular column (our first scenario), we need to set the overrideName attribute as true. If overrideName is set to true, the value supplied in name will remain as is. If the name is the same for all the columns, all the radio buttons inside that particular column will automatically fall in the same group. The following illustrates how to accomplish our first scenario: if ( aUICustomSelectOneRadio.getOverrideName() != null && aUICustomSelectOneRadio.getOverrideName().equals("true")) { return aUICustomSelectOneRadio.getName(); } Now let’s consider our second scenario; such as the radio buttons must be grouped in a row, instead of a column. The following code snippet from the getName() method handles the name generation of our second scenario: String id = aUICustomSelectOneRadio.getClientId(context); int lastIndexOfColon = id.lastIndexOf(":"); String partName = ""; if ( lastIndexOfColon != -1 ) { partName = id.substring(0, lastIndexOfColon + 1); if ( aUICustomSelectOneRadio.getName() == null ) { partName = partName + "generatedRad"; } else partName = partName + aUICustomSelectOneRadio.getName(); } return partName; This snippet actually removes the last part from the radio button’s name (which is generated by the container to make it unique for each cell) and appends a common name so that the radio button’s name becomes unique across each row (not each cell). In the same row, all the names of the radio buttons are the same. Using the above trick, we can now achieve the radio group for each row.For example, say the JSF container has generated the ID as testRadioForm:mySampleTable3:1:myRadioId2—we get this ID by calling the aUICustomSelectOneRadio.getClientId(context) method in the above code snippet. The code first gets the substring testRadioForm:mySampleTable3:1: and then appends the name supplied. If the name is not available, it just appends a default string generatedRad. Hence, if the name attribute contains a value myRadioRow, then the final name will be testRadioForm:mySampleTable3:1:myRadioRow, instead of testRadioForm:mySampleTable3:1:myRadioId2. The same new-name generation process repeats for all the radio tags in the other columns of the same dataTable. Eventually, all the radio buttons within a row will have the same name, testRadioForm:mySampleTable3:1:myRadioRow. Once the names are the same, the radio buttons will fall in the same radio group automatically. Now let’s look at the encodeEnd() method; encodeBegin() and encodeChildren() methods are not relevant for this particular renderer. In encodeBegin(), encodeChildren(), and encodeEnd(), we write the code needed for the client to render the control. The JSF container calls these methods in the “render response” phase (the final JSF life cycle phase): public void encodeEnd(FacesContext context, UIComponent component) throws IOException { if ((context == null) || (component == null)) { throw new NullPointerException(); } UICustomSelectOneRadio aUICustomSelectOneRadio = (UICustomSelectOneRadio)component; if ( component.isRendered() ) { ResponseWriter writer = context.getResponseWriter(); writer.write("<input type="radio""); writer.write(" id="" + component.getClientId(context) + """); writer.write(" name="" + getName(aUICustomSelectOneRadio, context) + """); if ( aUICustomSelectOneRadio.getStyleClass() != null && aUICustomSelectOneRadio.getStyleClass().trim().length() > 0 ) { writer.write(" class="" + aUICustomSelectOneRadio.getStyleClass().trim() + """); } if ( aUICustomSelectOneRadio.getStyle() != null && aUICustomSelectOneRadio.getStyle().trim().length() > 0 ) { writer.write(" style="" + aUICustomSelectOneRadio.getStyle().trim() + """); } if ( aUICustomSelectOneRadio.getDisabled() != null && aUICustomSelectOneRadio.getDisabled().trim().length() > 0 && aUICustomSelectOneRadio.getDisabled().trim().equals("true")) { writer.write(" disabled="disabled""); } if ( aUICustomSelectOneRadio.getItemValue() != null ) { writer.write(" value="" + aUICustomSelectOneRadio.getItemValue().trim() + """); } if ( aUICustomSelectOneRadio.getOnClick() != null && aUICustomSelectOneRadio.getOnClick().trim().length() > 0 ) { writer.write(" onclick="" + aUICustomSelectOneRadio.getOnClick().trim() + """); } if ( aUICustomSelectOneRadio.getOnMouseOver() != null && aUICustomSelectOneRadio.getOnMouseOver().trim().length() > 0 ) { writer.write(" onmouseover="" + aUICustomSelectOneRadio.getOnMouseOver().trim() + """); } if ( aUICustomSelectOneRadio.getOnMouseOut() != null && aUICustomSelectOneRadio.getOnMouseOut().trim().length() > 0 ) { writer.write(" onmouseout="" + aUICustomSelectOneRadio.getOnMouseOut().trim() + """); } if ( aUICustomSelectOneRadio.getOnFocus() != null && aUICustomSelectOneRadio.getOnFocus().trim().length() > 0 ) { writer.write(" onfocus="" + aUICustomSelectOneRadio.getOnFocus().trim() + """); } if ( aUICustomSelectOneRadio.getOnBlur() != null && aUICustomSelectOneRadio.getOnBlur().trim().length() > 0 ) { writer.write(" onblur="" + aUICustomSelectOneRadio.getOnBlur().trim() + """); } if ( aUICustomSelectOneRadio.getValue() != null && aUICustomSelectOneRadio.getValue().equals( aUICustomSelectOneRadio.getItemValue())) { writer.write(" checked="checked""); } writer.write(">"); if ( aUICustomSelectOneRadio.getItemLabel() != null ) { writer.write(aUICustomSelectOneRadio.getItemLabel()); } writer.write("</input>"); } } In the encodeEnd() method, we have written the HTML-related code needed for rendering a radio button. In the code snippet above, the most important line is writer.write(" name="" + getName(aUICustomSelectOneRadio, context) + """);. While rendering the radio button, we generate and provide our own name using the same getName() method. With the above line, we ensure that the radio button’s name attribute is not generated by the JSF container; instead, we provide it according to our logic.After we are done with our component and renderer class, we need to write the custom tag class. This task is straightforward (nearly the same for any custom tag you write in JSF) and requires no special handling. Our JSF custom tag extends javax.faces.webapp.UIComponentTag and looks like this: public class HTMLCustomSelectOneRadioTag extends UIComponentTag { //Other Code //... } The following methods of the custom tag class are important for any custom component you write in JSF: public String getComponentType() { return "component.CustomSelectOneRadio"; } public String getRendererType() { return "renderer.CustomSelectOneRadio"; } The values from the getComponentType() and getRendererType() methods are also located in faces-config.xml. You must define all the attributes, and you must supply the attributes’ accessor and mutator methods in your custom tag’s properties; some examples appear in the code below. For the whole set of attributes, please see the source files supplied in Resources. private String name = null; private String value = null; private String styleClass = null; //...Other Attributes public String getName() { return name; } public void setName(String string) { name = string; } public String getValue() { return value; } public void setValue(String string) { value = string; } public String getStyleClass() { return styleClass; } public void setStyleClass(String string) { styleClass = string; } Another important method in our custom tag is the setProperties() method, shown below. This method actually gets the values of each attribute of our custom tag from the JSF page and sets the value to our component class: protected void setProperties(UIComponent component) { super.setProperties(component); UICustomSelectOneRadio aUICustomSelectOneRadio = (UICustomSelectOneRadio) component; if (name != null) { if (isValueReference(name)) { aUICustomSelectOneRadio.setValueBinding("name", getValueBinding(name)); } else { aUICustomSelectOneRadio.getAttributes() .put("name", name); } } if (value != null) { if (isValueReference(value)) { aUICustomSelectOneRadio.setValueBinding("value", getValueBinding(value)); } else { aUICustomSelectOneRadio.getAttributes() .put("value", value); } } // For other attributes the same block repeats } public ValueBinding getValueBinding(String valueRef) { ApplicationFactory af = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder. APPLICATION_FACTORY); Application a = af.getApplication(); return (a.createValueBinding(valueRef)); } The setProperties() method checks whether the value supplied in each attribute is a value-binding reference (using the isValueReference method). Value-binding expressions start with #{, end with }, and refer to either some backing bean attribute or scoped variables. If the attribute is value-binded, then the setProperties() method creates a value-binding and sets it to the related component; otherwise the setProperties() method sets the hard-coded value supplied from the JSF page to this custom component.After the component, renderer and the custom tag class are written, it’s time to make the corresponding entries in faces-config.xml and write the tag library descriptor (tld) file.We must add a component definition in our faces-config.xml file. If you already have some other custom component definition, then append this component definition after the existing one: <component> <component-type>component.CustomSelectOneRadio</component-type> <component-class>com.srijeeb.jsf.components.UICustomSelectOneRadio </component-class> <component-extension> <component-family>CustomSelectOneRadio</component-family> <renderer-type>renderer.CustomSelectOneRadio</renderer-type> </component-extension> </component> We also need to add a renderer definition in our faces-config.xml file. If you already have some other custom component definition, append this renderer definition after the existing one. Make sure your renderer tag resides within the render-kit tag. <renderer> <component-family>CustomSelectOneRadio</component-family> <renderer-type>renderer.CustomSelectOneRadio</renderer-type> <renderer-class>com.srijeeb.jsf.renderers.HTMLCustomSelectOneRadioRenderer </renderer-class> </renderer> If you do not have any existing custom renderers in faces-config.xml, append the following definition: <render-kit> <renderer> <component-family>CustomSelectOneRadio</component-family> <renderer-type>renderer.CustomSelectOneRadio</renderer-type> <renderer-class>com.srijeeb.jsf.renderers.HTMLCustomSelectOneRadioRenderer </renderer-class> </renderer> </render-kit> Now we write our tld file. The following tag definition is needed in our tld file (for the whole tld file, please see Resources): <tag> <name>radioButton</name> <tag-class>com.srijeeb.jsf.tags.HTMLCustomSelectOneRadioTag</tag-class> <body-content>empty</body-content> <attribute> <name>name</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>overrideName</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>id</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>value</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>styleClass</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>style</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>disabled</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>rendered</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>Boolean</type> </attribute> <attribute> <name>itemLabel</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>itemValue</name> <required>true</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>onClick</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>onMouseOver</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>onMouseOut</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>onFocus</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> <attribute> <name>onBlur</name> <required>false</required> <rtexprvalue>false</rtexprvalue> <type>String</type> </attribute> </tag> We also need to add the tld file reference in web.xml. Say your tld file name is my_custom_tags.tld and you placed it under the web-inf directory. Add the following if your web.xml is Web Application 2.3 compliant (to view the DTD for Web Application 2.3, please see Resources): <taglib> <taglib-uri>/WEB-INF/my_custom_tags.tld</taglib-uri> <taglib-location>/WEB-INF/my_custom_tags.tld</taglib-location> </taglib> Add the following if your application is Web Application 2.4 compliant (to view the XSD for Web Application 2.4, please see Resources): <jsp-config> <taglib> <taglib-uri>/WEB-INF/my_custom_tags.tld</taglib-uri> <taglib-location>/WEB-INF/my_custom_tags.tld</taglib-location> </taglib> </jsp-config> Let’s now try to use the custom tag in our JSF page. To write a JSF page, we write a JSP page, a backing bean, and helper classes to hold the values of our radio buttons. The following is one example of the helper class (JavaBean): public class TestVO { private String empName = null; //The following attribute is needed if radio need to be grouped within a column. private String index = "-1"; //The following attribute is needed if radio need to be grouped within a row. private String radAns = null; public String getEmpName() { return empName; } public void setEmpName(String string) { empName = string; } public String getIndex() { return index; } public void setIndex(String i) { index = i; } public String getRadAns() { return radAns; } public void setRadAns(String ans) { radAns = ans; } } The code below is the example of our backing bean. The actual backing bean code supplied with this article contains more logic to show the user response back to the GUI. package pagecode.pages; //Required imports public class TestRadioBackingBean { public TestRadioBackingBean() { populateTable2Values(); populateTable3Values(); } private ArrayList sampleTable2 = null; private ArrayList sampleTable3 = null; private String radSelectIndex2 = null; //Also write the accessors and mutators methods of the above attributes. //... //... //Method to populate the table which contains //the radio which needs to be gropued in a column private void populateTable2Values() { sampleTable2 = new ArrayList(); for ( int i=0; i < 3; i++ ) { TestVO aTestVO = new TestVO(); aTestVO.setEmpName("Employee Name " + i); aTestVO.setIndex(String.valueOf(i)); sampleTable2.add(aTestVO); } } //Method to populate the table which contains //the radio which needs to be gropued in a row private void populateTable3Values() { sampleTable3 = new ArrayList(); for ( int i=0; i < 3; i++ ) { TestVO aTestVO = new TestVO(); aTestVO.setEmpName("Employee Name " + i); sampleTable3.add(aTestVO); } } //The following method will get executed when we will click a button in our page //Inside this method we will verify the values of each radio. public String executeTest() { System.out.println("Radio Selected for Table 2: " + getRadSelectIndex2()); System.out.println("Radio Selected for Table 3: " ); if ( sampleTable3 != null ) { for ( int i=0; i < sampleTable3.size(); i++ ) { TestVO aTestVO = (TestVO)sampleTable3.get(i); System.out.println("Row no :" + i + " Value : " + aTestVO.getRadAns()); } } return null; } } Now we need to add the backing bean definition to faces-config.xml: <managed-bean> <managed-bean-name>myBackingBean</managed-bean-name> <managed-bean-class>pagecode.pages.TestRadioBackingBean</managed-bean-class> <managed-bean-scope>request</managed-bean-scope> </managed-bean> The final step is to write the JSP page. Thus, in our JSF page, we need to include the following tag libraries:<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="/WEB-INF/my_custom_tags.tld" prefix="custom" %> And the following code snippet needs to be placed in our JSF page: <f:view> <BODY> <h:form id="testRadioForm"> <h:dataTable id="mySampleTable2" value="#{myBackingBean.sampleTable2}" var="item" width="100%" border="1" first="0"> <f:facet name="header"> <h:panelGrid id="gridHeader2" columns="2" width="100%" > <h:outputText id="outputText2" value="Radios grouped in column(With our custom tag)"/> </h:panelGrid> </f:facet> <h:column> <f:facet name="header"> <h:outputText value="Select It" /> </f:facet> <custom:radioButton id="myRadioId1" name="myRadioCol" overrideName="true" value="#{myBackingBean.radSelectIndex2}" itemValue="#{item.index}" /> </h:column> <h:column > <f:facet name="header"> <h:outputText value="Emp Name" /> </f:facet> <h:outputText value="#{item.empName}" /> </h:column> </h:dataTable> <h:dataTable id="mySampleTable3" value="#{myBackingBean.sampleTable3}" var="item" width="100%" border="1" first="0"> <f:facet name="header"> <h:panelGrid id="gridHeader3" columns="2" width="100%" > <h:outputText id="outputText3" value="Radios grouped in row(With our custom tag)"/> </h:panelGrid> </f:facet> <h:column> <f:facet name="header"> <h:outputText value="Emp Name" /> </f:facet> <h:outputText id="empName" value="#{item.empName}"/> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Excellent" /> </f:facet> <custom:radioButton id="myRadioId2" name="myRadioRow" value="#{item.radAns}" itemValue="E" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Good" /> </f:facet> <custom:radioButton id="myRadioId3" name="myRadioRow" value="#{item.radAns}" itemValue="G" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Average" /> </f:facet> <custom:radioButton id="myRadioId4" name="myRadioRow" value="#{item.radAns}" itemValue="A" /> </h:column> <h:column> <f:facet name="header"> <h:outputText value="Poor" /> </f:facet> <custom:radioButton id="myRadioId5" name="myRadioRow" value="#{item.radAns}" itemValue="P" /> </h:column> </h:dataTable> <h:panelGrid id="buttonGrid" columns="1" width="100%"> <h:commandButton id="btnTest" action="#{myBackingBean.executeTest}" value="Test It"/> </h:panelGrid> </h:form> </BODY> </f:view> In the code above, the first dataTable is populated with our backing bean’s sampleTable2 attribute. The var="item" attribute inside the h:dataTable represents each item of a row inside dataTable. Now look in the <custom:radioButton> tag inside the first dataTable: <custom:radioButton id="myRadioId1" name="myRadioCol" overrideName="true" value="#{myBackingBean.radSelectIndex2}" itemValue="#{item.index}" /> Here, the name of the radio button is myRadioCol and the overrideName attribute is set as true. Thus, the radio button name remains as is (such as myRadioCol for all the rows), and the JSF container does not override the name; radios will be grouped by a single column. Look inside the getName() method of our HTMLCustomSelectOneRadioRenderer class to see the logic of this name generation.Now look into the second dataTable tag. It is populated with our backing bean’s sampleTable3 attribute. Also look at one of the radio button’s definitions of the second dataTable: <custom:radioButton id="myRadioId2" name="myRadioRow" value="#{item.radAns}" itemValue="E" /> Here, the name of the radio is myRadioRow, but we have not mentioned the overrideName attribute. So the name we provided will not remain as is, but for a particular row, it will be the same. Look into the getName() method of our HTMLCustomSelectOneRadioRenderer class to see the logic of this name generation.Figure 5 shows our complete application.Once you select some radio buttons in the screen and click the “Test It” button, the call goes to server and you can see the output in the server log. Verify that the log is showing the correct radio button values (the selected ones). Also, the result displays in the GUI, as illustrated in Figure 6. Note that the part that displays the result in the frontend is not discussed in detail; for more information, see the source code supplied with this article.Testing environmentThis custom component was tested in the following environments:Server environment:Apache Tomcat 5.5 as the Web container and with MyFaces core 1.1.4 JSF implementation.Sun Java System Application Server 8.0 platform edition (J2EE 1.4) with Sun’s JSF implementation.Sun Java System Application Server 9.0 platform edition (Java EE 5) with Sun’s JSF implementation.IBM WebSphere Application Server 5.1 (J2EE 1.3) with IBM’s JSF implementationIBM WebSphere Application Server 6.0 (J2EE 1.4) with IBM’s JSF impementationClient-side environment:Internet Explorer 6.0Firefox 2.0.Ideally, this JSF radio component should run in all JSF implementations, as no vendor-specific API is used in the component. You can try it with other JSF implementations too.ConclusionI have shown how to write a custom tag to address radio button selection inside the JSF dataTable component without using any JavaScript. Though our custom radio button does not contain all the attributes you receive in an HTML radio button, you can easily add those attributes in this component and enrich it more.Also, take care while providing your custom radio button’s name attribute. Because we discard the name generated by the JSF container and use our name, the name may conflict accidentally with some other radio button names on your page. In addition, make sure that the custom:radioButton tag is directly under the h:column attribute. If you nest the radio within some other component (say, h:panelGrid) inside h:column, this solution will not work for our second scenario. You must tweak the getName() method inside the HTMLCustomSelectOneRadioRenderer class to accommodate this scenario.Srijeeb Roy holds a bachelor’s degree in computer science and engineering from Jadavpur University, Calcutta, India. He is currently working as a technical architect in Tata Consultancy Services Limited in a Java EE-based project. He has been working in Java/Java EE for more than seven years and has a total experience of more than eight years in the IT industry. He has developed several in-house frameworks and reusable components in Java for his company and clients. He has also worked in several other areas such as Forte, CORBA, and Java ME. Java