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

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 69345633bc00 CAMEL-24710: docs - YAML examples pass the catalog 
checks, guarded by CatalogDocExamplesTest
69345633bc00 is described below

commit 69345633bc00e61010af7251c1af6269dc1f0765
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Sep 16 11:02:33 2026 +0200

    CAMEL-24710: docs - YAML examples pass the catalog checks, guarded by 
CatalogDocExamplesTest
    
    The four page families already validated against the YAML schema in the
    build; this covers the second half of the ticket: the catalog checks
    (endpoint options, Simple, headers) that camel validate yaml and the
    authoring tools run after the schema. Re-measured on main: 1,820 YAML
    route examples, 87 failing the catalog checks on 28 pages; after this
    change 0, outside the pages skipped for the CAMEL-24748 metadata
    mismatches.
    
    CatalogDocExamplesTest in camel-jbang-core runs every YAML route example
    of every catalog page through SourceValidator.validateCamelYaml, with a
    skip table that cannot go stale. The checkers no longer misread trailing
    comments, block scalars, nested Map options, dotted or prefixed header
    names, or name: under setProperty; validateEndpointProperties accepts the
    map-entry property-binding syntax. Missing header metadata added for
    camel-crypto, camel-solr and camel-box; four doc pages corrected
    (xmlSecurity, metrics, fop, openai). Five further metadata-vs-runtime
    mismatches reported to CAMEL-24748.
    
    Closes #26494
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../org/apache/camel/catalog/components/box.json   |   3 +
 .../apache/camel/catalog/components/crypto.json    |   5 +-
 .../apache/camel/catalog/components/openai.json    |   2 +-
 .../org/apache/camel/catalog/components/solr.json  |   4 +-
 .../apache/camel/catalog/docs/fop-component.adoc   |   8 +-
 .../camel/catalog/docs/metrics-component.adoc      |   8 +-
 .../camel/catalog/docs/openai-component.adoc       |  16 +--
 .../camel/catalog/docs/xmlSecurity-dataformat.adoc |  20 ++--
 .../org/apache/camel/catalog/CamelCatalogTest.java |  13 +++
 .../org/apache/camel/component/openai/openai.json  |   2 +-
 .../src/main/docs/openai-component.adoc            |  16 +--
 .../component/openai/OpenAIConfiguration.java      |   2 +-
 .../org/apache/camel/component/box/box.json        |   3 +
 .../apache/camel/component/box/BoxEndpoint.java    |   3 +-
 .../camel/component/box/internal/BoxConstants.java |   7 +-
 .../org/apache/camel/component/crypto/crypto.json  |   5 +-
 .../crypto/DigitalSignatureConstants.java          |   3 +
 .../camel-fop/src/main/docs/fop-component.adoc     |   8 +-
 .../src/main/docs/metrics-component.adoc           |   8 +-
 .../org/apache/camel/component/solr/solr.json      |   4 +-
 .../apache/camel/component/solr/SolrConstants.java |   6 +
 .../src/main/docs/xmlSecurity-dataformat.adoc      |  20 ++--
 .../camel/catalog/impl/AbstractCamelCatalog.java   |  20 +++-
 .../builder/endpoint/EndpointHeaderBuilders.java   |  14 +++
 .../endpoint/dsl/BoxEndpointBuilderFactory.java    |  38 ++++++
 .../DigitalSignatureEndpointBuilderFactory.java    |  14 +++
 .../endpoint/dsl/OpenAIEndpointBuilderFactory.java |   8 +-
 .../endpoint/dsl/SolrEndpointBuilderFactory.java   |  26 +++++
 .../dsl/jbang/core/commands/ai/EndpointChecks.java |  30 ++++-
 .../dsl/jbang/core/commands/ai/HeaderChecks.java   |  54 ++++++++-
 .../dsl/jbang/core/commands/ai/YamlLines.java      |  27 +++++
 .../core/commands/ai/CatalogDocExamplesTest.java   | 128 +++++++++++++++++++++
 .../commands/ai/SourceValidatorEndpointTest.java   |  58 ++++++++++
 .../dsl/yaml/validator/EipDocExamplesTest.java     |  11 +-
 34 files changed, 511 insertions(+), 83 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/box.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/box.json
index 7327874b58e2..f17f0102eb31 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/box.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/box.json
@@ -45,6 +45,9 @@
     "userName": { "index": 17, "kind": "property", "displayName": "User Name", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.box.BoxConfiguration", "configurationField": 
"configuration", "description": "Box user name, MUST be provided" },
     "userPassword": { "index": 18, "kind": "property", "displayName": "User 
Password", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.box.BoxConfiguration", "configurationField": 
"configuration", "description": "Box user password, MUST be provided if 
authSecureStorage is not set, or returns null on [...]
   },
+  "headers": {
+    "CamelBox.": { "index": 0, "kind": "header", "displayName": "", "group": 
"common", "label": "", "required": false, "javaType": "Object", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The prefix of the headers that carry the parameters of the API 
method: the header CamelBox.fileName holds the fileName parameter.", 
"constantName": 
"org.apache.camel.component.box.internal.BoxConstants#PROPERTY_PREFIX" }
+  },
   "properties": {
     "apiName": { "index": 0, "kind": "path", "displayName": "Api Name", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.box.internal.BoxApiName", "enum": [ 
"COLLABORATIONS", "COMMENTS", "EVENT_LOGS", "FILES", "FOLDERS", "GROUPS", 
"EVENTS", "SEARCH", "TASKS", "USERS" ], "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.box.BoxConfiguration", "configura [...]
     "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.box.BoxConfiguration", "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/crypto.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/crypto.json
index 17f736dc943c..9f14e382ba45 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/crypto.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/crypto.json
@@ -49,8 +49,9 @@
   "headers": {
     "CamelSignaturePrivateKey": { "index": 0, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": 
"java.security.PrivateKey", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The PrivateKey that should 
be used to sign the message", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#SIGNATURE_PRIVATE_KEY"
 },
     "CamelSignaturePublicKeyOrCert": { "index": 1, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "Certificate or PublicKey", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The Certificate or 
PublicKey that should be used to verify the signature", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#SIGNATURE_PUBLIC_KEY_OR_CERT"
 },
-    "CamelSignatureKeyStoreAlias": { "index": 2, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The alias used to query the KeyStore 
for keys and Certificates to be used in signing and verifying exchanges", 
"constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#KEYSTORE_ALIAS" },
-    "CamelSignatureKeyStorePassword": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "char[]", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The password used to access an aliased 
PrivateKey in the KeyStore.", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#KEYSTORE_PASSWORD" 
}
+    "CamelDigitalSignature": { "index": 2, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "byte[] 
(Base64 encoded)", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The signature of the message, set by 
the sign operation and read by the verify operation (the signatureHeaderName 
option changes the header name)", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstant [...]
+    "CamelSignatureKeyStoreAlias": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The alias used to query the KeyStore 
for keys and Certificates to be used in signing and verifying exchanges", 
"constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#KEYSTORE_ALIAS" },
+    "CamelSignatureKeyStorePassword": { "index": 4, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "char[]", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The password used to access an aliased 
PrivateKey in the KeyStore.", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#KEYSTORE_PASSWORD" 
}
   },
   "properties": {
     "cryptoOperation": { "index": 0, "kind": "path", "displayName": "Crypto 
Operation", "group": "producer", "label": "", "required": true, "type": "enum", 
"javaType": "org.apache.camel.component.crypto.CryptoOperation", "enum": [ 
"sign", "verify" ], "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.crypto.DigitalSignatureConfiguration", 
"configurationField": "configuration", "description": "Set the Crypto o [...]
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json
index bcf5441c2d8c..1d7b30fbebc3 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json
@@ -123,7 +123,7 @@
     "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "responses", "responses-retrieve", "responses-cancel", 
"embeddings", "tool-execution", "audio-transcription", "audio-translation", 
"audio-speech", "moderation", "image-generation", "image-edit" ], "deprecated": 
false, "deprecationNote": "", "autowired":  [...]
     "additionalBodyProperty": { "index": 1, "kind": "parameter", 
"displayName": "Additional Body Property", "group": "producer", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalBodyProperty.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "configur [...]
     "additionalHeader": { "index": 2, "kind": "parameter", "displayName": 
"Additional Header", "group": "producer", "label": "", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.Object>", "prefix": "additionalHeader.", "multiValue": true, 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, 
"security": "secret", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"config [...]
-    "additionalResponseHeader": { "index": 3, "kind": "parameter", 
"displayName": "Additional Response Header", "group": "producer", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalResponseHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "co [...]
+    "additionalResponseHeader": { "index": 3, "kind": "parameter", 
"displayName": "Additional Response Header", "group": "producer", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalResponseHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "co [...]
     "apiKey": { "index": 4, "kind": "parameter", "displayName": "Api Key", 
"group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "OpenAI API key. Can also be set via 
OPENAI_API_KEY environment variable." },
     "audioLanguage": { "index": 5, "kind": "parameter", "displayName": "Audio 
Language", "group": "producer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "configuration", "description": "The language of the 
input audio in ISO-639-1 format (e.g., 'en'). Improves accuracy a [...]
     "audioModel": { "index": 6, "kind": "parameter", "displayName": "Audio 
Model", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "The model to use for audio transcription 
(e.g., whisper-1, gpt-4o-transcribe)" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/solr.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/solr.json
index 97c66fc517d0..299fa0fe908c 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/solr.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/solr.json
@@ -47,7 +47,9 @@
     "CamelSolrFrom": { "index": 5, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The starting index of the response.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_FROM" },
     "CamelSolrParams": { "index": 6, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": 
"org.apache.solr.common.params.SolrParams", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
solr parameters to use for the request.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_SOLR_PARAMS" },
     "CamelSolrDeleteByQuery": { "index": 7, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "boolean", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "defaultValue": "false", "description": "For the delete instruction, 
interpret body as query\/queries instead of id\/ids.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_DELETE_BY_QUERY" },
-    "Content-Type": { "index": 8, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content type is used to identify the type when 
inserting files.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_CONTENT_TYPE" }
+    "Content-Type": { "index": 8, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content type is used to identify the type when 
inserting files.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_CONTENT_TYPE" },
+    "CamelSolrField.": { "index": 9, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "Object", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The prefix of the headers that carry the fields of the 
document to insert: the header CamelSolrField.id holds the id field.", 
"constantName": 
"org.apache.camel.component.solr.SolrConstants#HEADER_FIELD_PREFIX" },
+    "CamelSolrParam.": { "index": 10, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The prefix of the headers that carry extra request 
parameters: the header CamelSolrParam.commit holds the commit parameter.", 
"constantName": 
"org.apache.camel.component.solr.SolrConstants#HEADER_PARAM_PREFIX" }
   },
   "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.solr.SolrConfiguration", "configurationField": 
"configuration", "description": "The solr instance host name (set to 'default' 
to use the host name defined on component level)" },
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/fop-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/fop-component.adoc
index 4b8140c6875c..d71438459ecb 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/fop-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/fop-component.adoc
@@ -72,6 +72,8 @@ supported:
 
 The complete list of valid output formats can be found in the 
`MimeConstants.java` source file.
 
+The endpoint URI takes either the name in lower case (`fop:pdf`) or the output 
format (`fop:application/pdf`).
+
 
 // component options: START
 include::partial$component-configure-options.adoc[]
@@ -137,7 +139,7 @@ Java::
 ----
 from("file:source/data/xml")
     .to("xslt:xslt/template.xsl")
-    .to("fop:application/pdf")
+    .to("fop:pdf")
     .to("file:target/data");
 ----
 
@@ -148,7 +150,7 @@ XML::
 <route>
   <from uri="file:source/data/xml"/>
   <to uri="xslt:xslt/template.xsl"/>
-  <to uri="fop:application/pdf"/>
+  <to uri="fop:pdf"/>
   <to uri="file:target/data"/>
 </route>
 ----
@@ -164,7 +166,7 @@ YAML::
         - to:
             uri: xslt:xslt/template.xsl
         - to:
-            uri: fop:application/pdf
+            uri: fop:pdf
         - to:
             uri: file:target/data
 ----
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/metrics-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/metrics-component.adoc
index a70cb8c85cbc..e84bfe571880 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/metrics-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/metrics-component.adoc
@@ -543,9 +543,9 @@ Java::
 +
 [source,java]
 ----
-// marks simple.meter without value
+// marks the simple.meter meter without value
 from("direct:in")
-    .to("metrics:simple.meter")
+    .to("metrics:meter:simple.meter")
     .to("direct:out");
 ----
 
@@ -555,7 +555,7 @@ XML::
 ----
 <route>
   <from uri="direct:in"/>
-  <to uri="metrics:simple.meter"/>
+  <to uri="metrics:meter:simple.meter"/>
   <to uri="direct:out"/>
 </route>
 ----
@@ -569,7 +569,7 @@ YAML::
       uri: direct:in
       steps:
         - to:
-            uri: metrics:simple.meter
+            uri: metrics:meter:simple.meter
         - to:
             uri: direct:out
 ----
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openai-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openai-component.adoc
index 79bd9c3949fa..039ce1f67b1b 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openai-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/openai-component.adoc
@@ -1046,9 +1046,9 @@ Java::
 ----
 from("direct:chat")
     .to("openai:chat-completion?model=qwen3"
-        + "&additionalResponseHeader.reasoning_content=CamelMyReasoning"
-        + "&additionalResponseHeader.custom_field=CamelMyCustomField")
-    .log("Custom reasoning: ${header.CamelMyReasoning}");
+        + "&additionalResponseHeader.reasoning_content=MyReasoning"
+        + "&additionalResponseHeader.custom_field=MyCustomField")
+    .log("Custom reasoning: ${header.MyReasoning}");
 ----
 
 XML::
@@ -1057,8 +1057,8 @@ XML::
 ----
 <route>
   <from uri="direct:chat"/>
-  <to 
uri="openai:chat-completion?model=qwen3&amp;additionalResponseHeader.reasoning_content=CamelMyReasoning&amp;additionalResponseHeader.custom_field=CamelMyCustomField"/>
-  <log message="Custom reasoning: ${header.CamelMyReasoning}"/>
+  <to 
uri="openai:chat-completion?model=qwen3&amp;additionalResponseHeader.reasoning_content=MyReasoning&amp;additionalResponseHeader.custom_field=MyCustomField"/>
+  <log message="Custom reasoning: ${header.MyReasoning}"/>
 </route>
 ----
 
@@ -1074,10 +1074,10 @@ YAML::
             uri: openai:chat-completion
             parameters:
               model: qwen3
-              additionalResponseHeader.reasoning_content: CamelMyReasoning
-              additionalResponseHeader.custom_field: CamelMyCustomField
+              additionalResponseHeader.reasoning_content: MyReasoning
+              additionalResponseHeader.custom_field: MyCustomField
         - log:
-            message: "Custom reasoning: ${header.CamelMyReasoning}"
+            message: "Custom reasoning: ${header.MyReasoning}"
 ----
 ====
 
diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/xmlSecurity-dataformat.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/xmlSecurity-dataformat.adoc
index eaf5a86d81c7..ced411c85754 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/xmlSecurity-dataformat.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/xmlSecurity-dataformat.adoc
@@ -208,7 +208,7 @@ Java::
 ----
 from("direct:start")
     .marshal().xmlSecurity("//cheese:cheesesites/italy", namespaces, true,
-            "recipient", XMLCipher.AES_128_CBC, XMLCipher.RSA_v1dot5, 
trustStoreParams)
+            "recipient", XMLCipher.AES_128, XMLCipher.RSA_v1dot5, 
trustStoreParams)
     .to("...");
 ----
 
@@ -227,8 +227,8 @@ XML::
             <marshal>
                 <xmlSecurity secureTag="//cheese:cheesesites/italy"
                            secureTagContents="true"
-                           
xmlCipherAlgorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc";
-                           
keyCipherAlgorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5";
+                           xmlCipherAlgorithm="AES_128"
+                           keyCipherAlgorithm="RSA_v1dot5"
                            recipientKeyAlias="recipient"
                            keyOrTrustStoreParameters="trustStoreParams"/>
             </marshal>
@@ -247,8 +247,8 @@ YAML::
             xmlSecurity:
               secureTag: "//cheese:cheesesites/italy"
               secureTagContents: true
-              xmlCipherAlgorithm: "http://www.w3.org/2001/04/xmlenc#aes128-cbc";
-              keyCipherAlgorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
+              xmlCipherAlgorithm: AES_128
+              keyCipherAlgorithm: RSA_v1dot5
               recipientKeyAlias: recipient
               keyOrTrustStoreParameters: "#trustStoreParams"
 ----
@@ -265,7 +265,7 @@ Java::
 ----
 from("direct:encrypted")
     .unmarshal().xmlSecurity("//cheese:cheesesites/italy", namespaces, true,
-            "recipient", XMLCipher.AES_128_CBC, XMLCipher.RSA_v1dot5, 
keyStoreParams)
+            "recipient", XMLCipher.AES_128, XMLCipher.RSA_v1dot5, 
keyStoreParams)
     .to("...");
 ----
 
@@ -284,8 +284,8 @@ XML::
             <unmarshal>
                 <xmlSecurity secureTag="//cheese:cheesesites/italy"
                            secureTagContents="true"
-                           
xmlCipherAlgorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc";
-                           
keyCipherAlgorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5";
+                           xmlCipherAlgorithm="AES_128"
+                           keyCipherAlgorithm="RSA_v1dot5"
                            recipientKeyAlias="recipient"
                            keyOrTrustStoreParameters="keyStoreParams"
                            keyPassword="privateKeyPassword" />
@@ -305,8 +305,8 @@ YAML::
             xmlSecurity:
               secureTag: "//cheese:cheesesites/italy"
               secureTagContents: true
-              xmlCipherAlgorithm: "http://www.w3.org/2001/04/xmlenc#aes128-cbc";
-              keyCipherAlgorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
+              xmlCipherAlgorithm: AES_128
+              keyCipherAlgorithm: RSA_v1dot5
               recipientKeyAlias: recipient
               keyOrTrustStoreParameters: "#keyStoreParams"
               keyPassword: privateKeyPassword
diff --git 
a/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java
 
b/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java
index 4fd62a61fc57..e5a7079f4a03 100644
--- 
a/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java
+++ 
b/catalog/camel-catalog/src/test/java/org/apache/camel/catalog/CamelCatalogTest.java
@@ -593,6 +593,19 @@ public class CamelCatalogTest {
         assertEquals("beer", map.get("myPrefix.baz"));
     }
 
+    @Test
+    public void validateMapOptionEntries() {
+        // userMetadata is a Map option: userMetadata.key=value fills an entry 
of the map, as property binding does
+        EndpointValidationResult result = catalog.validateEndpointProperties(
+                
"spring-ai-chat:assistant?chatModel=#myModel&userMetadata.messageId=abc&userMetadata.priority=high");
+        assertTrue(result.isSuccess(), result.summaryErrorMessage(false));
+
+        // the option before the dot must be a Map
+        result = 
catalog.validateEndpointProperties("spring-ai-chat:assistant?chatModel=#myModel&chatModel.foo=abc");
+        assertFalse(result.isSuccess());
+        assertTrue(result.getUnknown().contains("chatModel.foo"));
+    }
+
     @Test
     public void testEndpointPropertiesPlaceholders() throws Exception {
         Map<String, String> map = 
catalog.endpointProperties("timer:foo?period={{howoften}}&repeatCount=5");
diff --git 
a/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json
 
b/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json
index bcf5441c2d8c..1d7b30fbebc3 100644
--- 
a/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json
+++ 
b/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json
@@ -123,7 +123,7 @@
     "operation": { "index": 0, "kind": "path", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.openai.OpenAIOperations", "enum": [ 
"chat-completion", "responses", "responses-retrieve", "responses-cancel", 
"embeddings", "tool-execution", "audio-transcription", "audio-translation", 
"audio-speech", "moderation", "image-generation", "image-edit" ], "deprecated": 
false, "deprecationNote": "", "autowired":  [...]
     "additionalBodyProperty": { "index": 1, "kind": "parameter", 
"displayName": "Additional Body Property", "group": "producer", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalBodyProperty.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "configur [...]
     "additionalHeader": { "index": 2, "kind": "parameter", "displayName": 
"Additional Header", "group": "producer", "label": "", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.Object>", "prefix": "additionalHeader.", "multiValue": true, 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, 
"security": "secret", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"config [...]
-    "additionalResponseHeader": { "index": 3, "kind": "parameter", 
"displayName": "Additional Response Header", "group": "producer", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalResponseHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "co [...]
+    "additionalResponseHeader": { "index": 3, "kind": "parameter", 
"displayName": "Additional Response Header", "group": "producer", "label": "", 
"required": false, "type": "object", "javaType": 
"java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"additionalResponseHeader.", "multiValue": true, "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "co [...]
     "apiKey": { "index": 4, "kind": "parameter", "displayName": "Api Key", 
"group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "OpenAI API key. Can also be set via 
OPENAI_API_KEY environment variable." },
     "audioLanguage": { "index": 5, "kind": "parameter", "displayName": "Audio 
Language", "group": "producer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", 
"configurationField": "configuration", "description": "The language of the 
input audio in ISO-639-1 format (e.g., 'en'). Improves accuracy a [...]
     "audioModel": { "index": 6, "kind": "parameter", "displayName": "Audio 
Model", "group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": 
"configuration", "description": "The model to use for audio transcription 
(e.g., whisper-1, gpt-4o-transcribe)" },
diff --git 
a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc 
b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc
index 79bd9c3949fa..039ce1f67b1b 100644
--- a/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc
+++ b/components/camel-ai/camel-openai/src/main/docs/openai-component.adoc
@@ -1046,9 +1046,9 @@ Java::
 ----
 from("direct:chat")
     .to("openai:chat-completion?model=qwen3"
-        + "&additionalResponseHeader.reasoning_content=CamelMyReasoning"
-        + "&additionalResponseHeader.custom_field=CamelMyCustomField")
-    .log("Custom reasoning: ${header.CamelMyReasoning}");
+        + "&additionalResponseHeader.reasoning_content=MyReasoning"
+        + "&additionalResponseHeader.custom_field=MyCustomField")
+    .log("Custom reasoning: ${header.MyReasoning}");
 ----
 
 XML::
@@ -1057,8 +1057,8 @@ XML::
 ----
 <route>
   <from uri="direct:chat"/>
-  <to 
uri="openai:chat-completion?model=qwen3&amp;additionalResponseHeader.reasoning_content=CamelMyReasoning&amp;additionalResponseHeader.custom_field=CamelMyCustomField"/>
-  <log message="Custom reasoning: ${header.CamelMyReasoning}"/>
+  <to 
uri="openai:chat-completion?model=qwen3&amp;additionalResponseHeader.reasoning_content=MyReasoning&amp;additionalResponseHeader.custom_field=MyCustomField"/>
+  <log message="Custom reasoning: ${header.MyReasoning}"/>
 </route>
 ----
 
@@ -1074,10 +1074,10 @@ YAML::
             uri: openai:chat-completion
             parameters:
               model: qwen3
-              additionalResponseHeader.reasoning_content: CamelMyReasoning
-              additionalResponseHeader.custom_field: CamelMyCustomField
+              additionalResponseHeader.reasoning_content: MyReasoning
+              additionalResponseHeader.custom_field: MyCustomField
         - log:
-            message: "Custom reasoning: ${header.CamelMyReasoning}"
+            message: "Custom reasoning: ${header.MyReasoning}"
 ----
 ====
 
diff --git 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java
 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java
index 654052bad1b3..b086656cd54f 100644
--- 
a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java
+++ 
b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java
@@ -205,7 +205,7 @@ public class OpenAIConfiguration implements Cloneable {
     @UriParam(prefix = "additionalResponseHeader.", multiValue = true)
     @Metadata(description = "Map additional fields from the response message 
to Camel headers. "
                             + "The key is the field name in the API response, 
the value is the Camel header name "
-                            + "(e.g. 
additionalResponseHeader.reasoning_content=CamelMyReasoningHeader)")
+                            + "(e.g. 
additionalResponseHeader.reasoning_content=MyReasoningHeader)")
     private Map<String, Object> additionalResponseHeader;
 
     @UriParam(prefix = "mcpServer.", multiValue = true)
diff --git 
a/components/camel-box/camel-box-component/src/generated/resources/META-INF/org/apache/camel/component/box/box.json
 
b/components/camel-box/camel-box-component/src/generated/resources/META-INF/org/apache/camel/component/box/box.json
index 7327874b58e2..f17f0102eb31 100644
--- 
a/components/camel-box/camel-box-component/src/generated/resources/META-INF/org/apache/camel/component/box/box.json
+++ 
b/components/camel-box/camel-box-component/src/generated/resources/META-INF/org/apache/camel/component/box/box.json
@@ -45,6 +45,9 @@
     "userName": { "index": 17, "kind": "property", "displayName": "User Name", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.box.BoxConfiguration", "configurationField": 
"configuration", "description": "Box user name, MUST be provided" },
     "userPassword": { "index": 18, "kind": "property", "displayName": "User 
Password", "group": "security", "label": "security", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": true, "security": "secret", "configurationClass": 
"org.apache.camel.component.box.BoxConfiguration", "configurationField": 
"configuration", "description": "Box user password, MUST be provided if 
authSecureStorage is not set, or returns null on [...]
   },
+  "headers": {
+    "CamelBox.": { "index": 0, "kind": "header", "displayName": "", "group": 
"common", "label": "", "required": false, "javaType": "Object", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The prefix of the headers that carry the parameters of the API 
method: the header CamelBox.fileName holds the fileName parameter.", 
"constantName": 
"org.apache.camel.component.box.internal.BoxConstants#PROPERTY_PREFIX" }
+  },
   "properties": {
     "apiName": { "index": 0, "kind": "path", "displayName": "Api Name", 
"group": "common", "label": "", "required": true, "type": "enum", "javaType": 
"org.apache.camel.component.box.internal.BoxApiName", "enum": [ 
"COLLABORATIONS", "COMMENTS", "EVENT_LOGS", "FILES", "FOLDERS", "GROUPS", 
"EVENTS", "SEARCH", "TASKS", "USERS" ], "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.box.BoxConfiguration", "configura [...]
     "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.box.BoxConfiguration", "configurationField": 
"configuration", "description": "What sub operation to use for the selected 
operation" },
diff --git 
a/components/camel-box/camel-box-component/src/main/java/org/apache/camel/component/box/BoxEndpoint.java
 
b/components/camel-box/camel-box-component/src/main/java/org/apache/camel/component/box/BoxEndpoint.java
index c533c6c67efb..66e9231ef9f2 100644
--- 
a/components/camel-box/camel-box-component/src/main/java/org/apache/camel/component/box/BoxEndpoint.java
+++ 
b/components/camel-box/camel-box-component/src/main/java/org/apache/camel/component/box/BoxEndpoint.java
@@ -50,7 +50,8 @@ import 
org.apache.camel.support.component.ApiMethodPropertiesHelper;
  */
 @UriEndpoint(firstVersion = "2.14.0", scheme = "box", title = "Box", syntax = 
"box:apiName/methodName",
              apiSyntax = "apiName/methodName",
-             consumerPrefix = "consumer", category = { Category.CLOUD, 
Category.FILE, Category.API }, lenientProperties = true)
+             consumerPrefix = "consumer", category = { Category.CLOUD, 
Category.FILE, Category.API }, lenientProperties = true,
+             headersClass = BoxConstants.class)
 @Metadata(excludeProperties = 
"startScheduler,initialDelay,delay,timeUnit,useFixedDelay,pollStrategy,runLoggingLevel,sendEmptyMessageWhenIdle"
                               + 
",greedy,scheduler,schedulerProperties,scheduledExecutorService,backoffMultiplier,backoffIdleThreshold,backoffErrorThreshold,repeatCount,bridgeErrorHandler")
 public class BoxEndpoint extends AbstractApiEndpoint<BoxApiName, 
BoxConfiguration> {
diff --git 
a/components/camel-box/camel-box-component/src/main/java/org/apache/camel/component/box/internal/BoxConstants.java
 
b/components/camel-box/camel-box-component/src/main/java/org/apache/camel/component/box/internal/BoxConstants.java
index 61223d730729..71653b33851a 100644
--- 
a/components/camel-box/camel-box-component/src/main/java/org/apache/camel/component/box/internal/BoxConstants.java
+++ 
b/components/camel-box/camel-box-component/src/main/java/org/apache/camel/component/box/internal/BoxConstants.java
@@ -16,12 +16,17 @@
  */
 package org.apache.camel.component.box.internal;
 
+import org.apache.camel.spi.Metadata;
+
 /**
  * Constants for Box component.
  */
 public interface BoxConstants {
 
-    // suffix for parameters when passed as exchange header properties
+    // prefix for parameters when passed as exchange header properties
+    @Metadata(description = "The prefix of the headers that carry the 
parameters of the API method: the header"
+                            + " CamelBox.fileName holds the fileName 
parameter.",
+              javaType = "Object")
     String PROPERTY_PREFIX = "CamelBox.";
 
     // thread profile name for this component
diff --git 
a/components/camel-crypto/src/generated/resources/META-INF/org/apache/camel/component/crypto/crypto.json
 
b/components/camel-crypto/src/generated/resources/META-INF/org/apache/camel/component/crypto/crypto.json
index 17f736dc943c..9f14e382ba45 100644
--- 
a/components/camel-crypto/src/generated/resources/META-INF/org/apache/camel/component/crypto/crypto.json
+++ 
b/components/camel-crypto/src/generated/resources/META-INF/org/apache/camel/component/crypto/crypto.json
@@ -49,8 +49,9 @@
   "headers": {
     "CamelSignaturePrivateKey": { "index": 0, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": 
"java.security.PrivateKey", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The PrivateKey that should 
be used to sign the message", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#SIGNATURE_PRIVATE_KEY"
 },
     "CamelSignaturePublicKeyOrCert": { "index": 1, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "Certificate or PublicKey", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The Certificate or 
PublicKey that should be used to verify the signature", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#SIGNATURE_PUBLIC_KEY_OR_CERT"
 },
-    "CamelSignatureKeyStoreAlias": { "index": 2, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The alias used to query the KeyStore 
for keys and Certificates to be used in signing and verifying exchanges", 
"constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#KEYSTORE_ALIAS" },
-    "CamelSignatureKeyStorePassword": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "char[]", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The password used to access an aliased 
PrivateKey in the KeyStore.", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#KEYSTORE_PASSWORD" 
}
+    "CamelDigitalSignature": { "index": 2, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "byte[] 
(Base64 encoded)", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The signature of the message, set by 
the sign operation and read by the verify operation (the signatureHeaderName 
option changes the header name)", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstant [...]
+    "CamelSignatureKeyStoreAlias": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The alias used to query the KeyStore 
for keys and Certificates to be used in signing and verifying exchanges", 
"constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#KEYSTORE_ALIAS" },
+    "CamelSignatureKeyStorePassword": { "index": 4, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "char[]", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The password used to access an aliased 
PrivateKey in the KeyStore.", "constantName": 
"org.apache.camel.component.crypto.DigitalSignatureConstants#KEYSTORE_PASSWORD" 
}
   },
   "properties": {
     "cryptoOperation": { "index": 0, "kind": "path", "displayName": "Crypto 
Operation", "group": "producer", "label": "", "required": true, "type": "enum", 
"javaType": "org.apache.camel.component.crypto.CryptoOperation", "enum": [ 
"sign", "verify" ], "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.crypto.DigitalSignatureConfiguration", 
"configurationField": "configuration", "description": "Set the Crypto o [...]
diff --git 
a/components/camel-crypto/src/main/java/org/apache/camel/component/crypto/DigitalSignatureConstants.java
 
b/components/camel-crypto/src/main/java/org/apache/camel/component/crypto/DigitalSignatureConstants.java
index d94677d737b4..8dea9fda1d68 100644
--- 
a/components/camel-crypto/src/main/java/org/apache/camel/component/crypto/DigitalSignatureConstants.java
+++ 
b/components/camel-crypto/src/main/java/org/apache/camel/component/crypto/DigitalSignatureConstants.java
@@ -27,6 +27,9 @@ public final class DigitalSignatureConstants {
     @Metadata(description = "The Certificate or PublicKey that should be used 
to verify the signature",
               javaType = "Certificate or PublicKey")
     public static final String SIGNATURE_PUBLIC_KEY_OR_CERT = 
"CamelSignaturePublicKeyOrCert";
+    @Metadata(description = "The signature of the message, set by the sign 
operation and read by the verify operation"
+                            + " (the signatureHeaderName option changes the 
header name)",
+              javaType = "byte[] (Base64 encoded)")
     public static final String SIGNATURE = "CamelDigitalSignature";
     @Metadata(description = "The alias used to query the KeyStore for keys and 
Certificates to be\n" +
                             " used in signing and verifying exchanges",
diff --git a/components/camel-fop/src/main/docs/fop-component.adoc 
b/components/camel-fop/src/main/docs/fop-component.adoc
index 4b8140c6875c..d71438459ecb 100644
--- a/components/camel-fop/src/main/docs/fop-component.adoc
+++ b/components/camel-fop/src/main/docs/fop-component.adoc
@@ -72,6 +72,8 @@ supported:
 
 The complete list of valid output formats can be found in the 
`MimeConstants.java` source file.
 
+The endpoint URI takes either the name in lower case (`fop:pdf`) or the output 
format (`fop:application/pdf`).
+
 
 // component options: START
 include::partial$component-configure-options.adoc[]
@@ -137,7 +139,7 @@ Java::
 ----
 from("file:source/data/xml")
     .to("xslt:xslt/template.xsl")
-    .to("fop:application/pdf")
+    .to("fop:pdf")
     .to("file:target/data");
 ----
 
@@ -148,7 +150,7 @@ XML::
 <route>
   <from uri="file:source/data/xml"/>
   <to uri="xslt:xslt/template.xsl"/>
-  <to uri="fop:application/pdf"/>
+  <to uri="fop:pdf"/>
   <to uri="file:target/data"/>
 </route>
 ----
@@ -164,7 +166,7 @@ YAML::
         - to:
             uri: xslt:xslt/template.xsl
         - to:
-            uri: fop:application/pdf
+            uri: fop:pdf
         - to:
             uri: file:target/data
 ----
diff --git a/components/camel-metrics/src/main/docs/metrics-component.adoc 
b/components/camel-metrics/src/main/docs/metrics-component.adoc
index a70cb8c85cbc..e84bfe571880 100644
--- a/components/camel-metrics/src/main/docs/metrics-component.adoc
+++ b/components/camel-metrics/src/main/docs/metrics-component.adoc
@@ -543,9 +543,9 @@ Java::
 +
 [source,java]
 ----
-// marks simple.meter without value
+// marks the simple.meter meter without value
 from("direct:in")
-    .to("metrics:simple.meter")
+    .to("metrics:meter:simple.meter")
     .to("direct:out");
 ----
 
@@ -555,7 +555,7 @@ XML::
 ----
 <route>
   <from uri="direct:in"/>
-  <to uri="metrics:simple.meter"/>
+  <to uri="metrics:meter:simple.meter"/>
   <to uri="direct:out"/>
 </route>
 ----
@@ -569,7 +569,7 @@ YAML::
       uri: direct:in
       steps:
         - to:
-            uri: metrics:simple.meter
+            uri: metrics:meter:simple.meter
         - to:
             uri: direct:out
 ----
diff --git 
a/components/camel-solr/src/generated/resources/META-INF/org/apache/camel/component/solr/solr.json
 
b/components/camel-solr/src/generated/resources/META-INF/org/apache/camel/component/solr/solr.json
index 97c66fc517d0..299fa0fe908c 100644
--- 
a/components/camel-solr/src/generated/resources/META-INF/org/apache/camel/component/solr/solr.json
+++ 
b/components/camel-solr/src/generated/resources/META-INF/org/apache/camel/component/solr/solr.json
@@ -47,7 +47,9 @@
     "CamelSolrFrom": { "index": 5, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "Integer", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The starting index of the response.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_FROM" },
     "CamelSolrParams": { "index": 6, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": 
"org.apache.solr.common.params.SolrParams", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
solr parameters to use for the request.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_SOLR_PARAMS" },
     "CamelSolrDeleteByQuery": { "index": 7, "kind": "header", "displayName": 
"", "group": "producer", "label": "", "required": false, "javaType": "boolean", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "defaultValue": "false", "description": "For the delete instruction, 
interpret body as query\/queries instead of id\/ids.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_DELETE_BY_QUERY" },
-    "Content-Type": { "index": 8, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content type is used to identify the type when 
inserting files.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_CONTENT_TYPE" }
+    "Content-Type": { "index": 8, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content type is used to identify the type when 
inserting files.", "constantName": 
"org.apache.camel.component.solr.SolrConstants#PARAM_CONTENT_TYPE" },
+    "CamelSolrField.": { "index": 9, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "Object", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The prefix of the headers that carry the fields of the 
document to insert: the header CamelSolrField.id holds the id field.", 
"constantName": 
"org.apache.camel.component.solr.SolrConstants#HEADER_FIELD_PREFIX" },
+    "CamelSolrParam.": { "index": 10, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The prefix of the headers that carry extra request 
parameters: the header CamelSolrParam.commit holds the commit parameter.", 
"constantName": 
"org.apache.camel.component.solr.SolrConstants#HEADER_PARAM_PREFIX" }
   },
   "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.solr.SolrConfiguration", "configurationField": 
"configuration", "description": "The solr instance host name (set to 'default' 
to use the host name defined on component level)" },
diff --git 
a/components/camel-solr/src/main/java/org/apache/camel/component/solr/SolrConstants.java
 
b/components/camel-solr/src/main/java/org/apache/camel/component/solr/SolrConstants.java
index d5bfc3073005..1a786de7f013 100644
--- 
a/components/camel-solr/src/main/java/org/apache/camel/component/solr/SolrConstants.java
+++ 
b/components/camel-solr/src/main/java/org/apache/camel/component/solr/SolrConstants.java
@@ -42,7 +42,13 @@ public interface SolrConstants {
     @Metadata(description = "The content type is used to identify the type 
when inserting files.", javaType = "String")
     String PARAM_CONTENT_TYPE = Exchange.CONTENT_TYPE;
 
+    @Metadata(description = "The prefix of the headers that carry the fields 
of the document to insert: the header"
+                            + " CamelSolrField.id holds the id field.",
+              javaType = "Object")
     String HEADER_FIELD_PREFIX = "CamelSolrField.";
+    @Metadata(description = "The prefix of the headers that carry extra 
request parameters: the header"
+                            + " CamelSolrParam.commit holds the commit 
parameter.",
+              javaType = "String")
     String HEADER_PARAM_PREFIX = "CamelSolrParam.";
 
     String PROPERTY_ACTION_CONTEXT = "SolrActionContext";
diff --git 
a/components/camel-xmlsecurity/src/main/docs/xmlSecurity-dataformat.adoc 
b/components/camel-xmlsecurity/src/main/docs/xmlSecurity-dataformat.adoc
index eaf5a86d81c7..ced411c85754 100644
--- a/components/camel-xmlsecurity/src/main/docs/xmlSecurity-dataformat.adoc
+++ b/components/camel-xmlsecurity/src/main/docs/xmlSecurity-dataformat.adoc
@@ -208,7 +208,7 @@ Java::
 ----
 from("direct:start")
     .marshal().xmlSecurity("//cheese:cheesesites/italy", namespaces, true,
-            "recipient", XMLCipher.AES_128_CBC, XMLCipher.RSA_v1dot5, 
trustStoreParams)
+            "recipient", XMLCipher.AES_128, XMLCipher.RSA_v1dot5, 
trustStoreParams)
     .to("...");
 ----
 
@@ -227,8 +227,8 @@ XML::
             <marshal>
                 <xmlSecurity secureTag="//cheese:cheesesites/italy"
                            secureTagContents="true"
-                           
xmlCipherAlgorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc";
-                           
keyCipherAlgorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5";
+                           xmlCipherAlgorithm="AES_128"
+                           keyCipherAlgorithm="RSA_v1dot5"
                            recipientKeyAlias="recipient"
                            keyOrTrustStoreParameters="trustStoreParams"/>
             </marshal>
@@ -247,8 +247,8 @@ YAML::
             xmlSecurity:
               secureTag: "//cheese:cheesesites/italy"
               secureTagContents: true
-              xmlCipherAlgorithm: "http://www.w3.org/2001/04/xmlenc#aes128-cbc";
-              keyCipherAlgorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
+              xmlCipherAlgorithm: AES_128
+              keyCipherAlgorithm: RSA_v1dot5
               recipientKeyAlias: recipient
               keyOrTrustStoreParameters: "#trustStoreParams"
 ----
@@ -265,7 +265,7 @@ Java::
 ----
 from("direct:encrypted")
     .unmarshal().xmlSecurity("//cheese:cheesesites/italy", namespaces, true,
-            "recipient", XMLCipher.AES_128_CBC, XMLCipher.RSA_v1dot5, 
keyStoreParams)
+            "recipient", XMLCipher.AES_128, XMLCipher.RSA_v1dot5, 
keyStoreParams)
     .to("...");
 ----
 
@@ -284,8 +284,8 @@ XML::
             <unmarshal>
                 <xmlSecurity secureTag="//cheese:cheesesites/italy"
                            secureTagContents="true"
-                           
xmlCipherAlgorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc";
-                           
keyCipherAlgorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5";
+                           xmlCipherAlgorithm="AES_128"
+                           keyCipherAlgorithm="RSA_v1dot5"
                            recipientKeyAlias="recipient"
                            keyOrTrustStoreParameters="keyStoreParams"
                            keyPassword="privateKeyPassword" />
@@ -305,8 +305,8 @@ YAML::
             xmlSecurity:
               secureTag: "//cheese:cheesesites/italy"
               secureTagContents: true
-              xmlCipherAlgorithm: "http://www.w3.org/2001/04/xmlenc#aes128-cbc";
-              keyCipherAlgorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5";
+              xmlCipherAlgorithm: AES_128
+              keyCipherAlgorithm: RSA_v1dot5
               recipientKeyAlias: recipient
               keyOrTrustStoreParameters: "#keyStoreParams"
               keyPassword: privateKeyPassword
diff --git 
a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java
 
b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java
index 2f44c34ceb89..8d61163bf2ff 100644
--- 
a/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java
+++ 
b/core/camel-core-catalog/src/main/java/org/apache/camel/catalog/impl/AbstractCamelCatalog.java
@@ -304,8 +304,8 @@ public abstract class AbstractCamelCatalog {
                 boolean valuePlaceholder = value.startsWith("{{") || 
value.startsWith("${") || value.startsWith("$simple{");
                 boolean lookup = value.startsWith("#") && value.length() > 1;
                 // we cannot evaluate multi values as strict as the others, as 
we don't know their expected types
-                boolean multiValue = prefix != null && 
originalName.startsWith(prefix)
-                        && row.isMultiValue();
+                boolean multiValue = (prefix != null && 
originalName.startsWith(prefix) && row.isMultiValue())
+                        || isMapEntry(row, originalName);
 
                 // default value
                 Object defaultValue = row.getDefaultValue();
@@ -1844,9 +1844,25 @@ public abstract class AbstractCamelCatalog {
                 return row.getName();
             }
         }
+        int dot = name.indexOf('.');
+        if (dot > 0) {
+            BaseOptionModel row = rows.get(name.substring(0, dot));
+            if (row != null && isMapEntry(row, name)) {
+                return row.getName();
+            }
+        }
         return null;
     }
 
+    /**
+     * Whether the name sets an entry of a Map option 
(userMetadata.messageId=x fills the userMetadata map), as property
+     * binding does.
+     */
+    private static boolean isMapEntry(BaseOptionModel row, String name) {
+        String javaType = row.getJavaType();
+        return javaType != null && javaType.startsWith("java.util.Map") && 
name.startsWith(row.getName() + ".");
+    }
+
     /**
      * Converts the string from dash format into camel case (hello-great-world 
-> helloGreatWorld)
      *
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointHeaderBuilders.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointHeaderBuilders.java
index 8953cc8da21e..104188aba41c 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointHeaderBuilders.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/EndpointHeaderBuilders.java
@@ -839,6 +839,20 @@ public class EndpointHeaderBuilders {
     public static QueueEndpointBuilderFactory.QueueHeaderNameBuilder 
azureStorageQueue() {
         return QueueEndpointBuilderFactory.QueueHeaderNameBuilder.INSTANCE;
     }
+    /**
+     * Box (camel-box)
+     * Upload, download and manage files, folders, groups, collaborations, etc.
+     * on box.com.
+     * 
+     * Category: cloud,file,api
+     * Since: 2.14
+     * Maven coordinates: org.apache.camel:camel-box
+     * 
+     * @return the dsl builder for the headers' name.
+     */
+    public static BoxEndpointBuilderFactory.BoxHeaderNameBuilder box() {
+        return BoxEndpointBuilderFactory.BoxHeaderNameBuilder.INSTANCE;
+    }
     /**
      * Caffeine Cache (camel-caffeine)
      * Perform caching operations using Caffeine Cache.
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/BoxEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/BoxEndpointBuilderFactory.java
index e0b3719adac0..8a8e7f7292e7 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/BoxEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/BoxEndpointBuilderFactory.java
@@ -1150,6 +1150,20 @@ public interface BoxEndpointBuilderFactory {
     }
 
     public interface BoxBuilders {
+        /**
+         * Box (camel-box)
+         * Upload, download and manage files, folders, groups, collaborations,
+         * etc. on box.com.
+         * 
+         * Category: cloud,file,api
+         * Since: 2.14
+         * Maven coordinates: org.apache.camel:camel-box
+         * 
+         * @return the dsl builder for the headers' name.
+         */
+        default BoxHeaderNameBuilder box() {
+            return BoxHeaderNameBuilder.INSTANCE;
+        }
         /**
          * Box (camel-box)
          * Upload, download and manage files, folders, groups, collaborations,
@@ -1206,6 +1220,30 @@ public interface BoxEndpointBuilderFactory {
         }
 
     }
+    /**
+     * The builder of headers' name for the Box component.
+     */
+    public static class BoxHeaderNameBuilder {
+        /**
+         * The internal instance of the builder used to access to all the
+         * methods representing the name of headers.
+         */
+        public static final BoxHeaderNameBuilder INSTANCE = new 
BoxHeaderNameBuilder();
+
+        /**
+         * The prefix of the headers that carry the parameters of the API
+         * method: the header CamelBox.fileName holds the fileName parameter.
+         * 
+         * The option is a: {@code Object} type.
+         * 
+         * Group: common
+         * 
+         * @return the name of the header {@code Box.}.
+         */
+        public String box() {
+            return "CamelBox.";
+        }
+    }
     static BoxEndpointBuilder endpointBuilder(String componentName, String 
path) {
         class BoxEndpointBuilderImpl extends AbstractEndpointBuilder 
implements BoxEndpointBuilder, AdvancedBoxEndpointBuilder {
             public BoxEndpointBuilderImpl(String path) {
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/DigitalSignatureEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/DigitalSignatureEndpointBuilderFactory.java
index a6f5bce2df50..18a8da68f095 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/DigitalSignatureEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/DigitalSignatureEndpointBuilderFactory.java
@@ -630,6 +630,20 @@ public interface DigitalSignatureEndpointBuilderFactory {
         public String signaturePublicKeyOrCert() {
             return "CamelSignaturePublicKeyOrCert";
         }
+        /**
+         * The signature of the message, set by the sign operation and read by
+         * the verify operation (the signatureHeaderName option changes the
+         * header name).
+         * 
+         * The option is a: {@code byte[] (Base64 encoded)} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code DigitalSignature}.
+         */
+        public String digitalSignature() {
+            return "CamelDigitalSignature";
+        }
         /**
          * The alias used to query the KeyStore for keys and Certificates to be
          * used in signing and verifying exchanges.
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java
index ea7ea1add6b1..054189633b23 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java
@@ -133,8 +133,8 @@ public interface OpenAIEndpointBuilderFactory {
          * Map additional fields from the response message to Camel headers. 
The
          * key is the field name in the API response, the value is the Camel
          * header name (e.g.
-         * additionalResponseHeader.reasoning_content=CamelMyReasoningHeader).
-         * This is a multi-value option with prefix: additionalResponseHeader.
+         * additionalResponseHeader.reasoning_content=MyReasoningHeader). This
+         * is a multi-value option with prefix: additionalResponseHeader.
          * 
          * The option is a: <code>java.util.Map&lt;java.lang.String,
          * java.lang.Object&gt;</code> type.
@@ -156,8 +156,8 @@ public interface OpenAIEndpointBuilderFactory {
          * Map additional fields from the response message to Camel headers. 
The
          * key is the field name in the API response, the value is the Camel
          * header name (e.g.
-         * additionalResponseHeader.reasoning_content=CamelMyReasoningHeader).
-         * This is a multi-value option with prefix: additionalResponseHeader.
+         * additionalResponseHeader.reasoning_content=MyReasoningHeader). This
+         * is a multi-value option with prefix: additionalResponseHeader.
          * 
          * The option is a: <code>java.util.Map&lt;java.lang.String,
          * java.lang.Object&gt;</code> type.
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SolrEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SolrEndpointBuilderFactory.java
index 81a85bbfd441..8c8b9c6498cb 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SolrEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SolrEndpointBuilderFactory.java
@@ -719,6 +719,32 @@ public interface SolrEndpointBuilderFactory {
         public String contentType() {
             return "Content-Type";
         }
+        /**
+         * The prefix of the headers that carry the fields of the document to
+         * insert: the header CamelSolrField.id holds the id field.
+         * 
+         * The option is a: {@code Object} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code SolrField.}.
+         */
+        public String solrfield() {
+            return "CamelSolrField.";
+        }
+        /**
+         * The prefix of the headers that carry extra request parameters: the
+         * header CamelSolrParam.commit holds the commit parameter.
+         * 
+         * The option is a: {@code String} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code SolrParam.}.
+         */
+        public String solrparam() {
+            return "CamelSolrParam.";
+        }
     }
     static SolrEndpointBuilder endpointBuilder(String componentName, String 
path) {
         class SolrEndpointBuilderImpl extends AbstractEndpointBuilder 
implements SolrEndpointBuilder, AdvancedSolrEndpointBuilder {
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/EndpointChecks.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/EndpointChecks.java
index ccb1273dbef8..9c0aceb7905b 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/EndpointChecks.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/EndpointChecks.java
@@ -34,6 +34,7 @@ import static 
org.apache.camel.dsl.jbang.core.commands.ai.YamlLines.YAML_URI_PAT
 import static 
org.apache.camel.dsl.jbang.core.commands.ai.YamlLines.countLeadingSpaces;
 import static 
org.apache.camel.dsl.jbang.core.commands.ai.YamlLines.extractEipFromLine;
 import static 
org.apache.camel.dsl.jbang.core.commands.ai.YamlLines.findParentEip;
+import static 
org.apache.camel.dsl.jbang.core.commands.ai.YamlLines.stripComment;
 import static org.apache.camel.dsl.jbang.core.commands.ai.YamlLines.unquote;
 
 /**
@@ -150,6 +151,9 @@ final class EndpointChecks {
                 String nextTrimmed = next.trim();
                 if (nextIndent == lineIndent && 
nextTrimmed.startsWith("parameters:")) {
                     int paramBlockIndent = nextIndent;
+                    int blockScalarIndent = -1;
+                    String mapKey = null;
+                    int mapIndent = -1;
                     for (int k = j + 1; k < lines.length; k++) {
                         String paramLine = lines[k];
                         if (paramLine.isBlank()) {
@@ -159,11 +163,33 @@ final class EndpointChecks {
                         if (paramIndent <= paramBlockIndent) {
                             break;
                         }
+                        if (blockScalarIndent >= 0 && paramIndent > 
blockScalarIndent) {
+                            // the lines of a block scalar (argSchema: | 
followed by JSON) are its value, not options
+                            continue;
+                        }
+                        blockScalarIndent = -1;
+                        if (mapKey != null && paramIndent <= mapIndent) {
+                            mapKey = null;
+                        }
                         String paramTrimmed = paramLine.trim();
                         int colonPos = paramTrimmed.indexOf(':');
                         if (colonPos > 0) {
-                            String key = paramTrimmed.substring(0, 
colonPos).trim();
-                            String val = 
unquote(paramTrimmed.substring(colonPos + 1).trim());
+                            String key = unquote(paramTrimmed.substring(0, 
colonPos).trim());
+                            String val = 
unquote(stripComment(paramTrimmed.substring(colonPos + 1).trim()));
+                            if (mapKey != null) {
+                                // headers: with foo: bar under it is the 
entry foo of the headers map option
+                                key = mapKey + "." + key;
+                            } else if (val.isEmpty() && k + 1 < lines.length
+                                    && countLeadingSpaces(lines[k + 1]) > 
paramIndent) {
+                                mapKey = key;
+                                mapIndent = paramIndent;
+                                continue;
+                            }
+                            if (YamlLines.isBlockScalarIndicator(val)) {
+                                // the option is checked by name; its value is 
the block that follows
+                                blockScalarIndent = paramIndent;
+                                val = "";
+                            }
                             char sep = hasParams ? '&' : '?';
                             
uriBuilder.append(sep).append(key).append('=').append(val);
                             hasParams = true;
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/HeaderChecks.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/HeaderChecks.java
index 15d785f8aebf..23fd298f82d2 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/HeaderChecks.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/HeaderChecks.java
@@ -40,7 +40,7 @@ final class HeaderChecks {
     }
 
     static final Pattern CAMEL_HEADER_REF_PATTERN = Pattern.compile(
-            
"(?:\\$\\{headers?\\.|headers\\.|headers\\[['\"]|header\\(['\"]|name:\\s*['\"]?)(Camel[A-Z][A-Za-z0-9]*)");
+            
"(?:\\$\\{headers?\\.|headers\\.|headers\\[['\"]|header\\(['\"]|(name):\\s*['\"]?)(Camel[A-Z][A-Za-z0-9]*(?:\\.[A-Za-z0-9_]+)*)");
 
     static final Pattern SCHEME_IN_URI_PATTERN = 
Pattern.compile("uri:\\s*\"?([a-zA-Z][a-zA-Z0-9+.-]*):");
 
@@ -100,8 +100,12 @@ final class HeaderChecks {
         for (int i = 0; i < lines.length; i++) {
             Matcher m = CAMEL_HEADER_REF_PATTERN.matcher(lines[i]);
             while (m.find()) {
-                String name = m.group(1);
-                if (common.contains(name) || reported.contains(name)) {
+                if (m.group(1) != null && !isHeaderName(lines, i)) {
+                    // name: of a setProperty, setVariable, bean...: not a 
header
+                    continue;
+                }
+                String name = m.group(2);
+                if (common.contains(name) || reported.contains(name) || 
isKnown(name, known)) {
                     continue;
                 }
                 String propertyOwner = null;
@@ -117,7 +121,7 @@ final class HeaderChecks {
                              + ", not a header (the header would be null): 
write ${exchangeProperty." + name + "}");
                     continue;
                 }
-                if (known.contains(name) || !reported.add(name)) {
+                if (!reported.add(name)) {
                     continue;
                 }
                 String best = closestName(name, new ArrayList<>(known));
@@ -142,4 +146,46 @@ final class HeaderChecks {
         return msgs;
     }
 
+    /**
+     * A header the metadata lists: as is (CamelBox.fileName), by a prefix the 
component documents with a trailing dot
+     * (CamelSolrField. for CamelSolrField.id), or as the head of an OGNL path 
(CamelFileName.length()).
+     */
+    static boolean isKnown(String name, Set<String> known) {
+        String candidate = name;
+        while (true) {
+            if (known.contains(candidate)) {
+                return true;
+            }
+            for (String k : known) {
+                if (k.endsWith(".") && candidate.startsWith(k)) {
+                    return true;
+                }
+            }
+            int dot = candidate.lastIndexOf('.');
+            if (dot < 0) {
+                return false;
+            }
+            candidate = candidate.substring(0, dot);
+        }
+    }
+
+    /** Whether the name: on this line belongs to a setHeader or removeHeader 
step, not a setProperty, a bean... */
+    static boolean isHeaderName(String[] lines, int index) {
+        int indent = YamlLines.countLeadingSpaces(lines[index]);
+        for (int j = index - 1; j >= 0; j--) {
+            String line = lines[j];
+            if (line.isBlank() || line.trim().startsWith("#")) {
+                continue;
+            }
+            if (YamlLines.countLeadingSpaces(line) < indent) {
+                String step = line.trim();
+                if (step.startsWith("- ")) {
+                    step = step.substring(2).trim();
+                }
+                return step.startsWith("setHeader:") || 
step.startsWith("removeHeader:");
+            }
+        }
+        return false;
+    }
+
 }
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/YamlLines.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/YamlLines.java
index 0220b2ee7b86..0f245b07c3d7 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/YamlLines.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/YamlLines.java
@@ -130,6 +130,33 @@ final class YamlLines {
         return unquote(trimmed.substring(prefix.length()).trim());
     }
 
+    /**
+     * A scalar without the YAML comment that may follow it: {@code 30000 # 
the default is 300000} is 30000, and a
+     * quoted scalar keeps a # inside its quotes.
+     */
+    static String stripComment(String val) {
+        if (val.isEmpty()) {
+            return val;
+        }
+        char quote = val.charAt(0);
+        if (quote == '"' || quote == '\'') {
+            int close = val.indexOf(quote, 1);
+            return close > 0 ? val.substring(0, close + 1) : val;
+        }
+        for (int i = 1; i < val.length(); i++) {
+            if (val.charAt(i) == '#' && Character.isWhitespace(val.charAt(i - 
1))) {
+                return val.substring(0, i).stripTrailing();
+            }
+        }
+        return val;
+    }
+
+    /** Whether a value is the indicator of a block scalar: |, >, and the 
variants with a chomping or indent hint. */
+    static boolean isBlockScalarIndicator(String val) {
+        return !val.isEmpty() && (val.charAt(0) == '|' || val.charAt(0) == 
'>') && val.length() <= 3
+                && val.substring(1).chars().allMatch(c -> c == '-' || c == '+' 
|| Character.isDigit(c));
+    }
+
     static String unquote(String val) {
         if (val.length() >= 2 && val.startsWith("\"") && val.endsWith("\"")) {
             return val.substring(1, val.length() - 1);
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocExamplesTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocExamplesTest.java
new file mode 100644
index 000000000000..609a2682d77b
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocExamplesTest.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.ai;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * CAMEL-24710: every YAML route example of the documentation passes the 
checks {@code camel validate yaml} and the
+ * authoring tools run after the schema: endpoint URIs and their options, 
Simple expressions and Camel headers against
+ * the catalog. The schema itself is guarded by EipDocExamplesTest in 
camel-yaml-dsl-validator.
+ */
+class CatalogDocExamplesTest {
+
+    private static final Pattern YAML_BLOCK = 
Pattern.compile("\\[source,yaml\\]\\n-{4}\\n(.*?)\\n-{4}", Pattern.DOTALL);
+
+    /**
+     * Pages whose examples are right for the runtime but fail the catalog 
because the component metadata disagrees with
+     * the component (CAMEL-24748 and the notes on it); checked again when the 
metadata is fixed.
+     */
+    private static final Map<String, String> PAGES_SKIPPED = Map.ofEntries(
+            Map.entry("azure-storage-datalake-component", "CAMEL-24748: the 
operation enum lists 2 of 15 values"),
+            Map.entry("google-secret-manager-component", "CAMEL-24748: the 
operation enum lists 1 of 4 values"),
+            Map.entry("google-storage-component", "CAMEL-24748: objectName is 
labelled producer, the consumer uses it"),
+            Map.entry("web3j-component", "CAMEL-24748: operation is labelled 
producer, the consumer uses it"),
+            Map.entry("grpc-component", "CAMEL-24748: forwardOnError and 
forwardOnCompleted are labelled consumer"),
+            Map.entry("netty-http-component", "CAMEL-24748: 
bootstrapConfiguration is not in the metadata"),
+            Map.entry("jt400-component", "CAMEL-24748: the output options have 
no @UriParam; the syntax has literal"
+                                         + " segments (QSYS.LIB, 
objectPath.type) the catalog reads as options"),
+            Map.entry("olingo2-component", "CAMEL-24748: the syntax is 
apiName/methodName, the runtime reads"
+                                           + " methodName/resourcePath with 
the api name implicit"),
+            Map.entry("olingo4-component", "CAMEL-24748: the syntax is 
apiName/methodName, the runtime reads"
+                                           + " methodName/resourcePath with 
the api name implicit"),
+            Map.entry("xmpp-component", "CAMEL-24748: port is required in the 
metadata, the runtime defaults it and"
+                                        + " takes a user@ prefix on the host"),
+            Map.entry("huggingface-component", "CAMEL-24748: task is an enum 
in the metadata, the runtime takes any"
+                                               + " name with predictorBean"),
+            Map.entry("salesforce-rest-api", "CAMEL-24748: approval.* has no 
@UriParam"));
+
+    /** Examples that show what only the runtime knows, by page and a text 
found in the example. */
+    private static final Map<String, String> EXAMPLES_SKIPPED = Map.of(
+            "simple-advanced", "${foo", // a custom simple function registered 
at runtime
+            "yaml-dsl", "myStep:"); // a step contributed by a custom YAML 
deserializer
+
+    private static CamelCatalog catalog;
+
+    private record DocExamples(int examples, List<String> failures) {
+    }
+
+    @BeforeAll
+    static void setup() {
+        catalog = new DefaultCamelCatalog();
+    }
+
+    @Test
+    void everyYamlExampleOfTheDocumentationPassesTheCatalogChecks() {
+        List<String> pages = new ArrayList<>();
+        for (String name : catalog.findDocNames()) {
+            if (!PAGES_SKIPPED.containsKey(name)) {
+                pages.add(name);
+            }
+        }
+        DocExamples result = validate(pages);
+        assertThat(result.examples()).as("YAML route examples found in the 
documentation").isGreaterThan(1700);
+        assertThat(result.failures()).as("Documentation examples that fail the 
catalog checks").isEmpty();
+    }
+
+    @Test
+    void theSkippedPagesStillExist() {
+        for (String page : PAGES_SKIPPED.keySet()) {
+            assertThat(catalog.asciiDoc(page)).as("the skipped page %s (drop 
the entry when it is gone)", page).isNotNull();
+        }
+    }
+
+    private static DocExamples validate(List<String> pages) {
+        int examples = 0;
+        List<String> failures = new ArrayList<>();
+        for (String page : pages) {
+            String doc = catalog.asciiDoc(page);
+            if (doc == null) {
+                continue;
+            }
+            int n = 0;
+            Matcher m = YAML_BLOCK.matcher(doc);
+            while (m.find()) {
+                String yaml = m.group(1).stripTrailing() + "\n";
+                if (!yaml.stripLeading().startsWith("- ")) {
+                    // a fragment (an option list, a snippet), not a route file
+                    continue;
+                }
+                n++;
+                String skipped = EXAMPLES_SKIPPED.get(page);
+                if (skipped != null && yaml.contains(skipped)) {
+                    continue;
+                }
+                examples++;
+                for (String msg : SourceValidator.validateCamelYaml(yaml, 
catalog)) {
+                    failures.add(page + " example " + n + ": " + msg);
+                }
+            }
+        }
+        return new DocExamples(examples, failures);
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorEndpointTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorEndpointTest.java
index 911d3a3c7fa3..a9694ee8908b 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorEndpointTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/SourceValidatorEndpointTest.java
@@ -398,6 +398,64 @@ class SourceValidatorEndpointTest {
                 .contains("${exchangeProperty.CamelTimerCounter}");
     }
 
+    @Test
+    void aPropertyOrBeanNameIsNotAHeader() {
+        // CAMEL-24710: name: counts as a header only under 
setHeader/removeHeader; a dotted name is looked up as is,
+        // by the prefix the component documents (CamelSolrField.), and as the 
head of an OGNL path
+        List<String> msgs = SourceValidator.validateKnownHeaders("""
+                - beans:
+                    - name: CamelMyBean
+                      type: "#class:com.example.MyBean"
+                - from:
+                    uri: "file:in?noop=true"
+                    steps:
+                      - setProperty:
+                          name: CamelAwsSqsDeleteFiltered
+                          constant: "true"
+                      - setHeader:
+                          name: CamelSolrField.id
+                          simple: "${body}"
+                      - log: "${header.CamelFileName.length()} 
${header.CamelFileNam.length()}"
+                      - to:
+                          uri: solr:localhost:8983/mycollection
+                """, catalog);
+        assertThat(msgs).hasSize(1);
+        assertThat(msgs.get(0)).contains("header CamelFileNam.length is not 
set by").contains("did you mean CamelFileLength");
+    }
+
+    @Test
+    void aCommentABlockScalarAndANestedMapInTheParametersAreRead() {
+        // CAMEL-24710: a comment after a value is not the value; the body of 
a block scalar is not options; the keys
+        // under a Map option are its entries
+        List<String> msgs = SourceValidator.validateYamlEndpoints("""
+                - from:
+                    uri: ai-tool:createOrder
+                    parameters:
+                      description: "Create an order"
+                      argSchema: |
+                        {
+                          "type": "object",
+                          "properties": { "id": { "type": "string" } }
+                        }
+                    steps:
+                      - to:
+                          uri: log:out
+                          parameters:
+                            groupSize: 30000          # the default is none
+                            showAll: true
+                      - to:
+                          uri: once
+                          parameters:
+                            name: hello
+                            headers:
+                              foo: foolish
+                              bar: 456
+                            unknownOne: x
+                """, catalog);
+        assertThat(msgs).hasSize(1);
+        assertThat(msgs.get(0)).contains("Unknown option 'unknownOne'");
+    }
+
     @Test
     void aProducerOnlyComponentInFromIsNamed() {
         List<String> msgs = SourceValidator.validateYamlEndpoints("""
diff --git 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/EipDocExamplesTest.java
 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/EipDocExamplesTest.java
index 505ec1386e95..248ea4363421 100644
--- 
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/EipDocExamplesTest.java
+++ 
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/EipDocExamplesTest.java
@@ -19,7 +19,6 @@ package org.apache.camel.dsl.yaml.validator;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.function.Predicate;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -48,13 +47,6 @@ class EipDocExamplesTest {
             "point-to-point-channel", "publish-subscribe-channel", 
"return-address", "scatter-gather",
             "selective-consumer", "service-activator", "transactional-client");
 
-    /**
-     * The xmlSecurity examples write the cipher algorithms as the URIs the 
data format hands to XMLCipher, while the
-     * model's enums list the XMLCipher constant names, which XMLCipher 
rejects (CAMEL-24716). The page is checked again
-     * once the model accepts what the data format does.
-     */
-    private static final Set<String> DATA_FORMAT_PAGES_SKIPPED = 
Set.of("xmlSecurity-dataformat");
-
     private static final Pattern YAML_BLOCK = 
Pattern.compile("\\[source,yaml\\]\\n-{4}\\n(.*?)\\n-{4}", Pattern.DOTALL);
 
     /**
@@ -100,8 +92,7 @@ class EipDocExamplesTest {
 
     @Test
     void everyYamlExampleOfTheDataFormatDocumentationValidates() throws 
Exception {
-        List<String> pages
-                = docNames(name -> name.endsWith("-dataformat") && 
!DATA_FORMAT_PAGES_SKIPPED.contains(name));
+        List<String> pages = docNames(name -> name.endsWith("-dataformat"));
 
         DocExamples result = validate(pages);
 

Reply via email to