Creating and using a custom converter

JSF custom converters run on the server/client side and can accomplish many specific business needs. Basically, JSF custom converters are created by extending the javax.faces.convert.Converter interface or by extending a standard converter class. In this recipe, you will see both cases.

Getting ready

We developed this recipe with NetBeans 6.8, JSF 2.0, and GlassFish v3. The JSF 2.0 classes were obtained from the NetBeans JSF 2.0 bundled library.

How to do it...

First, let's talk about the converters that implement the Converters interface. In this case, a converter should implement two methods, as follows:

The getAsObject method takes the FacesContext instance, the UI component, and the String to be converted to a specified object. According to the official documentation, this method:

Converts the specified string value, which is associated with the specified UIComponent, into a model data object that is appropriate for being stored during the Apply Request Values phase of the request processing lifecycle.

public Object getAsObject(FacesContext context,
UIComponent component,
java.lang.String value){
…
}

The getAsString method takes the FacesContext instance, the UI component, and the object to be converted to a String. According to the official documentation, this method:

Converts the specified model object value, which is associated with the specified UIComponent, into a String that is suitable for being included in the response generated during the Render Response phase of the request processing lifecycle.

public String getAsString(FacesContext context,
UIComponent component,
Object value){
…
}

This converter logic should use javax.faces.converter.ConverterException to throw the appropriate exceptions and javax.faces.application.FacesMessage to generate the corresponding error messages.

For example, the following custom converter will convert a java.util.Date into a format of type yyyy-MM-dd. This implementation will extend the Converter interface, as shown next:

package datetime;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
@FacesConverter(value = "customDateConverterImpl")
public class CustomDateConverterImpl implements Converter {
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
if (arg0 == null) {
throw new NullPointerException("context");
}
if (arg1 == null) {
throw new NullPointerException("component");
}
final Date date = (Date) arg2;
String DATE_FORMAT = "yyyy-MM-dd";
SimpleDateFormat sdf =
new SimpleDateFormat(DATE_FORMAT);
Calendar c1 = Calendar.getInstance(); // today
c1.setTime(date);
return sdf.format(c1.getTime());
}
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
if (arg0 == null) {
throw new NullPointerException("context");
}
if (arg1 == null) {
throw new NullPointerException("component");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
Date today = df.parse(arg2);
return today;
} catch (ParseException e) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Parser error!", "Cannot parse this date!");
throw new ConverterException(message);
}
}
}

The previous converter can be called from an XHTML page as shown next (notice that we pass to the converter attribute the value from the @FacesConverter annotation; this annotation defines a name for a converter and it is specific to JSF 2.0):

<h:form id="customDateTimeID">
<h:inputText id="dateID" value="#{datetimeBean.currentdate}"
converter="customDateConverterImpl">
</h:inputText>
<h:message showSummary="true" showDetail="false" for="dateID"
style="color: red; text-decoration:overline"/>
<br />
<h:commandButton value="Submit"
action="selected?faces-redirect=true"/>
</h:form>

Now, let's discuss converters that extend existing converters. In this case, we override the getAsString and getAsObject methods (mark them with the @Override annotation) or we can call setter methods from the extended converter. For example, we can extend the DateTimeConverter and call the setPattern to obtain the same effect as the previous converter.

package datetime;
import java.util.TimeZone;
import javax.faces.convert.DateTimeConverter;
import javax.faces.convert.FacesConverter;
@FacesConverter(value = "customDateConverterExtend")
public class CustomDateConverterExtend extends DateTimeConverter {
public CustomDateConverterExtend() {
super();
setTimeZone(TimeZone.getDefault());
setPattern("yyyy-MM-dd");
}
}

How it works...

A JSF converter is called from two directions. It is called once during the Apply Request Values Phase and once during the Render Response Phase. In Apply Request Values Phase the converter is called through getAsObject method, which is responsible to for converting the user inputs, while in the Render Response the converter is called through the getAsString method, which is responsible to for converting outputs before rendering.

There's more...

Keep in mind that in JSF 2.0 we don't need a faces-config.xml descriptor, and converters need not be declared in any XML file. If you are using JSF 1.2 then you have to register converters in the faces-config.xml document following the syntax listed next:

<converter>
<converter-id>CONVERTER_ID</converter-id>
<converter-class>CONVERTER_CLASS_NAME</converter-class>
</converter>

See also

The code bundled with this book contains a complete example of this recipe. The project can be opened with NetBeans 6.8 and it is named: Creating_and_using_a_custom_converter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset