JSF:selectOneRadio转换器问题

时间:2011-05-17 15:59:39

标签: jsf converter

我在使用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实现)。

奖金问题:为什么我首先需要转换器?如果我离开转换器,组件将被渲染,但我想将所选书籍传递给某个动作方法,然后它就不会是一本书了。

有什么想法吗? 谢谢!

2 个答案:

答案 0 :(得分:3)

显然#{bookHandler.compareBookA}只是null

ConverterExceptionBook时,您不应该抛出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。