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

davsclaus pushed a commit to branch fix/CAMEL-25901
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 31a5cc6f981d5a1bdb1d684e41628d783ee94533
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Oct 21 07:48:18 2026 +0200

    CAMEL-25901: camel-jms - docs: a request-reply example in Java, XML and 
YAML, and the AI tools say to use InOut instead of setting JMSReplyTo
    
    - jms docs: "Sending a request and waiting for the reply" (Java, XML, YAML) 
after the first example: the caller sends
      with pattern InOut and variableReceive, the service route's last body is 
the reply, and Camel sets JMSReplyTo; it is
      the second jms sample. The filter example moves to "Routing JMS 
messages"; "Request-reply over JMS" points to it.
    - The header check: a header name with Reply that is not set 
(CamelJmsReplyTo) gets the request-reply hint (pattern:
      InOut on the to:, do not set JMSReplyTo), not "did you mean JMSReplyTo?".
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Claude-Session: https://claude.ai/code/session_01STT6whBgK1AqsSsUKrnE8m
---
 .../apache/camel/catalog/docs/jms-component.adoc   | 86 +++++++++++++++++++++-
 .../camel-jms/src/main/docs/jms-component.adoc     | 86 +++++++++++++++++++++-
 .../dsl/jbang/core/commands/ai/HeaderChecks.java   | 12 ++-
 .../commands/ai/SourceValidatorEndpointTest.java   | 19 +++++
 4 files changed, 200 insertions(+), 3 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jms-component.adoc
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jms-component.adoc
index aaba25bf786a..4b1a7e9c1af3 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jms-component.adoc
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/jms-component.adoc
@@ -323,6 +323,88 @@ YAML::
 ----
 ====
 
+=== Sending a request and waiting for the reply
+
+To send a request and wait for its reply, the caller sends with the `InOut` 
exchange pattern, and the service is a
+route that consumes the queue: the body at the end of its route is the reply. 
Camel creates a temporary reply queue
+and sets `JMSReplyTo` itself, so do not set the `replyTo` option or a 
`JMSReplyTo` header for this. With
+`variableReceive`, the reply goes into a variable, and the body is kept:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("timer:order?repeatCount=1")
+  .setBody(constant("{\"orderId\": \"ORD-1001\", \"sku\": \"CAMEL-MUG\"}"))
+  .setExchangePattern(ExchangePattern.InOut)
+  .toV("jms:queue:stock", null, "stockReply")
+  .log("Order ${body} got the reply ${variable.stockReply}");
+
+from("jms:queue:stock")
+  .log("Stock service got ${body}")
+  .setBody(constant("{\"reserved\": true}"));
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+  <from uri="timer:order?repeatCount=1"/>
+  <setBody>
+    <constant>{"orderId": "ORD-1001", "sku": "CAMEL-MUG"}</constant>
+  </setBody>
+  <to uri="jms:queue:stock" pattern="InOut" variableReceive="stockReply"/>
+  <log message="Order ${body} got the reply ${variable.stockReply}"/>
+</route>
+<route>
+  <from uri="jms:queue:stock"/>
+  <log message="Stock service got ${body}"/>
+  <setBody>
+    <constant>{"reserved": true}</constant>
+  </setBody>
+</route>
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+    from:
+      uri: timer:order
+      parameters:
+        repeatCount: 1
+      steps:
+        - setBody:
+            expression:
+              constant:
+                expression: '{"orderId": "ORD-1001", "sku": "CAMEL-MUG"}'
+        - to:
+            uri: jms:queue:stock
+            pattern: InOut
+            variableReceive: stockReply
+        - log:
+            message: "Order ${body} got the reply ${variable.stockReply}"
+- route:
+    from:
+      uri: jms:queue:stock
+      steps:
+        - log:
+            message: "Stock service got ${body}"
+        - setBody:
+            expression:
+              constant:
+                expression: '{"reserved": true}'
+----
+====
+
+The reply queue can also be shared or exclusive: see <<Request-reply over 
JMS>> below.
+
+=== Routing JMS messages
+
 You can use any of the EIP patterns so the route can be
 context based. For example, here's how to filter an order topic for the
 big spenders:
@@ -1107,7 +1189,9 @@ YAML::
 
 Camel supports Request Reply over JMS. In
 essence the MEP of the Exchange should be `InOut` when you send a
-message to a JMS queue.
+message to a JMS queue. The example in <<Sending a request and waiting for the 
reply>> shows the caller and the service.
+Camel sets the `JMSReplyTo` header and waits for the reply: do not set the 
`replyTo` option or a `JMSReplyTo` header to
+get a reply.
 
 Camel offers a number of options to configure request/reply over JMS
 that influence performance and clustered environments. The table below
diff --git a/components/camel-jms/src/main/docs/jms-component.adoc 
b/components/camel-jms/src/main/docs/jms-component.adoc
index aaba25bf786a..4b1a7e9c1af3 100644
--- a/components/camel-jms/src/main/docs/jms-component.adoc
+++ b/components/camel-jms/src/main/docs/jms-component.adoc
@@ -323,6 +323,88 @@ YAML::
 ----
 ====
 
+=== Sending a request and waiting for the reply
+
+To send a request and wait for its reply, the caller sends with the `InOut` 
exchange pattern, and the service is a
+route that consumes the queue: the body at the end of its route is the reply. 
Camel creates a temporary reply queue
+and sets `JMSReplyTo` itself, so do not set the `replyTo` option or a 
`JMSReplyTo` header for this. With
+`variableReceive`, the reply goes into a variable, and the body is kept:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("timer:order?repeatCount=1")
+  .setBody(constant("{\"orderId\": \"ORD-1001\", \"sku\": \"CAMEL-MUG\"}"))
+  .setExchangePattern(ExchangePattern.InOut)
+  .toV("jms:queue:stock", null, "stockReply")
+  .log("Order ${body} got the reply ${variable.stockReply}");
+
+from("jms:queue:stock")
+  .log("Stock service got ${body}")
+  .setBody(constant("{\"reserved\": true}"));
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+  <from uri="timer:order?repeatCount=1"/>
+  <setBody>
+    <constant>{"orderId": "ORD-1001", "sku": "CAMEL-MUG"}</constant>
+  </setBody>
+  <to uri="jms:queue:stock" pattern="InOut" variableReceive="stockReply"/>
+  <log message="Order ${body} got the reply ${variable.stockReply}"/>
+</route>
+<route>
+  <from uri="jms:queue:stock"/>
+  <log message="Stock service got ${body}"/>
+  <setBody>
+    <constant>{"reserved": true}</constant>
+  </setBody>
+</route>
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+    from:
+      uri: timer:order
+      parameters:
+        repeatCount: 1
+      steps:
+        - setBody:
+            expression:
+              constant:
+                expression: '{"orderId": "ORD-1001", "sku": "CAMEL-MUG"}'
+        - to:
+            uri: jms:queue:stock
+            pattern: InOut
+            variableReceive: stockReply
+        - log:
+            message: "Order ${body} got the reply ${variable.stockReply}"
+- route:
+    from:
+      uri: jms:queue:stock
+      steps:
+        - log:
+            message: "Stock service got ${body}"
+        - setBody:
+            expression:
+              constant:
+                expression: '{"reserved": true}'
+----
+====
+
+The reply queue can also be shared or exclusive: see <<Request-reply over 
JMS>> below.
+
+=== Routing JMS messages
+
 You can use any of the EIP patterns so the route can be
 context based. For example, here's how to filter an order topic for the
 big spenders:
@@ -1107,7 +1189,9 @@ YAML::
 
 Camel supports Request Reply over JMS. In
 essence the MEP of the Exchange should be `InOut` when you send a
-message to a JMS queue.
+message to a JMS queue. The example in <<Sending a request and waiting for the 
reply>> shows the caller and the service.
+Camel sets the `JMSReplyTo` header and waits for the reply: do not set the 
`replyTo` option or a `JMSReplyTo` header to
+get a reply.
 
 Camel offers a number of options to configure request/reply over JMS
 that influence performance and clustered environments. The table below
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 47b8bd33f75a..8a158d844107 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
@@ -108,6 +108,8 @@ final class HeaderChecks {
      * a beginner or a model writes CamelFromEndpoint or CamelEndpointUri for 
"which endpoint did this come from" and
      * was told only that the value would be null.
      */
+    private static final Pattern REPLY_NAME = Pattern.compile("Reply");
+
     static final List<Map.Entry<Pattern, String>> INTENT_HINTS = List.of(
             Map.entry(Pattern.compile("Endpoint|Uri|Source|From|Route|Origin"),
                     "For the endpoint or route a message came from use 
${exchange.fromEndpoint} or ${routeId}; for the"
@@ -115,6 +117,11 @@ final class HeaderChecks {
             Map.entry(Pattern.compile("Size|Length|Count"),
                     "The body size is ${body.length()} for a String body or 
${bodyAs(byte[]).length}; the number of"
                                                             + " headers is 
${headers.size()}."),
+            // a reply header read or set by hand: Camel does request-reply 
itself (r20 runs built replies by hand)
+            Map.entry(REPLY_NAME,
+                    "For request-reply over JMS, send with pattern: InOut on 
the to: and Camel sets JMSReplyTo and waits"
+                                  + " for the reply (the body at the end of 
the service route); do not set"
+                                  + " JMSReplyTo or replyTo yourself."),
             Map.entry(Pattern.compile("Timestamp|Time|Date"),
                     "The current time is ${date:now:yyyy-MM-dd HH:mm:ss} and 
the time the message was created is"
                                                               + " 
${date:exchangeCreated:yyyy-MM-dd HH:mm:ss}; ${messageTimestamp} is set only by"
@@ -293,7 +300,10 @@ final class HeaderChecks {
                 String scheme = best != null && 
owner.containsKey(best.split(", ")[0]) ? owner.get(best.split(", ")[0]) : null;
                 StringBuilder sb = new StringBuilder("Line ").append(i + 
1).append(": header ").append(name)
                         .append(" is not set by ").append(String.join(", ", 
schemes)).append(" (the value would be null)");
-                if (best != null) {
+                if (best != null && REPLY_NAME.matcher(name).find()) {
+                    // "did you mean JMSReplyTo?" led to replies set by hand: 
request-reply is done by Camel
+                    sb.append(" ").append(intentHint(name));
+                } else if (best != null) {
                     sb.append(": did you mean ").append(best).append("?");
                 } else {
                     String hint = intentHint(name);
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 5ffd282fe596..c8e8ae3f6c67 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
@@ -587,6 +587,25 @@ class SourceValidatorEndpointTest {
                 .contains("did you mean Exchange.FILE_NAME");
     }
 
+    /** "did you mean JMSReplyTo?" led to replies set by hand: Camel does 
request-reply with pattern InOut (r20). */
+    @Test
+    void aReplyHeaderGetsTheRequestReplyHint() {
+        List<String> msgs = SourceValidator.validateKnownHeaders("""
+                - from:
+                    uri: jms:queue:orders
+                    steps:
+                      - setHeader:
+                          name: CamelJmsReplyTo
+                          constant: stock-reply
+                      - to:
+                          uri: jms:queue:stock
+                """, catalog);
+        assertThat(msgs).singleElement().satisfies(m -> assertThat(m)
+                .contains("header CamelJmsReplyTo is not set by jms")
+                .contains("send with pattern: InOut on the to: and Camel sets 
JMSReplyTo and waits for the reply")
+                .doesNotContain("did you mean"));
+    }
+
     @Test
     void withIncludeMetadataAHeaderLookupFindsTheExchangeProperty() {
         // Simple's ${header.x} falls back to the exchange properties, so it 
reads the counter

Reply via email to