I have some tool method which I have been using to dump the contents of a RowSet, especially for debugging and testing purposes. At the core, the method looks like this:
void listRowSet(RowSet rowSet) {
while(rowSet.hasNext()) {
Row row = rowSet.next();
// ... dump the contents of the current row
}
}
and the result looks similar to this, dumping all the attributes in each row:
CId | CCreated | CLastupdated
-----------------------------------------------------------
0 | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0
1 | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0
2 | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0
Now, in a larger application, I was using the RowSet at several places, and I thought it would be a good idea to have the method always start at the first entry, and not rely on the fact that the iterator is already at the beginning when calling the method. This is what the RowIterator.reset() method is for. So, that seems to be easy:
void listRowSet(RowSet rowSet) {
rowSet.reset();
while(rowSet.hasNext()) {
Row row = rowSet.next();
// ... dump the contents of the current row
}
}
Now, the result looks like this:
CId | CCreated | CLastupdated
-----------------------------------------------------------
1 | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0
2 | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0
Ehmmm… Wait … Something’s wrong here … I have reset the iterator, but now the first row is missing? What is going on?
Lets review the documentation of RowIterator.reset():
After this method, the current slot status will be SLOT_BEFORE_FIRST [...]
Alright, I know that concept from JDBC – there, the method is called beforeFirst(), and subsequent calls to next() move the cursor to the next row, which is the first one when next() is called for the first time.
So, what is wrong here? Lets see – there is some additional information in the Javadoc:
... except in cases where this iterator is associated to an iterator binding in an ADF
application which sets the currency to the first row in the iterator if available.
Naturally, I skipped that part when I first looked up the documentation – but it looks like this is an important detail!
On a side note, the next sentence in the Javadoc says
A subsequent invocation of next() will cause the first row to become the current row.
which is confusing, since this is exactly not the case when “this iterator is associated to an iterator binding in an ADF application which sets the currency to the first row in the iterator if available.”.
Now that I know the problem, a quick search showed up a nice posting from Michael Koniotakis: Iterating through View Object RowIterator Bug.(NOT ADF BUG, Development Bug), and the suggestion is to use a secondary row iterator whenever iterating through a RowSet programmatically:
void listRowSet(ViewObject vo) {
RowSetIterator iter = vo.createRowSetIterator(null);
while(iter.hasNext()) {
Row row = iter.next();
// ... dump the contents of the current row
}
iter.closeRowSetIterator();
}
With that, I now get all rows again, starting at the first row:
CId | CCreated | CLastupdated
-----------------------------------------------------------
0 | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0
1 | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0
2 | 2014-07-04 13:16:46.0 | 2014-07-04 13:16:46.0
Instead of the ViewObject, we can also use a RowSet to create the new iterator (remember that a ViewObject is a RowSet), so that the method signature can remain unchanged:
void listRowSet(RowSet rowSet) {
RowSetIterator iter = rowSet.createRowSetIterator(null);
while(iter.hasNext()) {
Row row = iter.next();
// ... dump the contents of the current row
}
iter.closeRowSetIterator();
}