-
Available since OmniFaces 1.0
The <o:converter>
is a taghandler that extends the standard <f:converter>
tag family with support for deferred value expressions in all attributes. In other words, the converter attributes are not evaluated anymore on a per view build time basis, but just on every access like as with UI components and bean properties. This has among others the advantage that they can be evaluated on a per-iteration basis inside an iterating component, and that they can be set on a custom converter without needing to explicitly register it in a tagfile.
Usage
When you specify for example the standard <f:convertDateTime>
by converterId="jakarta.faces.DateTime"
, then you'll be able to use all its attributes such as pattern
and locale
as per its documentation, but then with the possibility to supply deferred value expressions.
<o:converter converterId="jakarta.faces.DateTime" pattern="#{item.pattern}" locale="#{item.locale}" />
The converter ID of all standard Faces converters can be found in their javadocs. First go to the javadoc of the class of interest, then go to CONVERTER_ID
in its field summary and finally click the Constant Field Values link to see the value.
JSF 2.3 compatibility
The <o:converter>
is currently not compatible with converters which are managed via the managed=true
attribute set on the FacesConverter
annotation, at least not when using Mojarra. Internally, the converters are wrapped in another instance which doesn't have the needed setter methods specified. In order to get them to work with <o:converter>
, the managed=true
attribute needs to be removed, so that OmniFaces ConverterManager
will automatically manage them.
Demo
In the below demo, it was the intent to use <f:convertDateTime>
as follows:
<f:convertDateTime type="localDateTime" dateStyle="full" timeStyle="full" locale="#{locale}" />
But this wouldn't even run, it will throw the following exception because the #{locale}
isn't
available during view build time (for a background explanation, check
this Stack Overflow answer).
jakarta.faces.view.facelets.TagAttributeException: /showcase/taghandlers/converter.xhtml @53,101 locale="" Attribute did not evaluate to a String or Locale: null at com.sun.jsf-impl@4.0.0.SP01//com.sun.faces.facelets.tag.faces.ComponentSupport.getLocale(ComponentSupport.java:423) at com.sun.jsf-impl@4.0.0.SP01//com.sun.faces.facelets.tag.faces.core.ConvertDateTimeHandler.setAttributes(ConvertDateTimeHandler.java:89) at com.sun.jsf-impl@4.0.0.SP01//com.sun.faces.facelets.tag.faces.ConverterTagHandlerDelegateImpl.applyAttachedObject(ConverterTagHandlerDelegateImpl.java:117)
It works as intuitively expected with the <o:converter>
as it allows a render time evaluation of attributes.
For another related use case, checkout the
<o:validator>
showcase page.
Language | Full date time pattern |
---|---|
English | Friday, March 21, 2025 at 12:29:58 PM Central Daylight Time |
Spanish | viernes, 21 de marzo de 2025, 12:29:58 (hora de verano central) |
French | vendredi 21 mars 2025 à 12:29:58 heure d’été du Centre |
German | Freitag, 21. März 2025 um 12:29:58 Nordamerikanische Inland-Sommerzeit |
Dutch | vrijdag 21 maart 2025 om 12:29:58 Central-zomertijd |
Arabic | الجمعة، 21 مارس 2025 في 12:29:58 م التوقيت الصيفي المركزي لأمريكا الشمالية |
Hebrew | יום שישי, 21 במרץ 2025 בשעה 12:29:58 שעון מרכז ארה״ב (קיץ) |
Chinese | 2025年3月21日星期五 北美中部夏令时间 下午12:29:58 |
<h:dataTable value="#{converterBean.locales}" var="locale">
<h:column>
<f:facet name="header">Language</f:facet>
#{locale.displayLanguage}
</h:column>
<h:column>
<f:facet name="header">Full date time pattern</f:facet>
<h:outputText value="#{now.zonedDateTime}">
<o:converter converterId="jakarta.faces.DateTime" type="localDateTime" dateStyle="full" timeStyle="full" locale="#{locale}" />
</h:outputText>
</h:column>
</h:dataTable>
package org.omnifaces.showcase.taghandlers;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
@Named
@RequestScoped
public class ConverterBean {
private List<Locale> locales;
@PostConstruct
public void init() {
locales = new ArrayList<>();
for (String language : new String[] { "en", "es", "fr", "de", "nl", "ar", "he", "zh" }) {
locales.add(new Locale(language));
}
}
public List<Locale> getLocales() {
return locales;
}
}