[jdom-interest] Bug in Element.getChildren().listIterator(pos)
Paul Cantrell
cantrell at pobox.com
Sun Aug 24 13:38:14 PDT 2003
Brad --
You're quite right -- and there's a deeper problem here: it's
impossible to choose a position which satisfies both hasNext() and
hasPrevious(). It looks like Vadim's patch solves this problem neatly.
The alternative would be to add a field which tracks the highest
matching position, and use that instead of size() for answering
hasNext(), but that gets awkward quickly -- Vadim's approach seems
simpler.
Another alternative, perhaps less error-prone (and perhaps not!), would
be to have FilterListIterator wrap an unfiltered ListIterator, and then
take an approach similar to InnigCollections.select(Iterator,Selector):
http://innig.net/util/innig-util/src/net/innig/collect/
InnigCollections.java
This avoids some of the complex machinery of tracking the iterator's
last operation ... but the simplicity might break down when you're
allowed to iterate in both directions.
Cheers,
Paul
On Sunday, August 24, 2003, at 01:43 PM, Bradley S. Huffman wrote:
> I think this is the same bug found by Vadim Strizhevsky at the end of
> July.
> There is a patch at
>
> http://lists.denveronline.net/lists/jdom-interest/2003-July/013289.html
>
> but it hasn't been fully tested either.
>
> Looking at your patch, I'm not sure it is correct. If start = 0 and the
> backing list contains only a single Text node then initializeCursor
> would return 0 cause a call to hasNext to be true, but index 0 in the
> backing
> list is a Text node not a Element.
>
> Brad
>
> Paul Cantrell writes:
>
>> Working on Macker (at http://innig.net/macker if you're curious), I
>> found a bug in the listIterator(int) method of the list returned by
>> Element.getChildren().
>>
>> The following code demonstrates the bug -- it incorrectly generates a
>> ClassCastException if element contains text content after its last
>> child element:
>>
>> List children = element.getChildren();
>> for(ListIterator childIter =
>> children.listIterator(children.size()); childIter.hasPrevious(); )
>> {
>> Element subElem = (Element) childIter.previous();
>> .......
>> }
>>
>> The exception occurs because the call to childIter.previous()
>> erroneously returns a Text object the first time it is called.
>>
>> The problem appears to be in the last line
>> ContentList.java.initializeCursor(int start), which is
>> ContentList.java:1277 in the nightly I just picked up. The final
>> return incorrectly presumes that the last element in the list matches
>> the filter. The method *should* go something like this:
>>
>> private int initializeCursor(int start) {
>> if (start < 0) {
>> throw new IndexOutOfBoundsException("Index: " +
>> start);
>> }
>>
>> int count = 0;
>> int lastMatchPos = -1; // <---------
>> for (int i = 0; i < ContentList.this.size(); i++) {
>> Object obj = ContentList.this.get(i);
>> if (filter.matches(obj)) {
>> lastMatchPos = i; // <----------
>> if (start == count) {
>> return i;
>> }
>> count++;
>> }
>> }
>>
>> if (start > count) {
>> throw new IndexOutOfBoundsException("Index: " +
>> start +
>> " Size: " +
>> count);
>> }
>>
>> return lastMatchPos + 1; // <---------
>> }
>>
>> WARNING: I haven't tested this patch -- I just typed it straight into
>> the email. (Sorry!) I hope it's not too far off the mark.
>>
>> Cheers,
>>
>> Paul
More information about the jdom-interest
mailing list