【问题标题】:JSF: selectOneRadio converter problemJSF:selectOneRadio 转换器问题
【发布时间】:2011-08-27 09:12:55
【问题描述】:

我在使用 selectOneRadio 组件时遇到了问题。我在转换器的 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 上使用 JSF 2(MyFaces 实现)和 Tomahawk。

额外问题:为什么我首先需要转换器?如果我离开转换器,组件会被渲染,但我想将选择的书传递给某个操作方法,那么它就不是书了。

有什么想法吗? 谢谢!

【问题讨论】:

    标签: jsf converter


    【解决方案1】:

    显然#{bookHandler.compareBookA} 只是null

    Booknull 时,你不应该抛出ConverterException,而是放手。

    return (book != null) ? book.getShortname() : null;
    

    至于附加问题,您需要转换器,因为 HTML 响应基本上是一个大字符串。所有 Java 对象都需要转换为字符串才能嵌入到 HTML 响应中。此外,HTTP 请求参数默认为字符串。 request.getParameter() 返回 String。 HTML/HTTP 完全不知道如何处理和传递完全有价值的 Java 对象。

    另见:

    【讨论】:

    • D'oh,我忘了初始化它。你说的对。谢谢!我尝试将 bookHandler.compareBookA 传递给某个操作方法,但它保持为空。任何想法为什么?
    • 那么getAsObject() 可能没有正确实现。我建议您通过“另请参阅”链接了解自己。
    【解决方案2】:

    转换器提供了一种将 POJO 转换为字符串 (HTML) 表示形式的机制,然后将该字符串转换回同一 POJO 的实例。在您的示例中,您不想抛出异常,而是在 Book 为 null 时返回 null。

    我在我的应用程序中经常做的一件事是创建一个适用于我所有 selectItems 的通用转换器。如果您的所有实体都使用例如 id 属性实现公共接口,这很容易。

    public interface Entity extends Serializable {
    
        /**
         * Return the primary key for this entity
         * 
         * @return id
         */
        public BigInteger getId();
    
    }
    

    然后,您可以为所有实体应如何转换为字符串并返回对象创建一个约定。我通常将类名和 id 连接起来,然后对它们进行 Base64 编码以将对象转换为字符串,然后进行反向转换:

    /*
     * (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;
    }
    

    您的实体结构可能与我的不同,但如果您遵循基本模式,您将拥有一个适用于应用中所有 POJO 的转换器,表示为 SelectItems。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      • 2013-07-05
      相关资源
      最近更新 更多