为什么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>
。