My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

duminică, 20 decembrie 2015

JSF 2.3 align the <f:convertDateTime/> to the new data and time classes in JDK 8 (JSR 310)

by Constantin Alin

JSF 2.3 will have Java 8 as a minimum dependency. One of the affected artifacts is the <f:convertDateTime/> built-in converter which has been updated in order to support new types for the type attribute, and, depending on the value of the type attribute, the converter will use the java.text.SimpleDateFormat or java.time.format.DateTimeFormatter class for formatting.

Note When the converter type attribute value is date, time or both, JSF (2.2 and 2.3) uses the java.text.SimpleDateFormat class. Starting with JSF 2.3, when the converter type attribute value is localDate, localTime, localDateTime, offsetTime, offsetDateTime or zonedDateTime, the java.time.format.DateTimeFormatter class will be used.

Note In both, JSF 2.2 and JSF 2.3, if the pattern attribute is specified, the dateStyle or timeStyle attributes are not taken in consideration during the parsing and formatting process.

In JSF 2.2, the type attribute can have only one of the date (default value that relies on DateFormat.getDateTimeInstance(dateStyle) when pattern is missing), time (relies on DateFormat.getDateTimeInstance(timeStyle)when pattern is missing) or both (relies on DateFormat.getDateTimeInstance(dateStyle, timeStyle) when pattern is missing) values. Let’s take a look at the following examples specific to JSF 2.2.

Using type="date" (default value) and the dateStyle attribute to format Date:

<h:form>
 <h:inputText value="#{myBean.date}">
  <f:convertDateTime pattern="dd-MM-yyyy" />
 </h:inputText>
</h:form>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime dateStyle="short" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime dateStyle="medium" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime dateStyle="long" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime dateStyle="full" />
</h:outputText>

 Using type="time" and the timeStyle attribute to format Date:

<h:form>
 <h:inputText value="#{myBean.date}">
  <f:convertDateTime type="time" pattern="h:mm" />
 </h:inputText>
</h:form>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime type="time" timeStyle="short" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime type="time" timeStyle="medium" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime type="time" timeStyle="long" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime type="time" timeStyle="full" />
</h:outputText>

Using type="both" and the dateStyle and timeStyle attributes to format Date:

<h:form>
 <h:inputText value="#{myBean.date}">
  <f:convertDateTime type="both" pattern="dd-MM-yyyy, h:mm" />
 </h:inputText>
</h:form>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime type="both" dateStyle="short" timeStyle="short" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime type="both" dateStyle="medium" timeStyle="medium" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime type="both" dateStyle="long" timeStyle="long" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime type="both" dateStyle="full" timeStyle="full" />
</h:outputText>


Using the pattern attribute to format Date:

<h:outputText value="#{myBean.date}">
 <f:convertDateTime pattern="H:mm" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime pattern="h:mm a" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime pattern="H:mm:ss:SSS" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime pattern="K:mm a,z" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime pattern="dd.MM.yy" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime pattern="EEE, MMM d, ''yy" />
</h:outputText>

<h:outputText value="#{myBean.date}">
 <f:convertDateTime pattern="yyyy.MMMMM.dd GGG hh:mm aaa" />
</h:outputText/>


<h:outputText value="#{myBean.date}">
 <f:convertDateTime pattern="yyyy.MM.dd G 'at' hh:mm:ss z" />
</h:outputText>


The managed bean behind the above examples is listed below:

@Named
@RequestScoped
public class MyBean {

 private Date date;

 public MyBean() {
  date = new Date();
 }

 // getter and setter
}

The upcoming JSF 2.3 now adds new possible values for the type attribute, as follows:

·         localDate, localTime, localDateTime, offsetTime, offsetDateTime, zonedDateTime

To see the new possible values in action, suppose we have the following managed bean:

@Named
@RequestScoped
public class MyBean {

 private LocalDate localDate;
 private LocalTime localTime;
 private LocalDateTime localDateTime;
 private OffsetTime offsetTime;
 private OffsetDateTime offsetDateTime;
 private ZonedDateTime zonedDateTime;

 public MyBean() {
  localDate = LocalDate.now();
  localTime = LocalTime.now();
  localDateTime = LocalDateTime.now();
  offsetTime = OffsetTime.now();
  offsetDateTime = OffsetDateTime.now();
  zonedDateTime = ZonedDateTime.now();
 }

 // getters and setters
}

To format an OffsetTime we can use type="offsetTime" with the pattern attribute as follows:

<h:form>
 <h:inputText value="#{myBean.offsetTime}">
  <f:convertDateTime type="offsetTime" pattern="H:mm" />
 </h:inputText>
</h:form>

<h:outputText value="#{myBean.offsetTime}">
 <f:convertDateTime type="offsetTime" pattern="h:mm a" />
</h:outputText>

<h:outputText value="#{myBean.offsetTime}">
 <f:convertDateTime type="offsetTime" pattern="H:mm:ss:SSS" />
</h:outputText>


To format an OffsetDateTime we can use type="offsetDateTime" with the pattern attribute as follows:

<h:form>
 <h:inputText value="#{myBean.offsetDateTime}">
  <f:convertDateTime type="offsetDateTime" pattern="dd-MM-yyyy, h:mm" />
 </h:inputText>
</h:form>

<h:outputText value="#{myBean.offsetDateTime}">
 <f:convertDateTime type="offsetDateTime" pattern="h:mm a" />
</h:outputText>

<h:outputText value="#{myBean.offsetDateTime}">
 <f:convertDateTime type="offsetDateTime" pattern="H:mm:ss:SSS" />
</h:outputText>

<h:outputText value="#{myBean.offsetDateTime}">
 <f:convertDateTime type="offsetDateTime" pattern="dd.MM.yy" />
</h:outputText>

<h:outputText value="#{myBean.offsetDateTime}">
 <f:convertDateTime type="offsetDateTime" pattern="EEE, MMM d, ''yy" />
</h:outputText>


To format a ZonedDateTime we can use type="zonedDateTime" with the pattern attribute as follows:

<h:form>
 <h:inputText value="#{myBean.zonedDateTime}">
  <f:convertDateTime type="zonedDateTime" pattern="dd-MM-yyyy, h:mm" />
 </h:inputText>
</h:form>

<h:outputText value="#{myBean.zonedDateTime}">
 <f:convertDateTime type="zonedDateTime" pattern="h:mm a" />
</h:outputText>

<h:outputText value="#{myBean.zonedDateTime}">
 <f:convertDateTime type="zonedDateTime" pattern="H:mm:ss:SSS" />
</h:outputText>

<h:outputText value="#{myBean.zonedDateTime}">
 <f:convertDateTime type="zonedDateTime" pattern="dd.MM.yy" />
</h:outputText>

<h:outputText value="#{myBean.zonedDateTime}">
 <f:convertDateTime type="zonedDateTime" pattern="EEE, MMM d, ''yy" />
</h:outputText>

<h:outputText value="#{myBean.zonedDateTime}">
 <f:convertDateTime type="zonedDateTime" pattern="yyyy.MM.dd G 'at' hh:mm:ss z" />
</h:outputText>


Note When type is offsetTime, offsetDateTime or zonedDateTime, the implementation of <f:convertDateTime/> ignores the dateStyle or timeStyle attributes and 
returns the default formatted value or the value formatted by the pattern attribute, if specified.

To format a LocalDate we can use type="localDate" and the dateStyle attribute:

<h:form>
 <h:inputText value="#{myBean.localDate}">
  <f:convertDateTime type="localDate" pattern="dd-MM-yyyy" />
 </h:inputText>
</h:form>

<h:outputText value="#{myBean.localDate}">
 <f:convertDateTime type="localDate" dateStyle="short" />
</h:outputText>

<h:outputText value="#{myBean.localDate}">
 <f:convertDateTime type="localDate" dateStyle="medium" />
</h:outputText>

<h:outputText value="#{myBean.localDate}">
 <f:convertDateTime type="localDate" dateStyle="long" />
</h:outputText>

<h:outputText value="#{myBean.localDate}">
 <f:convertDateTime type="localDate" dateStyle="full" />
</h:outputText>


The complete application is available here.

Some issues in JSF 2.3-m04

1.  The converter won’t work with type="localTime" and timeStyle. This seems to be a typo in source code, the dateStyle is used instead of timeStyle:

// Mojarra 2.3-m04 source code
public class DateTimeConverter implements Converter, PartialStateHolder {

 ...
 private String dateStyle = "default";
 private String timeStyle = "default";
 ...

 private FormatWrapper getDateFormat(Locale locale) {        
  ...
  } else if (type.equals("localTime")) {
     dtf = (null != pattern) ? DateTimeFormatter.ofPattern(pattern, locale) :
            DateTimeFormatter.ofLocalizedTime(getFormatStyle(dateStyle));
     from = LocalTime::from;
     ...
  }
  ...
}

As a consequence, you can write <f:convertDateTime type="localTime" dateStyle="short" /> and it will work.

2. You can’t format only time when type="localDateTime":

Consider the following example:

<h:outputText value="#{myBean.localDateTime}">
 <f:convertDateTime type="localDateTime" timeStyle="short" />
</h:outputText>

Similar to first issue, the value of the dateStyle attribute will be used instead of timeStyle.

As a consequence, you can’t "combine" timeStyle and dateStyle when type="localDateTime". A LocalDateTime object holds both date and time. So we should be able to format the date part with one style and the time part with another style. For example:

<h:outputText value="#{myBean.localDateTime}">
 <f:convertDateTime type="localDateTime" dateStyle="medium" timeStyle="short" />
</h:outputText>

This will not work as expected. During the parsing and formatting process, the timeStyle attribute will be ignored. Only dateStyle will be used:

// Mojarra 2.3-m04 source code
public class DateTimeConverter implements Converter, PartialStateHolder {

 ...
 private String dateStyle = "default";
 private String timeStyle = "default";
 ...

 private FormatWrapper getDateFormat(Locale locale) {
  ...
  } else if (type.equals("localDateTime")) {
     dtf = (null != pattern) ? DateTimeFormatter.ofPattern(pattern, locale) :
            DateTimeFormatter.ofLocalizedDateTime(getFormatStyle(dateStyle));
     from = LocalDateTime::from;
  }
  ...
}

The fix may consist in calling the DateTimeFormatter.ofLocalizedDateTime() method with two parameters, something like DateTimeFormatter.ofLocalizedDateTime(getFormatStyle(dateStyle), getFormatStyle(timeStyle)).

3. Notice that you can’t use the converter with type="localTime" or type="localDateTime" and dateStyle or timeStyle with a value of long or full. This will cause an javax.faces.convert.ConverterException exception which "hides" the "original" exception caused by the JDK-8085887 bug. Although the bug only mentions LocalDateTime, the same happens when using LocalTime.

Further reading:
JDK 8 time support in f:convertDateTime

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors