我在使用selectOneRadio组件时遇到问题。我在Converter的getAsString中得到一个NullPointerException。在我看到该组件之前就抛出了这个异常。
这就是它的样子:
<h:selectOneRadio id="bookA"
value="#{bookHandler.compareBookA}">
<f:converter converterId="bookConverter" />
<f:selectItems value="#{bookHandler.selectedBooks}"
var="book" itemLabel="#{book.shortname}" itemValue="#{book}" />
</h:selectOneRadio>
属性compareBookA是Book类型的对象。
这是抛出NPE的方法:
@Override
public String getAsString(FacesContext fc, UIComponent uic, Object value)
throws ConverterException {
Book book = (Book) value;
if (book == null ) {
throw new ConverterException("NPE...");
}
return book.getShortname();
}
我也覆盖了toString()。
由于某种原因,如果我将组件更改为selectManyCheckbox(并保留其余部分),则会呈现该组件。
我在Tomcat上使用了Tomahawk的JSF 2(MyFaces实现)。
奖金问题:为什么我首先需要转换器?如果我离开转换器,组件将被渲染,但我想将所选书籍传递给某个动作方法,然后它就不会是一本书了。
有什么想法吗? 谢谢!
答案 0 :(得分:3)
显然#{bookHandler.compareBookA}
只是null
。
当ConverterException
为Book
时,您不应该抛出null
,而是放手。
return (book != null) ? book.getShortname() : null;
关于奖金问题,您需要转换器,因为HTML响应基本上是一个大字符串。需要将所有Java对象转换为字符串以嵌入HTML响应中。此外,HTTP请求参数默认为字符串。 request.getParameter()
会返回String
。 HTML / HTTP完全没有关于如何处理和传递适当的Java对象的概念。
答案 1 :(得分:1)
Converter提供了一种机制,可以将POJO转换为String(HTML)表示形式,然后将该String转换回同一个POJO的实例。在您的示例中,您不希望抛出异常,而只是在Book为null时返回null。
我在我的应用程序中经常做的一件事是创建一个适用于我所有selectItem的通用转换器。如果您的所有实体都使用例如id属性实现公共接口,那么这很容易。
public interface Entity extends Serializable {
/**
* Return the primary key for this entity
*
* @return id
*/
public BigInteger getId();
}
然后,您可以创建一个约定,以了解如何将所有实体转换为String并返回到Object。我通常连接classname和id,然后Base64编码它们将对象转换为String然后反转转换:
/*
* (non-Javadoc)
* @see javax.faces.convert.Converter#getAsObject(javax.faces.context.FacesContext, javax.faces.component.UIComponent, java.lang.String)
*/
@SuppressWarnings("unchecked")
public Object getAsObject(FacesContext context, UIComponent component, String value) {
Object objectValue = null;
try {
BigInteger id = null;
value = this.unhash(value);
String[] array = value.split(CLASS_KEY_SEPARATOR);
if (array.length == 2) {
id = new BigInteger(array[1]);
}
Collection<UIComponent> childComponents = component.getChildren();
for (UIComponent childComponent : childComponents) {
if (childComponent.getClass().equals(UISelectItems.class)) {
Collection<Entity> values =
(Collection<Entity>) childComponent.getValueExpression("value").getValue(FacesContext.getCurrentInstance().getELContext());
for (Entity selectItemValue : values) {
if (id.equals(selectItemValue.getId())) {
return selectItemValue;
}
}
}
}
} catch (Exception ex) {
LOGGER.error(ex.getMessage(), ex);
}
return objectValue;
}
您的实体结构可能与我的不同,但如果您遵循基本模式,则您的转换器适用于您的应用中表示为SelectItems的所有POJO。