Document Information

Preface

Part I Introduction

1.  Overview

2.  Using the Tutorial Examples

Part II The Web Tier

3.  Getting Started with Web Applications

4.  JavaServer Faces Technology

5.  Introduction to Facelets

6.  Expression Language

7.  Using JavaServer Faces Technology in Web Pages

8.  Using Converters, Listeners, and Validators

9.  Developing with JavaServer Faces Technology

10.  JavaServer Faces Technology: Advanced Concepts

11.  Using Ajax with JavaServer Faces Technology

12.  Composite Components: Advanced Topics and Example

13.  Creating Custom UI Components and Other Custom Objects

Determining Whether You Need a Custom Component or Renderer

When to Use a Custom Component

When to Use a Custom Renderer

Component, Renderer, and Tag Combinations

Understanding the Image Map Example

Why Use JavaServer Faces Technology to Implement an Image Map?

Understanding the Rendered HTML

Understanding the Facelets Page

Configuring Model Data

Summary of the Image Map Application Classes

Steps for Creating a Custom Component

Creating Custom Component Classes

Specifying the Component Family

Performing Encoding

Performing Decoding

Enabling Component Properties to Accept Expressions

Saving and Restoring State

Delegating Rendering to a Renderer

Creating the Renderer Class

Identifying the Renderer Type

Implementing an Event Listener

Implementing Value-Change Listeners

Implementing Action Listeners

Handling Events for Custom Components

Defining the Custom Component Tag in a Tag Library Descriptor

Using a Custom Component

Creating and Using a Custom Validator

Implementing the Validator Interface

Specifying a Custom Tag

Using a Custom Validator

Binding Component Values and Instances to Managed Bean Properties

Binding a Component Value to a Property

Binding a Component Value to an Implicit Object

Binding a Component Instance to a Bean Property

Binding Converters, Listeners, and Validators to Managed Bean Properties

14.  Configuring JavaServer Faces Applications

15.  Java Servlet Technology

16.  Uploading Files with Java Servlet Technology

17.  Internationalizing and Localizing Web Applications

Part III Web Services

18.  Introduction to Web Services

19.  Building Web Services with JAX-WS

20.  Building RESTful Web Services with JAX-RS

21.  JAX-RS: Advanced Topics and Example

Part IV Enterprise Beans

22.  Enterprise Beans

23.  Getting Started with Enterprise Beans

24.  Running the Enterprise Bean Examples

25.  A Message-Driven Bean Example

26.  Using the Embedded Enterprise Bean Container

27.  Using Asynchronous Method Invocation in Session Beans

Part V Contexts and Dependency Injection for the Java EE Platform

28.  Introduction to Contexts and Dependency Injection for the Java EE Platform

29.  Running the Basic Contexts and Dependency Injection Examples

30.  Contexts and Dependency Injection for the Java EE Platform: Advanced Topics

31.  Running the Advanced Contexts and Dependency Injection Examples

Part VI Persistence

32.  Introduction to the Java Persistence API

33.  Running the Persistence Examples

34.  The Java Persistence Query Language

35.  Using the Criteria API to Create Queries

36.  Creating and Using String-Based Criteria Queries

37.  Controlling Concurrent Access to Entity Data with Locking

38.  Using a Second-Level Cache with Java Persistence API Applications

Part VII Security

39.  Introduction to Security in the Java EE Platform

40.  Getting Started Securing Web Applications

41.  Getting Started Securing Enterprise Applications

42.  Java EE Security: Advanced Topics

Part VIII Java EE Supporting Technologies

43.  Introduction to Java EE Supporting Technologies

44.  Transactions

45.  Resources and Resource Adapters

46.  The Resource Adapter Example

47.  Java Message Service Concepts

48.  Java Message Service Examples

49.  Bean Validation: Advanced Topics

50.  Using Java EE Interceptors

Part IX Case Studies

51.  Duke's Bookstore Case Study Example

52.  Duke's Tutoring Case Study Example

53.  Duke's Forest Case Study Example

Index

 

Creating and Using a Custom Converter

A JavaServer Faces converter class converts strings to objects and objects to strings as required. Several standard converters are provided by JavaServer Faces for this purpose. See for more information on these included converters.

As explained in Conversion Model, if the standard converters included with JavaServer Faces cannot perform the data conversion that you need, you can create a custom converter to perform this specialized conversion. This implementation, at a minimum, must define how to convert data both ways between the two views of the data described in Conversion Model.

All custom converters must implement the javax.faces.convert.Converter interface. This section explains how to implement this interface to perform a custom data conversion.

The Duke's Bookstore case study uses a custom Converter implementation, located in tut-install/examples/case-studies/dukes-bookstore/src/java/dukesbookstore/converters/CreditCardConverter.java, to convert the data entered in the Credit Card Number field on the bookcashier.xhtml page. It strips blanks and hyphens from the text string and formats it so that a blank space separates every four characters.

Another common use case for a custom converter is in a drop-down menu for a nonstandard object type. In the Duke's Tutoring case study, the Student and Guardian entities require a custom converter so they can be converted to and from a UISelectItems input component.

Creating a Custom Converter

The CreditCardConverter custom converter class is created as follows:

@FacesConverter("ccno")
public class CreditCardConverter implements Converter {
    ...
}

The @FacesConverter annotation registers the custom converter class as a converter with the name of ccno with the JavaServer Faces implementation. Alternatively, you can register the converter with entries in the application configuration resource file, as shown in Registering a Custom Converter.

To define how the data is converted from the presentation view to the model view, the Converter implementation must implement the getAsObject(FacesContext, UIComponent, String) method from the Converter interface. Here is the implementation of this method from CreditCardConverter:

@Override
public Object getAsObject(FacesContext context,
        UIComponent component, String newValue)
        throws ConverterException {

    String convertedValue = null;
    if ( newValue == null ) {
        return newValue;
    }
    // Since this is only a String to String conversion,
    // this conversion does not throw ConverterException.
    
    convertedValue = newValue.trim();
    if ( (convertedValue.contains("-")) ||
         (convertedValue.contains(" "))) {
        char[] input = convertedValue.toCharArray();
        StringBuilder builder = new StringBuilder(input.length);
        for ( int i = 0; i < input.length; ++i ) {
            if ( input[i] == ’-’ || input[i] == ’ ’  ) {
                continue;
            } else {
                builder.append(input[i]);
            }
        }
        convertedValue = builder.toString();
    }
    return convertedValue;
}

During the Apply Request Values phase, when the components’ decode methods are processed, the JavaServer Faces implementation looks up the component’s local value in the request and calls the getAsObject method. When calling this method, the JavaServer Faces implementation passes in the current FacesContext instance, the component whose data needs conversion, and the local value as a String. The method then writes the local value to a character array, trims the hyphens and blanks, adds the rest of the characters to a String, and returns the String.

To define how the data is converted from the model view to the presentation view, the Converter implementation must implement the getAsString(FacesContext, UIComponent, Object) method from the Converter interface. Here is an implementation of this method:

@Override
public String getAsString(FacesContext context,
        UIComponent component, Object value)
        throws ConverterException {
    
    String inputVal = null;
    if ( value == null ) {
        return null;
    }
    // value must be of a type that can be cast to a String.
    try {
        inputVal = (String)value;
    } catch (ClassCastException ce) {
        FacesMessage errMsg = new FacesMessage(CONVERSION_ERROR_MESSAGE_ID);
        FacesContext.getCurrentInstance().addMessage(null, errMsg);
        throw new ConverterException(errMsg.getSummary());
    }
    // insert spaces after every four characters for better
    // readability if they are not already present.
    char[] input = inputVal.toCharArray();
    StringBuilder builder = new StringBuilder(input.length + 3);
    for ( int i = 0; i < input.length; ++i ) {
        if ( (i % 4) == 0 && i != 0) {
            if (input[i] != ’ ’ || input[i] != ’-’){
                builder.append(" ");
                // if there are any "-"’s convert them to blanks.
            } else if (input[i] == ’-’) {
                builder.append(" ");
            }
         }
         builder.append(input[i]);
    }
    String convertedValue = builder.toString();
    return convertedValue;
}

During the Render Response phase, in which the components' encode methods are called, the JavaServer Faces implementation calls the getAsString method in order to generate the appropriate output. When the JavaServer Faces implementation calls this method, it passes in the current FacesContext, the UIComponent whose value needs to be converted, and the bean value to be converted. Because this converter does a String-to-String conversion, this method can cast the bean value to a String.

If the value cannot be converted to a String, the method throws an exception, passing an error message from the resource bundle that is registered with the application. Registering Application Messages explains how to register custom error messages with the application.

If the value can be converted to a String, the method reads the String to a character array and loops through the array, adding a space after every four characters.

You can also create a custom converter with a @FacesConverter annotation that specifies the forClass attribute, as shown in the following example from the Duke's Tutoring case study:

@FacesConverter(forClass=Guardian.class)
public class GuardianConverter implements Converter { ...

The forClass attribute registers the converter as the default converter for the Guardian class. Therefore, whenever that class is specified by a value attribute of an input component, the converter is invoked automatically.

A converter class can be a separate Java POJO class, as in the Duke's Bookstore and Duke's Tutoring case studies. If it needs to access objects defined in a managed bean class, however, it can be a subclass of a JavaServer Faces managed bean, as in the address-book persistence example and the Duke's Forest case study, where the converters use an enterprise bean that is injected into the managed bean class.

Using a Custom Converter

To apply the data conversion performed by a custom converter to a particular component's value, you must do one of the following:

  • Reference the converter from the component tag's converter attribute.

  • Nest an f:converter tag inside the component’s tag and reference the custom converter from one of the f:converter tag’s attributes.

If you are using the component tag’s converter attribute, this attribute must reference the Converter implementation’s identifier or the fully-qualified class name of the converter. Creating and Using a Custom Converter explains how to implement a custom converter.

The identifier for the credit card converter class is ccno, the value specified in the @FacesConverter annotation:

@FacesConverter("ccno")
public class CreditCardConverter implements Converter {
    ...

Therefore, the CreditCardConverter instance can be registered on the ccno component as shown in the following example:

<h:inputText id="ccno"
    size="19"
    converter="ccno"
    value="#{cashier.creditCardNumber}"
    required="true"
    requiredMessage="#{bundle.ReqCreditCard}">
    ...
</h:inputText>

By setting the converter attribute of a component’s tag to the converter’s identifier or its class name, you cause that component’s local value to be automatically converted according to the rules specified in the Converter implementation.

Instead of referencing the converter from the component tag’s converter attribute, you can reference the converter from an f:converter tag nested inside the component’s tag. To reference the custom converter using the f:converter tag, you do one of the following:

  • Set the f:converter tag’s converterId attribute to the Converter implementation’s identifier defined in the @FacesConverter annotation or in the application configuration resource file. This method is shown in bookcashier.xhtml:

    <h:inputText id="ccno" 
                 size="19"
                 value="#{cashier.creditCardNumber}"
                 required="true"
                 requiredMessage="#{bundle.ReqCreditCard}" >
        <f:converter converterId="ccno"/>
        <f:validateRegex 
            pattern="\d{16}|\d{4} \d{4} \d{4} \d{4}|\d{4}-\d{4}-\d{4}-\d{4}" /> 
    </h:inputText>
  • Bind the Converter implementation to a managed bean property using the f:converter tag’s binding attribute, as described in Binding Converters, Listeners, and Validators to Managed Bean Properties.

The JavaServer Faces implementation calls the converter's getAsObject method to strip spaces and hyphens from the input value. The getAsString method is called when the bookcashier.xhtml page is redisplayed; this happens if the user orders more than $100 worth of books.

In the Duke's Tutoring case study, each converter is registered as the converter for a particular class. The converter is automatically invoked whenever that class is specified by a value attribute of an input component. In the following example, the itemValue attribute (highlighted in bold) calls the converter for the Guardian class:

<h:selectManyListbox id="selectGuardiansMenu"
                     value="#{guardianManager.selectedGuardians}"
                     size="5">
    <f:selectItems value="#{guardianManager.allGuardians}"
                   var="selectedGuardian"
                   itemLabel="#{selectedGuardian.name}"
                   itemValue="#{selectedGuardian}" />
</h:selectManyListbox>