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

davsclaus pushed a commit to branch feature/CAMEL-24710-catalog-checks
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 045d7166dcd7ecf83088eebf7984aed13aab7ca6
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Sep 16 10:07:25 2026 +0200

    CAMEL-24710: docs - the YAML examples pass the catalog checks too, guarded 
by CatalogDocExamplesTest in camel-jbang-core: the checks read a comment after 
a value, a block scalar and a nested map in parameters:, a dotted or prefixed 
header name and name: only under setHeader; the catalog validator accepts 
option.key for a Map option; crypto, solr and box declare the headers their 
examples use; xmlSecurity, metrics, fop and openai examples corrected
    
    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 +-
 .../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 +++
 .../src/main/docs/openai-component.adoc            |  16 +--
 .../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   |  18 ++-
 .../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 +-
 26 files changed, 411 insertions(+), 75 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/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/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-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..957c6e06c0a9 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
@@ -305,7 +305,7 @@ public abstract class AbstractCamelCatalog {
                 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();
+                        && 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-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 f992dd13de86..3d93405485e4 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
@@ -32,6 +32,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;
 
 /**
@@ -148,6 +149,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()) {
@@ -157,11 +161,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