In Jakarta Server Faces (JSF), you can use converters to convert data between its model (backend) representation and its view (UI) representation. By default, JSF provides built-in converters for common types such as Integer
, Double
, Date
, etc. However, in some cases, you may need to create a custom converter to handle custom data types or data conversion logic specific to your application. In this tutorial, we’ll create a custom JSF converter to convert a custom object User to and from its string representation in the UI.
In this first article of this series we discuss how to use built-in converters in JSF applications: Using Built-in Converters in JSF Applications . In this tutorial we will see a more advanced use case where we code our own Converters to manage the conversion of fields between the Model and the View.
Step 1: Define a simple Model class
Firstly, add a Class User to your JSF Project which represents your Model:
public class User implements Serializable { public User(int id, String name) { this.id = id; this.name = name; } private int id; private String name; // Getters/Setters omitted @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }
Step 2: Implement the Custom Converter
To create a custom converter, you need to implement the javax.faces.convert.Converter
interface. This interface requires you to implement two methods: getAsString
and getAsObject
.
getAsString
: Converts the User object to its string representation to be displayed in the UI.getAsObject
: Converts the string representation from the UI back to the User object in the backend.
Here’s the implementation of the
@FacesConverter("myConverter") public class UserConverter implements Converter { HashMap<Integer, User> map = new HashMap<>() {{ put(1, new User(1, "John Smith")); put(2, new User(2, "Frank Doe")); }}; @Override public Object getAsObject(FacesContext context, UIComponent component, String value) { try { Integer intValue = Integer.parseInt(value); return map.get(intValue); } catch (NumberFormatException e) { throw new ConverterException( new FacesMessage("Invalid ID"), e); } } @Override public String getAsString(FacesContext context, UIComponent component, Object value) { System.out.println("getAsString "+value); if (value == null) { throw new ConverterException( new FacesMessage("ID not found")); } return value.toString(); } }
As you can see, the FacesConverter is a two phase step:
At first the getAsObject callback method will kick in with the String value we will pass from the User Interface. We will return an Object that we can build from the String. Typically, we would query a resource like the DB at this point. To make it simple, we are just returning an User from an HashMap
Then, the getAsString method will render the User object it receives as input. In this case, we merely return the toString version of the User Object
Step 3: Define a Controller
Finally, you need to define a Controller for your Jakarta Faces application. The role of the Controller is minimal. We leave a no-op implementation of the update method and we add a String field that will map the text field of the User Interface:
@Named @RequestScoped public class Manager { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void update() { // Add business logic here FacesMessage facesMsg = new FacesMessage(FacesMessage.SEVERITY_INFO, "Saved", null); FacesContext.getCurrentInstance().addMessage(null, facesMsg); } }
Step 4: Define the User Interface
The application View will contain an HTML form with a TextField in it:
<h:form id="sampleform"> <h:messages id="version" errorStyle="color: red" infoStyle="color: green" /> <h:inputText value="#{manager.name}" converter="myConverter" /> <h:commandButton value="Submit" action="#{manager.update}"></h:commandButton> </h:form>
Notice that we are setting the converter attribute for the inputText field. This way, when we hit return on the inputField (or when we click on the Submit button) the FacesConverter will kick-in and perform the transformation.
Running the application
Finally, deploy your Jakarta Faces application on your application server. For example, we will deploy it on WildFly:
mvn install wildfly:deploy
Then, try entering an ID in the text field, for example “1”:
As you can see from the next picture, the text field will automatically replace the “ID” with the toString() of the User object:
Conclusion
That’s it! You have successfully created a custom JSF converter using the @FacesConverter
annotation. The converter can now be used to handle conversions between the Product
object and its string representation in your JSF application.
Source code: https://github.com/fmarchioni/mastertheboss/tree/master/web/jsf-custom-converter