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

Selenium - Override javascript functions to ignore downloading process

I have got an issue with downloading process on IE 8. This browser blocks my automatic-download functionality on my app so that I could not work with my test case any more after that. In my case, I didn't care about the file is downloaded or not, I just focus on the result after downloading process finished successfully. Therefore, I found a solution to ignore this process so that I can work normally. I use Primefaces, here is the remote command to trigger the download process <p:remoteCommand name="cmdGenerateDocument" actionListener="#{logic.onGenerateDocument}" update="xrflDocumentCreationPanel" oncomplete="clickDownloadButton();"/> The following is my test case: @Test public void shouldUpdateStep6ToWarningIfStep1IsValidAfterFinished(){ MainPage mainPage = new MainPage(); waitForLoading(mainPage.getDriver()); EmployeeDetailPage empDetailPage = new EmployeeDetailPage(); waitForLoading(empDetailPage.getDriver()); e...

[Snippet] CSS - Child element overlap parent

I searched from somewhere and found that a lot of people says a basic concept for implementing this feature looks like below: HTML code: <div id="parent">  <div id="child">  </div> </div> And, CSS: #parent{   position: relative;   overflow:hidden; } #child{   position: absolute;   top: -1;   right: -1px; } However, I had a lot of grand-parents in my case and the above code didn't work. Therefore, I needed an alternative. I presumed that my app uses Boostrap and AngularJs, maybe some CSS from them affects mine. I didn't know exactly the problem, but I believed when all CSS is loaded into my browser, I could completely handle it. www.tom-collinson.com I tried to create an example to investigated this problem by Fiddle . Accidentally, I just changed: position: parent; to position: static; for one of parents -> the problem is solved. Look at my code: <div class="modal-body dn-placeholder-parent-positi...

Coding Exercise, Episode 1

I have received the following exercise from an interviewer, he didn't give the name of the problem. Honestly, I have no idea how to solve this problem even I have tried to read it three times before. Since I used to be a person who always tells myself "I am not the one good at algorithms", but giving up something too soon which I feel that I didn't spend enough effort to overcome is not my way. Then, I have sticked on it for 24 hours. According to the given image on the problem, I tried to get more clues by searching. Thanks to Google, I found a similar problem on Hackerrank (attached link below). My target here was trying my best to just understand the problem and was trying to solve it accordingly by the Editorial on Hackerrank. Due to this circumstance, it turns me to love solving algorithms from now on (laugh). Check it out! Problem You are given a very organized square of size N (1-based index) and a list of S commands The i th command will follow t...

[Snippet] Generate a new unique "name" string from an existing list

Suppose that we have a list of employees. Everytime, we want to add new employee into this list, the name of the employee will be generated with the following rules: - the name of the new one is set to " [originalname] 1 " - in case the name already exist, " [originalname] 2 " is used, and so on. Here is my code snippet by Javascript: var employees =[ {id: 1, name: 'name'}, {id: 2, name: 'name 1'}, {id: 3, name: 'name 2'}, {id: 5, name: 'name 4'} ]; var commonUtils = { isExistName: function(_name, _collection, _prop) { for(var i = 0; i< _collection.length; i++){ if(_collection[i][_prop].localeCompare(_name)==0){ return true; } } return false; }, generateNewName: function(_name, _collection, _prop){ var i = 1; var searching = true; while (searching) { var newName = _name+ " " + i; if (!this.isExistName(newName, _collection, _pro...

Generating PDF/A From HTML in Meteor

My live-chat app was a folk of project Rocket.Chat which was built with Meteor. The app had a feature that administrative users were able to export the conversations into PDF files. And, they wanted to archive these files for a long time. I happened to know that PDF/A documents were good for this purpose. It was really frustrated to find a solution with free libraries. Actually, it took me more than two weeks to find a possible approach. TL, DR; Using Puppeteer to generate a normal PDF and using PDFBox to load and converting the generated PDF into PDF/A compliance. What is PDF/A? Here is a definition from Wikipedia: PDF/A  is an  ISO -standardized version of the  Portable Document Format  (PDF) specialized for use in the  archiving  and long-term  preservation  of  electronic documents . PDF/A differs from PDF by prohibiting features unsuitable for long-term archiving, such as  font  linking (as opposed to  font em...