NOTE: This article is the next update in a series about using the deeper JSF functionality in XPages, and continues concepts learned in the articles "Writing a Managed Bean to Automate Server Side Functionality in XPages" and "Writing Your Own Complex Custom Validator - JSF Style." I will be expanding upon topics covered there, and you may want to (re-)read those articles before continuing with this one.
In yesterday's post I described ways in which you can write complex validators to verify the integrity of data the user submits. Hand-in-hand with that functionality, you may want to translate the values the user submits to conform to a specific format. Classic Domino development provided this functionality through the use of a field's Input Translation formula.

XPages have a similar functionality in what are called "Converters." Converters work just like the Input Translation formula, as they take an input value, apply transformations upon that data, and then return the modified value to the field.
The Converter is a Java class that can transform a value from its native type, to a String type, and back again, applying any data transformations to the value in the process. The conversion from string to object, and back again is necessary because HTML is a textual representation of data, and when the data is presented to the browser, it must be in text form, hence the need for the two way conversion.
You may have already used converters in your XPages application. Domino provides a pre-built set of converters you can use:

The base converter types handle simple formatting and conversion of data for items like date/times, phone numbers (convertMask) and other simple types. However, in some cases you need to be able to do complex conversion of input data, and one powerful aspect of the Input Translation formula was the ability to affect other data based on the data input from another field, something simple Converters can't do.
To accomplish this, we have the xp:converter and xp:customConverter at our disposal. These works very similarly in nature to the custom validator we created in our last post. We create a simple Java class, identify it in our faces-config file, and then we can apply the converter to any field we wish.
Let's get down to the nitty gritty of creating a custom converter. Every converter class needs to follow a basic structure:
package com.ZetaOne.myFirstBeans;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.context.FacesContext;
import javax.faces.component.UIComponent;
public class myFirstConverter implements Converter {
public myFirstConverter() {
// TODO Initialization Code
}
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// TODO Transform your data here
return (Object)value;
}
public String getAsString(FacesContext context, UIComponent component, Object value) {
// TODO Transform your data here
return (String)value;
}
}
Here we have a basic class that defines our converter. First, we import some basic JSF types that we need to use throughout the class, then we create the class, implementing the javax.faces.convert.Converter type. Every converter must implement this type to make it usable as a converter. Then there is the optional constructor function, and then two functions that actually handle the data conversion, getAsString() and getAsObject(). XPages will call your converter's getAsObject() function, passing in the current context, the component being converted, and the value the user submitted during the Apply Request Values phase of the JSF Lifecycle, before performing validation, and will call the getAsString() function during the Render Response phase. That's all there is to the custom converter.
Let's create a simple sample converter now. For simplicity, let's say the user enters an integer value, up to 4 digits long, and we want to take the value, and format it so the value appears with a "A0-" at the beginning of the entered value, and a "-00" at the end, but the value we want to store is just the four digit integer the user entered.
Let's take the getAsString() conversion first. We're going to assume for a moment that the object is represented by a simple Integer type, so to convert the object to a string, our function might look like this:
public String getAsString(FacesContext context, UIComponent component, Object value) {
String tmp = String.format("%1$-4s", (Integer)value);
return "A0-" + tmp.substring(tmp.length-5,tmp.length-1) + "-00";
}
That function will pad the integer value with four leading 0's, restrict the overall length to 4 characters, and pre/append the pre/suffix and return the value.
Now, let's take a look at the converter's getAsObject() function. Remember, we want to store the value as the simple integer value that the user entered, so we need to convert the value we'll get from the user (which could be either just an integer up to four digits, or, if the getAsString() conversion has already run, it may be in our A0-0000-00 format. Here's our sample function:
public Object getAsObject(FacesContext context, UIComponent component, Object value) {
String subVal = (String)value;
if (subVal.substring(0,3).equalsIgnoreCase("A0-")) {
subVal = subVal.substring(3, subVal.length-4);
}
if (subVal.substring(subVal.length-4,3).equalsIgnoreCase("-00")) {
subVal = subVal.substring(0, subVal.length-4);
}
return (Object)(new Integer(subVal))
}
This function will strip the pre/suffix from the string, and return the integer value of what was contained within.
For new Java Developers
There are a few concepts in this code you may be unfamiliar with. Particularly type-casting. Type casting is a tenent of polymorphism that allows you to treat an object of one type as an object of another type. The two types must be related, such as one being the superclass (a class from which the current obect has been inherited from at some point in it's history) or a subclass, that is valid for the object, again somewhere in the chain of the real object's inheritance. In these examples, we have been receiving the value we are going to operate in as a java.lang.Object, which is the base class from which every other java class inherits. We can tell Java to treat this object as for example, a java.lang.String, by referencing the object with a type cast, syntaically done by placing the class in parethesis before the object, like this:
(String)value
That's a basic converter! Now to use the converter in our XPages application, we need to register it in our faces-config.xml file, like we would a managed bean or a validator. To add the converter, add the following lines to your faces-config:
myConverter
com.ZetaOne.myFirstBeans.myFirstConverter
Then, you can add your converter to your xp:input (or any other convertable control), by adding an xp:converter type, and specifying the id (myConverter in this example):

You can also use the xp:customConverter type, which allows you to specify method bindings to the getAsString and getAsObject methods, so you can have your converter methods located in managed beans, or even server side javascript libraries. The parameters and functionality of the methods are the same, you just provide the binding (such as an Expression Language expression such as #{ObjectName.getAsString}
Now, here are a few things to note and remember about converters
1. Unlike validators, which are only executed when the user actually places a value in a field (empty fields do not trigger validation), converters always run.
2. You must create both the getAsString and getAsObject methods for your converter.
3. You shouldn't directly modify the component or component's value in these methods, return the value that you want to be validated/applied to the field.
4. Conversion and Validation happens in the same order, every time, and conversion runs twice per request, once to decode the values (getAsObject) and once to encode the values (getAsString)
5. You can modify other fields / data from within a conversion, but if the field you are modifying has not been converted/validated yet, the value you need to reference is retreived getSubmittedValue(), and set using setSubmittedValue() ... if you modify it any other way, it will be overwritten when that fields conversion & validation occurs.
6. If something happens during conversion that prevents you from further converting the data, you can throw a conversion exception, like this:
throw new ConverterException(new FacesMessage("An exception occurred converting data."));
7. Using the JSFUtils object from the first article, you can retrieve and cache items in the requestScope object to aid in converting/validating objects against each other in a single submission.
Happy Coding!