This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch 
feature/CAMEL-24961-catalog-body-types-most-used-3
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c69f0b2b0c73e8f3002f551c862ae9c160b62fd7
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Oct 22 23:54:56 2026 +0200

    CAMEL-24961: Catalog body types for as2, jdbc, smooks, vertx-http and eight 
more
    
    Declares the body types of as2, jdbc, spring-jdbc, smooks, vertx-http,
    tika, snmp, pdf, file-watch, scp, graphql and micrometer. All were checked
    at runtime with camel run, against local servers where needed: an H2
    data source, a fake HTTP server, an SSH server with scp, an SNMP agent
    and the as2 server of the component itself.
    
    The producers that read the body: jdbc (the SQL statement), scp (the
    file), vertx-http (the request), tika, smooks and pdf (the document or
    the text), graphql (the query, when no query option is set), the as2
    client (the EDI message, text or a stream only) and the snmp trap
    producer (an SNMP4J PDU). micrometer keeps the body. tika parse and pdf
    create, append and merge give a ByteArrayOutputStream; the smooks output
    depends on the exports of its config.
    
    Fixes the doc prose about the body of jdbc, graphql, tika, pdf, smooks
    and snmp.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../org/apache/camel/catalog/components/as2.json   |   5 +
 .../camel/catalog/components/file-watch.json       |   3 +
 .../apache/camel/catalog/components/graphql.json   |   4 +
 .../org/apache/camel/catalog/components/jdbc.json  |   4 +
 .../camel/catalog/components/micrometer.json       |   4 +
 .../org/apache/camel/catalog/components/pdf.json   |   4 +
 .../org/apache/camel/catalog/components/scp.json   |   4 +
 .../apache/camel/catalog/components/smooks.json    |   4 +
 .../org/apache/camel/catalog/components/snmp.json  |   5 +
 .../camel/catalog/components/spring-jdbc.json      |   4 +
 .../org/apache/camel/catalog/components/tika.json  |   4 +
 .../camel/catalog/components/vertx-http.json       |   4 +
 .../camel/catalog/docs/graphql-component.adoc      |   2 +-
 .../apache/camel/catalog/docs/jdbc-component.adoc  |  10 +-
 .../apache/camel/catalog/docs/pdf-component.adoc   |   3 +
 .../camel/catalog/docs/smooks-component.adoc       |   2 +
 .../apache/camel/catalog/docs/snmp-component.adoc  |  11 +-
 .../apache/camel/catalog/docs/tika-component.adoc  |   8 +-
 .../org/apache/camel/component/as2/as2.json        |   5 +
 .../apache/camel/component/as2/AS2Endpoint.java    |  28 ++++
 .../camel/component/file/watch/file-watch.json     |   3 +
 .../component/file/watch/FileWatchEndpoint.java    |  22 ++-
 .../apache/camel/component/graphql/graphql.json    |   4 +
 .../src/main/docs/graphql-component.adoc           |   2 +-
 .../camel/component/graphql/GraphqlEndpoint.java   |  17 ++-
 .../org/apache/camel/component/jdbc/jdbc.json      |   4 +
 .../camel-jdbc/src/main/docs/jdbc-component.adoc   |  10 +-
 .../apache/camel/component/jdbc/JdbcEndpoint.java  |  22 +++
 .../org/apache/camel/component/scp/scp.json        |   4 +
 .../apache/camel/component/scp/ScpEndpoint.java    |  13 ++
 .../camel/component/micrometer/micrometer.json     |   4 +
 .../component/micrometer/MicrometerEndpoint.java   |   8 +
 .../org/apache/camel/component/pdf/pdf.json        |   4 +
 .../camel-pdf/src/main/docs/pdf-component.adoc     |   3 +
 .../apache/camel/component/pdf/PdfEndpoint.java    |  21 +++
 .../org/apache/camel/component/smooks/smooks.json  |   4 +
 .../src/main/docs/smooks-component.adoc            |   2 +
 .../camel/component/smooks/SmooksEndpoint.java     |  10 ++
 .../org/apache/camel/component/snmp/snmp.json      |   5 +
 .../camel-snmp/src/main/docs/snmp-component.adoc   |  11 +-
 .../apache/camel/component/snmp/SnmpEndpoint.java  |  23 +++
 .../camel/component/spring/jdbc/spring-jdbc.json   |   4 +
 .../component/spring/jdbc/SpringJdbcEndpoint.java  |  22 +++
 .../org/apache/camel/component/tika/tika.json      |   4 +
 .../camel-tika/src/main/docs/tika-component.adoc   |   8 +-
 .../apache/camel/component/tika/TikaEndpoint.java  |  14 ++
 .../camel/component/vertx/http/vertx-http.json     |   4 +
 .../component/vertx/http/VertxHttpEndpoint.java    |  13 ++
 .../jbang/core/commands/ai/CatalogDocsTest.java    |   6 +-
 .../camel/dsl/yaml/validator/TextBodyFlowTest.java | 168 +++++++++++++++++++++
 50 files changed, 523 insertions(+), 34 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
index b348e9105ce7..dd094da41c7b 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/as2.json
@@ -32,6 +32,11 @@
     "sslContextParameters": { "index": 4, "kind": "property", "displayName": 
"Ssl Context Parameters", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, 
"autowired": false, "secret": false, "description": "To configure security 
using SSLContextParameters" },
     "useGlobalSslContextParameters": { "index": 5, "kind": "property", 
"displayName": "Use Global Ssl Context Parameters", "group": "security", 
"label": "security", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Enable usage of global SSL context 
parameters." }
   },
+  "bodyTypes": {
+    "consumerOut": { "carriers": [ "text", "stream" ], "byOption": [ { 
"option": "apiName", "value": "RECEIPT", "carriers": [ "pojo" ] } ], 
"description": "The EDI message that server\/listen receives, decrypted, 
decompressed and without its signature: text in the charset of its 
Content-Type, or a stream when the sender used the base64 or binary transfer 
encoding. The component answers with its own receipt (MDN), never the body of 
the route. receipt\/receive gives the receipt: a Disposit [...]
+    "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "inBody", 
"value": "ediMessage", "carriers": [ "text", "stream" ] } ], "description": 
"The EDI message of client\/send with inBody=ediMessage, as it is: text, 
encoded in ediMessageCharset (us-ascii when not set), or a stream. Bytes, a 
file or a Map fail: convertBodyTo String first. Without inBody, the message 
comes from the CamelAs2.ediMessage header" },
+    "producerOut": { "carriers": [ "pojo", "null" ], "description": "The 
receipt (MDN) in the response when dispositionNotificationTo asks for one: a 
DispositionNotificationMultipartReportEntity, or a MultipartSignedEntity when 
it is signed. null without a receipt, when receiptDeliveryOption sends it to a 
receipt\/receive consumer, or when the response has none, such as an HTTP 
error, which does not fail the exchange: the CamelAs2.interchange exchange 
property holds the HttpCoreContext w [...]
+  },
   "properties": {
     "apiName": { "index": 0, "kind": "path", "displayName": "Api Name", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.as2.internal.AS2ApiName", "enum": [ "CLIENT", 
"SERVER", "RECEIPT" ], "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "What kind of operation to perform" },
     "methodName": { "index": 1, "kind": "path", "displayName": "Method Name", 
"group": "common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "What sub operation to use for the selected 
operation" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file-watch.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file-watch.json
index 2e66d88fe3c9..e0fb4ccc0731 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file-watch.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/file-watch.json
@@ -44,6 +44,9 @@
     "CamelFileParent": { "index": 8, "kind": "header", "displayName": "", 
"group": "consumer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The parent path.", "constantName": 
"org.apache.camel.component.file.watch.FileWatchConstants#FILE_PARENT" },
     "CamelFileLastModified": { "index": 9, "kind": "header", "displayName": 
"", "group": "consumer", "label": "", "required": false, "javaType": "long", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "A Long value containing the last modified timestamp of 
the file.", "constantName": 
"org.apache.camel.component.file.watch.FileWatchConstants#FILE_LAST_MODIFIED" }
   },
+  "bodyTypes": {
+    "consumerOut": { "carriers": [ "file" ], "javaType": "java.io.File", 
"description": "The java.io.File of the file or directory of the event, also 
for DELETE, with the event in the CamelFileEventType header. The consumer does 
not read it: it converts to text, bytes or a stream by reading the file, which 
fails after a DELETE" }
+  },
   "properties": {
     "path": { "index": 0, "kind": "path", "displayName": "Path", "group": 
"consumer", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Path of directory to consume events 
from." },
     "antInclude": { "index": 1, "kind": "parameter", "displayName": "Ant 
Include", "group": "consumer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": "**", "description": "ANT style pattern 
to match files. The file is matched against path relative to endpoint path. 
Pattern must be also relative (not starting with slash)" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/graphql.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/graphql.json
index 73ef1d1a19f3..06daa6c1ad22 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/graphql.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/graphql.json
@@ -30,6 +30,10 @@
     "httpClient": { "index": 3, "kind": "property", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." },
     "headerFilterStrategy": { "index": 4, "kind": "property", "displayName": 
"Header Filter Strategy", "group": "filter", "label": "filter", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom 
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel 
message." }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"dependsOn": [ "query", "queryFile", "queryHeader" ], "description": "The 
query, when none of query, queryFile and queryHeader is set: text, or bytes, a 
stream or a file of it. A Map is not a query. With one of them the body is not 
sent, except that an org.apache.camel.util.json.JsonObject body is the 
variables when neither variables nor variablesHeader is set" },
+    "producerOut": { "carriers": [ "text", "null" ], "description": "The 
response as text, the JSON with the data and errors of GraphQL: unmarshal it to 
read them. Errors in the response do not fail the exchange; a status outside 
2xx does, unless throwExceptionOnFailure=false, which keeps the response as 
text. null for a response without a body" }
+  },
   "properties": {
     "httpUri": { "index": 0, "kind": "path", "displayName": "Http Uri", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The GraphQL server URI." },
     "headerFilterStrategy": { "index": 1, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "common (advanced)", "label": 
"common,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jdbc.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jdbc.json
index 5109e6432688..141b79d25a3e 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jdbc.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jdbc.json
@@ -39,6 +39,10 @@
     "CamelGeneratedKeysRowCount": { "index": 6, "kind": "header", 
"displayName": "", "group": "producer", "label": "producer", "required": false, 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The number of rows in the header that 
contains generated keys.", "constantName": 
"org.apache.camel.component.jdbc.JdbcConstants#JDBC_GENERATED_KEYS_ROW_COUNT" },
     "CamelGeneratedKeysRows": { "index": 7, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"List<Map<String, Object>>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Rows that contains the 
generated keys.", "constantName": 
"org.apache.camel.component.jdbc.JdbcConstants#JDBC_GENERATED_KEYS_DATA" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"description": "The SQL statement as text, or bytes, a stream or a file of it; 
a Map or a List is not a statement: set the SQL as the body. With 
useHeadersAsParameters, the values of its placeholders come from the 
CamelJdbcParameters header, or else from the headers" },
+    "producerOut": { "carriers": [ "list", "unchanged" ], "dependsOn": [ 
"outputClass" ], "byOption": [ { "option": "outputType", "value": "SelectOne", 
"carriers": [ "map", "text", "value", "bytes", "pojo", "null", "unchanged" ] }, 
{ "option": "outputType", "value": "StreamList", "carriers": [ "iterator", 
"unchanged" ] } ], "description": "The rows of a select: a List of Maps of the 
column names and their values (beans of outputClass when set). SelectOne gives 
the Map of the one row, the [...]
+  },
   "properties": {
     "dataSourceName": { "index": 0, "kind": "path", "displayName": "Data 
Source Name", "group": "producer", "label": "", "required": true, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Name of DataSource to lookup in the Registry. If the name is dataSource or 
default, then Camel will attempt to lookup a default DataSource from the 
registry, meaning if there is a only one instance of DataS [...]
     "allowNamedParameters": { "index": 1, "kind": "parameter", "displayName": 
"Allow Named Parameters", "group": "producer", "label": "", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": true, "description": "Whether to allow 
using named parameters in the queries." },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/micrometer.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/micrometer.json
index f7e9210de897..8896fc905db2 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/micrometer.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/micrometer.json
@@ -37,6 +37,10 @@
     "CamelMetricsDescription": { "index": 5, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Override description value in URI", "constantName": 
"org.apache.camel.component.micrometer.MicrometerConstants#HEADER_METRIC_DESCRIPTION"
 },
     "CamelMetricsTags": { "index": 6, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": 
"java.lang.Iterable<Tag>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "To augment meter tags 
defined as URI parameters", "constantName": 
"org.apache.camel.component.micrometer.MicrometerConstants#HEADER_METRIC_TAGS" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "any" ], "description": "Not used, unless an 
option such as increment, decrement or value is a simple expression that reads 
it, which must then give a number. The CamelMetrics headers override the 
options" },
+    "producerOut": { "carriers": [ "unchanged" ], "description": "Unchanged; 
the CamelMetrics headers are removed" }
+  },
   "properties": {
     "metricsType": { "index": 0, "kind": "path", "displayName": "Metrics 
Type", "group": "producer", "label": "", "required": true, "type": "enum", 
"javaType": "io.micrometer.core.instrument.Meter.Type", "enum": [ "counter", 
"summary", "timer" ], "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Type of metrics" },
     "metricsName": { "index": 1, "kind": "path", "displayName": "Metrics 
Name", "group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "supportSimpleExpression": true, 
"description": "Name of metrics" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pdf.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pdf.json
index f2edff0482dd..5a579be3f433 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pdf.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pdf.json
@@ -33,6 +33,10 @@
     "CamelPdfDecryptionMaterial": { "index": 2, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "org.apache.pdfbox.pdmodel.encryption.DecryptionMaterial", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Expected type is 
https:\/\/pdfbox.apache.org\/docs\/2.0.13\/javadocs\/org\/apache\/pdfbox\/pdmodel\/encryption\/DecryptionMaterial.htmlDecryptionMaterial.
 Mandatory header if PDF documen [...]
     "CamelPdfFilesToMerge": { "index": 3, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": 
"java.util.List<java.io.File>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Mandatory header for merge 
operation and ignored in all other operations. The array of pdf files that will 
be merged.", "constantName": 
"org.apache.camel.component.pdf.PdfHeaderConstants#FILES_TO_MERGE_HEADER_NAME" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"byOption": [ { "option": "operation", "value": "extractText", "carriers": [ 
"bytes", "stream", "file", "pojo" ] }, { "option": "operation", "value": 
"merge", "carriers": [ "any" ] } ], "description": "The text to write for 
create and append, which takes the document from the CamelPdfDocument header; a 
Map or a POJO is written as its toString: marshal it first. extractText reads a 
PDF from bytes, a stream, a file or a [...]
+    "producerOut": { "carriers": [ "pojo" ], "javaType": 
"java.io.ByteArrayOutputStream", "byOption": [ { "option": "operation", 
"value": "extractText", "carriers": [ "text" ], "javaType": "java.lang.String" 
} ], "description": "The PDF of create, append and merge in a 
ByteArrayOutputStream, which converts to bytes (convertBodyTo byte[] before 
extractText). The text of the document for extractText" }
+  },
   "properties": {
     "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.pdf.PdfOperation", "enum": [ "create", "append", 
"extractText", "merge" ], "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.pdf.PdfConfiguration", "configurationField": 
"pdfConfiguration", "description": "Operation type" },
     "font": { "index": 1, "kind": "parameter", "displayName": "Font", "group": 
"producer", "label": "", "required": false, "type": "enum", "javaType": 
"java.lang.String", "enum": [ "COURIER", "COURIER_BOLD", "COURIER_OBLIQUE", 
"COURIER_BOLD_OBLIQUE", "HELVETICA", "HELVETICA_BOLD", "HELVETICA_OBLIQUE", 
"HELVETICA_BOLD_OBLIQUE", "TIMES_ROMAN", "TIMES_BOLD", "TIMES_ITALIC", 
"TIMES_BOLD_ITALIC", "SYMBOL", "ZAPF_DINGBATS" ], "deprecated": false, 
"autowired": false, "secret": false, "defaultVa [...]
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/scp.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/scp.json
index c725d39cb7a8..a5fafc55d1fa 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/scp.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/scp.json
@@ -30,6 +30,10 @@
     "healthCheckConsumerEnabled": { "index": 3, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
     "healthCheckProducerEnabled": { "index": 4, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on producer [...]
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"byOption": [ { "option": "allowNullBody", "value": "true", "carriers": [ 
"null", "text", "bytes", "stream", "file" ] } ], "description": "The content of 
the file: text, bytes, a stream or a file, which is read into memory first to 
send its size. A Map or a List fails: marshal it first" },
+    "producerOut": { "carriers": [ "unchanged" ], "description": "Unchanged, 
with the name of the remote file in the CamelFileNameProduced header" }
+  },
   "properties": {
     "host": { "index": 0, "kind": "path", "displayName": "Host", "group": 
"producer", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.scp.ScpConfiguration", "configurationField": 
"configuration", "description": "Hostname of the FTP server" },
     "port": { "index": 1, "kind": "path", "displayName": "Port", "group": 
"producer", "label": "", "required": false, "type": "integer", "javaType": 
"int", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.scp.ScpConfiguration", 
"configurationField": "configuration", "description": "Port of the FTP server" 
},
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smooks.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smooks.json
index d96eead22f1f..b1ab2749020f 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smooks.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smooks.json
@@ -31,6 +31,10 @@
   "headers": {
     "CamelSmooksExecutionContext": { "index": 0, "kind": "header", 
"displayName": "", "group": "advanced", "label": "advanced", "required": false, 
"javaType": "org.smooks.api.ExecutionContext", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
Smooks execution context.", "constantName": 
"org.apache.camel.component.smooks.SmooksConstants#SMOOKS_EXECUTION_CONTEXT" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"description": "The data the reader of the smooks config reads: XML by default, 
or EDI, CSV or JSON with a reader. A Map, a List or a POJO fails" },
+    "producerOut": { "carriers": [ "unknown" ], "description": "What the 
exports of the smooks config give: the bean a JavaSink export extracts (a Map 
of the beans when it extracts none), or the text of a StringSink. Without 
exports, the input as a stream" }
+  },
   "properties": {
     "smooksConfig": { "index": 0, "kind": "path", "displayName": "Smooks 
Config", "group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "supportFileReference": true, 
"description": "Path to the Smooks configuration file" },
     "reportPath": { "index": 1, "kind": "parameter", "displayName": "Report 
Path", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "File path to place the generated HTML 
execution report. The report is a useful tool in the developers arsenal for 
diagnosing issues or comprehending a transformation. Do not set in production 
since this is a major performance drain" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/snmp.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/snmp.json
index 4dc8c5a836cd..5033597bc5c6 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/snmp.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/snmp.json
@@ -30,6 +30,11 @@
     "healthCheckConsumerEnabled": { "index": 3, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
     "healthCheckProducerEnabled": { "index": 4, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on producer [...]
   },
+  "bodyTypes": {
+    "consumerOut": { "carriers": [ "text" ], "javaType": "java.lang.String", 
"format": "xml", "description": "The variable bindings of the response of a 
poll or of a trap as XML text: an snmp element with an entry of an oid and a 
value for each, and the community of a trap in the securityName header" },
+    "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "type", 
"value": "TRAP", "carriers": [ "pojo" ], "javaType": "org.snmp4j.PDU" } ], 
"description": "Not used by a POLL or GET_NEXT, which requests the oids. A TRAP 
sends the body, which must be a PDU of SNMP4J for the snmpVersion: a PDUv1 for 
0, the default, a PDU for 1 and a ScopedPDU for 3. Another body fails" },
+    "producerOut": { "carriers": [ "pojo" ], "javaType": 
"org.apache.camel.component.snmp.SnmpMessage", "byOption": [ { "option": 
"type", "value": "GET_NEXT", "carriers": [ "list" ], "javaType": 
"java.util.List<org.apache.camel.component.snmp.SnmpMessage>" }, { "option": 
"type", "value": "TRAP", "carriers": [ "unchanged" ] } ], "description": "The 
response of a POLL as an SnmpMessage, a Camel message as the body, whose own 
body is the XML text of the consumer; it does not convert to text [...]
+  },
   "properties": {
     "host": { "index": 0, "kind": "path", "displayName": "Host", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Hostname of the SNMP enabled device" },
     "port": { "index": 1, "kind": "path", "displayName": "Port", "group": 
"common", "label": "", "required": true, "type": "integer", "javaType": 
"java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Port number of the SNMP enabled device" 
},
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-jdbc.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-jdbc.json
index 3e5e9fbd4669..9cfba1b8222e 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-jdbc.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/spring-jdbc.json
@@ -39,6 +39,10 @@
     "CamelGeneratedKeysRowCount": { "index": 6, "kind": "header", 
"displayName": "", "group": "producer", "label": "producer", "required": false, 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The number of rows in the header that 
contains generated keys.", "constantName": 
"org.apache.camel.component.jdbc.JdbcConstants#JDBC_GENERATED_KEYS_ROW_COUNT" },
     "CamelGeneratedKeysRows": { "index": 7, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"List<Map<String, Object>>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Rows that contains the 
generated keys.", "constantName": 
"org.apache.camel.component.jdbc.JdbcConstants#JDBC_GENERATED_KEYS_DATA" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"description": "The SQL statement as text, or bytes, a stream or a file of it; 
a Map or a List is not a statement: set the SQL as the body. With 
useHeadersAsParameters, the values of its placeholders come from the 
CamelJdbcParameters header, or else from the headers" },
+    "producerOut": { "carriers": [ "list", "unchanged" ], "dependsOn": [ 
"outputClass" ], "byOption": [ { "option": "outputType", "value": "SelectOne", 
"carriers": [ "map", "text", "value", "bytes", "pojo", "null", "unchanged" ] }, 
{ "option": "outputType", "value": "StreamList", "carriers": [ "iterator", 
"unchanged" ] } ], "description": "The rows of a select: a List of Maps of the 
column names and their values (beans of outputClass when set). SelectOne gives 
the Map of the one row, the [...]
+  },
   "properties": {
     "dataSourceName": { "index": 0, "kind": "path", "displayName": "Data 
Source Name", "group": "producer", "label": "", "required": true, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Name of DataSource to lookup in the Registry. If the name is dataSource or 
default, then Camel will attempt to lookup a default DataSource from the 
registry, meaning if there is a only one instance of DataS [...]
     "allowNamedParameters": { "index": 1, "kind": "parameter", "displayName": 
"Allow Named Parameters", "group": "producer", "label": "", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": true, "description": "Whether to allow 
using named parameters in the queries." },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/tika.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/tika.json
index ddc7c899b1b7..0f8029d743e1 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/tika.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/tika.json
@@ -27,6 +27,10 @@
     "lazyStartProducer": { "index": 0, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
     "autowiredEnabled": { "index": 1, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"description": "The document: text, bytes, a stream or a file. A Map, a List, a 
POJO or no body fails, and parse fails on an empty document" },
+    "producerOut": { "carriers": [ "pojo" ], "javaType": 
"java.io.ByteArrayOutputStream", "byOption": [ { "option": "operation", 
"value": "detect", "carriers": [ "text" ], "javaType": "java.lang.String" } ], 
"description": "parse gives a ByteArrayOutputStream with the content as XHTML, 
or as HTML or plain text with tikaParseOutputFormat, in 
tikaParseOutputEncoding, and the metadata of the document in headers; 
camel-tika parses HTML and text, other types need their Tika parser module. det 
[...]
+  },
   "properties": {
     "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.tika.TikaOperation", "enum": [ "parse", "detect" ], 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "configurationClass": 
"org.apache.camel.component.tika.TikaConfiguration", "configurationField": 
"tikaConfiguration", "description": "Operation type" },
     "tikaParseOutputEncoding": { "index": 1, "kind": "parameter", 
"displayName": "Tika Parse Output Encoding", "group": "producer", "label": "", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.tika.TikaConfiguration", "configurationField": 
"tikaConfiguration", "description": "Tika Parse Output Encoding" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-http.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-http.json
index 81042fb956a6..e3091d4173ea 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-http.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/vertx-http.json
@@ -55,6 +55,10 @@
     "CamelHttpPath": { "index": 6, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Request URI's path, the header will be used to build the 
request URI with the HTTP_URI.", "constantName": 
"org.apache.camel.component.vertx.http.VertxHttpConstants#HTTP_PATH" },
     "Content-Encoding": { "index": 7, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The HTTP content encoding. Is set to provide a content 
encoding, such as gzip.", "constantName": 
"org.apache.camel.component.vertx.http.VertxHttpConstants#CONTENT_ENCODING" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], 
"description": "The request body: text, bytes, a stream or a file (a file as a 
multipart form with multipartUpload), or a Vert.x Buffer, MultiMap (a form) or 
MultipartForm. A Map, a List or a POJO fails: marshal it first. Without 
httpMethod, a query string in the URI or no body sends a GET, and a body a 
POST" },
+    "producerOut": { "carriers": [ "bytes", "null" ], "description": "The 
response body as a byte array, or null for a response without a body. A Vert.x 
Buffer with responsePayloadAsByteArray=false, which stream caching turns into a 
stream" }
+  },
   "properties": {
     "httpUri": { "index": 0, "kind": "path", "displayName": "Http Uri", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.vertx.http.VertxHttpConfiguration", 
"configurationField": "configuration", "description": "The HTTP URI to connect 
to" },
     "bridgeEndpoint": { "index": 1, "kind": "parameter", "displayName": 
"Bridge Endpoint", "group": "producer", "label": "producer", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.vertx.http.VertxHttpConfiguration", 
"configurationField": "configuration", "description": "If the option is true, 
the Exchange.HTTP_URI header will be ignored and the  [...]
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/graphql-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/graphql-component.adoc
index 3ec1d0083d54..63f921a7ac59 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/graphql-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/graphql-component.adoc
@@ -37,7 +37,7 @@ include::partial$component-endpoint-headers.adoc[]
 
 == Message Body
 
-If the `variables` and `variablesHeader` parameters are not set and the IN 
body is a JsonObject instance, Camel will use it for the operation's variables. 
If the `query` and `queryFile` parameters are not set and the IN body is a 
String, Camel will use it as the query. Camel will store the GraphQL response 
from the external server on the OUT message body.
+If the `variables` and `variablesHeader` parameters are not set and the IN 
body is an `org.apache.camel.util.json.JsonObject` instance, Camel will use it 
for the operation's variables (another `Map` is not used). If the `query`, 
`queryFile` and `queryHeader` parameters are not set, Camel will use the IN 
body as the query: text, or bytes, a stream or a file of it. Camel will store 
the GraphQL response from the external server on the OUT message body, as a 
`String` of the JSON response, wi [...]
 All headers from the IN message will be copied to the OUT message, so headers 
are preserved during routing.
 Additionally, Camel will add the HTTP response headers as well to the OUT 
message headers.
 
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jdbc-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jdbc-component.adoc
index 04943660e73f..059bdd5b9f6a 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jdbc-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jdbc-component.adoc
@@ -54,11 +54,15 @@ include::partial$component-endpoint-headers.adoc[]
 
 === Result
 
-By default, the result is returned in the OUT body as an
-`ArrayList<HashMap<String, Object>>`. The `List` object contains the
+By default, the result of a select is returned in the OUT body as an
+`ArrayList<LinkedHashMap<String, Object>>`. The `List` object contains the
 list of rows and the `Map` objects contain each row with the `String`
 key as the column name. You can use the option `outputType` to control
-the result.
+the result: `SelectOne` gives the `Map` of the one row, the value of its
+column when it has one column, or `null` when there is no row, and
+`StreamList` gives an `Iterator` of the rows, which can be read once.
+A statement that is not a select leaves the body as it is, with the count
+in the `CamelJdbcUpdateCount` header.
 
 *Note:* This component fetches `ResultSetMetaData` to be able to return
 the column name as the key in the `Map`.
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pdf-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pdf-component.adoc
index e2e9dcebcb9a..fd890c034ca6 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pdf-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pdf-component.adoc
@@ -95,5 +95,8 @@ YAML::
 It is now possible to get the body as a PD Document by using `PDDocument doc = 
exchange.getIn().getBody(PDDocument.class);`,
 which saves the trouble of converting the byte-array to a document.
 
+The body after `create`, `append` and `merge` is a `ByteArrayOutputStream` 
with the PDF, which does not convert to a
+`PDDocument`: convert it to `byte[]` before `extractText`.
+
 NOTE: this only works for unprotected PDF files. For password-protected, the 
files still need to be converted
 manually.
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/smooks-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/smooks-component.adoc
index 677f8b82670f..a3568ee63eee 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/smooks-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/smooks-component.adoc
@@ -14,6 +14,8 @@
 
 The Camel Smooks component uses https://www.smooks.org/[Smooks] to break up 
the structured data (EDI, CSV, POJO, etc...) of a Camel message body into 
fragments. These fragments can be processed independently of one another from 
within Smooks.
 
+The body is read by the reader of the Smooks configuration (XML by default) as 
text, bytes, a stream or a file. A POJO is read when the body is a 
`org.smooks.io.source.JavaSource` that holds it: a POJO, a `Map` or a `List` as 
the body itself fails.
+
 Common applications of Smooks include:
 
 * transformation: EDI to CSV, POJO to EDI, POJO to XML, and so on.
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/snmp-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/snmp-component.adoc
index 2f0eda76b8e8..c0409fcea38c 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/snmp-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/snmp-component.adoc
@@ -41,7 +41,9 @@ and receiving traps.
 
 It can also be used to request information using GET method.
 
-The response body type is `org.apache.camel.component.snmp.SnmpMessage`.
+After a `POLL`, the body is an `org.apache.camel.component.snmp.SnmpMessage`: 
a Camel message whose own body is the
+response as XML text. It does not convert to a `String` itself. A `GET_NEXT` 
gives a `List` of them, one per variable
+of the walk. A `TRAP` producer sends the body, which must be an 
`org.snmp4j.PDU`, and leaves it as it is.
 
 
 // component options: START
@@ -64,13 +66,10 @@ Given the situation, that I poll for the following OIDs:
 1.3.6.1.2.1.43.5.1.1.11.1
 -------------------------
 
-The result will be the following:
-
-*Result of toString conversion*
+The body is the result as XML text, written on one line without an XML 
declaration (indented here):
 
 [source,xml]
 -----------------------------------------------------------
-<?xml version="1.0" encoding="UTF-8"?>
 <snmp>
   <entry>
     <oid>1.3.6.1.2.1.1.3.0</oid>
@@ -127,7 +126,7 @@ snmp:127.0.0.1:162?protocol=udp&type=TRAP
 You can get the community of SNMP TRAP with message
 header `securityName`, peer address of the SNMP TRAP with message header 
`peerAddress`.
 
-Routing example in Java: (converts the SNMP PDU to XML String)
+Routing example in Java: (the body of the consumer is the SNMP PDU as XML text)
 
 [tabs]
 ====
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/tika-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/tika-component.adoc
index 52c7916bdd82..89071eaedbe4 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/tika-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/tika-component.adoc
@@ -43,7 +43,8 @@ include::partial$component-endpoint-headers.adoc[]
 
 === To Detect a file's MIME Type
 
-The file should be placed in the Body.
+The body is the document: text, bytes, a stream or a file. After `detect`, the 
body is the MIME type as text, such as
+`text/html`.
 
 [tabs]
 ====
@@ -80,7 +81,10 @@ YAML::
 
 === To Parse a File
 
-The file should be placed in the Body.
+The body is the document: text, bytes, a stream or a file. After `parse`, the 
body is a `ByteArrayOutputStream` with
+the content as XHTML, or as HTML or plain text with `tikaParseOutputFormat`, 
which converts to a `String`, and the
+metadata of the document are headers, such as `dc:title`. The component has 
the Tika parsers of HTML and text: other
+types need their Tika parser module, such as 
`org.apache.tika:tika-parser-pdf-module` for PDF, or the content is empty.
 
 [tabs]
 ====
diff --git 
a/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
 
b/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
index b348e9105ce7..dd094da41c7b 100644
--- 
a/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
+++ 
b/components/camel-as2/camel-as2-component/src/generated/resources/META-INF/org/apache/camel/component/as2/as2.json
@@ -32,6 +32,11 @@
     "sslContextParameters": { "index": 4, "kind": "property", "displayName": 
"Ssl Context Parameters", "group": "security", "label": "security", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false, 
"autowired": false, "secret": false, "description": "To configure security 
using SSLContextParameters" },
     "useGlobalSslContextParameters": { "index": 5, "kind": "property", 
"displayName": "Use Global Ssl Context Parameters", "group": "security", 
"label": "security", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Enable usage of global SSL context 
parameters." }
   },
+  "bodyTypes": {
+    "consumerOut": { "carriers": [ "text", "stream" ], "byOption": [ { 
"option": "apiName", "value": "RECEIPT", "carriers": [ "pojo" ] } ], 
"description": "The EDI message that server\/listen receives, decrypted, 
decompressed and without its signature: text in the charset of its 
Content-Type, or a stream when the sender used the base64 or binary transfer 
encoding. The component answers with its own receipt (MDN), never the body of 
the route. receipt\/receive gives the receipt: a Disposit [...]
+    "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "inBody", 
"value": "ediMessage", "carriers": [ "text", "stream" ] } ], "description": 
"The EDI message of client\/send with inBody=ediMessage, as it is: text, 
encoded in ediMessageCharset (us-ascii when not set), or a stream. Bytes, a 
file or a Map fail: convertBodyTo String first. Without inBody, the message 
comes from the CamelAs2.ediMessage header" },
+    "producerOut": { "carriers": [ "pojo", "null" ], "description": "The 
receipt (MDN) in the response when dispositionNotificationTo asks for one: a 
DispositionNotificationMultipartReportEntity, or a MultipartSignedEntity when 
it is signed. null without a receipt, when receiptDeliveryOption sends it to a 
receipt\/receive consumer, or when the response has none, such as an HTTP 
error, which does not fail the exchange: the CamelAs2.interchange exchange 
property holds the HttpCoreContext w [...]
+  },
   "properties": {
     "apiName": { "index": 0, "kind": "path", "displayName": "Api Name", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.as2.internal.AS2ApiName", "enum": [ "CLIENT", 
"SERVER", "RECEIPT" ], "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "What kind of operation to perform" },
     "methodName": { "index": 1, "kind": "path", "displayName": "Method Name", 
"group": "common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.as2.AS2Configuration", "configurationField": 
"configuration", "description": "What sub operation to use for the selected 
operation" },
diff --git 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Endpoint.java
 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Endpoint.java
index 14b4b8dbba47..5d1c122aa260 100644
--- 
a/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Endpoint.java
+++ 
b/components/camel-as2/camel-as2-component/src/main/java/org/apache/camel/component/as2/AS2Endpoint.java
@@ -44,6 +44,9 @@ import org.apache.camel.component.as2.internal.AS2ApiName;
 import org.apache.camel.component.as2.internal.AS2ConnectionHelper;
 import org.apache.camel.component.as2.internal.AS2Constants;
 import org.apache.camel.component.as2.internal.AS2PropertiesHelper;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -60,6 +63,31 @@ import org.apache.camel.support.jsse.SSLContextParameters;
              category = { Category.FILE })
 @Metadata(excludeProperties = 
"startScheduler,initialDelay,delay,timeUnit,useFixedDelay,pollStrategy,runLoggingLevel,sendEmptyMessageWhenIdle"
                               + 
",greedy,scheduler,schedulerProperties,scheduledExecutorService,backoffMultiplier,backoffIdleThreshold,backoffErrorThreshold,repeatCount,bridgeErrorHandler")
+@BodyTypes(consumerOut = @BodyType(value = { Carrier.TEXT, Carrier.STREAM },
+                                   byOption = @BodyType.When(option = 
"apiName", value = "RECEIPT", carriers = Carrier.POJO),
+                                   description = "The EDI message that 
server/listen receives, decrypted, decompressed and"
+                                                 + " without its signature: 
text in the charset of its Content-Type, or a"
+                                                 + " stream when the sender 
used the base64 or binary transfer encoding. The"
+                                                 + " component answers with 
its own receipt (MDN), never the body of the route."
+                                                 + " receipt/receive gives the 
receipt: a"
+                                                 + " 
DispositionNotificationMultipartReportEntity, or a MultipartSignedEntity"
+                                                 + " when it is signed. The 
CamelAs2.interchange exchange property holds the"
+                                                 + " HttpCoreContext"),
+           producerIn = @BodyType(value = Carrier.ANY,
+                                  byOption = @BodyType.When(option = "inBody", 
value = "ediMessage",
+                                                            carriers = { 
Carrier.TEXT, Carrier.STREAM }),
+                                  description = "The EDI message of 
client/send with inBody=ediMessage, as it is: text, encoded"
+                                                + " in ediMessageCharset 
(us-ascii when not set), or a stream. Bytes, a file or"
+                                                + " a Map fail: convertBodyTo 
String first. Without inBody, the message comes"
+                                                + " from the 
CamelAs2.ediMessage header"),
+           producerOut = @BodyType(value = { Carrier.POJO, Carrier.NULL },
+                                   description = "The receipt (MDN) in the 
response when dispositionNotificationTo asks for"
+                                                 + " one: a 
DispositionNotificationMultipartReportEntity, or a"
+                                                 + " MultipartSignedEntity 
when it is signed. null without a receipt, when"
+                                                 + " receiptDeliveryOption 
sends it to a receipt/receive consumer, or when the"
+                                                 + " response has none, such 
as an HTTP error, which does not fail the"
+                                                 + " exchange: the 
CamelAs2.interchange exchange property holds the"
+                                                 + " HttpCoreContext with the 
response"))
 public class AS2Endpoint extends AbstractApiEndpoint<AS2ApiName, 
AS2Configuration> {
 
     @UriParam
diff --git 
a/components/camel-file-watch/src/generated/resources/META-INF/org/apache/camel/component/file/watch/file-watch.json
 
b/components/camel-file-watch/src/generated/resources/META-INF/org/apache/camel/component/file/watch/file-watch.json
index 2e66d88fe3c9..e0fb4ccc0731 100644
--- 
a/components/camel-file-watch/src/generated/resources/META-INF/org/apache/camel/component/file/watch/file-watch.json
+++ 
b/components/camel-file-watch/src/generated/resources/META-INF/org/apache/camel/component/file/watch/file-watch.json
@@ -44,6 +44,9 @@
     "CamelFileParent": { "index": 8, "kind": "header", "displayName": "", 
"group": "consumer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The parent path.", "constantName": 
"org.apache.camel.component.file.watch.FileWatchConstants#FILE_PARENT" },
     "CamelFileLastModified": { "index": 9, "kind": "header", "displayName": 
"", "group": "consumer", "label": "", "required": false, "javaType": "long", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "A Long value containing the last modified timestamp of 
the file.", "constantName": 
"org.apache.camel.component.file.watch.FileWatchConstants#FILE_LAST_MODIFIED" }
   },
+  "bodyTypes": {
+    "consumerOut": { "carriers": [ "file" ], "javaType": "java.io.File", 
"description": "The java.io.File of the file or directory of the event, also 
for DELETE, with the event in the CamelFileEventType header. The consumer does 
not read it: it converts to text, bytes or a stream by reading the file, which 
fails after a DELETE" }
+  },
   "properties": {
     "path": { "index": 0, "kind": "path", "displayName": "Path", "group": 
"consumer", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Path of directory to consume events 
from." },
     "antInclude": { "index": 1, "kind": "parameter", "displayName": "Ant 
Include", "group": "consumer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": "**", "description": "ANT style pattern 
to match files. The file is matched against path relative to endpoint path. 
Pattern must be also relative (not starting with slash)" },
diff --git 
a/components/camel-file-watch/src/main/java/org/apache/camel/component/file/watch/FileWatchEndpoint.java
 
b/components/camel-file-watch/src/main/java/org/apache/camel/component/file/watch/FileWatchEndpoint.java
index 60d0a08a3461..742dd9ba72ff 100644
--- 
a/components/camel-file-watch/src/main/java/org/apache/camel/component/file/watch/FileWatchEndpoint.java
+++ 
b/components/camel-file-watch/src/main/java/org/apache/camel/component/file/watch/FileWatchEndpoint.java
@@ -22,6 +22,9 @@ import org.apache.camel.Consumer;
 import org.apache.camel.MultipleConsumersSupport;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -33,6 +36,11 @@ import org.apache.camel.support.DefaultEndpoint;
  */
 @UriEndpoint(firstVersion = "3.0.0", scheme = "file-watch", title = "File 
Watch", syntax = "file-watch:path",
              category = { Category.FILE }, consumerOnly = true, headersClass = 
FileWatchConstants.class)
+@BodyTypes(consumerOut = @BodyType(value = Carrier.FILE, javaType = 
"java.io.File",
+                                   description = "The java.io.File of the file 
or directory of the event, also for DELETE, with"
+                                                 + " the event in the 
CamelFileEventType header. The consumer does not read it:"
+                                                 + " it converts to text, 
bytes or a stream by reading the file, which fails"
+                                                 + " after a DELETE"))
 public class FileWatchEndpoint extends DefaultEndpoint implements 
MultipleConsumersSupport {
 
     @UriPath(description = "Path of directory to consume events from.")
@@ -47,11 +55,13 @@ public class FileWatchEndpoint extends DefaultEndpoint 
implements MultipleConsum
               defaultValue = "true")
     private boolean recursive = true;
     @UriParam(label = "advanced",
-              description = "The number of concurrent consumers. Increase this 
value, if your route is slow to prevent buffering in queue.",
+              description = "The number of concurrent consumers. Increase this 
value, if your route is slow to prevent"
+                            + " buffering in queue.",
               defaultValue = "1")
     private int concurrentConsumers;
     @UriParam(label = "advanced",
-              description = "The number of threads polling WatchService. 
Increase this value, if you see OVERFLOW messages in log.",
+              description = "The number of threads polling WatchService. 
Increase this value, if you see OVERFLOW messages in"
+                            + " log.",
               defaultValue = "1")
     private int pollThreads;
     @UriParam(description = "ANT style pattern to match files. The file is 
matched against path relative to endpoint path. "
@@ -63,10 +73,10 @@ public class FileWatchEndpoint extends DefaultEndpoint 
implements MultipleConsum
               defaultValue = "" + Integer.MAX_VALUE)
     private int queueSize;
     @UriParam(label = "advanced",
-              description = "Reference to 
io.methvin.watcher.hashing.FileHasher. "
-                            + "This prevents emitting duplicate events on some 
platforms. "
-                            + "For working with large files and if you dont 
need detect multiple modifications per second per file, "
-                            + "use #lastModifiedTimeFileHasher. You can also 
provide custom implementation in registry.",
+              description = "Reference to 
io.methvin.watcher.hashing.FileHasher. This prevents emitting duplicate events 
on"
+                            + " some platforms. For working with large files 
and if you dont need detect multiple modifications"
+                            + " per second per file, use 
#lastModifiedTimeFileHasher. You can also provide custom"
+                            + " implementation in registry.",
               defaultValue = "#murmur3FFileHasher")
     private FileHasher fileHasher;
     @UriParam(description = "Enables or disables file hashing to detect 
duplicate events. "
diff --git 
a/components/camel-graphql/src/generated/resources/META-INF/org/apache/camel/component/graphql/graphql.json
 
b/components/camel-graphql/src/generated/resources/META-INF/org/apache/camel/component/graphql/graphql.json
index 73ef1d1a19f3..06daa6c1ad22 100644
--- 
a/components/camel-graphql/src/generated/resources/META-INF/org/apache/camel/component/graphql/graphql.json
+++ 
b/components/camel-graphql/src/generated/resources/META-INF/org/apache/camel/component/graphql/graphql.json
@@ -30,6 +30,10 @@
     "httpClient": { "index": 3, "kind": "property", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." },
     "headerFilterStrategy": { "index": 4, "kind": "property", "displayName": 
"Header Filter Strategy", "group": "filter", "label": "filter", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom 
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel 
message." }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"dependsOn": [ "query", "queryFile", "queryHeader" ], "description": "The 
query, when none of query, queryFile and queryHeader is set: text, or bytes, a 
stream or a file of it. A Map is not a query. With one of them the body is not 
sent, except that an org.apache.camel.util.json.JsonObject body is the 
variables when neither variables nor variablesHeader is set" },
+    "producerOut": { "carriers": [ "text", "null" ], "description": "The 
response as text, the JSON with the data and errors of GraphQL: unmarshal it to 
read them. Errors in the response do not fail the exchange; a status outside 
2xx does, unless throwExceptionOnFailure=false, which keeps the response as 
text. null for a response without a body" }
+  },
   "properties": {
     "httpUri": { "index": 0, "kind": "path", "displayName": "Http Uri", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The GraphQL server URI." },
     "headerFilterStrategy": { "index": 1, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "common (advanced)", "label": 
"common,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." },
diff --git a/components/camel-graphql/src/main/docs/graphql-component.adoc 
b/components/camel-graphql/src/main/docs/graphql-component.adoc
index 3ec1d0083d54..63f921a7ac59 100644
--- a/components/camel-graphql/src/main/docs/graphql-component.adoc
+++ b/components/camel-graphql/src/main/docs/graphql-component.adoc
@@ -37,7 +37,7 @@ include::partial$component-endpoint-headers.adoc[]
 
 == Message Body
 
-If the `variables` and `variablesHeader` parameters are not set and the IN 
body is a JsonObject instance, Camel will use it for the operation's variables. 
If the `query` and `queryFile` parameters are not set and the IN body is a 
String, Camel will use it as the query. Camel will store the GraphQL response 
from the external server on the OUT message body.
+If the `variables` and `variablesHeader` parameters are not set and the IN 
body is an `org.apache.camel.util.json.JsonObject` instance, Camel will use it 
for the operation's variables (another `Map` is not used). If the `query`, 
`queryFile` and `queryHeader` parameters are not set, Camel will use the IN 
body as the query: text, or bytes, a stream or a file of it. Camel will store 
the GraphQL response from the external server on the OUT message body, as a 
`String` of the JSON response, wi [...]
 All headers from the IN message will be copied to the OUT message, so headers 
are preserved during routing.
 Additionally, Camel will add the HTTP response headers as well to the OUT 
message headers.
 
diff --git 
a/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlEndpoint.java
 
b/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlEndpoint.java
index 1a0fb874023c..6ca952f33ec9 100644
--- 
a/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlEndpoint.java
+++ 
b/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlEndpoint.java
@@ -30,6 +30,9 @@ import org.apache.camel.Producer;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.http.HttpClientConfigurer;
 import org.apache.camel.http.base.HttpHeaderFilterStrategy;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.EndpointServiceLocation;
 import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.spi.Metadata;
@@ -60,6 +63,17 @@ import org.slf4j.LoggerFactory;
  */
 @UriEndpoint(firstVersion = "3.0.0", scheme = "graphql", title = "GraphQL", 
syntax = "graphql:httpUri",
              category = { Category.API }, producerOnly = true, 
lenientProperties = true)
+@BodyTypes(producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, 
Carrier.STREAM, Carrier.FILE },
+                                  dependsOn = { "query", "queryFile", 
"queryHeader" },
+                                  description = "The query, when none of 
query, queryFile and queryHeader is set: text, or"
+                                                + " bytes, a stream or a file 
of it. A Map is not a query. With one of them the"
+                                                + " body is not sent, except 
that an org.apache.camel.util.json.JsonObject body"
+                                                + " is the variables when 
neither variables nor variablesHeader is set"),
+           producerOut = @BodyType(value = { Carrier.TEXT, Carrier.NULL },
+                                   description = "The response as text, the 
JSON with the data and errors of GraphQL: unmarshal"
+                                                 + " it to read them. Errors 
in the response do not fail the exchange; a status"
+                                                 + " outside 2xx does, unless 
throwExceptionOnFailure=false, which keeps the"
+                                                 + " response as text. null 
for a response without a body"))
 public class GraphqlEndpoint extends DefaultEndpoint implements 
EndpointServiceLocation {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(GraphqlEndpoint.class);
@@ -92,7 +106,8 @@ public class GraphqlEndpoint extends DefaultEndpoint 
implements EndpointServiceL
     @UriParam(label = "advanced")
     private HttpClient httpClient;
     @UriParam(label = "producer", defaultValue = "true",
-              description = "Option to disable throwing the 
HttpOperationFailedException in case of failed responses from the remote 
server. This allows you to get all responses regardless of the HTTP status 
code.")
+              description = "Option to disable throwing the 
HttpOperationFailedException in case of failed responses from the"
+                            + " remote server. This allows you to get all 
responses regardless of the HTTP status code.")
     private boolean throwExceptionOnFailure = true;
     @UriParam(label = "common,advanced",
               description = "To use a custom HeaderFilterStrategy to filter 
header to and from Camel message.")
diff --git 
a/components/camel-jdbc/src/generated/resources/META-INF/org/apache/camel/component/jdbc/jdbc.json
 
b/components/camel-jdbc/src/generated/resources/META-INF/org/apache/camel/component/jdbc/jdbc.json
index 5109e6432688..141b79d25a3e 100644
--- 
a/components/camel-jdbc/src/generated/resources/META-INF/org/apache/camel/component/jdbc/jdbc.json
+++ 
b/components/camel-jdbc/src/generated/resources/META-INF/org/apache/camel/component/jdbc/jdbc.json
@@ -39,6 +39,10 @@
     "CamelGeneratedKeysRowCount": { "index": 6, "kind": "header", 
"displayName": "", "group": "producer", "label": "producer", "required": false, 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The number of rows in the header that 
contains generated keys.", "constantName": 
"org.apache.camel.component.jdbc.JdbcConstants#JDBC_GENERATED_KEYS_ROW_COUNT" },
     "CamelGeneratedKeysRows": { "index": 7, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"List<Map<String, Object>>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Rows that contains the 
generated keys.", "constantName": 
"org.apache.camel.component.jdbc.JdbcConstants#JDBC_GENERATED_KEYS_DATA" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"description": "The SQL statement as text, or bytes, a stream or a file of it; 
a Map or a List is not a statement: set the SQL as the body. With 
useHeadersAsParameters, the values of its placeholders come from the 
CamelJdbcParameters header, or else from the headers" },
+    "producerOut": { "carriers": [ "list", "unchanged" ], "dependsOn": [ 
"outputClass" ], "byOption": [ { "option": "outputType", "value": "SelectOne", 
"carriers": [ "map", "text", "value", "bytes", "pojo", "null", "unchanged" ] }, 
{ "option": "outputType", "value": "StreamList", "carriers": [ "iterator", 
"unchanged" ] } ], "description": "The rows of a select: a List of Maps of the 
column names and their values (beans of outputClass when set). SelectOne gives 
the Map of the one row, the [...]
+  },
   "properties": {
     "dataSourceName": { "index": 0, "kind": "path", "displayName": "Data 
Source Name", "group": "producer", "label": "", "required": true, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Name of DataSource to lookup in the Registry. If the name is dataSource or 
default, then Camel will attempt to lookup a default DataSource from the 
registry, meaning if there is a only one instance of DataS [...]
     "allowNamedParameters": { "index": 1, "kind": "parameter", "displayName": 
"Allow Named Parameters", "group": "producer", "label": "", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": true, "description": "Whether to allow 
using named parameters in the queries." },
diff --git a/components/camel-jdbc/src/main/docs/jdbc-component.adoc 
b/components/camel-jdbc/src/main/docs/jdbc-component.adoc
index 04943660e73f..059bdd5b9f6a 100644
--- a/components/camel-jdbc/src/main/docs/jdbc-component.adoc
+++ b/components/camel-jdbc/src/main/docs/jdbc-component.adoc
@@ -54,11 +54,15 @@ include::partial$component-endpoint-headers.adoc[]
 
 === Result
 
-By default, the result is returned in the OUT body as an
-`ArrayList<HashMap<String, Object>>`. The `List` object contains the
+By default, the result of a select is returned in the OUT body as an
+`ArrayList<LinkedHashMap<String, Object>>`. The `List` object contains the
 list of rows and the `Map` objects contain each row with the `String`
 key as the column name. You can use the option `outputType` to control
-the result.
+the result: `SelectOne` gives the `Map` of the one row, the value of its
+column when it has one column, or `null` when there is no row, and
+`StreamList` gives an `Iterator` of the rows, which can be read once.
+A statement that is not a select leaves the body as it is, with the count
+in the `CamelJdbcUpdateCount` header.
 
 *Note:* This component fetches `ResultSetMetaData` to be able to return
 the column name as the key in the `Map`.
diff --git 
a/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcEndpoint.java
 
b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcEndpoint.java
index 927733d122b8..305ae2e8f861 100644
--- 
a/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcEndpoint.java
+++ 
b/components/camel-jdbc/src/main/java/org/apache/camel/component/jdbc/JdbcEndpoint.java
@@ -25,6 +25,9 @@ import org.apache.camel.Component;
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -36,6 +39,25 @@ import org.apache.camel.support.DefaultEndpoint;
  */
 @UriEndpoint(firstVersion = "1.2.0", scheme = "jdbc", title = "JDBC", syntax = 
"jdbc:dataSourceName", producerOnly = true,
              category = { Category.DATABASE }, headersClass = 
JdbcConstants.class)
+@BodyTypes(producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, 
Carrier.STREAM, Carrier.FILE },
+                                  description = "The SQL statement as text, or 
bytes, a stream or a file of it; a Map or a List"
+                                                + " is not a statement: set 
the SQL as the body. With useHeadersAsParameters,"
+                                                + " the values of its 
placeholders come from the CamelJdbcParameters header, or"
+                                                + " else from the headers"),
+           producerOut = @BodyType(value = { Carrier.LIST, Carrier.UNCHANGED 
}, dependsOn = "outputClass",
+                                   byOption = {
+                                           @BodyType.When(option = 
"outputType", value = "SelectOne",
+                                                          carriers = {
+                                                                  Carrier.MAP, 
Carrier.TEXT, Carrier.VALUE, Carrier.BYTES,
+                                                                  
Carrier.POJO, Carrier.NULL, Carrier.UNCHANGED }),
+                                           @BodyType.When(option = 
"outputType", value = "StreamList",
+                                                          carriers = { 
Carrier.ITERATOR, Carrier.UNCHANGED }) },
+                                   description = "The rows of a select: a List 
of Maps of the column names and their values"
+                                                 + " (beans of outputClass 
when set). SelectOne gives the Map of the one row,"
+                                                 + " the value of its column 
as the driver reads it when it has one, or null"
+                                                 + " for no row; StreamList an 
Iterator of the rows, read once. A statement"
+                                                 + " that is not a select 
leaves the body unchanged, with the count in the"
+                                                 + " CamelJdbcUpdateCount 
header"))
 public class JdbcEndpoint extends DefaultEndpoint {
 
     private DataSource dataSource;
diff --git 
a/components/camel-jsch/src/generated/resources/META-INF/org/apache/camel/component/scp/scp.json
 
b/components/camel-jsch/src/generated/resources/META-INF/org/apache/camel/component/scp/scp.json
index c725d39cb7a8..a5fafc55d1fa 100644
--- 
a/components/camel-jsch/src/generated/resources/META-INF/org/apache/camel/component/scp/scp.json
+++ 
b/components/camel-jsch/src/generated/resources/META-INF/org/apache/camel/component/scp/scp.json
@@ -30,6 +30,10 @@
     "healthCheckConsumerEnabled": { "index": 3, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
     "healthCheckProducerEnabled": { "index": 4, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on producer [...]
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"byOption": [ { "option": "allowNullBody", "value": "true", "carriers": [ 
"null", "text", "bytes", "stream", "file" ] } ], "description": "The content of 
the file: text, bytes, a stream or a file, which is read into memory first to 
send its size. A Map or a List fails: marshal it first" },
+    "producerOut": { "carriers": [ "unchanged" ], "description": "Unchanged, 
with the name of the remote file in the CamelFileNameProduced header" }
+  },
   "properties": {
     "host": { "index": 0, "kind": "path", "displayName": "Host", "group": 
"producer", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.scp.ScpConfiguration", "configurationField": 
"configuration", "description": "Hostname of the FTP server" },
     "port": { "index": 1, "kind": "path", "displayName": "Port", "group": 
"producer", "label": "", "required": false, "type": "integer", "javaType": 
"int", "deprecated": false, "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.scp.ScpConfiguration", 
"configurationField": "configuration", "description": "Port of the FTP server" 
},
diff --git 
a/components/camel-jsch/src/main/java/org/apache/camel/component/scp/ScpEndpoint.java
 
b/components/camel-jsch/src/main/java/org/apache/camel/component/scp/ScpEndpoint.java
index 5f97aff0c484..4f888a5a7ae8 100644
--- 
a/components/camel-jsch/src/main/java/org/apache/camel/component/scp/ScpEndpoint.java
+++ 
b/components/camel-jsch/src/main/java/org/apache/camel/component/scp/ScpEndpoint.java
@@ -24,6 +24,9 @@ import org.apache.camel.component.file.GenericFileProducer;
 import org.apache.camel.component.file.remote.RemoteFileConsumer;
 import org.apache.camel.component.file.remote.RemoteFileEndpoint;
 import org.apache.camel.component.file.remote.RemoteFileOperations;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -39,6 +42,16 @@ import org.apache.camel.spi.UriParam;
                               + 
",transferLoggingIntervalSeconds,transferLoggingLevel,transferLoggingVerbose,resumeDownload"
                               + 
",handleDirectoryParserAbsoluteResult,activePortRange,ftpClient,ftpClientConfig"
                               + 
",ftpClientConfigParameters,ftpClientParameters,account,synchronous")
+@BodyTypes(producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, 
Carrier.STREAM, Carrier.FILE },
+                                  byOption = @BodyType.When(option = 
"allowNullBody", value = "true",
+                                                            carriers = {
+                                                                    
Carrier.NULL, Carrier.TEXT, Carrier.BYTES,
+                                                                    
Carrier.STREAM, Carrier.FILE }),
+                                  description = "The content of the file: 
text, bytes, a stream or a file, which is read into"
+                                                + " memory first to send its 
size. A Map or a List fails: marshal it first"),
+           producerOut = @BodyType(value = Carrier.UNCHANGED,
+                                   description = "Unchanged, with the name of 
the remote file in the CamelFileNameProduced"
+                                                 + " header"))
 public class ScpEndpoint extends RemoteFileEndpoint<ScpFile> {
 
     @UriParam
diff --git 
a/components/camel-micrometer/src/generated/resources/META-INF/org/apache/camel/component/micrometer/micrometer.json
 
b/components/camel-micrometer/src/generated/resources/META-INF/org/apache/camel/component/micrometer/micrometer.json
index f7e9210de897..8896fc905db2 100644
--- 
a/components/camel-micrometer/src/generated/resources/META-INF/org/apache/camel/component/micrometer/micrometer.json
+++ 
b/components/camel-micrometer/src/generated/resources/META-INF/org/apache/camel/component/micrometer/micrometer.json
@@ -37,6 +37,10 @@
     "CamelMetricsDescription": { "index": 5, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Override description value in URI", "constantName": 
"org.apache.camel.component.micrometer.MicrometerConstants#HEADER_METRIC_DESCRIPTION"
 },
     "CamelMetricsTags": { "index": 6, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": 
"java.lang.Iterable<Tag>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "To augment meter tags 
defined as URI parameters", "constantName": 
"org.apache.camel.component.micrometer.MicrometerConstants#HEADER_METRIC_TAGS" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "any" ], "description": "Not used, unless an 
option such as increment, decrement or value is a simple expression that reads 
it, which must then give a number. The CamelMetrics headers override the 
options" },
+    "producerOut": { "carriers": [ "unchanged" ], "description": "Unchanged; 
the CamelMetrics headers are removed" }
+  },
   "properties": {
     "metricsType": { "index": 0, "kind": "path", "displayName": "Metrics 
Type", "group": "producer", "label": "", "required": true, "type": "enum", 
"javaType": "io.micrometer.core.instrument.Meter.Type", "enum": [ "counter", 
"summary", "timer" ], "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Type of metrics" },
     "metricsName": { "index": 1, "kind": "path", "displayName": "Metrics 
Name", "group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "supportSimpleExpression": true, 
"description": "Name of metrics" },
diff --git 
a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/MicrometerEndpoint.java
 
b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/MicrometerEndpoint.java
index 90fb0911a1f9..5c5917433e51 100644
--- 
a/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/MicrometerEndpoint.java
+++ 
b/components/camel-micrometer/src/main/java/org/apache/camel/component/micrometer/MicrometerEndpoint.java
@@ -28,6 +28,9 @@ import org.apache.camel.Component;
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -41,6 +44,11 @@ import org.apache.camel.support.DefaultEndpoint;
              remote = false, syntax = "micrometer:metricsType:metricsName", 
producerOnly = true,
              category = { Category.MONITORING },
              headersClass = MicrometerConstants.class)
+@BodyTypes(producerIn = @BodyType(value = Carrier.ANY,
+                                  description = "Not used, unless an option 
such as increment, decrement or value is a simple"
+                                                + " expression that reads it, 
which must then give a number. The CamelMetrics"
+                                                + " headers override the 
options"),
+           producerOut = @BodyType(value = Carrier.UNCHANGED, description = 
"Unchanged; the CamelMetrics headers are removed"))
 public class MicrometerEndpoint extends DefaultEndpoint {
 
     protected MeterRegistry registry;
diff --git 
a/components/camel-pdf/src/generated/resources/META-INF/org/apache/camel/component/pdf/pdf.json
 
b/components/camel-pdf/src/generated/resources/META-INF/org/apache/camel/component/pdf/pdf.json
index f2edff0482dd..5a579be3f433 100644
--- 
a/components/camel-pdf/src/generated/resources/META-INF/org/apache/camel/component/pdf/pdf.json
+++ 
b/components/camel-pdf/src/generated/resources/META-INF/org/apache/camel/component/pdf/pdf.json
@@ -33,6 +33,10 @@
     "CamelPdfDecryptionMaterial": { "index": 2, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "org.apache.pdfbox.pdmodel.encryption.DecryptionMaterial", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Expected type is 
https:\/\/pdfbox.apache.org\/docs\/2.0.13\/javadocs\/org\/apache\/pdfbox\/pdmodel\/encryption\/DecryptionMaterial.htmlDecryptionMaterial.
 Mandatory header if PDF documen [...]
     "CamelPdfFilesToMerge": { "index": 3, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": 
"java.util.List<java.io.File>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Mandatory header for merge 
operation and ignored in all other operations. The array of pdf files that will 
be merged.", "constantName": 
"org.apache.camel.component.pdf.PdfHeaderConstants#FILES_TO_MERGE_HEADER_NAME" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"byOption": [ { "option": "operation", "value": "extractText", "carriers": [ 
"bytes", "stream", "file", "pojo" ] }, { "option": "operation", "value": 
"merge", "carriers": [ "any" ] } ], "description": "The text to write for 
create and append, which takes the document from the CamelPdfDocument header; a 
Map or a POJO is written as its toString: marshal it first. extractText reads a 
PDF from bytes, a stream, a file or a [...]
+    "producerOut": { "carriers": [ "pojo" ], "javaType": 
"java.io.ByteArrayOutputStream", "byOption": [ { "option": "operation", 
"value": "extractText", "carriers": [ "text" ], "javaType": "java.lang.String" 
} ], "description": "The PDF of create, append and merge in a 
ByteArrayOutputStream, which converts to bytes (convertBodyTo byte[] before 
extractText). The text of the document for extractText" }
+  },
   "properties": {
     "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.pdf.PdfOperation", "enum": [ "create", "append", 
"extractText", "merge" ], "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.pdf.PdfConfiguration", "configurationField": 
"pdfConfiguration", "description": "Operation type" },
     "font": { "index": 1, "kind": "parameter", "displayName": "Font", "group": 
"producer", "label": "", "required": false, "type": "enum", "javaType": 
"java.lang.String", "enum": [ "COURIER", "COURIER_BOLD", "COURIER_OBLIQUE", 
"COURIER_BOLD_OBLIQUE", "HELVETICA", "HELVETICA_BOLD", "HELVETICA_OBLIQUE", 
"HELVETICA_BOLD_OBLIQUE", "TIMES_ROMAN", "TIMES_BOLD", "TIMES_ITALIC", 
"TIMES_BOLD_ITALIC", "SYMBOL", "ZAPF_DINGBATS" ], "deprecated": false, 
"autowired": false, "secret": false, "defaultVa [...]
diff --git a/components/camel-pdf/src/main/docs/pdf-component.adoc 
b/components/camel-pdf/src/main/docs/pdf-component.adoc
index e2e9dcebcb9a..fd890c034ca6 100644
--- a/components/camel-pdf/src/main/docs/pdf-component.adoc
+++ b/components/camel-pdf/src/main/docs/pdf-component.adoc
@@ -95,5 +95,8 @@ YAML::
 It is now possible to get the body as a PD Document by using `PDDocument doc = 
exchange.getIn().getBody(PDDocument.class);`,
 which saves the trouble of converting the byte-array to a document.
 
+The body after `create`, `append` and `merge` is a `ByteArrayOutputStream` 
with the PDF, which does not convert to a
+`PDDocument`: convert it to `byte[]` before `extractText`.
+
 NOTE: this only works for unprotected PDF files. For password-protected, the 
files still need to be converted
 manually.
diff --git 
a/components/camel-pdf/src/main/java/org/apache/camel/component/pdf/PdfEndpoint.java
 
b/components/camel-pdf/src/main/java/org/apache/camel/component/pdf/PdfEndpoint.java
index 5310e999665b..cdbee30e74be 100644
--- 
a/components/camel-pdf/src/main/java/org/apache/camel/component/pdf/PdfEndpoint.java
+++ 
b/components/camel-pdf/src/main/java/org/apache/camel/component/pdf/PdfEndpoint.java
@@ -21,6 +21,9 @@ import org.apache.camel.Component;
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.support.DefaultEndpoint;
@@ -31,6 +34,24 @@ import org.apache.camel.support.DefaultEndpoint;
 @UriEndpoint(firstVersion = "2.16.0", scheme = "pdf", title = "PDF", syntax = 
"pdf:operation", producerOnly = true,
              remote = false, category = { Category.DOCUMENT, 
Category.TRANSFORMATION },
              headersClass = PdfHeaderConstants.class)
+@BodyTypes(producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, 
Carrier.STREAM, Carrier.FILE },
+                                  byOption = {
+                                          @BodyType.When(option = "operation", 
value = "extractText",
+                                                         carriers = {
+                                                                 
Carrier.BYTES, Carrier.STREAM, Carrier.FILE,
+                                                                 Carrier.POJO 
}),
+                                          @BodyType.When(option = "operation", 
value = "merge", carriers = Carrier.ANY) },
+                                  description = "The text to write for create 
and append, which takes the document from the"
+                                                + " CamelPdfDocument header; a 
Map or a POJO is written as its toString:"
+                                                + " marshal it first. 
extractText reads a PDF from bytes, a stream, a file or a"
+                                                + " PDDocument, not from text. 
merge takes the files from the"
+                                                + " CamelPdfFilesToMerge 
header"),
+           producerOut = @BodyType(value = Carrier.POJO, javaType = 
"java.io.ByteArrayOutputStream",
+                                   byOption = @BodyType.When(option = 
"operation", value = "extractText",
+                                                             carriers = 
Carrier.TEXT, javaType = "java.lang.String"),
+                                   description = "The PDF of create, append 
and merge in a ByteArrayOutputStream, which"
+                                                 + " converts to bytes 
(convertBodyTo byte[] before extractText). The text of"
+                                                 + " the document for 
extractText"))
 public class PdfEndpoint extends DefaultEndpoint {
 
     @UriParam
diff --git 
a/components/camel-smooks/src/generated/resources/META-INF/org/apache/camel/component/smooks/smooks.json
 
b/components/camel-smooks/src/generated/resources/META-INF/org/apache/camel/component/smooks/smooks.json
index d96eead22f1f..b1ab2749020f 100644
--- 
a/components/camel-smooks/src/generated/resources/META-INF/org/apache/camel/component/smooks/smooks.json
+++ 
b/components/camel-smooks/src/generated/resources/META-INF/org/apache/camel/component/smooks/smooks.json
@@ -31,6 +31,10 @@
   "headers": {
     "CamelSmooksExecutionContext": { "index": 0, "kind": "header", 
"displayName": "", "group": "advanced", "label": "advanced", "required": false, 
"javaType": "org.smooks.api.ExecutionContext", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
Smooks execution context.", "constantName": 
"org.apache.camel.component.smooks.SmooksConstants#SMOOKS_EXECUTION_CONTEXT" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"description": "The data the reader of the smooks config reads: XML by default, 
or EDI, CSV or JSON with a reader. A Map, a List or a POJO fails" },
+    "producerOut": { "carriers": [ "unknown" ], "description": "What the 
exports of the smooks config give: the bean a JavaSink export extracts (a Map 
of the beans when it extracts none), or the text of a StringSink. Without 
exports, the input as a stream" }
+  },
   "properties": {
     "smooksConfig": { "index": 0, "kind": "path", "displayName": "Smooks 
Config", "group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "supportFileReference": true, 
"description": "Path to the Smooks configuration file" },
     "reportPath": { "index": 1, "kind": "parameter", "displayName": "Report 
Path", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "description": "File path to place the generated HTML 
execution report. The report is a useful tool in the developers arsenal for 
diagnosing issues or comprehending a transformation. Do not set in production 
since this is a major performance drain" },
diff --git a/components/camel-smooks/src/main/docs/smooks-component.adoc 
b/components/camel-smooks/src/main/docs/smooks-component.adoc
index 677f8b82670f..a3568ee63eee 100644
--- a/components/camel-smooks/src/main/docs/smooks-component.adoc
+++ b/components/camel-smooks/src/main/docs/smooks-component.adoc
@@ -14,6 +14,8 @@
 
 The Camel Smooks component uses https://www.smooks.org/[Smooks] to break up 
the structured data (EDI, CSV, POJO, etc...) of a Camel message body into 
fragments. These fragments can be processed independently of one another from 
within Smooks.
 
+The body is read by the reader of the Smooks configuration (XML by default) as 
text, bytes, a stream or a file. A POJO is read when the body is a 
`org.smooks.io.source.JavaSource` that holds it: a POJO, a `Map` or a `List` as 
the body itself fails.
+
 Common applications of Smooks include:
 
 * transformation: EDI to CSV, POJO to EDI, POJO to XML, and so on.
diff --git 
a/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksEndpoint.java
 
b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksEndpoint.java
index a86a20829bbb..1ffd96330e7a 100644
--- 
a/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksEndpoint.java
+++ 
b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksEndpoint.java
@@ -21,6 +21,9 @@ import org.apache.camel.Component;
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -34,6 +37,13 @@ import org.apache.camel.support.service.ServiceHelper;
 @UriEndpoint(firstVersion = "4.7.0", scheme = "smooks", title = "Smooks", 
syntax = "smooks:smooksConfig",
              producerOnly = true,
              category = { Category.TRANSFORMATION }, headersClass = 
SmooksConstants.class)
+@BodyTypes(producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, 
Carrier.STREAM, Carrier.FILE },
+                                  description = "The data the reader of the 
smooks config reads: XML by default, or EDI, CSV"
+                                                + " or JSON with a reader. A 
Map, a List or a POJO fails"),
+           producerOut = @BodyType(value = Carrier.UNKNOWN,
+                                   description = "What the exports of the 
smooks config give: the bean a JavaSink export"
+                                                 + " extracts (a Map of the 
beans when it extracts none), or the text of a"
+                                                 + " StringSink. Without 
exports, the input as a stream"))
 public class SmooksEndpoint extends DefaultEndpoint {
 
     @UriPath(description = "Path to the Smooks configuration file")
diff --git 
a/components/camel-snmp/src/generated/resources/META-INF/org/apache/camel/component/snmp/snmp.json
 
b/components/camel-snmp/src/generated/resources/META-INF/org/apache/camel/component/snmp/snmp.json
index 4dc8c5a836cd..5033597bc5c6 100644
--- 
a/components/camel-snmp/src/generated/resources/META-INF/org/apache/camel/component/snmp/snmp.json
+++ 
b/components/camel-snmp/src/generated/resources/META-INF/org/apache/camel/component/snmp/snmp.json
@@ -30,6 +30,11 @@
     "healthCheckConsumerEnabled": { "index": 3, "kind": "property", 
"displayName": "Health Check Consumer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all consumer based health checks 
from this component" },
     "healthCheckProducerEnabled": { "index": 4, "kind": "property", 
"displayName": "Health Check Producer Enabled", "group": "health", "label": 
"health", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Used for enabling or disabling all producer based health checks 
from this component. Notice: Camel has by default disabled all producer based 
health-checks. You can turn on producer [...]
   },
+  "bodyTypes": {
+    "consumerOut": { "carriers": [ "text" ], "javaType": "java.lang.String", 
"format": "xml", "description": "The variable bindings of the response of a 
poll or of a trap as XML text: an snmp element with an entry of an oid and a 
value for each, and the community of a trap in the securityName header" },
+    "producerIn": { "carriers": [ "any" ], "byOption": [ { "option": "type", 
"value": "TRAP", "carriers": [ "pojo" ], "javaType": "org.snmp4j.PDU" } ], 
"description": "Not used by a POLL or GET_NEXT, which requests the oids. A TRAP 
sends the body, which must be a PDU of SNMP4J for the snmpVersion: a PDUv1 for 
0, the default, a PDU for 1 and a ScopedPDU for 3. Another body fails" },
+    "producerOut": { "carriers": [ "pojo" ], "javaType": 
"org.apache.camel.component.snmp.SnmpMessage", "byOption": [ { "option": 
"type", "value": "GET_NEXT", "carriers": [ "list" ], "javaType": 
"java.util.List<org.apache.camel.component.snmp.SnmpMessage>" }, { "option": 
"type", "value": "TRAP", "carriers": [ "unchanged" ] } ], "description": "The 
response of a POLL as an SnmpMessage, a Camel message as the body, whose own 
body is the XML text of the consumer; it does not convert to text [...]
+  },
   "properties": {
     "host": { "index": 0, "kind": "path", "displayName": "Host", "group": 
"common", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Hostname of the SNMP enabled device" },
     "port": { "index": 1, "kind": "path", "displayName": "Port", "group": 
"common", "label": "", "required": true, "type": "integer", "javaType": 
"java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Port number of the SNMP enabled device" 
},
diff --git a/components/camel-snmp/src/main/docs/snmp-component.adoc 
b/components/camel-snmp/src/main/docs/snmp-component.adoc
index 2f0eda76b8e8..c0409fcea38c 100644
--- a/components/camel-snmp/src/main/docs/snmp-component.adoc
+++ b/components/camel-snmp/src/main/docs/snmp-component.adoc
@@ -41,7 +41,9 @@ and receiving traps.
 
 It can also be used to request information using GET method.
 
-The response body type is `org.apache.camel.component.snmp.SnmpMessage`.
+After a `POLL`, the body is an `org.apache.camel.component.snmp.SnmpMessage`: 
a Camel message whose own body is the
+response as XML text. It does not convert to a `String` itself. A `GET_NEXT` 
gives a `List` of them, one per variable
+of the walk. A `TRAP` producer sends the body, which must be an 
`org.snmp4j.PDU`, and leaves it as it is.
 
 
 // component options: START
@@ -64,13 +66,10 @@ Given the situation, that I poll for the following OIDs:
 1.3.6.1.2.1.43.5.1.1.11.1
 -------------------------
 
-The result will be the following:
-
-*Result of toString conversion*
+The body is the result as XML text, written on one line without an XML 
declaration (indented here):
 
 [source,xml]
 -----------------------------------------------------------
-<?xml version="1.0" encoding="UTF-8"?>
 <snmp>
   <entry>
     <oid>1.3.6.1.2.1.1.3.0</oid>
@@ -127,7 +126,7 @@ snmp:127.0.0.1:162?protocol=udp&type=TRAP
 You can get the community of SNMP TRAP with message
 header `securityName`, peer address of the SNMP TRAP with message header 
`peerAddress`.
 
-Routing example in Java: (converts the SNMP PDU to XML String)
+Routing example in Java: (the body of the consumer is the SNMP PDU as XML text)
 
 [tabs]
 ====
diff --git 
a/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpEndpoint.java
 
b/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpEndpoint.java
index 81bf37263a51..7f37c20b7f6a 100644
--- 
a/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpEndpoint.java
+++ 
b/components/camel-snmp/src/main/java/org/apache/camel/component/snmp/SnmpEndpoint.java
@@ -23,6 +23,9 @@ import org.apache.camel.Consumer;
 import org.apache.camel.Exchange;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.EndpointServiceLocation;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
@@ -40,6 +43,26 @@ import org.snmp4j.security.SecurityLevel;
  */
 @UriEndpoint(firstVersion = "2.1.0", scheme = "snmp", title = "SNMP", syntax = 
"snmp:host:port",
              category = { Category.MONITORING })
+@BodyTypes(consumerOut = @BodyType(value = Carrier.TEXT, javaType = 
"java.lang.String", format = "xml",
+                                   description = "The variable bindings of the 
response of a poll or of a trap as XML text: an"
+                                                 + " snmp element with an 
entry of an oid and a value for each, and the"
+                                                 + " community of a trap in 
the securityName header"),
+           producerIn = @BodyType(value = Carrier.ANY,
+                                  byOption = @BodyType.When(option = "type", 
value = "TRAP", carriers = Carrier.POJO,
+                                                            javaType = 
"org.snmp4j.PDU"),
+                                  description = "Not used by a POLL or 
GET_NEXT, which requests the oids. A TRAP sends the"
+                                                + " body, which must be a PDU 
of SNMP4J for the snmpVersion: a PDUv1 for 0, the"
+                                                + " default, a PDU for 1 and a 
ScopedPDU for 3. Another body fails"),
+           producerOut = @BodyType(value = Carrier.POJO, javaType = 
"org.apache.camel.component.snmp.SnmpMessage",
+                                   byOption = {
+                                           @BodyType.When(option = "type", 
value = "GET_NEXT", carriers = Carrier.LIST,
+                                                          javaType = 
"java.util.List<"
+                                                                     + 
"org.apache.camel.component.snmp.SnmpMessage>"),
+                                           @BodyType.When(option = "type", 
value = "TRAP", carriers = Carrier.UNCHANGED) },
+                                   description = "The response of a POLL as an 
SnmpMessage, a Camel message as the body, whose"
+                                                 + " own body is the XML text 
of the consumer; it does not convert to text. A"
+                                                 + " List of them, one per 
step of the walk, for GET_NEXT. A TRAP leaves the"
+                                                 + " body unchanged"))
 public class SnmpEndpoint extends DefaultPollingEndpoint implements 
EndpointServiceLocation {
 
     public static final String DEFAULT_COMMUNITY = "public";
diff --git 
a/components/camel-spring-parent/camel-spring-jdbc/src/generated/resources/META-INF/org/apache/camel/component/spring/jdbc/spring-jdbc.json
 
b/components/camel-spring-parent/camel-spring-jdbc/src/generated/resources/META-INF/org/apache/camel/component/spring/jdbc/spring-jdbc.json
index 3e5e9fbd4669..9cfba1b8222e 100644
--- 
a/components/camel-spring-parent/camel-spring-jdbc/src/generated/resources/META-INF/org/apache/camel/component/spring/jdbc/spring-jdbc.json
+++ 
b/components/camel-spring-parent/camel-spring-jdbc/src/generated/resources/META-INF/org/apache/camel/component/spring/jdbc/spring-jdbc.json
@@ -39,6 +39,10 @@
     "CamelGeneratedKeysRowCount": { "index": 6, "kind": "header", 
"displayName": "", "group": "producer", "label": "producer", "required": false, 
"javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The number of rows in the header that 
contains generated keys.", "constantName": 
"org.apache.camel.component.jdbc.JdbcConstants#JDBC_GENERATED_KEYS_ROW_COUNT" },
     "CamelGeneratedKeysRows": { "index": 7, "kind": "header", "displayName": 
"", "group": "producer", "label": "producer", "required": false, "javaType": 
"List<Map<String, Object>>", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Rows that contains the 
generated keys.", "constantName": 
"org.apache.camel.component.jdbc.JdbcConstants#JDBC_GENERATED_KEYS_DATA" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"description": "The SQL statement as text, or bytes, a stream or a file of it; 
a Map or a List is not a statement: set the SQL as the body. With 
useHeadersAsParameters, the values of its placeholders come from the 
CamelJdbcParameters header, or else from the headers" },
+    "producerOut": { "carriers": [ "list", "unchanged" ], "dependsOn": [ 
"outputClass" ], "byOption": [ { "option": "outputType", "value": "SelectOne", 
"carriers": [ "map", "text", "value", "bytes", "pojo", "null", "unchanged" ] }, 
{ "option": "outputType", "value": "StreamList", "carriers": [ "iterator", 
"unchanged" ] } ], "description": "The rows of a select: a List of Maps of the 
column names and their values (beans of outputClass when set). SelectOne gives 
the Map of the one row, the [...]
+  },
   "properties": {
     "dataSourceName": { "index": 0, "kind": "path", "displayName": "Data 
Source Name", "group": "producer", "label": "", "required": true, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Name of DataSource to lookup in the Registry. If the name is dataSource or 
default, then Camel will attempt to lookup a default DataSource from the 
registry, meaning if there is a only one instance of DataS [...]
     "allowNamedParameters": { "index": 1, "kind": "parameter", "displayName": 
"Allow Named Parameters", "group": "producer", "label": "", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": true, "description": "Whether to allow 
using named parameters in the queries." },
diff --git 
a/components/camel-spring-parent/camel-spring-jdbc/src/main/java/org/apache/camel/component/spring/jdbc/SpringJdbcEndpoint.java
 
b/components/camel-spring-parent/camel-spring-jdbc/src/main/java/org/apache/camel/component/spring/jdbc/SpringJdbcEndpoint.java
index 0f872849b4fa..0904041ad82f 100644
--- 
a/components/camel-spring-parent/camel-spring-jdbc/src/main/java/org/apache/camel/component/spring/jdbc/SpringJdbcEndpoint.java
+++ 
b/components/camel-spring-parent/camel-spring-jdbc/src/main/java/org/apache/camel/component/spring/jdbc/SpringJdbcEndpoint.java
@@ -21,6 +21,9 @@ import javax.sql.DataSource;
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.component.jdbc.JdbcEndpoint;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.UriEndpoint;
 
 /**
@@ -29,6 +32,25 @@ import org.apache.camel.spi.UriEndpoint;
 @UriEndpoint(firstVersion = "3.10.0", scheme = "spring-jdbc", title = "Spring 
JDBC", syntax = "spring-jdbc:dataSourceName",
              producerOnly = true,
              category = { Category.DATABASE })
+@BodyTypes(producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, 
Carrier.STREAM, Carrier.FILE },
+                                  description = "The SQL statement as text, or 
bytes, a stream or a file of it; a Map or a List"
+                                                + " is not a statement: set 
the SQL as the body. With useHeadersAsParameters,"
+                                                + " the values of its 
placeholders come from the CamelJdbcParameters header, or"
+                                                + " else from the headers"),
+           producerOut = @BodyType(value = { Carrier.LIST, Carrier.UNCHANGED 
}, dependsOn = "outputClass",
+                                   byOption = {
+                                           @BodyType.When(option = 
"outputType", value = "SelectOne",
+                                                          carriers = {
+                                                                  Carrier.MAP, 
Carrier.TEXT, Carrier.VALUE, Carrier.BYTES,
+                                                                  
Carrier.POJO, Carrier.NULL, Carrier.UNCHANGED }),
+                                           @BodyType.When(option = 
"outputType", value = "StreamList",
+                                                          carriers = { 
Carrier.ITERATOR, Carrier.UNCHANGED }) },
+                                   description = "The rows of a select: a List 
of Maps of the column names and their values"
+                                                 + " (beans of outputClass 
when set). SelectOne gives the Map of the one row,"
+                                                 + " the value of its column 
as the driver reads it when it has one, or null"
+                                                 + " for no row; StreamList an 
Iterator of the rows, read once. A statement"
+                                                 + " that is not a select 
leaves the body unchanged, with the count in the"
+                                                 + " CamelJdbcUpdateCount 
header"))
 public class SpringJdbcEndpoint extends JdbcEndpoint {
 
     public SpringJdbcEndpoint() {
diff --git 
a/components/camel-tika/src/generated/resources/META-INF/org/apache/camel/component/tika/tika.json
 
b/components/camel-tika/src/generated/resources/META-INF/org/apache/camel/component/tika/tika.json
index ddc7c899b1b7..0f8029d743e1 100644
--- 
a/components/camel-tika/src/generated/resources/META-INF/org/apache/camel/component/tika/tika.json
+++ 
b/components/camel-tika/src/generated/resources/META-INF/org/apache/camel/component/tika/tika.json
@@ -27,6 +27,10 @@
     "lazyStartProducer": { "index": 0, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
     "autowiredEnabled": { "index": 1, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ], 
"description": "The document: text, bytes, a stream or a file. A Map, a List, a 
POJO or no body fails, and parse fails on an empty document" },
+    "producerOut": { "carriers": [ "pojo" ], "javaType": 
"java.io.ByteArrayOutputStream", "byOption": [ { "option": "operation", 
"value": "detect", "carriers": [ "text" ], "javaType": "java.lang.String" } ], 
"description": "parse gives a ByteArrayOutputStream with the content as XHTML, 
or as HTML or plain text with tikaParseOutputFormat, in 
tikaParseOutputEncoding, and the metadata of the document in headers; 
camel-tika parses HTML and text, other types need their Tika parser module. det 
[...]
+  },
   "properties": {
     "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.tika.TikaOperation", "enum": [ "parse", "detect" ], 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "configurationClass": 
"org.apache.camel.component.tika.TikaConfiguration", "configurationField": 
"tikaConfiguration", "description": "Operation type" },
     "tikaParseOutputEncoding": { "index": 1, "kind": "parameter", 
"displayName": "Tika Parse Output Encoding", "group": "producer", "label": "", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.tika.TikaConfiguration", "configurationField": 
"tikaConfiguration", "description": "Tika Parse Output Encoding" },
diff --git a/components/camel-tika/src/main/docs/tika-component.adoc 
b/components/camel-tika/src/main/docs/tika-component.adoc
index 52c7916bdd82..89071eaedbe4 100644
--- a/components/camel-tika/src/main/docs/tika-component.adoc
+++ b/components/camel-tika/src/main/docs/tika-component.adoc
@@ -43,7 +43,8 @@ include::partial$component-endpoint-headers.adoc[]
 
 === To Detect a file's MIME Type
 
-The file should be placed in the Body.
+The body is the document: text, bytes, a stream or a file. After `detect`, the 
body is the MIME type as text, such as
+`text/html`.
 
 [tabs]
 ====
@@ -80,7 +81,10 @@ YAML::
 
 === To Parse a File
 
-The file should be placed in the Body.
+The body is the document: text, bytes, a stream or a file. After `parse`, the 
body is a `ByteArrayOutputStream` with
+the content as XHTML, or as HTML or plain text with `tikaParseOutputFormat`, 
which converts to a `String`, and the
+metadata of the document are headers, such as `dc:title`. The component has 
the Tika parsers of HTML and text: other
+types need their Tika parser module, such as 
`org.apache.tika:tika-parser-pdf-module` for PDF, or the content is empty.
 
 [tabs]
 ====
diff --git 
a/components/camel-tika/src/main/java/org/apache/camel/component/tika/TikaEndpoint.java
 
b/components/camel-tika/src/main/java/org/apache/camel/component/tika/TikaEndpoint.java
index f23be5aeb801..d4913f00bce1 100644
--- 
a/components/camel-tika/src/main/java/org/apache/camel/component/tika/TikaEndpoint.java
+++ 
b/components/camel-tika/src/main/java/org/apache/camel/component/tika/TikaEndpoint.java
@@ -21,6 +21,9 @@ import org.apache.camel.Component;
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.support.DefaultEndpoint;
@@ -30,6 +33,17 @@ import org.apache.camel.support.DefaultEndpoint;
  */
 @UriEndpoint(firstVersion = "2.19.0", scheme = "tika", title = "Tika", syntax 
= "tika:operation", producerOnly = true,
              remote = false, category = { Category.DOCUMENT, 
Category.TRANSFORMATION })
+@BodyTypes(producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES, 
Carrier.STREAM, Carrier.FILE },
+                                  description = "The document: text, bytes, a 
stream or a file. A Map, a List, a POJO or no"
+                                                + " body fails, and parse 
fails on an empty document"),
+           producerOut = @BodyType(value = Carrier.POJO, javaType = 
"java.io.ByteArrayOutputStream",
+                                   byOption = @BodyType.When(option = 
"operation", value = "detect", carriers = Carrier.TEXT,
+                                                             javaType = 
"java.lang.String"),
+                                   description = "parse gives a 
ByteArrayOutputStream with the content as XHTML, or as HTML or"
+                                                 + " plain text with 
tikaParseOutputFormat, in tikaParseOutputEncoding, and the"
+                                                 + " metadata of the document 
in headers; camel-tika parses HTML and text,"
+                                                 + " other types need their 
Tika parser module. detect gives the media type as"
+                                                 + " text, such as text/html"))
 public class TikaEndpoint extends DefaultEndpoint {
 
     @UriParam
diff --git 
a/components/camel-vertx/camel-vertx-http/src/generated/resources/META-INF/org/apache/camel/component/vertx/http/vertx-http.json
 
b/components/camel-vertx/camel-vertx-http/src/generated/resources/META-INF/org/apache/camel/component/vertx/http/vertx-http.json
index 81042fb956a6..e3091d4173ea 100644
--- 
a/components/camel-vertx/camel-vertx-http/src/generated/resources/META-INF/org/apache/camel/component/vertx/http/vertx-http.json
+++ 
b/components/camel-vertx/camel-vertx-http/src/generated/resources/META-INF/org/apache/camel/component/vertx/http/vertx-http.json
@@ -55,6 +55,10 @@
     "CamelHttpPath": { "index": 6, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Request URI's path, the header will be used to build the 
request URI with the HTTP_URI.", "constantName": 
"org.apache.camel.component.vertx.http.VertxHttpConstants#HTTP_PATH" },
     "Content-Encoding": { "index": 7, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The HTTP content encoding. Is set to provide a content 
encoding, such as gzip.", "constantName": 
"org.apache.camel.component.vertx.http.VertxHttpConstants#CONTENT_ENCODING" }
   },
+  "bodyTypes": {
+    "producerIn": { "carriers": [ "null", "text", "bytes", "stream", "file" ], 
"description": "The request body: text, bytes, a stream or a file (a file as a 
multipart form with multipartUpload), or a Vert.x Buffer, MultiMap (a form) or 
MultipartForm. A Map, a List or a POJO fails: marshal it first. Without 
httpMethod, a query string in the URI or no body sends a GET, and a body a 
POST" },
+    "producerOut": { "carriers": [ "bytes", "null" ], "description": "The 
response body as a byte array, or null for a response without a body. A Vert.x 
Buffer with responsePayloadAsByteArray=false, which stream caching turns into a 
stream" }
+  },
   "properties": {
     "httpUri": { "index": 0, "kind": "path", "displayName": "Http Uri", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.vertx.http.VertxHttpConfiguration", 
"configurationField": "configuration", "description": "The HTTP URI to connect 
to" },
     "bridgeEndpoint": { "index": 1, "kind": "parameter", "displayName": 
"Bridge Endpoint", "group": "producer", "label": "producer", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.vertx.http.VertxHttpConfiguration", 
"configurationField": "configuration", "description": "If the option is true, 
the Exchange.HTTP_URI header will be ignored and the  [...]
diff --git 
a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpEndpoint.java
 
b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpEndpoint.java
index 4da417868706..9c2895e746f8 100644
--- 
a/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpEndpoint.java
+++ 
b/components/camel-vertx/camel-vertx-http/src/main/java/org/apache/camel/component/vertx/http/VertxHttpEndpoint.java
@@ -28,6 +28,9 @@ import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.component.vertx.common.VertxHelper;
 import org.apache.camel.http.base.HttpHelper;
+import org.apache.camel.spi.BodyType;
+import org.apache.camel.spi.BodyType.Carrier;
+import org.apache.camel.spi.BodyTypes;
 import org.apache.camel.spi.EndpointServiceLocation;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -39,6 +42,16 @@ import org.apache.camel.util.ObjectHelper;
 @UriEndpoint(firstVersion = "3.5.0", scheme = "vertx-http", title = "Vert.x 
HTTP Client", syntax = "vertx-http:httpUri",
              category = { Category.HTTP }, producerOnly = true, 
lenientProperties = true,
              headersClass = VertxHttpConstants.class)
+@BodyTypes(producerIn = @BodyType(value = { Carrier.NULL, Carrier.TEXT, 
Carrier.BYTES, Carrier.STREAM, Carrier.FILE },
+                                  description = "The request body: text, 
bytes, a stream or a file (a file as a multipart form"
+                                                + " with multipartUpload), or 
a Vert.x Buffer, MultiMap (a form) or"
+                                                + " MultipartForm. A Map, a 
List or a POJO fails: marshal it first. Without"
+                                                + " httpMethod, a query string 
in the URI or no body sends a GET, and a body a"
+                                                + " POST"),
+           producerOut = @BodyType(value = { Carrier.BYTES, Carrier.NULL },
+                                   description = "The response body as a byte 
array, or null for a response without a body. A"
+                                                 + " Vert.x Buffer with 
responsePayloadAsByteArray=false, which stream caching"
+                                                 + " turns into a stream"))
 public class VertxHttpEndpoint extends DefaultEndpoint implements 
EndpointServiceLocation {
 
     @UriParam
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
index 51a1730eb677..7091f6cb8183 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java
@@ -161,9 +161,9 @@ class CatalogDocsTest {
                 .startsWith("pojo (org.w3c.dom.NodeList). The nodes the 
expression selects. With resultQName=STRING: text"));
 
         // a component that does not declare them has none, rather than a guess
-        JsonObject jdbc = catalogDoc(Map.of("name", "jdbc", "kind", 
"component", "includeOptions", false));
-        assertNull(jdbc.get("bodyTypes"));
-        assertNull(jdbc.get("bodyTypesHint"));
+        JsonObject ldif = catalogDoc(Map.of("name", "ldif", "kind", 
"component", "includeOptions", false));
+        assertNull(ldif.get("bodyTypes"));
+        assertNull(ldif.get("bodyTypesHint"));
     }
 
     @Test
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
index c9b1180d50c3..88695c3f6004 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
@@ -1731,6 +1731,174 @@ public class TextBodyFlowTest {
                 .anySatisfy(m -> assertThat(m).contains("route events: simple 
reads a field of the body (${body[id]})"));
     }
 
+    @Test
+    public void testTheBodyOfQueriesDocumentsAndFiles() {
+        // jdbc, scp, vertx-http, tika, pdf create and graphql without a query 
option need the body as text, bytes, a
+        // stream or a file, so parsed data must be marshalled first (graphql 
with a query does not send the body);
+        // graphql, tika detect, pdf extractText, as2 and the snmp consumer 
give text, and jdbc rows, micrometer (which
+        // keeps the body) and smooks (whatever its config exports) say nothing
+        String yaml = """
+                - route:
+                    id: query
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: jdbc:myDataSource
+                - route:
+                    id: upload
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: scp:localhost:22/upload
+                - route:
+                    id: post
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: vertx-http:http://localhost:8080/orders
+                - route:
+                    id: parse
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: tika:parse
+                - route:
+                    id: print
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: pdf:create
+                - route:
+                    id: ask
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: graphql://http://localhost:8080/graphql
+                - route:
+                    id: variables
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: 
graphql://http://localhost:8080/graphql?query={books{id}}
+                - route:
+                    id: graph
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - to: 
graphql://http://localhost:8080/graphql?query={books{id}}
+                        - setHeader:
+                            name: books
+                            simple: ${body[data]}
+                - route:
+                    id: detect
+                    from:
+                      uri: file:inbox
+                      steps:
+                        - to: tika:detect
+                        - setHeader:
+                            name: type
+                            simple: ${body[type]}
+                - route:
+                    id: extract
+                    from:
+                      uri: file:inbox
+                      steps:
+                        - to: pdf:extractText
+                        - setHeader:
+                            name: title
+                            simple: ${body[title]}
+                - route:
+                    id: partner
+                    from:
+                      uri: as2:server/listen?requestUriPattern=/orders
+                      steps:
+                        - setHeader:
+                            name: id
+                            simple: ${body[id]}
+                - route:
+                    id: trap
+                    from:
+                      uri: snmp:0.0.0.0:162?type=TRAP
+                      steps:
+                        - setHeader:
+                            name: oid
+                            simple: ${body[oid]}
+                - route:
+                    id: rows
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: select * from orders
+                        - to: jdbc:myDataSource
+                        - setHeader:
+                            name: id
+                            simple: ${body[0][ID]}
+                - route:
+                    id: count
+                    from:
+                      uri: timer:tick
+                      steps:
+                        - setBody:
+                            constant: '{"id": 1}'
+                        - unmarshal:
+                            json: {}
+                        - to: micrometer:counter:orders
+                        - setHeader:
+                            name: id
+                            simple: ${body[id]}
+                - route:
+                    id: transform
+                    from:
+                      uri: file:inbox
+                      steps:
+                        - to: smooks:smooks-config.xml
+                        - setHeader:
+                            name: id
+                            simple: ${body[id]}
+                """;
+        assertThat(lines(yaml)).hasSize(11)
+                .anySatisfy(m -> assertThat(m).contains("route query: to: jdbc 
needs the body as text"))
+                .anySatisfy(m -> assertThat(m).contains("route ask: to: 
graphql needs the body as text"))
+                .anySatisfy(m -> assertThat(m).contains("route upload: to: scp 
needs the body as text"))
+                .anySatisfy(m -> assertThat(m).contains("route post: to: 
vertx-http needs the body as text"))
+                .anySatisfy(m -> assertThat(m).contains("route parse: to: tika 
needs the body as text"))
+                .anySatisfy(m -> assertThat(m).contains("route print: to: pdf 
needs the body as text"))
+                .anySatisfy(m -> assertThat(m).contains("route graph: simple 
reads a field of the body (${body[data]})"))
+                .anySatisfy(m -> assertThat(m).contains("route detect: simple 
reads a field of the body (${body[type]})"))
+                .anySatisfy(m -> assertThat(m).contains("route extract: simple 
reads a field of the body (${body[title]})"))
+                .anySatisfy(m -> assertThat(m).contains("route partner: simple 
reads a field of the body (${body[id]})"))
+                .anySatisfy(m -> assertThat(m).contains("route trap: simple 
reads a field of the body (${body[oid]})"));
+    }
+
     @Test
     public void testAnOptionValueInAnotherStyleOfTheEnum() {
         // the catalog and the enum type converter take convert-to-json and 
convertToJson as CONVERT_TO_JSON, so after

Reply via email to