p:datePicker(或p:calendar)上的最小和最大日期导致 ClassCastException 或最小日期必须小于最大日期
Min and maxdate on p:datePicker (or p:calendar) causes ClassCastException or minimum date must be less than maximum date
我正在使用 PrimeFaces 10.0.0。当使用固定 mindate
.
的 p:datePicker
时,我需要将 maxdate
动态设置为 10 年后
要设置的实用程序 bean maxdate
:
@Named @ApplicationScoped
public class Dates {
public LocalDate getLocalDateNow() {
return LocalDate.now();
}
}
日期选择器:
<p:datePicker pattern="MM/dd/yyyy"
mindate="1/1/2011"
maxdate="#{dates.localDateNow.plusYears(10)}"
.../>
引发此异常:
javax.servlet.ServletException: java.lang.String cannot be cast to java.time.chrono.ChronoLocalDate
...
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.time.chrono.ChronoLocalDate
at java.time.LocalDate.compareTo(LocalDate.java:137)
at org.primefaces.component.api.UICalendar.validateMinMax(UICalendar.java:375)
at org.primefaces.component.calendar.BaseCalendarRenderer.encodeEnd(BaseCalendarRenderer.java:84)
at org.primefaces.component.datepicker.DatePickerRenderer.encodeEnd(DatePickerRenderer.java:89)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:619)
...
当我将实用程序 bean 更改为 return a String
:
public String getLocalDateNow() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/uuuu");
LocalDate localDateNow = LocalDate.now().plusYears(10);
return localDateNow.format(dtf);
}
随后:
maxdate="#{dates.localDateNow}"
事情是这样的:
javax.servlet.ServletException: DatePicker : "form:startDate" minimum date must be less than maximum date.
...
Caused by: javax.faces.FacesException: DatePicker : "form:serviceStart" minimum date must be less than maximum date.
at org.primefaces.component.api.UICalendar.validateMinMax(UICalendar.java:378)
at org.primefaces.component.calendar.BaseCalendarRenderer.encodeEnd(BaseCalendarRenderer.java:84)
at
...
如何防止这些异常?
看看 source code of UICalendar.validateMinMax
:
public void validateMinMax(FacesContext context) {
Comparable minDate = (Comparable) getMindate();
Comparable maxDate = (Comparable) getMaxdate();
if (minDate != null && maxDate != null && maxDate.compareTo(minDate) < 0) {
String id = getClientId(context);
String component = this.getClass().getSimpleName();
throw new FacesException(component + " : \"" + id + "\" minimum date must be less than maximum date.");
}
}
它只是检查 Comparable
,并不关心实际类型。如果您对一个日期使用 LocalDate
而对另一个日期使用 String
,比较将导致错误(如您的第一个堆栈跟踪所示)。
对两者都使用 String
也不好,因为比较字符串与日期值无关。如果您使用像 yyyy-MM-dd
这样的日期模式,可能会更好,但最好不要使用字符串。
您应该为最小日期和最大日期使用相同的(非字符串)类型(例如 LocalDate
),这样就可以了。
话虽如此,validateMinMax
的当前实施存在缺陷。这已被报告(并在撰写此答案时修复):
- 问题:https://github.com/primefaces/primefaces/issues/7576
- 修复:https://github.com/primefaces/primefaces/pull/7637
修复将在 PrimeFaces 11 中结束。
顺便说一下,此代码与 p:calendar
组件共享,因此同样的原则适用于那里。请注意 p:calendar
已弃用!
我正在使用 PrimeFaces 10.0.0。当使用固定 mindate
.
p:datePicker
时,我需要将 maxdate
动态设置为 10 年后
要设置的实用程序 bean maxdate
:
@Named @ApplicationScoped
public class Dates {
public LocalDate getLocalDateNow() {
return LocalDate.now();
}
}
日期选择器:
<p:datePicker pattern="MM/dd/yyyy"
mindate="1/1/2011"
maxdate="#{dates.localDateNow.plusYears(10)}"
.../>
引发此异常:
javax.servlet.ServletException: java.lang.String cannot be cast to java.time.chrono.ChronoLocalDate
...
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.time.chrono.ChronoLocalDate
at java.time.LocalDate.compareTo(LocalDate.java:137)
at org.primefaces.component.api.UICalendar.validateMinMax(UICalendar.java:375)
at org.primefaces.component.calendar.BaseCalendarRenderer.encodeEnd(BaseCalendarRenderer.java:84)
at org.primefaces.component.datepicker.DatePickerRenderer.encodeEnd(DatePickerRenderer.java:89)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:619)
...
当我将实用程序 bean 更改为 return a String
:
public String getLocalDateNow() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/uuuu");
LocalDate localDateNow = LocalDate.now().plusYears(10);
return localDateNow.format(dtf);
}
随后:
maxdate="#{dates.localDateNow}"
事情是这样的:
javax.servlet.ServletException: DatePicker : "form:startDate" minimum date must be less than maximum date.
...
Caused by: javax.faces.FacesException: DatePicker : "form:serviceStart" minimum date must be less than maximum date.
at org.primefaces.component.api.UICalendar.validateMinMax(UICalendar.java:378)
at org.primefaces.component.calendar.BaseCalendarRenderer.encodeEnd(BaseCalendarRenderer.java:84)
at
...
如何防止这些异常?
看看 source code of UICalendar.validateMinMax
:
public void validateMinMax(FacesContext context) {
Comparable minDate = (Comparable) getMindate();
Comparable maxDate = (Comparable) getMaxdate();
if (minDate != null && maxDate != null && maxDate.compareTo(minDate) < 0) {
String id = getClientId(context);
String component = this.getClass().getSimpleName();
throw new FacesException(component + " : \"" + id + "\" minimum date must be less than maximum date.");
}
}
它只是检查 Comparable
,并不关心实际类型。如果您对一个日期使用 LocalDate
而对另一个日期使用 String
,比较将导致错误(如您的第一个堆栈跟踪所示)。
对两者都使用 String
也不好,因为比较字符串与日期值无关。如果您使用像 yyyy-MM-dd
这样的日期模式,可能会更好,但最好不要使用字符串。
您应该为最小日期和最大日期使用相同的(非字符串)类型(例如 LocalDate
),这样就可以了。
话虽如此,validateMinMax
的当前实施存在缺陷。这已被报告(并在撰写此答案时修复):
- 问题:https://github.com/primefaces/primefaces/issues/7576
- 修复:https://github.com/primefaces/primefaces/pull/7637
修复将在 PrimeFaces 11 中结束。
顺便说一下,此代码与 p:calendar
组件共享,因此同样的原则适用于那里。请注意 p:calendar
已弃用!