This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch backport/25330-to-camel-4.18.x in repository https://gitbox.apache.org/repos/asf/camel.git
commit 1b7b1bd416e7b3abcf70df18302d7d2d9b1ac019 Author: Omar Atie <[email protected]> AuthorDate: Tue Aug 4 13:31:34 2026 -0700 CAMEL-24355: Fix NIOConverter.toByteArray for fully consumed ByteBuffer Use duplicate().rewind() to read bytes from position 0 to limit without mutating the original buffer, fixing BufferUnderflowException when the buffer position equals limit (e.g. Kinesis KCL dead letter queue flow). Co-authored-by: Claude Opus 4.6 <[email protected]> Co-authored-by: Cursor <[email protected]> --- .../org/apache/camel/converter/NIOConverter.java | 6 ++- .../apache/camel/converter/NIOConverterTest.java | 62 ++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/core/camel-base/src/main/java/org/apache/camel/converter/NIOConverter.java b/core/camel-base/src/main/java/org/apache/camel/converter/NIOConverter.java index d4bb5548fff8..8e08c9eb4bde 100644 --- a/core/camel-base/src/main/java/org/apache/camel/converter/NIOConverter.java +++ b/core/camel-base/src/main/java/org/apache/camel/converter/NIOConverter.java @@ -50,7 +50,11 @@ public final class NIOConverter { @Converter(order = 1) public static byte[] toByteArray(ByteBuffer buffer) { byte[] bArray = new byte[buffer.limit()]; - buffer.get(bArray); + if (bArray.length > 0) { + ByteBuffer copy = buffer.duplicate(); + copy.rewind(); + copy.get(bArray); + } return bArray; } diff --git a/core/camel-core/src/test/java/org/apache/camel/converter/NIOConverterTest.java b/core/camel-core/src/test/java/org/apache/camel/converter/NIOConverterTest.java index 85a0e61e7b3b..8afe34a0cbdf 100644 --- a/core/camel-core/src/test/java/org/apache/camel/converter/NIOConverterTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/converter/NIOConverterTest.java @@ -25,6 +25,7 @@ import org.apache.camel.ContextTestSupport; import org.apache.camel.Exchange; import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -53,6 +54,67 @@ public class NIOConverterTest extends ContextTestSupport { assertEquals(5, out.length); } + @Test + void testToByteArrayFullyConsumedBuffer() { + ByteBuffer bb = ByteBuffer.wrap("Hello".getBytes()); + while (bb.hasRemaining()) { + bb.get(); + } + assertThat(bb.position()).isEqualTo(bb.limit()); + + byte[] out = NIOConverter.toByteArray(bb); + + assertThat(out).containsExactly("Hello".getBytes()); + assertThat(bb.position()).isEqualTo(bb.limit()); + } + + @Test + void testToByteArrayPartiallyConsumedBuffer() { + ByteBuffer bb = ByteBuffer.allocate(100); + bb.put("Hello".getBytes()); + bb.flip(); + bb.get(); + assertThat(bb.position()).isEqualTo(1); + + byte[] out = NIOConverter.toByteArray(bb); + + assertThat(out).containsExactly("Hello".getBytes()); + assertThat(bb.position()).isEqualTo(1); + } + + @Test + void testToByteArrayEmptyBuffer() { + ByteBuffer bb = ByteBuffer.allocate(0); + + byte[] out = NIOConverter.toByteArray(bb); + + assertThat(out).isEmpty(); + } + + @Test + void testToStringFullyConsumedBuffer() throws Exception { + ByteBuffer bb = ByteBuffer.wrap("Hello".getBytes()); + while (bb.hasRemaining()) { + bb.get(); + } + + String out = NIOConverter.toString(bb, null); + + assertThat(out).isEqualTo("Hello"); + } + + @Test + void testToInputStreamFullyConsumedBuffer() throws Exception { + ByteBuffer bb = ByteBuffer.wrap("Hello".getBytes()); + while (bb.hasRemaining()) { + bb.get(); + } + + InputStream is = NIOConverter.toInputStream(bb); + + assertThat(IOConverter.toString(is, null)).isEqualTo("Hello"); + } + @Test public void testToString() throws Exception { ByteBuffer bb = ByteBuffer.wrap("Hello".getBytes());
