shashank created CAMEL-26452:
--------------------------------
Summary: camel-beanio - BeanIOSplitter drops the record after each
invalid record that the error handler replaces with a result
Key: CAMEL-26452
URL: https://issues.apache.org/jira/browse/CAMEL-26452
Project: Camel
Issue Type: Bug
Components: camel-beanio
Reporter: shashank
Assignee: shashank
A custom {{BeanIOErrorHandler}} can turn an invalid record into a result with
{{handleErrorAndAddAsResult(Object)}} (the {{MyErrorHandler}} of the component
tests does it). The {{beanio}} data format adds that result to its list;
{{BeanIOSplitter}} gives it to its {{BeanIOIterator}} with {{setNext(result)}}.
The error handler is called from inside {{BeanReader.read()}}. After the
handler returns, BeanIO goes on reading and {{read()}} returns the next valid
record. {{BeanIOIterator.next()}} then does:
{code:java}
next = reader.read(); // the valid record after the invalid one
if (forceNext != null) {
next = forceNext; // ... is replaced by the result of the error
handler
forceNext = null;
}
{code}
So the valid record that follows a handled invalid record is lost, and of two
invalid records in a row only the last result is kept (the single {{forceNext}}
field is overwritten). Nothing is logged. Only a single invalid record at the
end of the data (where {{read()}} returns null) works, which is what
{{BeanIOSplitterCustomBeanReaderErrorHandlerTest.testSplitFail}} covers.
Reproducer (the employee mapping of the component tests,
{{split(splitter).streaming()}} with
{{setBeanReaderErrorHandlerType(MyErrorHandler.class)}}):
||Records||split on main (4ab42b192b26)||unmarshal with the data format||
|Joe, Jane (invalid salary), Jon|Joe, ErrorDto|Joe, ErrorDto, Jon|
|Joe, Jane (invalid), Jim (invalid), Jon, Jack|Joe, ErrorDto, Jack|Joe,
ErrorDto, ErrorDto, Jon, Jack|
A route that splits data with such an error handler silently drops a valid
record after each invalid one, with any BeanIO stream format. The same code is
on the 4.14.x, 4.18.x and 4.22.x branches.
*Proposal*
* {{BeanIOIterator}} keeps the results that the error handler adds during a
read in a queue, and returns them in their order before the record that the
read returned (the same order as the data format's list). {{setNext}} adds to
the queue.
* Tests: an invalid record in the middle, two invalid records in a row followed
by valid ones (with their order), an invalid first record, and an error handler
type that cannot be created.
Next to it: the first record is read in the {{BeanIOIterator}} constructor,
before {{BeanIOSplitter}} sets the error handler on the reader, so an invalid
first record fails the split even with {{ignoreInvalidRecords=true}} or a
custom error handler; and when the error handler cannot be created (a wrong
{{beanReaderErrorHandlerType}}), the reader of the body is not closed.
Proposal: set the error handler before the first read, inside the block that
closes the reader on a failure.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)