This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 3dcae5b56bf9 CAMEL-25074: camel-sql - say in the outputType
description that a StreamList body is an Iterator with no size
3dcae5b56bf9 is described below
commit 3dcae5b56bf92af7d35aaeb263e8ef959724c8e2
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Sep 28 11:58:05 2026 +0200
CAMEL-25074: camel-sql - say in the outputType description that a
StreamList body is an Iterator with no size
outputType=StreamList makes the body a ResultSetIterator. The description
said
the result is streamed "using an Iterator" and "can be used with the
Splitter
EIP in streaming mode", which is accurate but stops one sentence short of
the
consequence: the body has no size and can be read only once. Treating it as
a
list then fails with an error that does not mention the option that caused
it:
MethodNotFoundException: Method with name: size() not found on bean:
org.apache.camel.component.sql.ResultSetIterator@1bdc4d7c
Measured while benchmarking a local model on a step that selects rows, logs
${body.size()} and splits the list, 30 times over three runs: SelectList
and no
outputType worked, StreamList failed 8 times out of 8, always on size(). It
reads that the result is an Iterator for the Splitter, chooses it, and
sizes the
body anyway.
Closes #26965
Signed-off-by: Claus Ibsen <[email protected]>
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
.../org/apache/camel/catalog/components/sql.json | 2 +-
.../org/apache/camel/component/sql/sql.json | 2 +-
.../camel/component/sql/DefaultSqlEndpoint.java | 4 ++-
.../endpoint/dsl/SqlEndpointBuilderFactory.java | 30 +++++++++++++++++-----
4 files changed, 29 insertions(+), 9 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql.json
index fca8d9d34bd1..6386c9f71bc3 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/sql.json
@@ -54,7 +54,7 @@
"dataSource": { "index": 2, "kind": "parameter", "displayName": "Data
Source", "group": "common", "label": "", "required": false, "type": "object",
"javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "",
"autowired": true, "secret": false, "description": "Sets the DataSource to use
to communicate with the database at endpoint level." },
"outputClass": { "index": 3, "kind": "parameter", "displayName": "Output
Class", "group": "common", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "Specify the full package and class name to use
as conversion when outputType=SelectOne." },
"outputHeader": { "index": 4, "kind": "parameter", "displayName": "Output
Header", "group": "common", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "Store the query result in a header instead of
the message body. By default, outputHeader == null and the query result is
stored in the message body, any existing content in the message body is
discarded. If outputHeader is set, th [...]
- "outputType": { "index": 5, "kind": "parameter", "displayName": "Output
Type", "group": "common", "label": "", "required": false, "type": "enum",
"javaType": "org.apache.camel.component.sql.SqlOutputType", "enum": [
"SelectOne", "SelectList", "StreamList" ], "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "SelectList", "description": "Make the
output of consumer or producer to SelectList as List of Map, or SelectOne as
single Java object in the following way [...]
+ "outputType": { "index": 5, "kind": "parameter", "displayName": "Output
Type", "group": "common", "label": "", "required": false, "type": "enum",
"javaType": "org.apache.camel.component.sql.SqlOutputType", "enum": [
"SelectOne", "SelectList", "StreamList" ], "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "SelectList", "description": "Make the
output of consumer or producer to SelectList as List of Map, or SelectOne as
single Java object in the following way [...]
"separator": { "index": 6, "kind": "parameter", "displayName":
"Separator", "group": "common", "label": "", "required": false, "type":
"string", "javaType": "char", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": ",", "description": "The separator to use when
parameter values is taken from message body (if the body is a String type), to
be inserted at # placeholders. Notice if you use named parameters, then a Map
type is used instead. The default value is comma" },
"breakBatchOnConsumeFail": { "index": 7, "kind": "parameter",
"displayName": "Break Batch On Consume Fail", "group": "consumer", "label":
"consumer", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "description": "Sets whether to break batch if onConsume failed." },
"expectedUpdateCount": { "index": 8, "kind": "parameter", "displayName":
"Expected Update Count", "group": "consumer", "label": "consumer", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": -1, "description": "Sets an expected
update count to validate when using onConsume." },
diff --git
a/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/sql.json
b/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/sql.json
index fca8d9d34bd1..6386c9f71bc3 100644
---
a/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/sql.json
+++
b/components/camel-sql/src/generated/resources/META-INF/org/apache/camel/component/sql/sql.json
@@ -54,7 +54,7 @@
"dataSource": { "index": 2, "kind": "parameter", "displayName": "Data
Source", "group": "common", "label": "", "required": false, "type": "object",
"javaType": "javax.sql.DataSource", "deprecated": false, "deprecationNote": "",
"autowired": true, "secret": false, "description": "Sets the DataSource to use
to communicate with the database at endpoint level." },
"outputClass": { "index": 3, "kind": "parameter", "displayName": "Output
Class", "group": "common", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "Specify the full package and class name to use
as conversion when outputType=SelectOne." },
"outputHeader": { "index": 4, "kind": "parameter", "displayName": "Output
Header", "group": "common", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "description": "Store the query result in a header instead of
the message body. By default, outputHeader == null and the query result is
stored in the message body, any existing content in the message body is
discarded. If outputHeader is set, th [...]
- "outputType": { "index": 5, "kind": "parameter", "displayName": "Output
Type", "group": "common", "label": "", "required": false, "type": "enum",
"javaType": "org.apache.camel.component.sql.SqlOutputType", "enum": [
"SelectOne", "SelectList", "StreamList" ], "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "SelectList", "description": "Make the
output of consumer or producer to SelectList as List of Map, or SelectOne as
single Java object in the following way [...]
+ "outputType": { "index": 5, "kind": "parameter", "displayName": "Output
Type", "group": "common", "label": "", "required": false, "type": "enum",
"javaType": "org.apache.camel.component.sql.SqlOutputType", "enum": [
"SelectOne", "SelectList", "StreamList" ], "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "SelectList", "description": "Make the
output of consumer or producer to SelectList as List of Map, or SelectOne as
single Java object in the following way [...]
"separator": { "index": 6, "kind": "parameter", "displayName":
"Separator", "group": "common", "label": "", "required": false, "type":
"string", "javaType": "char", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": ",", "description": "The separator to use when
parameter values is taken from message body (if the body is a String type), to
be inserted at # placeholders. Notice if you use named parameters, then a Map
type is used instead. The default value is comma" },
"breakBatchOnConsumeFail": { "index": 7, "kind": "parameter",
"displayName": "Break Batch On Consume Fail", "group": "consumer", "label":
"consumer", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue":
false, "description": "Sets whether to break batch if onConsume failed." },
"expectedUpdateCount": { "index": 8, "kind": "parameter", "displayName":
"Expected Update Count", "group": "consumer", "label": "consumer", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": -1, "description": "Sets an expected
update count to validate when using onConsume." },
diff --git
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlEndpoint.java
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlEndpoint.java
index f808ab51ccef..68e9d19576bc 100644
---
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlEndpoint.java
+++
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/DefaultSqlEndpoint.java
@@ -114,7 +114,9 @@ public abstract class DefaultSqlEndpoint extends
DefaultPollingEndpoint implemen
+ " c) If the outputClass is set, then it will
convert the query result into an Java bean object by calling all the setters
that match the column names."
+ " It will assume your class has a default
constructor to create instance with."
+ " d) If the query resulted in more than one
rows, it throws an non-unique result exception."
- + " StreamList streams the result of the query
using an Iterator. This can be used with the Splitter EIP in streaming mode to
process the ResultSet in streaming fashion.")
+ + " StreamList streams the result of the query
using an Iterator. This can be used with the Splitter EIP in streaming mode to
process the ResultSet in streaming fashion."
+ + " The body is then a ResultSetIterator and not a
List: it has no size, and it can only be read once, so split it to work on the
rows"
+ + " instead of calling size() or indexing it. Use
SelectList when the whole result is wanted as a List of Map.")
private SqlOutputType outputType = SqlOutputType.SelectList;
@UriParam(description = "Specify the full package and class name to use as
conversion when outputType=SelectOne.")
private String outputClass;
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlEndpointBuilderFactory.java
index 29c523e3706d..848f3d681a93 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SqlEndpointBuilderFactory.java
@@ -150,7 +150,10 @@ public interface SqlEndpointBuilderFactory {
* in more than one rows, it throws an non-unique result exception.
* StreamList streams the result of the query using an Iterator. This
* can be used with the Splitter EIP in streaming mode to process the
- * ResultSet in streaming fashion.
+ * ResultSet in streaming fashion. The body is then a ResultSetIterator
+ * and not a List: it has no size, and it can only be read once, so
+ * split it to work on the rows instead of calling size() or indexing
+ * it. Use SelectList when the whole result is wanted as a List of Map.
*
* The option is a:
* <code>org.apache.camel.component.sql.SqlOutputType</code> type.
@@ -178,7 +181,10 @@ public interface SqlEndpointBuilderFactory {
* in more than one rows, it throws an non-unique result exception.
* StreamList streams the result of the query using an Iterator. This
* can be used with the Splitter EIP in streaming mode to process the
- * ResultSet in streaming fashion.
+ * ResultSet in streaming fashion. The body is then a ResultSetIterator
+ * and not a List: it has no size, and it can only be read once, so
+ * split it to work on the rows instead of calling size() or indexing
+ * it. Use SelectList when the whole result is wanted as a List of Map.
*
* The option will be converted to a
* <code>org.apache.camel.component.sql.SqlOutputType</code> type.
@@ -1538,7 +1544,10 @@ public interface SqlEndpointBuilderFactory {
* in more than one rows, it throws an non-unique result exception.
* StreamList streams the result of the query using an Iterator. This
* can be used with the Splitter EIP in streaming mode to process the
- * ResultSet in streaming fashion.
+ * ResultSet in streaming fashion. The body is then a ResultSetIterator
+ * and not a List: it has no size, and it can only be read once, so
+ * split it to work on the rows instead of calling size() or indexing
+ * it. Use SelectList when the whole result is wanted as a List of Map.
*
* The option is a:
* <code>org.apache.camel.component.sql.SqlOutputType</code> type.
@@ -1566,7 +1575,10 @@ public interface SqlEndpointBuilderFactory {
* in more than one rows, it throws an non-unique result exception.
* StreamList streams the result of the query using an Iterator. This
* can be used with the Splitter EIP in streaming mode to process the
- * ResultSet in streaming fashion.
+ * ResultSet in streaming fashion. The body is then a ResultSetIterator
+ * and not a List: it has no size, and it can only be read once, so
+ * split it to work on the rows instead of calling size() or indexing
+ * it. Use SelectList when the whole result is wanted as a List of Map.
*
* The option will be converted to a
* <code>org.apache.camel.component.sql.SqlOutputType</code> type.
@@ -2229,7 +2241,10 @@ public interface SqlEndpointBuilderFactory {
* in more than one rows, it throws an non-unique result exception.
* StreamList streams the result of the query using an Iterator. This
* can be used with the Splitter EIP in streaming mode to process the
- * ResultSet in streaming fashion.
+ * ResultSet in streaming fashion. The body is then a ResultSetIterator
+ * and not a List: it has no size, and it can only be read once, so
+ * split it to work on the rows instead of calling size() or indexing
+ * it. Use SelectList when the whole result is wanted as a List of Map.
*
* The option is a:
* <code>org.apache.camel.component.sql.SqlOutputType</code> type.
@@ -2257,7 +2272,10 @@ public interface SqlEndpointBuilderFactory {
* in more than one rows, it throws an non-unique result exception.
* StreamList streams the result of the query using an Iterator. This
* can be used with the Splitter EIP in streaming mode to process the
- * ResultSet in streaming fashion.
+ * ResultSet in streaming fashion. The body is then a ResultSetIterator
+ * and not a List: it has no size, and it can only be read once, so
+ * split it to work on the rows instead of calling size() or indexing
+ * it. Use SelectList when the whole result is wanted as a List of Map.
*
* The option will be converted to a
* <code>org.apache.camel.component.sql.SqlOutputType</code> type.