allthingssecurity opened a new pull request, #28784: URL: https://github.com/apache/camel/pull/28784
# Description [CAMEL-26437](https://issues.apache.org/jira/browse/CAMEL-26437) Follow-up of CAMEL-26290 (#28643), which made `FilterIterator.remove()` throw `IllegalStateException` after a `hasNext()` look-ahead. `next()` looks ahead in the same way when it has no element ready: `checkNext()` calls `next()` on the wrapped iterator until the filter accepts an element. When that does not end with an accepted element, `next()` fails, but the permission to remove from the previous successful `next()` was kept while the wrapped iterator had moved on. A `remove()` then removed an element that `next()` never returned: ```java List<Integer> list = new ArrayList<>(List.of(1, 2)); FilterIterator<Integer> it = new FilterIterator<>(list.iterator(), n -> n == 1); it.next(); // 1 it.next(); // looks at 2, rejects it, throws NoSuchElementException it.remove(); // removed 2, leaving [1]; now throws IllegalStateException ``` The same happened when the filter threw while it looked at the next element, and when the elements left were null (they are skipped). `FilterIterator` has no caller in Camel itself; it is a public utility class. Changes: - `FilterIterator.checkNext()` clears the permission right before each `next()` on the wrapped iterator. A successful `next()` sets it again, as before. A `next()` that fails at the end of the wrapped iterator, without moving it, still leaves the element returned before it removable, as the iterator of a list does. - This also covers a wrapped iterator whose own `next()` throws. As before, `hasNext()` always blocks a following `remove()`, also at the end of the wrapped iterator. - The javadoc of `remove()` and the CAMEL-26290 entry of the 4.24 upgrade guide (one paragraph folded into it, under its existing heading) say so. Tests: `FilterIteratorRemoveTest` (camel-util) gets 5 tests. - `NoSuchElementException` after the filter rejected the rest, an exception from the filter (the iteration then goes on, and the next returned element can be removed), and a skipped null tail: these 3 fail on main (`remove()` removes the element) and pass with the change. - Controls, passing on main as well: `next()` at the end of the wrapped iterator keeps the element returned before removable, and a `hasNext()` before the failed `next()`. - A variant that clears the permission at the start of every `next()` instead fails the first control, so the controls pin the end-of-iterator case. - `FilterIteratorRemoveTest` 20 times in one JVM: 200 tests, 0 failures. camel-util, all tests: 325, 0 failures; the formatter and import-sort plugins ran and the tree was clean afterwards. How it was found: an OpenJML/JML verification pilot of the `FilterIterator` contract. The removal-safety condition failed on the original source and holds with this change; the case was then reduced to the plain JUnit tests above. Not changed: `SkipIterator.remove()` delegates to the wrapped iterator, so a `remove()` after a `hasNext()` that did the initial skip (before any `next()`) removes a skipped element; `GroupIterator.remove()` removes only the last element of a group. They are separate classes with no Camel caller of `remove()`; I can open a JIRA if wanted. Backport: not needed; CAMEL-26290 itself is only on main. # Target - [x] I checked that the commit is targeting the correct branch (Camel 4 uses the `main` branch) # Tracking - [x] If this is a large change, bug fix, or code improvement, I checked there is a [JIRA issue](https://issues.apache.org/jira/browse/CAMEL-26437) filed for the change (usually before you start working on it): [CAMEL-26437](https://issues.apache.org/jira/browse/CAMEL-26437). # Apache Camel coding standards and style - [x] I checked that each commit in the pull request has a meaningful subject line and body. - [ ] I have run `mvn clean install -DskipTests` locally from root folder and I have committed all auto-generated changes. (I built camel-util and ran its tests, including the formatter and import-sort plugins. I did not run the full root build.) # AI-assisted contributions - [x] If this PR includes AI-generated code, commits have proper co-authorship attribution (e.g., `Co-authored-by` trailers) and the PR description identifies the AI tool used. This PR was prepared with Claude Code (Claude Opus 5.5). The commit carries a `Co-Authored-By` trailer. _Claude Code on behalf of allthingssecurity_ 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
