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 01b6fd55c000 CAMEL-24460: Mark ProducerTemplate body, header and 
property values as @Nullable
01b6fd55c000 is described below

commit 01b6fd55c000e1b012bfc2aa71eaaab5de79096b
Author: Claus Ibsen <[email protected]>
AuthorDate: Wed Sep 2 13:32:49 2026 +0200

    CAMEL-24460: Mark ProducerTemplate body, header and property values as 
@Nullable
    
    The org.apache.camel package is @NullMarked, so unannotated reference
    parameters are treated as non-null under JSpecify. Camel supports null
    message bodies at runtime, and the sibling FluentProducerTemplate already
    annotates its withBody/withHeader/withExchangeProperty values as @Nullable.
    ProducerTemplate was missed in that rollout.
    
    Align ProducerTemplate by marking body, header value and property value
    parameters as @Nullable. Header/property names and the headers Map stay
    non-null (keys cannot be null). Annotation-only change with no runtime or
    binary compatibility impact. Adds a test driving a null body, header value
    and property value through the API end-to-end.
    
    Closes #26032
    
    Co-authored-by: Claude Opus 4.8 <[email protected]>
---
 .../java/org/apache/camel/ProducerTemplate.java    | 121 ++++++++++++---------
 .../camel/impl/DefaultProducerTemplateTest.java    |  30 +++++
 2 files changed, 97 insertions(+), 54 deletions(-)

diff --git 
a/core/camel-api/src/main/java/org/apache/camel/ProducerTemplate.java 
b/core/camel-api/src/main/java/org/apache/camel/ProducerTemplate.java
index 6406786c81d3..09f62b7d851b 100644
--- a/core/camel-api/src/main/java/org/apache/camel/ProducerTemplate.java
+++ b/core/camel-api/src/main/java/org/apache/camel/ProducerTemplate.java
@@ -190,7 +190,7 @@ public interface ProducerTemplate extends Service {
      * @param  body                    the payload to send
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBody(Object body) throws CamelExecutionException;
+    void sendBody(@Nullable Object body) throws CamelExecutionException;
 
     /**
      * Sends the body to the default endpoint with a specified header and 
header value <br/>
@@ -204,7 +204,7 @@ public interface ProducerTemplate extends Service {
      * @param  headerValue             the header value
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBodyAndHeader(Object body, String header, Object headerValue) 
throws CamelExecutionException;
+    void sendBodyAndHeader(@Nullable Object body, String header, @Nullable 
Object headerValue) throws CamelExecutionException;
 
     /**
      * Sends the body to the default endpoint with a specified property and 
property value <br/>
@@ -218,7 +218,8 @@ public interface ProducerTemplate extends Service {
      * @param  propertyValue           the property value
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBodyAndProperty(Object body, String property, Object 
propertyValue) throws CamelExecutionException;
+    void sendBodyAndProperty(@Nullable Object body, String property, @Nullable 
Object propertyValue)
+            throws CamelExecutionException;
 
     /**
      * Sends the body to the default endpoint with the specified headers and 
header values <br/>
@@ -231,7 +232,7 @@ public interface ProducerTemplate extends Service {
      * @param  headers                 the headers
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBodyAndHeaders(Object body, Map<String, Object> headers) throws 
CamelExecutionException;
+    void sendBodyAndHeaders(@Nullable Object body, Map<String, Object> 
headers) throws CamelExecutionException;
 
     // Allow sending to arbitrary endpoints
     // -----------------------------------------------------------------------
@@ -349,7 +350,7 @@ public interface ProducerTemplate extends Service {
      * @param  body                    the payload
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBody(Endpoint endpoint, Object body) throws 
CamelExecutionException;
+    void sendBody(Endpoint endpoint, @Nullable Object body) throws 
CamelExecutionException;
 
     /**
      * Send the body to an endpoint <br/>
@@ -362,7 +363,7 @@ public interface ProducerTemplate extends Service {
      * @param  body                    the payload
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBody(String endpointUri, Object body) throws 
CamelExecutionException;
+    void sendBody(String endpointUri, @Nullable Object body) throws 
CamelExecutionException;
 
     /**
      * Send the body to an endpoint with the given {@link ExchangePattern} 
returning any result output body <br/>
@@ -379,7 +380,7 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object sendBody(Endpoint endpoint, ExchangePattern pattern, Object body) 
throws CamelExecutionException;
+    Object sendBody(Endpoint endpoint, ExchangePattern pattern, @Nullable 
Object body) throws CamelExecutionException;
 
     /**
      * Send the body to an endpoint returning any result output body <br/>
@@ -396,7 +397,7 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object sendBody(String endpointUri, ExchangePattern pattern, Object body) 
throws CamelExecutionException;
+    Object sendBody(String endpointUri, ExchangePattern pattern, @Nullable 
Object body) throws CamelExecutionException;
 
     /**
      * Sends the body to an endpoint with a specified header and header value 
<br/>
@@ -411,7 +412,8 @@ public interface ProducerTemplate extends Service {
      * @param  headerValue             the header value
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBodyAndHeader(String endpointUri, Object body, String header, 
Object headerValue) throws CamelExecutionException;
+    void sendBodyAndHeader(String endpointUri, @Nullable Object body, String 
header, @Nullable Object headerValue)
+            throws CamelExecutionException;
 
     /**
      * Sends the body to an endpoint with a specified header and header value 
<br/>
@@ -426,7 +428,8 @@ public interface ProducerTemplate extends Service {
      * @param  headerValue             the header value
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBodyAndHeader(Endpoint endpoint, Object body, String header, 
Object headerValue) throws CamelExecutionException;
+    void sendBodyAndHeader(Endpoint endpoint, @Nullable Object body, String 
header, @Nullable Object headerValue)
+            throws CamelExecutionException;
 
     /**
      * Sends the body to an endpoint with a specified header and header value 
<br/>
@@ -446,8 +449,8 @@ public interface ProducerTemplate extends Service {
      */
     @Nullable
     Object sendBodyAndHeader(
-            Endpoint endpoint, ExchangePattern pattern, Object body,
-            String header, Object headerValue)
+            Endpoint endpoint, ExchangePattern pattern, @Nullable Object body,
+            String header, @Nullable Object headerValue)
             throws CamelExecutionException;
 
     /**
@@ -468,8 +471,8 @@ public interface ProducerTemplate extends Service {
      */
     @Nullable
     Object sendBodyAndHeader(
-            String endpoint, ExchangePattern pattern, Object body,
-            String header, Object headerValue)
+            String endpoint, ExchangePattern pattern, @Nullable Object body,
+            String header, @Nullable Object headerValue)
             throws CamelExecutionException;
 
     /**
@@ -485,7 +488,7 @@ public interface ProducerTemplate extends Service {
      * @param  propertyValue           the property value
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBodyAndProperty(String endpointUri, Object body, String property, 
Object propertyValue)
+    void sendBodyAndProperty(String endpointUri, @Nullable Object body, String 
property, @Nullable Object propertyValue)
             throws CamelExecutionException;
 
     /**
@@ -501,7 +504,7 @@ public interface ProducerTemplate extends Service {
      * @param  propertyValue           the property value
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBodyAndProperty(Endpoint endpoint, Object body, String property, 
Object propertyValue)
+    void sendBodyAndProperty(Endpoint endpoint, @Nullable Object body, String 
property, @Nullable Object propertyValue)
             throws CamelExecutionException;
 
     /**
@@ -522,8 +525,8 @@ public interface ProducerTemplate extends Service {
      */
     @Nullable
     Object sendBodyAndProperty(
-            Endpoint endpoint, ExchangePattern pattern, Object body,
-            String property, Object propertyValue)
+            Endpoint endpoint, ExchangePattern pattern, @Nullable Object body,
+            String property, @Nullable Object propertyValue)
             throws CamelExecutionException;
 
     /**
@@ -544,8 +547,8 @@ public interface ProducerTemplate extends Service {
      */
     @Nullable
     Object sendBodyAndProperty(
-            String endpoint, ExchangePattern pattern, Object body,
-            String property, Object propertyValue)
+            String endpoint, ExchangePattern pattern, @Nullable Object body,
+            String property, @Nullable Object propertyValue)
             throws CamelExecutionException;
 
     /**
@@ -560,7 +563,8 @@ public interface ProducerTemplate extends Service {
      * @param  headers                 headers
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBodyAndHeaders(String endpointUri, Object body, Map<String, 
Object> headers) throws CamelExecutionException;
+    void sendBodyAndHeaders(String endpointUri, @Nullable Object body, 
Map<String, Object> headers)
+            throws CamelExecutionException;
 
     /**
      * Sends the body to an endpoint with the specified headers and header 
values <br/>
@@ -574,7 +578,8 @@ public interface ProducerTemplate extends Service {
      * @param  headers                 headers
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    void sendBodyAndHeaders(Endpoint endpoint, Object body, Map<String, 
Object> headers) throws CamelExecutionException;
+    void sendBodyAndHeaders(Endpoint endpoint, @Nullable Object body, 
Map<String, Object> headers)
+            throws CamelExecutionException;
 
     /**
      * Sends the body to an endpoint with the specified headers and header 
values <br/>
@@ -593,7 +598,7 @@ public interface ProducerTemplate extends Service {
      */
     @Nullable
     Object sendBodyAndHeaders(
-            String endpointUri, ExchangePattern pattern, Object body,
+            String endpointUri, ExchangePattern pattern, @Nullable Object body,
             Map<String, Object> headers)
             throws CamelExecutionException;
 
@@ -614,7 +619,7 @@ public interface ProducerTemplate extends Service {
      */
     @Nullable
     Object sendBodyAndHeaders(
-            Endpoint endpoint, ExchangePattern pattern, Object body,
+            Endpoint endpoint, ExchangePattern pattern, @Nullable Object body,
             Map<String, Object> headers)
             throws CamelExecutionException;
 
@@ -662,7 +667,7 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object requestBody(Object body) throws CamelExecutionException;
+    Object requestBody(@Nullable Object body) throws CamelExecutionException;
 
     /**
      * Sends the body to the default endpoint and returns the result content 
Uses an {@link ExchangePattern#InOut}
@@ -677,7 +682,7 @@ public interface ProducerTemplate extends Service {
      * @return                         the result (see class javadoc)
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    <T> @Nullable T requestBody(Object body, Class<T> type) throws 
CamelExecutionException;
+    <T> @Nullable T requestBody(@Nullable Object body, Class<T> type) throws 
CamelExecutionException;
 
     /**
      * Send the body to an endpoint returning any result output body. Uses an 
{@link ExchangePattern#InOut} message
@@ -693,7 +698,7 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object requestBody(Endpoint endpoint, Object body) throws 
CamelExecutionException;
+    Object requestBody(Endpoint endpoint, @Nullable Object body) throws 
CamelExecutionException;
 
     /**
      * Send the body to an endpoint returning any result output body. Uses an 
{@link ExchangePattern#InOut} message
@@ -709,7 +714,7 @@ public interface ProducerTemplate extends Service {
      * @return                         the result (see class javadoc)
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    <T> @Nullable T requestBody(Endpoint endpoint, Object body, Class<T> type) 
throws CamelExecutionException;
+    <T> @Nullable T requestBody(Endpoint endpoint, @Nullable Object body, 
Class<T> type) throws CamelExecutionException;
 
     /**
      * Send the body to an endpoint returning any result output body. Uses an 
{@link ExchangePattern#InOut} message
@@ -725,7 +730,7 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object requestBody(String endpointUri, Object body) throws 
CamelExecutionException;
+    Object requestBody(String endpointUri, @Nullable Object body) throws 
CamelExecutionException;
 
     /**
      * Send the body to an endpoint returning any result output body. Uses an 
{@link ExchangePattern#InOut} message
@@ -741,7 +746,7 @@ public interface ProducerTemplate extends Service {
      * @return                         the result (see class javadoc)
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    <T> @Nullable T requestBody(String endpointUri, Object body, Class<T> 
type) throws CamelExecutionException;
+    <T> @Nullable T requestBody(String endpointUri, @Nullable Object body, 
Class<T> type) throws CamelExecutionException;
 
     /**
      * Sends the body to the default endpoint and returns the result content 
Uses an {@link ExchangePattern#InOut}
@@ -758,7 +763,8 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object requestBodyAndHeader(Object body, String header, Object 
headerValue) throws CamelExecutionException;
+    Object requestBodyAndHeader(@Nullable Object body, String header, 
@Nullable Object headerValue)
+            throws CamelExecutionException;
 
     /**
      * Send the body to an endpoint returning any result output body. Uses an 
{@link ExchangePattern#InOut} message
@@ -776,7 +782,7 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object requestBodyAndHeader(Endpoint endpoint, Object body, String header, 
Object headerValue)
+    Object requestBodyAndHeader(Endpoint endpoint, @Nullable Object body, 
String header, @Nullable Object headerValue)
             throws CamelExecutionException;
 
     /**
@@ -795,7 +801,8 @@ public interface ProducerTemplate extends Service {
      * @return                         the result (see class javadoc)
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    <T> @Nullable T requestBodyAndHeader(Endpoint endpoint, Object body, 
String header, Object headerValue, Class<T> type)
+    <T> @Nullable T requestBodyAndHeader(
+            Endpoint endpoint, @Nullable Object body, String header, @Nullable 
Object headerValue, Class<T> type)
             throws CamelExecutionException;
 
     /**
@@ -814,7 +821,7 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object requestBodyAndHeader(String endpointUri, Object body, String 
header, Object headerValue)
+    Object requestBodyAndHeader(String endpointUri, @Nullable Object body, 
String header, @Nullable Object headerValue)
             throws CamelExecutionException;
 
     /**
@@ -833,7 +840,8 @@ public interface ProducerTemplate extends Service {
      * @return                         the result (see class javadoc)
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    <T> @Nullable T requestBodyAndHeader(String endpointUri, Object body, 
String header, Object headerValue, Class<T> type)
+    <T> @Nullable T requestBodyAndHeader(
+            String endpointUri, @Nullable Object body, String header, 
@Nullable Object headerValue, Class<T> type)
             throws CamelExecutionException;
 
     /**
@@ -851,7 +859,8 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object requestBodyAndHeaders(String endpointUri, Object body, Map<String, 
Object> headers) throws CamelExecutionException;
+    Object requestBodyAndHeaders(String endpointUri, @Nullable Object body, 
Map<String, Object> headers)
+            throws CamelExecutionException;
 
     /**
      * Sends the body to an endpoint with the specified headers and header 
values. Uses an {@link ExchangePattern#InOut}
@@ -868,7 +877,7 @@ public interface ProducerTemplate extends Service {
      * @return                         the result (see class javadoc)
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    <T> @Nullable T requestBodyAndHeaders(String endpointUri, Object body, 
Map<String, Object> headers, Class<T> type)
+    <T> @Nullable T requestBodyAndHeaders(String endpointUri, @Nullable Object 
body, Map<String, Object> headers, Class<T> type)
             throws CamelExecutionException;
 
     /**
@@ -886,7 +895,8 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object requestBodyAndHeaders(Endpoint endpoint, Object body, Map<String, 
Object> headers) throws CamelExecutionException;
+    Object requestBodyAndHeaders(Endpoint endpoint, @Nullable Object body, 
Map<String, Object> headers)
+            throws CamelExecutionException;
 
     /**
      * Sends the body to the default endpoint and returns the result content 
Uses an {@link ExchangePattern#InOut}
@@ -902,7 +912,7 @@ public interface ProducerTemplate extends Service {
      * @throws CamelExecutionException if the processing of the exchange failed
      */
     @Nullable
-    Object requestBodyAndHeaders(Object body, Map<String, Object> headers) 
throws CamelExecutionException;
+    Object requestBodyAndHeaders(@Nullable Object body, Map<String, Object> 
headers) throws CamelExecutionException;
 
     /**
      * Sends the body to an endpoint with the specified headers and header 
values. Uses an {@link ExchangePattern#InOut}
@@ -919,7 +929,7 @@ public interface ProducerTemplate extends Service {
      * @return                         the result (see class javadoc)
      * @throws CamelExecutionException if the processing of the exchange failed
      */
-    <T> @Nullable T requestBodyAndHeaders(Endpoint endpoint, Object body, 
Map<String, Object> headers, Class<T> type)
+    <T> @Nullable T requestBodyAndHeaders(Endpoint endpoint, @Nullable Object 
body, Map<String, Object> headers, Class<T> type)
             throws CamelExecutionException;
 
     // Asynchronous methods
@@ -962,7 +972,7 @@ public interface ProducerTemplate extends Service {
      * @param  body        the body to send
      * @return             a handle to be used to get the response in the 
future
      */
-    CompletableFuture<Object> asyncSendBody(String endpointUri, Object body);
+    CompletableFuture<Object> asyncSendBody(String endpointUri, @Nullable 
Object body);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -971,7 +981,7 @@ public interface ProducerTemplate extends Service {
      * @param  body        the body to send
      * @return             a handle to be used to get the response in the 
future
      */
-    CompletableFuture<Object> asyncRequestBody(String endpointUri, Object 
body);
+    CompletableFuture<Object> asyncRequestBody(String endpointUri, @Nullable 
Object body);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -982,7 +992,8 @@ public interface ProducerTemplate extends Service {
      * @param  headerValue the header value
      * @return             a handle to be used to get the response in the 
future
      */
-    CompletableFuture<Object> asyncRequestBodyAndHeader(String endpointUri, 
Object body, String header, Object headerValue);
+    CompletableFuture<Object> asyncRequestBodyAndHeader(
+            String endpointUri, @Nullable Object body, String header, 
@Nullable Object headerValue);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -992,7 +1003,8 @@ public interface ProducerTemplate extends Service {
      * @param  headers     headers
      * @return             a handle to be used to get the response in the 
future
      */
-    CompletableFuture<Object> asyncRequestBodyAndHeaders(String endpointUri, 
Object body, Map<String, Object> headers);
+    CompletableFuture<Object> asyncRequestBodyAndHeaders(
+            String endpointUri, @Nullable Object body, Map<String, Object> 
headers);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -1002,7 +1014,7 @@ public interface ProducerTemplate extends Service {
      * @param  type        the expected response type
      * @return             a handle to be used to get the response in the 
future
      */
-    <T> CompletableFuture<T> asyncRequestBody(String endpointUri, Object body, 
Class<T> type);
+    <T> CompletableFuture<T> asyncRequestBody(String endpointUri, @Nullable 
Object body, Class<T> type);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -1015,7 +1027,7 @@ public interface ProducerTemplate extends Service {
      * @return             a handle to be used to get the response in the 
future
      */
     <T> CompletableFuture<T> asyncRequestBodyAndHeader(
-            String endpointUri, Object body, String header, Object 
headerValue, Class<T> type);
+            String endpointUri, @Nullable Object body, String header, 
@Nullable Object headerValue, Class<T> type);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -1027,7 +1039,7 @@ public interface ProducerTemplate extends Service {
      * @return             a handle to be used to get the response in the 
future
      */
     <T> CompletableFuture<T> asyncRequestBodyAndHeaders(
-            String endpointUri, Object body, Map<String, Object> headers, 
Class<T> type);
+            String endpointUri, @Nullable Object body, Map<String, Object> 
headers, Class<T> type);
 
     /**
      * Sends an asynchronous exchange to the given endpoint.
@@ -1059,7 +1071,7 @@ public interface ProducerTemplate extends Service {
      * @param  body     the body to send
      * @return          a handle to be used to get the response in the future
      */
-    CompletableFuture<Object> asyncSendBody(Endpoint endpoint, Object body);
+    CompletableFuture<Object> asyncSendBody(Endpoint endpoint, @Nullable 
Object body);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -1068,7 +1080,7 @@ public interface ProducerTemplate extends Service {
      * @param  body     the body to send
      * @return          a handle to be used to get the response in the future
      */
-    CompletableFuture<Object> asyncRequestBody(Endpoint endpoint, Object body);
+    CompletableFuture<Object> asyncRequestBody(Endpoint endpoint, @Nullable 
Object body);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -1079,7 +1091,8 @@ public interface ProducerTemplate extends Service {
      * @param  headerValue the header value
      * @return             a handle to be used to get the response in the 
future
      */
-    CompletableFuture<Object> asyncRequestBodyAndHeader(Endpoint endpoint, 
Object body, String header, Object headerValue);
+    CompletableFuture<Object> asyncRequestBodyAndHeader(
+            Endpoint endpoint, @Nullable Object body, String header, @Nullable 
Object headerValue);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -1089,7 +1102,7 @@ public interface ProducerTemplate extends Service {
      * @param  headers  headers
      * @return          a handle to be used to get the response in the future
      */
-    CompletableFuture<Object> asyncRequestBodyAndHeaders(Endpoint endpoint, 
Object body, Map<String, Object> headers);
+    CompletableFuture<Object> asyncRequestBodyAndHeaders(Endpoint endpoint, 
@Nullable Object body, Map<String, Object> headers);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -1099,7 +1112,7 @@ public interface ProducerTemplate extends Service {
      * @param  type     the expected response type
      * @return          a handle to be used to get the response in the future
      */
-    <T> CompletableFuture<T> asyncRequestBody(Endpoint endpoint, Object body, 
Class<T> type);
+    <T> CompletableFuture<T> asyncRequestBody(Endpoint endpoint, @Nullable 
Object body, Class<T> type);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -1112,7 +1125,7 @@ public interface ProducerTemplate extends Service {
      * @return             a handle to be used to get the response in the 
future
      */
     <T> CompletableFuture<T> asyncRequestBodyAndHeader(
-            Endpoint endpoint, Object body, String header, Object headerValue, 
Class<T> type);
+            Endpoint endpoint, @Nullable Object body, String header, @Nullable 
Object headerValue, Class<T> type);
 
     /**
      * Sends an asynchronous body to the given endpoint. Uses an {@link 
ExchangePattern#InOut} message exchange pattern.
@@ -1124,7 +1137,7 @@ public interface ProducerTemplate extends Service {
      * @return          a handle to be used to get the response in the future
      */
     <T> CompletableFuture<T> asyncRequestBodyAndHeaders(
-            Endpoint endpoint, Object body, Map<String, Object> headers, 
Class<T> type);
+            Endpoint endpoint, @Nullable Object body, Map<String, Object> 
headers, Class<T> type);
 
     /**
      * Gets the response body from the future handle, will wait until the 
response is ready.
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/impl/DefaultProducerTemplateTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultProducerTemplateTest.java
index e8c18119298c..ebfd4ad60912 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/impl/DefaultProducerTemplateTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/impl/DefaultProducerTemplateTest.java
@@ -34,6 +34,7 @@ import org.junit.jupiter.api.Test;
 
 import static org.awaitility.Awaitility.await;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -257,6 +258,33 @@ public class DefaultProducerTemplateTest extends 
ContextTestSupport {
         producer.stop();
     }
 
+    @Test
+    public void testNullBodyAndValues() throws Exception {
+        // ProducerTemplate marks body, header value and property value 
parameters as @Nullable;
+        // verify null values are accepted and routed end-to-end (CAMEL-24460)
+        MockEndpoint mock = getMockEndpoint("mock:echo");
+        mock.expectedMessageCount(3);
+
+        // null body
+        template.sendBody("direct:echo", null);
+        // null body and null header value (header key must be non-null, value 
may be null)
+        template.sendBodyAndHeader("direct:echo", null, "foo", null);
+        // null body and null property value
+        template.sendBodyAndProperty("direct:echo", null, "bar", null);
+
+        assertMockEndpointsSatisfied();
+
+        // all three bodies are null
+        for (Exchange exchange : mock.getExchanges()) {
+            assertNull(exchange.getIn().getBody(), "Body should be null");
+        }
+
+        // null header value propagated
+        assertNull(mock.getExchanges().get(1).getIn().getHeader("foo"), 
"Header value should be null");
+        // null property value propagated
+        assertNull(mock.getExchanges().get(2).getProperty("bar"), "Property 
value should be null");
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
@@ -287,6 +315,8 @@ public class DefaultProducerTemplateTest extends 
ContextTestSupport {
                 }).to("mock:result");
 
                 from("direct:inout").transform(constant(123));
+
+                from("direct:echo").to("mock:echo");
             }
         };
     }

Reply via email to