我想让JSF表单中的Calendar输入成为可选的。当用户不通知出生时,Calendar字段必须保持为空。
我的代码:@Model
public class Registration {
private User user = new User();
public void register() {
// stuff
}
//getUser
}
模型类:
public class User {
//other fields
private Calendar birth;
// gets and sets
}
页面:
<h:outputLabel for="birth" value="Birth Date" />
<h:inputText id="birth" value="#{registration.user.birth.time}" >
<f:convertDateTime pattern="dd/MM/yyyy" />
</h:inputText>
到目前为止,这里的问题是<f:convertDateTime>
,它依赖于Calendar
的getTime()
方法来进行转换。它在执行时抛出一个NPE(空指针异常)。我知道,如果我初始化出生,问题就解决了,但是我真的希望当用户不填充字段时,字段为空。
有什么方法可以做到这一点吗?
问题与转换无关,而与表达式有关:
#{registration.user.birth.time}
实际上这是DateTimeConverter
代码:
public Object getAsObject(FacesContext context, UIComponent component,
String value) {
...
Object returnValue = null;
DateFormat parser = null;
try {
// If the specified value is null or zero-length, return null
if (value == null) {
return (null);
}
value = value.trim();
if (value.length() < 1) {
return (null);
}
...
returnValue = parser.parse(value);
} catch (ParseException e) {
...
}
return returnValue;
}
您可以注意到,null和空值是正确管理的。但是当这些值被应用时,表达式birth.time
被求值,但是birth
引用是空的,所以当调用setter on time时,你得到NPE。
一个可能的解决方案是将birth
字段直接绑定到java.util.Date
类型,这是DateTimeConverter
管理的类型,如下所示:
public class User {
//other fields
private Date birth;
// gets and sets
}
好吧,我会把这个贴出来给后人看的。我想这样就可以了:
@FacesConverter("CustomCalendarConverter")
public class CalConverter implements Converter{
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if(value != null && !value.toString().isEmpty()){
try {
String pattern = (String) component.getAttributes().get("pattern");
Calendar calendar = Calendar.getInstance();
calendar.setTime(new SimpleDateFormat(pattern).parse(value));
return calendar;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return null;
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if(value != null && !value.toString().isEmpty()){
Calendar cal = (Calendar) value;
String pattern = (String) component.getAttributes().get("pattern");
return new SimpleDateFormat(pattern).format(cal.getTime());
}
else return null;
}
}
视图应该是:
<h:outputLabel for="birth" value="Birth Date" />
<h:inputText id="birth" value="#{registration.user.birth}">
<f:converter converterId="CustomCalendarConverter" />
<f:attribute name="pattern" value="dd/MM/yyyy" />
</h:inputText>
您也可以创建一个复合组件,例如<custom:inputCalendar>
。