为什么<ui:repeat>不能与java.util.Iterator一起使用?



为什么JSF2/Facelet的ui:repeat不接受java.util.Iterator的值?一个迭代器可以隐藏这么多的实现和内存节约,因为长度不需要知道,所以拥有它会非常有用。但相反,我需要将我的Iterator转换为Lists,并放弃我所有的优势,以便ui:repeat。

可能有阶段、时间或可序列化的原因,但我对可用文档的浏览并没有给出这些原因。难道我们还没有科学使这种不可能成为可能吗?

<ui:repeat>不支持java.util.Iterator
查看UIRepeat.getDataModel()源代码:

 private DataModel getDataModel() {
    if (this.model == null) {
        Object val = this.getValue();
        if (val == null) {
            this.model = EMPTY_MODEL;
        } else if (val instanceof DataModel) {
            //noinspection unchecked
            this.model = (DataModel<Object>) val;
        } else if (val instanceof List) {
            //noinspection unchecked
            this.model = new ListDataModel<Object>((List<Object>) val);
        } else if (Object[].class.isAssignableFrom(val.getClass())) {
            this.model = new ArrayDataModel<Object>((Object[]) val);
        } else if (val instanceof ResultSet) {
            this.model = new ResultSetDataModel((ResultSet) val);
        } else {
            this.model = new ScalarDataModel<Object>(val);
        }
    }
    return this.model;
}

您可以使<ui:repeat>使用Iterator,但必须使用扩展javax.faces.model.DataModel的对象包装Iterator。下面是我的IteratorDataModel类,它可以使任何Iterator都可访问<ui:重复>。我用JSF 2.1.26:测试了这一点

/**
 * Make a DataModel out of an Iterator that may be used with JSF's ui:repeat tag
 *
 * This DataModel does not support the use of offset or step attributes in the
 * ui:repeat tag, and the size attribute in ui:repeat, when used with this DataModel, 
 * will report an inaccurate value.
 *
 * Copyright (c) 2014 Woldrich, Inc.
 * Licensed under MIT (https://clubcompy.com/wcm/license/mit.txt)
 * 
 * @author Dave Woldrich
 */
public class IteratorDataModel<T> extends DataModel<T> {
    private static final Logger logger = LogManager.getLogger(IteratorDataModel.class);
    private Iterator<?> iterator;
    private int rowIndex; 
    private T item;
    public IteratorDataModel(Iterator<?> iterator) {
        setWrappedData(iterator);      
    }
    @Override
    public int getRowCount() {
        return Integer.MAX_VALUE;
    }
    @Override
    public T getRowData() {
        return this.item;
    }
    @Override
    public int getRowIndex() {
        if(this.rowIndex == -1 && this.iterator.hasNext()) {
            this.setRowIndex(0);
        }
        if(logger.isTraceEnabled()) {
            logger.trace("getRowIndex returns " + this.rowIndex);
        }
        return this.rowIndex;
    }
    @Override
    public Object getWrappedData() {
        return this.iterator;
    }
    @Override
    public boolean isRowAvailable() {
        boolean hasNext = this.item != null || this.iterator.hasNext(); 
        if(logger.isTraceEnabled()) {
            logger.trace("isRowAvailable " + hasNext);
        }
        return hasNext;
    }
    @SuppressWarnings("unchecked")
    @Override
    public void setRowIndex(int newIndex) {
        if(logger.isTraceEnabled()) {
            logger.trace("setRowIndex (" + newIndex + ")");
        }
        if(newIndex == this.rowIndex+1) {
            this.rowIndex = newIndex;
            this.item = (T) (this.iterator.hasNext() ? this.iterator.next() : null);
        } 
        else if(newIndex > -1 || newIndex != this.rowIndex) {
            if(logger.isTraceEnabled()) {
                logger.trace("setRowIndex not incrementing by 1 as expected, ignored");            
            }
        }
    }
    @Override
    public void setWrappedData(Object data) {
        this.iterator = (Iterator<?>) data;
        this.rowIndex = -1;
        this.item = null;
    }    
}

例如,在你的facelets代码中,你可以使用:

<ul>
    <ui:repeat value="#{chatRoom.allComments}" var="aComment" varStatus="status">
        <li><h:outputText value="#{aComment.text}" /></li>
    </ui:repeat>
</ul>

其中chatRoom.getAllComments()将返回通过Iterator<Comment>构造的IteratorDataModel<Comment>

相关内容

  • 没有找到相关文章

最新更新