Skip to main content

A Case Study of Custom JSF Converters - Automatically Converting Years With 2 Digits Into 4 Digits


You can find the demonstrated code of this post on my Github repo here.

The user story

" As a banker, I want to enter a client's birthday like 01.01.80 or 01.01.1980,
So that the birthday can be displayed as 01.01.1980 "

Implementation

Firstly, I thought about how to use a built-in converter likes the following.

<h:inputText id="birthdate" 
 value="#{data.birthdate}" 
 type="date" >
 <f:convertDateTime/> 
 <f:ajax event="change" 
   listener="#{data.onCalculate}" 
   execute="@this"
   render="@this" />
</h:inputText>

However, without defining a pattern, JSF used its default one which was not my desire. It threw an exception when I tried to enter a date like "01.01.90".

> myform:birthdate: '01.01.90' could not be understood as a date. Example: Mar 4, 2018 

Actually, I even could not define either pattern "dd.MM.yyyy" or "dd.MM.yy" for "f:convertDateTime":
- "dd.MM.yyyy" --> 01.01.80 becomes 01.01.0080
- "dd.MM.yy" --> 01.01.1980 becomes 01.01.80

Well, this was a case for us to define our own custom converter.
- XHTML code
<h:inputText id="birthdate" 
 value="#{data.birthdate}" 
 type="date">
 <f:converter converterId="myDateTimeConverter" /> 
 <f:ajax event="change" 
   listener="#{data.onCalculate}" 
   execute="@this"
   render="@this" />
</h:inputText>

- Java code
package vn.nvanhuong.javalab.jsf.dateformat;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

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;

import org.apache.commons.lang3.StringUtils;

@FacesConverter("myDateTimeConverter")
public class DateTimeConverter implements Converter {

 private static final String DD_MM_YY = "dd.MM.yy";
 private static final String DD_MM_YYYY = "dd.MM.yyyy";
 
 public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
  if (StringUtils.isEmpty(value)) {
   return null;
  }

  SimpleDateFormat formatter = new SimpleDateFormat(DD_MM_YY);
  Date parsedObject = null;
  try {
   parsedObject = formatter.parse(value);
  } catch (ParseException e) {
   throw new ConverterException(e);
  }
  return parsedObject;
 }
 
 public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException {
  if (value == null) {
   return null;
  }

  SimpleDateFormat formatter = new SimpleDateFormat(DD_MM_YYYY);
  return formatter.format(value);
 }

}

The idea was that I allowed users to enter the year with 4 or 2 digits. Then, I used SimpleDateFormatter to convert the entered value into a value with type Date at JSF's phase "Apply Request" which calls method "getAsObject".

The cool thing here was with pattern "dd.MM.yy" the formatter allowed us to do that! Then, we always displayed the date with format "dd.MM.yyyy" at JSF's phase "Render Response" which calls method "getAsString".

Comments

Popular posts from this blog

The power of acceptance test

User Story is the place PO gives his ideas about features so that developers are able to know what requirements are. Acceptance tests are these show the most valuable things of the features represented by some specific cases. Usually PO defines them, but not always. Therefore, refining existing acceptance tests – even defining new ones that cover all features of the User Story must be a worth task. Acceptance test with Given When Then pattern If we understand what we are going to do, we can complete it by 50% I have worked with some members those just start implementing the features one by one and from top to down of the User Story description. Be honest, I am the one used to be. What a risky approach! Because it might meet a case that is very easy to miss requirements or needs to re-work after finding any misunderstood things. I have also worked with some members those accept spending a long time to clarify the User Story. Reading carefully of whole User Story by defining...

Set up a web server for learning HTTP headers

Motivation We all follow the client-server model using the HTTP protocol for most of our web apps today. In development, we simply may have a backend API server and a frontend (web pages or mobile apps) only. However, it seemed that a proxy server is always required for production. In fact, most of the hardest issues in production come from integration. The requests and responses might be modified by the proxy server. Therefore, the understanding of HTTP protocol is one of the key skills to resolve those issues. I wanted to dive deep into HTTP with some core concepts such as caching, cookies, and CORS. I didn't intend to go quickly rather than moved slowly to have a well understanding of what I do. Prepare a server The easiest way is to use my laptop as a server then I can just use "localhost". I can also use ngrok to make my web server online. Finally, I use an online tool such as RedBot to check the HTTP headers. To make it more excited though, I deployed the app on A...

What the heck is Meteor DDP?

I was using Meteor for my messenger project. I was so curious about the real time connection. I wanted to know how exactly this mechanism works. In this post, I will go through the DDP Specification, an overview of WebSocket, and a simple demo about how to subscribe a publication of Rocket.Chat (containing a DDP server) from an external webpage. At a glance, I knew that Meteor invented a protocol called DDP which uses for handling real time connection. So then, what is DDP? "DDP (Distributed Data Protocol) is the stateful WebSocket protocol that Meteor uses to communicate between the client and the server." [1] All right! Why does DDP matter? "DDP is a standard way to solve the biggest problem facing client-side JavaScript developers: querying a server-side database, sending the results down to the client, and then pushing changes to the client whenever anything changes in the database" . [2] In order to understand deeply the protocol, I decided ...

DevOps Toolchain Enhancement

 Historically, our company ubitec had started with a customer project. Agile/Scrum was our proposal for working with customers. Time by time, Agile/Scrum also became our culture for software development. To be successful with this development approach, we somehow needed to have a fast release for customers (i.e. every one week). Back then, we had a build tool Jenkins which was responsible for having sprint release packages for our customers. The build job pipelines contain some steps such as gathering the artifacts, checking the code convention, running the tests, building docker images, and packaging an archived file (a zip file). The set of tools involved in a pipeline is roughly called a toolchain. It is just a part of a bigger process called the DevOps toolchain. Source: https://www.ibm.com/blogs/cloud-archive/2016/11/devops-architecture-available-on-bluemix-garage-method-site/ DevOps is a proven method that fits Agile. Today,  it is even treated as a mandatory factor...

Solving your data visualization needs with open source reporting

Most of applications have some types of data visualization needs: - Gather the data. - Perform calculation, sort, group, aggregate, total,.. - Present information professionally. and meeting user demand is crucial to the success of an application. To solve this problem, there are some different approaches: - Buy a closed-source commercial product (for example, Crystal Reports, JReport,..), we must to pay for a lot of features but maybe more of features we don't need. - Build a custom-developed solution, so we need a team to develop our solution but the problem is how much time and money that we need to spend for that. Nowaday, open source creates new choices. Firstly, we can leverage open source in a customer solution by plug-in it to our solution. Secondly, we can build open-source-based products by using open source code. There are many open source reporting tools for use in the enterprise such as BIRT, iReport, JasperReports,... In this post, I wou...