Search code examples
jsfconverterslocale

Prevent localized date time from being submitted


The basic converter (merely a prototype) converting to and fro between String and java.time.LocalDateTime.

@FacesConverter("localDateTimeConverter")
public class LocalDateTimeConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
        if (submittedValue == null || submittedValue.isEmpty()) {
            return null;
        }

        try {
            return ZonedDateTime.parse(submittedValue, DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime());
        } catch (IllegalArgumentException | DateTimeException e) {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "Message"), e);
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
        if (modelValue == null) {
            return "";
        }

        if (!(modelValue instanceof LocalDateTime)) {
            throw new ConverterException("Message");
        }

        Locale locale = context.getViewRoot().getLocale();

        return DateTimeFormatter.ofPattern(pattern, locale).withZone(ZoneId).format(ZonedDateTime.of((LocalDateTime) modelValue, ZoneOffset.UTC));
    }
}

The date times to be submitted to the database should be based on Locale.ENGLISH. Therefore, it is constant / static in getAsObject().

The date times to be retrieved from the database i.e. to be presented to end-users are based on a selected locale of the user's choice. Therefore, Locale is dynamic in getAsString().

Date time is submitted using a <p:calendar> which is not localized to avoid troublesome.

This will work as expected unless a <p:calendar> component being submitted itself or some other components on the same form being submitted fail during conversion / validation in which case, the calendar component will be pre-filled with a localized date-time which will then fail to be converted in getAsObject() in all subsequent attempts to submit the form unless the localized date-time in the given <p:calendar> is reset to the default locale manually.

The following will pass on the very first attempt to submit the form as there is no conversion / validation violation.

enter image description here

If there is however, a conversion error in one of the fields as follows,

enter image description here

then both the dates in the calendar components will be changed according to the selected locale (hi_IN), since there is a conversion error in one of the fields which will obviously fail to be converted in getAsObject() in subsequent attempts, if the form holding the components is attempted to be submitted after fixing the conversion error by providing the field a correct value.

Any suggestion?


Solution

  • In the converter's getAsString() you're using the view's locale for formatting the date.

    Locale locale = context.getViewRoot().getLocale();
    

    In order to use a component-specific locale, it has to be provided as component attribute. Here's an example provided that <locale-config><default-locale> in faces-config.xml is set to en.

    <p:calendar ... locale="#{facesContext.application.defaultLocale}">
    

    In the converter you can extract it as below:

    Locale locale = (Locale) component.getAttributes().get("locale");
    

    The base converter example of your converter has in the meanwhile been altered to take this properly into account: How to use java.time.ZonedDateTime / LocalDateTime in p:calendar.