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.
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:
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>
<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>
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