From 9305d41f672da00262d119dad1112a5274d6d34b Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 18 Jan 2025 16:46:34 -0400 Subject: [PATCH 1/3] IT #5541 --- test/issue5541/pom.xml | 41 ++ .../mojarra/test/issue5541/Issue5541Bean.java | 85 ++++ .../issue5541/src/main/webapp/WEB-INF/web.xml | 34 ++ .../issue5541/src/main/webapp/issue5541.xhtml | 77 ++++ .../mojarra/test/issue5541/Issue5541IT.java | 404 ++++++++++++++++++ test/pom.xml | 1 + 6 files changed, 642 insertions(+) create mode 100644 test/issue5541/pom.xml create mode 100644 test/issue5541/src/main/java/org/eclipse/mojarra/test/issue5541/Issue5541Bean.java create mode 100644 test/issue5541/src/main/webapp/WEB-INF/web.xml create mode 100644 test/issue5541/src/main/webapp/issue5541.xhtml create mode 100644 test/issue5541/src/test/java/org/eclipse/mojarra/test/issue5541/Issue5541IT.java diff --git a/test/issue5541/pom.xml b/test/issue5541/pom.xml new file mode 100644 index 0000000000..adfdc2fe25 --- /dev/null +++ b/test/issue5541/pom.xml @@ -0,0 +1,41 @@ + + + + 4.0.0 + + + org.eclipse.mojarra.test + pom + 4.0.10-SNAPSHOT + + + issue5541 + war + + Mojarra ${project.version} - INTEGRATION TESTS - ${project.artifactId} + + + + org.eclipse.mojarra.test + base + ${project.version} + test + + + diff --git a/test/issue5541/src/main/java/org/eclipse/mojarra/test/issue5541/Issue5541Bean.java b/test/issue5541/src/main/java/org/eclipse/mojarra/test/issue5541/Issue5541Bean.java new file mode 100644 index 0000000000..efb4205689 --- /dev/null +++ b/test/issue5541/src/main/java/org/eclipse/mojarra/test/issue5541/Issue5541Bean.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GPL-2.0 with Classpath-exception-2.0 which + * is available at https://openjdk.java.net/legal/gplv2+ce.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 or Apache-2.0 + */ +package org.eclipse.mojarra.test.issue5541; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZonedDateTime; +import java.util.Date; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Named; + +@Named +@RequestScoped +public class Issue5541Bean { + + private Date date; + private Date dateTime; + private LocalDate localDate; + private LocalTime localTime; + private LocalDateTime localDateTime; + private ZonedDateTime zonedDateTime; + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public Date getDateTime() { + return dateTime; + } + + public void setDateTime(Date dateTime) { + this.dateTime = dateTime; + } + + public LocalDate getLocalDate() { + return localDate; + } + + public void setLocalDate(LocalDate localDate) { + this.localDate = localDate; + } + + public LocalTime getLocalTime() { + return localTime; + } + + public void setLocalTime(LocalTime localTime) { + this.localTime = localTime; + } + + public LocalDateTime getLocalDateTime() { + return localDateTime; + } + + public void setLocalDateTime(LocalDateTime localDateTime) { + this.localDateTime = localDateTime; + } + + public ZonedDateTime getZonedDateTime() { + return zonedDateTime; + } + + public void setZonedDateTime(ZonedDateTime zonedDateTime) { + this.zonedDateTime = zonedDateTime; + } +} diff --git a/test/issue5541/src/main/webapp/WEB-INF/web.xml b/test/issue5541/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..8784690178 --- /dev/null +++ b/test/issue5541/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,34 @@ + + + + + facesServlet + jakarta.faces.webapp.FacesServlet + 1 + + + facesServlet + *.xhtml + + \ No newline at end of file diff --git a/test/issue5541/src/main/webapp/issue5541.xhtml b/test/issue5541/src/main/webapp/issue5541.xhtml new file mode 100644 index 0000000000..7d3b36be3a --- /dev/null +++ b/test/issue5541/src/main/webapp/issue5541.xhtml @@ -0,0 +1,77 @@ + + + + + issue5541 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/issue5541/src/test/java/org/eclipse/mojarra/test/issue5541/Issue5541IT.java b/test/issue5541/src/test/java/org/eclipse/mojarra/test/issue5541/Issue5541IT.java new file mode 100644 index 0000000000..035ff66549 --- /dev/null +++ b/test/issue5541/src/test/java/org/eclipse/mojarra/test/issue5541/Issue5541IT.java @@ -0,0 +1,404 @@ +/* + * Copyright (c) Contributors to the Eclipse Foundation. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GPL-2.0 with Classpath-exception-2.0 which + * is available at https://openjdk.java.net/legal/gplv2+ce.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 or Apache-2.0 + */ +package org.eclipse.mojarra.test.issue5541; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.mojarra.test.base.BaseIT; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.support.FindBy; + +class Issue5541IT extends BaseIT { + + @FindBy(id = "form:inputDate") + private WebElement inputDate; + + @FindBy(id = "form:inputDateTime") + private WebElement inputDateTime; + + @FindBy(id = "form:inputLocalDate") + private WebElement inputLocalDate; + + @FindBy(id = "form:inputLocalTime") + private WebElement inputLocalTime; + + @FindBy(id = "form:inputLocalDateTime") + private WebElement inputLocalDateTime; + + @FindBy(id = "form:inputZonedDateTime") + private WebElement inputZonedDateTime; + + @FindBy(id = "form:submit") + private WebElement submit; + + @FindBy(id = "form:outputDate") + private WebElement outputDate; + + @FindBy(id = "form:outputDateTime") + private WebElement outputDateTime; + + @FindBy(id = "form:outputLocalDate") + private WebElement outputLocalDate; + + @FindBy(id = "form:outputLocalTime") + private WebElement outputLocalTime; + + @FindBy(id = "form:outputLocalDateTime") + private WebElement outputLocalDateTime; + + @FindBy(id = "form:outputZonedDateTime") + private WebElement outputZonedDateTime; + + @FindBy(id = "form:messages") + private WebElement messages; + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidDate() { + open("issue5541.xhtml"); + inputDate.sendKeys("2024-06-30"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("2024-06-30", outputDate.getText()), + () -> assertEquals("", messages.getText()) + ); + } + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidDate() { + open("issue5541.xhtml"); + inputDate.sendKeys("2024-06-31"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputDate.getText()), + () -> assertEquals("form:inputDate: '2024-06-31' could not be understood as a date.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidDateTime() { + open("issue5541.xhtml"); + inputDateTime.sendKeys("2024-06-30 12:34:56"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("2024-06-30 12:34:56", outputDateTime.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidDateTime() { + open("issue5541.xhtml"); + inputDateTime.sendKeys("2024-06-30 23:45:67"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputDateTime.getText()), + () -> assertEquals("form:inputDateTime: '2024-06-30 23:45:67' could not be understood as a date.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidLocalDate() { + open("issue5541.xhtml"); + inputLocalDate.sendKeys("2024-06-30"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("2024-06-30", outputLocalDate.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidLocalDateBce() { + open("issue5541.xhtml?acceptBce=true"); + inputLocalDate.sendKeys("2024-06-30"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("2024-06-30", outputLocalDate.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidLocalDateBceNegative() { + open("issue5541.xhtml?acceptBce=true"); + inputLocalDate.sendKeys("-2024-06-30"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("-2024-06-30", outputLocalDate.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidLocalDate() { + open("issue5541.xhtml"); + inputLocalDate.sendKeys("2024-06-31"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputLocalDate.getText()), + () -> assertEquals("form:inputLocalDate: '2024-06-31' could not be understood as a date.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidLocalDateBce() { + open("issue5541.xhtml?acceptBce=true"); + inputLocalDate.sendKeys("2024-06-31"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputLocalDate.getText()), + () -> assertEquals("form:inputLocalDate: '2024-06-31' could not be understood as a date.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidLocalDateBceNegative() { + open("issue5541.xhtml?acceptBce=true"); + inputLocalDate.sendKeys("-2024-06-31"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputLocalDate.getText()), + () -> assertEquals("form:inputLocalDate: '-2024-06-31' could not be understood as a date.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidLocalTime() { + open("issue5541.xhtml"); + inputLocalTime.sendKeys("12:34:56"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("12:34:56", outputLocalTime.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidLocalTime() { + open("issue5541.xhtml"); + inputLocalTime.sendKeys("23:45:67"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputLocalTime.getText()), + () -> assertEquals("form:inputLocalTime: '23:45:67' could not be understood as a time.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidLocalDateTime() { + open("issue5541.xhtml"); + inputLocalDateTime.sendKeys("2024-06-30 12:34:56"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("2024-06-30 12:34:56", outputLocalDateTime.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidLocalDateTimeBce() { + open("issue5541.xhtml?acceptBce=true"); + inputLocalDateTime.sendKeys("2024-06-30 12:34:56"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("2024-06-30 12:34:56", outputLocalDateTime.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidLocalDateTimeBceNegative() { + open("issue5541.xhtml?acceptBce=true"); + inputLocalDateTime.sendKeys("-2024-06-30 12:34:56"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("-2024-06-30 12:34:56", outputLocalDateTime.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidLocalDateTime() { + open("issue5541.xhtml"); + inputLocalDateTime.sendKeys("2024-06-30 23:45:67"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputLocalDateTime.getText()), + () -> assertEquals("form:inputLocalDateTime: '2024-06-30 23:45:67' could not be understood as a date and time.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidLocalDateTimeBce() { + open("issue5541.xhtml?acceptBce=true"); + inputLocalDateTime.sendKeys("2024-06-30 23:45:67"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputLocalDateTime.getText()), + () -> assertEquals("form:inputLocalDateTime: '2024-06-30 23:45:67' could not be understood as a date and time.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidLocalDateTimeBceNegative() { + open("issue5541.xhtml?acceptBce=true"); + inputLocalDateTime.sendKeys("-2024-06-30 23:45:67"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputLocalDateTime.getText()), + () -> assertEquals("form:inputLocalDateTime: '-2024-06-30 23:45:67' could not be understood as a date and time.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidZonedDateTime() { + open("issue5541.xhtml"); + inputZonedDateTime.sendKeys("2024-06-30 12 uur 34 min +0130"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("2024-06-30 12 uur 34 min +0130", outputZonedDateTime.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidZonedDateTimeBce() { + open("issue5541.xhtml?acceptBce=true"); + inputZonedDateTime.sendKeys("2024-06-30 12 uur 34 min +0130"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("2024-06-30 12 uur 34 min +0130", outputZonedDateTime.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testValidZonedDateTimeBceNegative() { + open("issue5541.xhtml?acceptBce=true"); + inputZonedDateTime.sendKeys("-2024-06-30 12 uur 34 min +0130"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("-2024-06-30 12 uur 34 min +0130", outputZonedDateTime.getText()), + () -> assertEquals("", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidZonedDateTime() { + open("issue5541.xhtml"); + inputZonedDateTime.sendKeys("2024-06-31 12 uur 34 min +0130"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputZonedDateTime.getText()), + () -> assertEquals("form:inputZonedDateTime: '2024-06-31 12 uur 34 min +0130' could not be understood as a date and time.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidZonedDateTimeBce() { + open("issue5541.xhtml?acceptBce=true"); + inputZonedDateTime.sendKeys("2024-06-31 12 uur 34 min +0130"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputZonedDateTime.getText()), + () -> assertEquals("form:inputZonedDateTime: '2024-06-31 12 uur 34 min +0130' could not be understood as a date and time.", messages.getText()) + ); + } + + /** + * https://github.com/eclipse-ee4j/mojarra/issues/5541 + */ + @Test + void testInvalidZonedDateTimeBceNegative() { + open("issue5541.xhtml?acceptBce=true"); + inputZonedDateTime.sendKeys("-2024-06-31 12 uur 34 min +0130"); + guardHttp(submit::click); + assertAll( + () -> assertEquals("", outputZonedDateTime.getText()), + () -> assertEquals("form:inputZonedDateTime: '-2024-06-31 12 uur 34 min +0130' could not be understood as a date and time.", messages.getText()) + ); + } +} diff --git a/test/pom.xml b/test/pom.xml index a0935dcdfe..986f43ef33 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -41,6 +41,7 @@ issue5503 issue5507 issue5511 + issue5541 From 115296efd74158557bc8ab3d9015794305321802 Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sat, 18 Jan 2025 16:46:40 -0400 Subject: [PATCH 2/3] Fix #5541 --- .../faces/convert/DateTimeConverter.java | 88 ++++++++----------- 1 file changed, 39 insertions(+), 49 deletions(-) diff --git a/impl/src/main/java/jakarta/faces/convert/DateTimeConverter.java b/impl/src/main/java/jakarta/faces/convert/DateTimeConverter.java index 2989814812..650eab8b65 100644 --- a/impl/src/main/java/jakarta/faces/convert/DateTimeConverter.java +++ b/impl/src/main/java/jakarta/faces/convert/DateTimeConverter.java @@ -28,14 +28,20 @@ import java.time.OffsetDateTime; import java.time.OffsetTime; import java.time.ZonedDateTime; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.format.FormatStyle; +import java.time.format.ResolverStyle; +import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQuery; import java.util.Date; import java.util.Locale; +import java.util.Map; import java.util.TimeZone; +import java.util.regex.Pattern; import jakarta.faces.component.PartialStateHolder; import jakarta.faces.component.UIComponent; @@ -169,6 +175,17 @@ public class DateTimeConverter implements Converter, PartialStateHolder { private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("GMT"); + private static final Map> TEMPORAL_QUERIES = Map.of( + "localDate", LocalDate::from, + "localDateTime", LocalDateTime::from, + "localTime", LocalTime::from, + "offsetTime", OffsetTime::from, + "offsetDateTime", OffsetDateTime::from, + "zonedDateTime", ZonedDateTime::from + ); + + private static final Pattern ESCAPED_DATE_TIME_PATTERN = Pattern.compile("'[^']*+'"); + // ------------------------------------------------------ Instance Variables private String dateStyle = "default"; @@ -508,9 +525,20 @@ private FormatWrapper getDateFormat(Locale locale) { DateFormat df = null; DateTimeFormatter dtf = null; - TemporalQuery from = null; - if (pattern != null && !isJavaTimeType(type)) { - df = new SimpleDateFormat(pattern, locale); + TemporalQuery from = TEMPORAL_QUERIES.get(type); + + if (pattern != null) { + if (from == null) { + df = new SimpleDateFormat(pattern, locale); + } else { + DateTimeFormatterBuilder dtfBuilder = new DateTimeFormatterBuilder().appendPattern(pattern); + + if (!ESCAPED_DATE_TIME_PATTERN.matcher(pattern).replaceAll("").contains("uu")) { + dtfBuilder.parseDefaulting(ChronoField.ERA, 1); + } + + dtf = dtfBuilder.toFormatter(locale); + } } else if (type.equals("both")) { df = DateFormat.getDateTimeInstance(getStyle(dateStyle), getStyle(timeStyle), locale); } else if (type.equals("date")) { @@ -518,55 +546,27 @@ private FormatWrapper getDateFormat(Locale locale) { } else if (type.equals("time")) { df = DateFormat.getTimeInstance(getStyle(timeStyle), locale); } else if (type.equals("localDate")) { - if (null != pattern) { - dtf = DateTimeFormatter.ofPattern(pattern, locale); - } else { - dtf = DateTimeFormatter.ofLocalizedDate(getFormatStyle(dateStyle)).withLocale(locale); - } - from = LocalDate::from; + dtf = DateTimeFormatter.ofLocalizedDate(getFormatStyle(dateStyle)).withLocale(locale); } else if (type.equals("localDateTime")) { - if (null != pattern) { - dtf = DateTimeFormatter.ofPattern(pattern, locale); - } else { - dtf = DateTimeFormatter.ofLocalizedDateTime(getFormatStyle(dateStyle), getFormatStyle(timeStyle)).withLocale(locale); - } - from = LocalDateTime::from; + dtf = DateTimeFormatter.ofLocalizedDateTime(getFormatStyle(dateStyle), getFormatStyle(timeStyle)).withLocale(locale); } else if (type.equals("localTime")) { - if (null != pattern) { - dtf = DateTimeFormatter.ofPattern(pattern, locale); - } else { - dtf = DateTimeFormatter.ofLocalizedTime(getFormatStyle(timeStyle)).withLocale(locale); - } - from = LocalTime::from; + dtf = DateTimeFormatter.ofLocalizedTime(getFormatStyle(timeStyle)).withLocale(locale); } else if (type.equals("offsetTime")) { - if (null != pattern) { - dtf = DateTimeFormatter.ofPattern(pattern, locale); - } else { - dtf = DateTimeFormatter.ISO_OFFSET_TIME.withLocale(locale); - } - from = OffsetTime::from; + dtf = DateTimeFormatter.ISO_OFFSET_TIME.withLocale(locale); } else if (type.equals("offsetDateTime")) { - if (null != pattern) { - dtf = DateTimeFormatter.ofPattern(pattern, locale); - } else { - dtf = DateTimeFormatter.ISO_OFFSET_DATE_TIME.withLocale(locale); - } - from = OffsetDateTime::from; + dtf = DateTimeFormatter.ISO_OFFSET_DATE_TIME.withLocale(locale); } else if (type.equals("zonedDateTime")) { - if (null != pattern) { - dtf = DateTimeFormatter.ofPattern(pattern, locale); - } else { - dtf = DateTimeFormatter.ISO_ZONED_DATE_TIME.withLocale(locale); - } - from = ZonedDateTime::from; + dtf = DateTimeFormatter.ISO_ZONED_DATE_TIME.withLocale(locale); } else { // PENDING(craigmcc) - i18n throw new IllegalArgumentException("Invalid type: " + type); } + if (null != df) { df.setLenient(false); return new FormatWrapper(df); } else if (null != dtf) { + dtf = dtf.withChronology(IsoChronology.INSTANCE).withResolverStyle(ResolverStyle.STRICT); return new FormatWrapper(dtf, from); } @@ -574,16 +574,6 @@ private FormatWrapper getDateFormat(Locale locale) { throw new IllegalArgumentException("Invalid type: " + type); } - private static boolean isJavaTimeType(String type) { - boolean result = false; - if (null != type && type.length() > 1) { - char c = type.charAt(0); - result = c == 'l' || c == 'o' || c == 'z'; - } - - return result; - } - /** *

* Return the Locale we will use for localizing our formatting and parsing processing. From 8b8f997d25e5f040eb4e0f47c20ba50b3f81cc0a Mon Sep 17 00:00:00 2001 From: Bauke Scholtz Date: Sun, 19 Jan 2025 10:17:33 -0400 Subject: [PATCH 3/3] Improved #5541 --- .../faces/convert/DateTimeConverter.java | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/impl/src/main/java/jakarta/faces/convert/DateTimeConverter.java b/impl/src/main/java/jakarta/faces/convert/DateTimeConverter.java index 650eab8b65..c1c018eba1 100644 --- a/impl/src/main/java/jakarta/faces/convert/DateTimeConverter.java +++ b/impl/src/main/java/jakarta/faces/convert/DateTimeConverter.java @@ -175,7 +175,7 @@ public class DateTimeConverter implements Converter, PartialStateHolder { private static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone("GMT"); - private static final Map> TEMPORAL_QUERIES = Map.of( + private static final Map> JAVA_TIME_TYPES = Map.of( "localDate", LocalDate::from, "localDateTime", LocalDateTime::from, "localTime", LocalTime::from, @@ -524,20 +524,15 @@ private FormatWrapper getDateFormat(Locale locale) { } DateFormat df = null; + DateTimeFormatterBuilder dtfBuilder = null; DateTimeFormatter dtf = null; - TemporalQuery from = TEMPORAL_QUERIES.get(type); + TemporalQuery fromJavaTime = JAVA_TIME_TYPES.get(type); if (pattern != null) { - if (from == null) { + if (fromJavaTime == null) { df = new SimpleDateFormat(pattern, locale); } else { - DateTimeFormatterBuilder dtfBuilder = new DateTimeFormatterBuilder().appendPattern(pattern); - - if (!ESCAPED_DATE_TIME_PATTERN.matcher(pattern).replaceAll("").contains("uu")) { - dtfBuilder.parseDefaulting(ChronoField.ERA, 1); - } - - dtf = dtfBuilder.toFormatter(locale); + dtfBuilder = new DateTimeFormatterBuilder().appendPattern(pattern); } } else if (type.equals("both")) { df = DateFormat.getDateTimeInstance(getStyle(dateStyle), getStyle(timeStyle), locale); @@ -546,11 +541,11 @@ private FormatWrapper getDateFormat(Locale locale) { } else if (type.equals("time")) { df = DateFormat.getTimeInstance(getStyle(timeStyle), locale); } else if (type.equals("localDate")) { - dtf = DateTimeFormatter.ofLocalizedDate(getFormatStyle(dateStyle)).withLocale(locale); + dtfBuilder = new DateTimeFormatterBuilder().appendLocalized(getFormatStyle(dateStyle), null); } else if (type.equals("localDateTime")) { - dtf = DateTimeFormatter.ofLocalizedDateTime(getFormatStyle(dateStyle), getFormatStyle(timeStyle)).withLocale(locale); + dtfBuilder = new DateTimeFormatterBuilder().appendLocalized(getFormatStyle(dateStyle), getFormatStyle(timeStyle)); } else if (type.equals("localTime")) { - dtf = DateTimeFormatter.ofLocalizedTime(getFormatStyle(timeStyle)).withLocale(locale); + dtfBuilder = new DateTimeFormatterBuilder().appendLocalized(null, getFormatStyle(timeStyle)); } else if (type.equals("offsetTime")) { dtf = DateTimeFormatter.ISO_OFFSET_TIME.withLocale(locale); } else if (type.equals("offsetDateTime")) { @@ -562,12 +557,21 @@ private FormatWrapper getDateFormat(Locale locale) { throw new IllegalArgumentException("Invalid type: " + type); } - if (null != df) { + if (df != null) { df.setLenient(false); return new FormatWrapper(df); - } else if (null != dtf) { - dtf = dtf.withChronology(IsoChronology.INSTANCE).withResolverStyle(ResolverStyle.STRICT); - return new FormatWrapper(dtf, from); + } else { + if (dtfBuilder != null) { + if (pattern == null || !ESCAPED_DATE_TIME_PATTERN.matcher(pattern).replaceAll("").contains("uu")) { + dtfBuilder.parseDefaulting(ChronoField.ERA, 1); + } + + dtf = dtfBuilder.toFormatter(locale).withChronology(IsoChronology.INSTANCE).withResolverStyle(ResolverStyle.STRICT); + } + + if (dtf != null) { + return new FormatWrapper(dtf, fromJavaTime); + } } // PENDING(craigmcc) - i18n