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 f00daddb65a5 CAMEL-26012: camel-pulsar - the producer no longer sends
a body with Java serialization (#29753)
f00daddb65a5 is described below
commit f00daddb65a59c13a8b90cd8fdf56cbeb6805050
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Nov 13 08:05:05 2026 +0100
CAMEL-26012: camel-pulsar - the producer no longer sends a body with Java
serialization (#29753)
The pulsar producer fell back to Java serialization for a body that does not
convert to byte[] (a Map, List, number or POJO, and no body as a serialized
null). Now such a body, and no body, fail with an InvalidPayloadException
that
says to marshal it first. Text, bytes, streams and files are sent as before.
The new deprecated option allowJavaSerializedObject (insecure:serialization)
turns the old fallback back on. The ITs that sent an Integer now send a
String.
New "Message body" section on the component page and a 4.24 upgrade-guide
entry.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../apache/camel/catalog/components/pulsar.json | 12 +-
.../camel/catalog/docs/pulsar-component.adoc | 10 +
.../pulsar/PulsarComponentConfigurer.java | 6 +
.../component/pulsar/PulsarEndpointConfigurer.java | 6 +
.../component/pulsar/PulsarEndpointUriFactory.java | 3 +-
.../org/apache/camel/component/pulsar/pulsar.json | 12 +-
.../src/main/docs/pulsar-component.adoc | 10 +
.../component/pulsar/PulsarConfiguration.java | 20 ++
.../camel/component/pulsar/PulsarEndpoint.java | 6 +-
.../camel/component/pulsar/PulsarProducer.java | 35 ++--
.../component/pulsar/PulsarProducerBodyTest.java | 203 +++++++++++++++++++++
.../pulsar/integration/PulsarProducerInIT.java | 2 +-
.../integration/PulsarProducerURIClientIT.java | 2 +-
.../java/org/apache/camel/util/SecurityUtils.java | 1 +
.../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc | 11 ++
.../dsl/PulsarComponentBuilderFactory.java | 25 +++
.../endpoint/dsl/PulsarEndpointBuilderFactory.java | 44 +++++
17 files changed, 373 insertions(+), 35 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pulsar.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pulsar.json
index 1d239db34bbb..f2d26b095a8f 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pulsar.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/pulsar.json
@@ -71,9 +71,10 @@
"messageRoutingMode": { "index": 44, "kind": "property", "displayName":
"Message Routing Mode", "group": "producer", "label": "producer", "required":
false, "type": "enum", "javaType":
"org.apache.pulsar.client.api.MessageRoutingMode", "enum": [ "SinglePartition",
"RoundRobinPartition", "CustomPartition" ], "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "RoundRobinPartition",
"configurationClass": "org.apache.camel.component.pulsar.PulsarConfiguration",
"co [...]
"producerName": { "index": 45, "kind": "property", "displayName":
"Producer Name", "group": "producer", "label": "producer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.pulsar.PulsarConfiguration", "configurationField":
"configuration", "description": "Name of the producer. If unset, lets Pulsar
select a unique identifier." },
"sendTimeoutMs": { "index": 46, "kind": "property", "displayName": "Send
Timeout Ms", "group": "producer", "label": "producer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 30000, "configurationClass":
"org.apache.camel.component.pulsar.PulsarConfiguration", "configurationField":
"configuration", "description": "Send timeout in milliseconds" },
- "autoConfiguration": { "index": 47, "kind": "property", "displayName":
"Auto Configuration", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType":
"org.apache.camel.component.pulsar.utils.AutoConfiguration", "deprecated":
false, "autowired": false, "secret": false, "description": "The pulsar auto
configuration" },
- "autowiredEnabled": { "index": 48, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching [...]
- "pulsarClient": { "index": 49, "kind": "property", "displayName": "Pulsar
Client", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "org.apache.pulsar.client.api.PulsarClient",
"deprecated": false, "autowired": true, "secret": false, "description": "The
pulsar client" }
+ "allowJavaSerializedObject": { "index": 47, "kind": "property",
"displayName": "Allow Java Serialized Object", "group": "producer (advanced)",
"label": "producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": true, "deprecationNote": "Java serialization of the
body is kept only for compatibility, and will be removed: marshal the body
before sending it", "autowired": false, "secret": false, "security":
"insecure:serialization", "defaultValue": fa [...]
+ "autoConfiguration": { "index": 48, "kind": "property", "displayName":
"Auto Configuration", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType":
"org.apache.camel.component.pulsar.utils.AutoConfiguration", "deprecated":
false, "autowired": false, "secret": false, "description": "The pulsar auto
configuration" },
+ "autowiredEnabled": { "index": 49, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching [...]
+ "pulsarClient": { "index": 50, "kind": "property", "displayName": "Pulsar
Client", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "org.apache.pulsar.client.api.PulsarClient",
"deprecated": false, "autowired": true, "secret": false, "description": "The
pulsar client" }
},
"headers": {
"properties": { "index": 0, "kind": "header", "displayName": "", "group":
"consumer", "label": "consumer", "required": false, "javaType": "Map<String,
String>", "deprecated": false, "autowired": false, "secret": false,
"description": "The properties attached to the message.", "constantName":
"org.apache.camel.component.pulsar.utils.message.PulsarMessageHeaders#PROPERTIES"
},
@@ -96,7 +97,7 @@
},
"bodyTypes": {
"consumerOut": { "carriers": [ "bytes", "null" ], "javaType": "byte[]",
"description": "The payload of the Pulsar message as a byte array, null for a
message with a null value (a tombstone), with the key and the properties in
headers: convert or unmarshal it" },
- "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ],
"description": "What converts to a byte array: text, bytes, a stream or a file,
sent as the payload. Any other body is sent with Java serialization, a Map, a
List, a number and no body too, and an object that is not Serializable fails:
marshal it first" },
+ "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ],
"dependsOn": [ "allowJavaSerializedObject" ], "description": "What converts to
a byte array: text, bytes, a stream or a file, sent as the payload. Any other
body, such as a Map, a List, a number or a POJO, fails, and so does no body:
marshal it first" },
"producerOut": { "carriers": [ "unchanged" ], "description": "Unchanged,
also when the exchange expects a reply, with the id of the published message in
a header" }
},
"properties": {
@@ -150,7 +151,8 @@
"messageRoutingMode": { "index": 47, "kind": "parameter", "displayName":
"Message Routing Mode", "group": "producer", "label": "producer", "required":
false, "type": "enum", "javaType":
"org.apache.pulsar.client.api.MessageRoutingMode", "enum": [ "SinglePartition",
"RoundRobinPartition", "CustomPartition" ], "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "RoundRobinPartition",
"configurationClass": "org.apache.camel.component.pulsar.PulsarConfiguration",
"c [...]
"producerName": { "index": 48, "kind": "parameter", "displayName":
"Producer Name", "group": "producer", "label": "producer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.pulsar.PulsarConfiguration", "configurationField":
"pulsarConfiguration", "description": "Name of the producer. If unset, lets
Pulsar select a unique identifier." },
"sendTimeoutMs": { "index": 49, "kind": "parameter", "displayName": "Send
Timeout Ms", "group": "producer", "label": "producer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 30000, "configurationClass":
"org.apache.camel.component.pulsar.PulsarConfiguration", "configurationField":
"pulsarConfiguration", "description": "Send timeout in milliseconds" },
- "lazyStartProducer": { "index": 50, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
+ "allowJavaSerializedObject": { "index": 50, "kind": "parameter",
"displayName": "Allow Java Serialized Object", "group": "producer (advanced)",
"label": "producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": true, "deprecationNote": "Java serialization of the
body is kept only for compatibility, and will be removed: marshal the body
before sending it", "autowired": false, "secret": false, "security":
"insecure:serialization", "defaultValue": f [...]
+ "lazyStartProducer": { "index": 51, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
},
"dstWorlds": {
"PulsarWorld": { "javaType":
"org.apache.camel.component.pulsar.dst.PulsarWorld", "fake": "FakePulsar: a
broker and client for one topic and one durable subscription", "covers": [
"subscription types Exclusive, Shared, Failover and Key_Shared with one to
three consumers", "the message listener (messageListener=true, one consumer
thread)", "the ack timeout and the redelivery of a failed exchange after a
negative acknowledgement", "route start, restart, suspend and resume", "an
asynchr [...]
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pulsar-component.adoc
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pulsar-component.adoc
index dd055e1772b3..0711ed91d912 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pulsar-component.adoc
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/pulsar-component.adoc
@@ -73,6 +73,16 @@ The following routes send a message to the `orders` topic
every five seconds, an
message: "Received ${body}"
----
+=== Message body
+
+The producer sends the body as a byte array: text, bytes, a stream or a file
are sent as their content. A body that
+does not convert to a byte array, such as a `Map`, a `List`, a number or a
POJO, fails, and so does no body: marshal it
+first, for example to JSON with `marshal().json()`. The consumer gives the
payload as a byte array, so convert or
+unmarshal it in the route.
+
+Before Camel 4.24 such a body was sent with Java serialization, which only a
Java client that deserializes it can
+read. The deprecated `allowJavaSerializedObject` option turns this back on for
compatibility, and will be removed.
+
=== Producer sequence ids and deduplication
With a `producerName` and deduplication enabled on the broker, the producer
continues the sequence ids after the
diff --git
a/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarComponentConfigurer.java
b/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarComponentConfigurer.java
index e490cf635e72..dbf5e5185798 100644
---
a/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarComponentConfigurer.java
+++
b/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarComponentConfigurer.java
@@ -37,6 +37,8 @@ public class PulsarComponentConfigurer extends
PropertyConfigurerSupport impleme
case "ackTimeoutMillis":
getOrCreateConfiguration(target).setAckTimeoutMillis(property(camelContext,
long.class, value)); return true;
case "acktimeoutredeliverybackoff":
case "ackTimeoutRedeliveryBackoff":
getOrCreateConfiguration(target).setAckTimeoutRedeliveryBackoff(property(camelContext,
org.apache.pulsar.client.api.RedeliveryBackoff.class, value)); return true;
+ case "allowjavaserializedobject":
+ case "allowJavaSerializedObject":
getOrCreateConfiguration(target).setAllowJavaSerializedObject(property(camelContext,
boolean.class, value)); return true;
case "allowmanualacknowledgement":
case "allowManualAcknowledgement":
getOrCreateConfiguration(target).setAllowManualAcknowledgement(property(camelContext,
boolean.class, value)); return true;
case "authenticationclass":
@@ -148,6 +150,8 @@ public class PulsarComponentConfigurer extends
PropertyConfigurerSupport impleme
case "ackTimeoutMillis": return long.class;
case "acktimeoutredeliverybackoff":
case "ackTimeoutRedeliveryBackoff": return
org.apache.pulsar.client.api.RedeliveryBackoff.class;
+ case "allowjavaserializedobject":
+ case "allowJavaSerializedObject": return boolean.class;
case "allowmanualacknowledgement":
case "allowManualAcknowledgement": return boolean.class;
case "authenticationclass":
@@ -255,6 +259,8 @@ public class PulsarComponentConfigurer extends
PropertyConfigurerSupport impleme
case "ackTimeoutMillis": return
getOrCreateConfiguration(target).getAckTimeoutMillis();
case "acktimeoutredeliverybackoff":
case "ackTimeoutRedeliveryBackoff": return
getOrCreateConfiguration(target).getAckTimeoutRedeliveryBackoff();
+ case "allowjavaserializedobject":
+ case "allowJavaSerializedObject": return
getOrCreateConfiguration(target).isAllowJavaSerializedObject();
case "allowmanualacknowledgement":
case "allowManualAcknowledgement": return
getOrCreateConfiguration(target).isAllowManualAcknowledgement();
case "authenticationclass":
diff --git
a/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarEndpointConfigurer.java
b/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarEndpointConfigurer.java
index 9a390aa59046..b4b1c1806fe8 100644
---
a/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarEndpointConfigurer.java
+++
b/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarEndpointConfigurer.java
@@ -30,6 +30,8 @@ public class PulsarEndpointConfigurer extends
PropertyConfigurerSupport implemen
case "ackTimeoutMillis":
target.getPulsarConfiguration().setAckTimeoutMillis(property(camelContext,
long.class, value)); return true;
case "acktimeoutredeliverybackoff":
case "ackTimeoutRedeliveryBackoff":
target.getPulsarConfiguration().setAckTimeoutRedeliveryBackoff(property(camelContext,
org.apache.pulsar.client.api.RedeliveryBackoff.class, value)); return true;
+ case "allowjavaserializedobject":
+ case "allowJavaSerializedObject":
target.getPulsarConfiguration().setAllowJavaSerializedObject(property(camelContext,
boolean.class, value)); return true;
case "allowmanualacknowledgement":
case "allowManualAcknowledgement":
target.getPulsarConfiguration().setAllowManualAcknowledgement(property(camelContext,
boolean.class, value)); return true;
case "authenticationclass":
@@ -131,6 +133,8 @@ public class PulsarEndpointConfigurer extends
PropertyConfigurerSupport implemen
case "ackTimeoutMillis": return long.class;
case "acktimeoutredeliverybackoff":
case "ackTimeoutRedeliveryBackoff": return
org.apache.pulsar.client.api.RedeliveryBackoff.class;
+ case "allowjavaserializedobject":
+ case "allowJavaSerializedObject": return boolean.class;
case "allowmanualacknowledgement":
case "allowManualAcknowledgement": return boolean.class;
case "authenticationclass":
@@ -233,6 +237,8 @@ public class PulsarEndpointConfigurer extends
PropertyConfigurerSupport implemen
case "ackTimeoutMillis": return
target.getPulsarConfiguration().getAckTimeoutMillis();
case "acktimeoutredeliverybackoff":
case "ackTimeoutRedeliveryBackoff": return
target.getPulsarConfiguration().getAckTimeoutRedeliveryBackoff();
+ case "allowjavaserializedobject":
+ case "allowJavaSerializedObject": return
target.getPulsarConfiguration().isAllowJavaSerializedObject();
case "allowmanualacknowledgement":
case "allowManualAcknowledgement": return
target.getPulsarConfiguration().isAllowManualAcknowledgement();
case "authenticationclass":
diff --git
a/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarEndpointUriFactory.java
b/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarEndpointUriFactory.java
index e8d947edb5a9..e41d972bf0a7 100644
---
a/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarEndpointUriFactory.java
+++
b/components/camel-pulsar/src/generated/java/org/apache/camel/component/pulsar/PulsarEndpointUriFactory.java
@@ -24,10 +24,11 @@ public class PulsarEndpointUriFactory extends
org.apache.camel.support.component
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(51);
+ Set<String> props = new HashSet<>(52);
props.add("ackGroupTimeMillis");
props.add("ackTimeoutMillis");
props.add("ackTimeoutRedeliveryBackoff");
+ props.add("allowJavaSerializedObject");
props.add("allowManualAcknowledgement");
props.add("authenticationClass");
props.add("authenticationParams");
diff --git
a/components/camel-pulsar/src/generated/resources/META-INF/org/apache/camel/component/pulsar/pulsar.json
b/components/camel-pulsar/src/generated/resources/META-INF/org/apache/camel/component/pulsar/pulsar.json
index 1d239db34bbb..f2d26b095a8f 100644
---
a/components/camel-pulsar/src/generated/resources/META-INF/org/apache/camel/component/pulsar/pulsar.json
+++
b/components/camel-pulsar/src/generated/resources/META-INF/org/apache/camel/component/pulsar/pulsar.json
@@ -71,9 +71,10 @@
"messageRoutingMode": { "index": 44, "kind": "property", "displayName":
"Message Routing Mode", "group": "producer", "label": "producer", "required":
false, "type": "enum", "javaType":
"org.apache.pulsar.client.api.MessageRoutingMode", "enum": [ "SinglePartition",
"RoundRobinPartition", "CustomPartition" ], "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "RoundRobinPartition",
"configurationClass": "org.apache.camel.component.pulsar.PulsarConfiguration",
"co [...]
"producerName": { "index": 45, "kind": "property", "displayName":
"Producer Name", "group": "producer", "label": "producer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.pulsar.PulsarConfiguration", "configurationField":
"configuration", "description": "Name of the producer. If unset, lets Pulsar
select a unique identifier." },
"sendTimeoutMs": { "index": 46, "kind": "property", "displayName": "Send
Timeout Ms", "group": "producer", "label": "producer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 30000, "configurationClass":
"org.apache.camel.component.pulsar.PulsarConfiguration", "configurationField":
"configuration", "description": "Send timeout in milliseconds" },
- "autoConfiguration": { "index": 47, "kind": "property", "displayName":
"Auto Configuration", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType":
"org.apache.camel.component.pulsar.utils.AutoConfiguration", "deprecated":
false, "autowired": false, "secret": false, "description": "The pulsar auto
configuration" },
- "autowiredEnabled": { "index": 48, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching [...]
- "pulsarClient": { "index": 49, "kind": "property", "displayName": "Pulsar
Client", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "org.apache.pulsar.client.api.PulsarClient",
"deprecated": false, "autowired": true, "secret": false, "description": "The
pulsar client" }
+ "allowJavaSerializedObject": { "index": 47, "kind": "property",
"displayName": "Allow Java Serialized Object", "group": "producer (advanced)",
"label": "producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": true, "deprecationNote": "Java serialization of the
body is kept only for compatibility, and will be removed: marshal the body
before sending it", "autowired": false, "secret": false, "security":
"insecure:serialization", "defaultValue": fa [...]
+ "autoConfiguration": { "index": 48, "kind": "property", "displayName":
"Auto Configuration", "group": "advanced", "label": "advanced", "required":
false, "type": "object", "javaType":
"org.apache.camel.component.pulsar.utils.AutoConfiguration", "deprecated":
false, "autowired": false, "secret": false, "description": "The pulsar auto
configuration" },
+ "autowiredEnabled": { "index": 49, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching [...]
+ "pulsarClient": { "index": 50, "kind": "property", "displayName": "Pulsar
Client", "group": "advanced", "label": "advanced", "required": false, "type":
"object", "javaType": "org.apache.pulsar.client.api.PulsarClient",
"deprecated": false, "autowired": true, "secret": false, "description": "The
pulsar client" }
},
"headers": {
"properties": { "index": 0, "kind": "header", "displayName": "", "group":
"consumer", "label": "consumer", "required": false, "javaType": "Map<String,
String>", "deprecated": false, "autowired": false, "secret": false,
"description": "The properties attached to the message.", "constantName":
"org.apache.camel.component.pulsar.utils.message.PulsarMessageHeaders#PROPERTIES"
},
@@ -96,7 +97,7 @@
},
"bodyTypes": {
"consumerOut": { "carriers": [ "bytes", "null" ], "javaType": "byte[]",
"description": "The payload of the Pulsar message as a byte array, null for a
message with a null value (a tombstone), with the key and the properties in
headers: convert or unmarshal it" },
- "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ],
"description": "What converts to a byte array: text, bytes, a stream or a file,
sent as the payload. Any other body is sent with Java serialization, a Map, a
List, a number and no body too, and an object that is not Serializable fails:
marshal it first" },
+ "producerIn": { "carriers": [ "text", "bytes", "stream", "file" ],
"dependsOn": [ "allowJavaSerializedObject" ], "description": "What converts to
a byte array: text, bytes, a stream or a file, sent as the payload. Any other
body, such as a Map, a List, a number or a POJO, fails, and so does no body:
marshal it first" },
"producerOut": { "carriers": [ "unchanged" ], "description": "Unchanged,
also when the exchange expects a reply, with the id of the published message in
a header" }
},
"properties": {
@@ -150,7 +151,8 @@
"messageRoutingMode": { "index": 47, "kind": "parameter", "displayName":
"Message Routing Mode", "group": "producer", "label": "producer", "required":
false, "type": "enum", "javaType":
"org.apache.pulsar.client.api.MessageRoutingMode", "enum": [ "SinglePartition",
"RoundRobinPartition", "CustomPartition" ], "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "RoundRobinPartition",
"configurationClass": "org.apache.camel.component.pulsar.PulsarConfiguration",
"c [...]
"producerName": { "index": 48, "kind": "parameter", "displayName":
"Producer Name", "group": "producer", "label": "producer", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.pulsar.PulsarConfiguration", "configurationField":
"pulsarConfiguration", "description": "Name of the producer. If unset, lets
Pulsar select a unique identifier." },
"sendTimeoutMs": { "index": 49, "kind": "parameter", "displayName": "Send
Timeout Ms", "group": "producer", "label": "producer", "required": false,
"type": "integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 30000, "configurationClass":
"org.apache.camel.component.pulsar.PulsarConfiguration", "configurationField":
"pulsarConfiguration", "description": "Send timeout in milliseconds" },
- "lazyStartProducer": { "index": 50, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
+ "allowJavaSerializedObject": { "index": 50, "kind": "parameter",
"displayName": "Allow Java Serialized Object", "group": "producer (advanced)",
"label": "producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": true, "deprecationNote": "Java serialization of the
body is kept only for compatibility, and will be removed: marshal the body
before sending it", "autowired": false, "secret": false, "security":
"insecure:serialization", "defaultValue": f [...]
+ "lazyStartProducer": { "index": 51, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
},
"dstWorlds": {
"PulsarWorld": { "javaType":
"org.apache.camel.component.pulsar.dst.PulsarWorld", "fake": "FakePulsar: a
broker and client for one topic and one durable subscription", "covers": [
"subscription types Exclusive, Shared, Failover and Key_Shared with one to
three consumers", "the message listener (messageListener=true, one consumer
thread)", "the ack timeout and the redelivery of a failed exchange after a
negative acknowledgement", "route start, restart, suspend and resume", "an
asynchr [...]
diff --git a/components/camel-pulsar/src/main/docs/pulsar-component.adoc
b/components/camel-pulsar/src/main/docs/pulsar-component.adoc
index dd055e1772b3..0711ed91d912 100644
--- a/components/camel-pulsar/src/main/docs/pulsar-component.adoc
+++ b/components/camel-pulsar/src/main/docs/pulsar-component.adoc
@@ -73,6 +73,16 @@ The following routes send a message to the `orders` topic
every five seconds, an
message: "Received ${body}"
----
+=== Message body
+
+The producer sends the body as a byte array: text, bytes, a stream or a file
are sent as their content. A body that
+does not convert to a byte array, such as a `Map`, a `List`, a number or a
POJO, fails, and so does no body: marshal it
+first, for example to JSON with `marshal().json()`. The consumer gives the
payload as a byte array, so convert or
+unmarshal it in the route.
+
+Before Camel 4.24 such a body was sent with Java serialization, which only a
Java client that deserializes it can
+read. The deprecated `allowJavaSerializedObject` option turns this back on for
compatibility, and will be removed.
+
=== Producer sequence ids and deduplication
With a `producerName` and deduplication enabled on the broker, the producer
continues the sequence ids after the
diff --git
a/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarConfiguration.java
b/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarConfiguration.java
index 12c2926be563..598d98ccffa8 100644
---
a/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarConfiguration.java
+++
b/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarConfiguration.java
@@ -22,6 +22,7 @@ import org.apache.camel.RuntimeCamelException;
import
org.apache.camel.component.pulsar.utils.consumers.SubscriptionInitialPosition;
import org.apache.camel.component.pulsar.utils.consumers.SubscriptionMode;
import org.apache.camel.component.pulsar.utils.consumers.SubscriptionType;
+import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriParams;
import org.apache.pulsar.client.api.BatcherBuilder;
@@ -158,6 +159,15 @@ public class PulsarConfiguration implements Cloneable {
description = "Hashing function to use when choosing the
partition to use for a particular message",
enums = "JavaStringHash,Murmur3_32Hash", defaultValue =
"JavaStringHash")
private String hashingScheme = "JavaStringHash";
+ @UriParam(label = "producer,advanced", security = "insecure:serialization",
+ description = "Whether the producer sends a body that does not
convert to a byte array (such as a Map, a List,"
+ + " a number or a POJO) with Java serialization,
as Camel did before 4.24. Such a message can only"
+ + " be read by a Java client that deserializes it.
By default the producer fails such a body:"
+ + " marshal it first, for example to JSON.")
+ @Metadata(deprecationNote = "Java serialization of the body is kept only
for compatibility, and will be removed:"
+ + " marshal the body before sending it")
+ @Deprecated
+ private boolean allowJavaSerializedObject;
/**
* Returns a copy of this configuration
@@ -170,6 +180,16 @@ public class PulsarConfiguration implements Cloneable {
}
}
+ @Deprecated
+ public boolean isAllowJavaSerializedObject() {
+ return allowJavaSerializedObject;
+ }
+
+ @Deprecated
+ public void setAllowJavaSerializedObject(boolean
allowJavaSerializedObject) {
+ this.allowJavaSerializedObject = allowJavaSerializedObject;
+ }
+
public boolean isTopicsPattern() {
return topicsPattern;
}
diff --git
a/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarEndpoint.java
b/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarEndpoint.java
index fd5fdb1ee8c0..e11b289b8d22 100644
---
a/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarEndpoint.java
+++
b/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarEndpoint.java
@@ -46,9 +46,9 @@ import org.apache.pulsar.client.api.PulsarClient;
+ " convert or unmarshal it"),
producerIn = @BodyType(value = { Carrier.TEXT, Carrier.BYTES,
Carrier.STREAM, Carrier.FILE },
description = "What converts to a byte
array: text, bytes, a stream or a file, sent as the"
- + " payload. Any other body is
sent with Java serialization, a Map, a List, a"
- + " number and no body too,
and an object that is not Serializable fails:"
- + " marshal it first"),
+ + " payload. Any other body,
such as a Map, a List, a number or a POJO, fails,"
+ + " and so does no body:
marshal it first",
+ dependsOn = "allowJavaSerializedObject"),
producerOut = @BodyType(value = Carrier.UNCHANGED,
description = "Unchanged, also when the
exchange expects a reply, with the id of the"
+ " published message in a
header"))
diff --git
a/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarProducer.java
b/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarProducer.java
index 7a40d2617d11..ac4e26e0f740 100644
---
a/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarProducer.java
+++
b/components/camel-pulsar/src/main/java/org/apache/camel/component/pulsar/PulsarProducer.java
@@ -16,16 +16,14 @@
*/
package org.apache.camel.component.pulsar;
-import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.camel.AsyncCallback;
import org.apache.camel.CamelExchangeException;
import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
import org.apache.camel.Message;
-import org.apache.camel.NoTypeConversionAvailableException;
-import org.apache.camel.TypeConversionException;
import org.apache.camel.component.pulsar.utils.message.PulsarMessageHeaders;
import org.apache.camel.component.pulsar.utils.message.PulsarMessageUtils;
import org.apache.camel.support.DefaultAsyncProducer;
@@ -103,24 +101,23 @@ public class PulsarProducer extends DefaultAsyncProducer {
}
/**
- * Serialize the given content using the appropriate converter if any,
otherwise it relies on
- * {@link PulsarMessageUtils#serialize(Object)}.
- *
- * @param exchange the exchange used as context for the serialization
process.
- * @param content the content to serialize.
- * @return the serialized counterpart of the given content
- * @throws IOException if an error occurs while serializing the content.
+ * The payload of the message: the body converted to a byte array. A body
that does not convert, such as a Map or a
+ * POJO, and no body, fail unless allowJavaSerializedObject is enabled,
which sends them with Java serialization.
*/
- private static byte[] serialize(Exchange exchange, Object content) throws
IOException {
- byte[] result;
- try {
- result = exchange.getContext().getTypeConverter()
- .mandatoryConvertTo(byte[].class, exchange, content);
- } catch (NoTypeConversionAvailableException | TypeConversionException
exception) {
- // fallback to try to serialize the data
- result = PulsarMessageUtils.serialize(content);
+ private byte[] serialize(Exchange exchange, Object content) throws
Exception {
+ if (content != null) {
+ byte[] result =
exchange.getContext().getTypeConverter().tryConvertTo(byte[].class, exchange,
content);
+ if (result != null) {
+ return result;
+ }
+ }
+ if
(pulsarEndpoint.getPulsarConfiguration().isAllowJavaSerializedObject()) {
+ return PulsarMessageUtils.serialize(content);
}
- return result;
+ String hint = content == null
+ ? "the pulsar producer does not send a message without a body"
+ : "the pulsar producer sends the body as a byte array: marshal
it first, for example with marshal().json()";
+ throw new InvalidPayloadException(exchange, byte[].class,
exchange.getIn(), hint);
}
private void createProducer() throws PulsarClientException {
diff --git
a/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/PulsarProducerBodyTest.java
b/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/PulsarProducerBodyTest.java
new file mode 100644
index 000000000000..f00615ccfe0d
--- /dev/null
+++
b/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/PulsarProducerBodyTest.java
@@ -0,0 +1,203 @@
+/*
+ * 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.component.pulsar;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.apache.pulsar.client.api.MessageId;
+import org.apache.pulsar.client.api.Producer;
+import org.apache.pulsar.client.api.ProducerBuilder;
+import org.apache.pulsar.client.api.PulsarClient;
+import org.apache.pulsar.client.api.TypedMessageBuilder;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Answers.RETURNS_SELF;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * The producer sends the body as a byte array. A body that does not convert
to one, and no body, fail unless the
+ * deprecated allowJavaSerializedObject option turns the Java serialization of
the body back on.
+ */
+public class PulsarProducerBodyTest extends CamelTestSupport {
+
+ private final List<byte[]> sent = new ArrayList<>();
+
+ @TempDir
+ Path tempDir;
+
+ @BeforeEach
+ void clearSent() {
+ sent.clear();
+ }
+
+ @Test
+ public void testTextIsSentAsItsBytes() {
+ Exchange out = template.send("direct:start", e ->
e.getIn().setBody("Hello World"));
+
+ assertNull(out.getException());
+ assertArrayEquals("Hello World".getBytes(StandardCharsets.UTF_8),
sent.get(0));
+ }
+
+ @Test
+ public void testBytesAreSentAsTheyAre() {
+ byte[] bytes = { 1, 2, 3 };
+ Exchange out = template.send("direct:start", e ->
e.getIn().setBody(bytes));
+
+ assertNull(out.getException());
+ assertArrayEquals(bytes, sent.get(0));
+ }
+
+ @Test
+ public void testStreamIsSentAsItsContent() {
+ Exchange out = template.send("direct:start",
+ e -> e.getIn().setBody(new ByteArrayInputStream("from a
stream".getBytes(StandardCharsets.UTF_8))));
+
+ assertNull(out.getException());
+ assertEquals("from a stream", new String(sent.get(0),
StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void testFileIsSentAsItsContent() throws Exception {
+ File file = Files.writeString(tempDir.resolve("order.json"),
"{\"id\":1}").toFile();
+ Exchange out = template.send("direct:start", e ->
e.getIn().setBody(file));
+
+ assertNull(out.getException());
+ assertEquals("{\"id\":1}", new String(sent.get(0),
StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void testMapFails() {
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("id", 1);
+ Exchange out = template.send("direct:start", e ->
e.getIn().setBody(map));
+
+ InvalidPayloadException cause =
assertInstanceOf(InvalidPayloadException.class, out.getException());
+ assertTrue(cause.getMessage().contains("marshal it first"),
cause.getMessage());
+ assertTrue(sent.isEmpty(), "nothing should be sent");
+ }
+
+ @Test
+ public void testSerializablePojoFails() {
+ Exchange out = template.send("direct:start", e ->
e.getIn().setBody(new Order(42)));
+
+ InvalidPayloadException cause =
assertInstanceOf(InvalidPayloadException.class, out.getException());
+
assertTrue(cause.getMessage().contains(Order.class.getCanonicalName()),
cause.getMessage());
+ assertTrue(sent.isEmpty(), "nothing should be sent");
+ }
+
+ @Test
+ public void testNoBodyFails() {
+ Exchange out = template.send("direct:start", e ->
e.getIn().setBody(null));
+
+ InvalidPayloadException cause =
assertInstanceOf(InvalidPayloadException.class, out.getException());
+ assertTrue(cause.getMessage().contains("without a body"),
cause.getMessage());
+ assertTrue(sent.isEmpty(), "nothing should be sent");
+ }
+
+ @Test
+ public void testAllowJavaSerializedObjectSerializesAMap() throws Exception
{
+ Map<String, Object> map = new LinkedHashMap<>();
+ map.put("id", 1);
+ Exchange out = template.send("direct:legacy", e ->
e.getIn().setBody(map));
+
+ assertNull(out.getException());
+ byte[] payload = sent.get(0);
+ // the Java serialization stream magic
+ assertEquals((byte) 0xAC, payload[0]);
+ assertEquals((byte) 0xED, payload[1]);
+ try (ObjectInputStream in = new ObjectInputStream(new
ByteArrayInputStream(payload))) {
+ assertEquals(map, in.readObject());
+ }
+ }
+
+ @Test
+ public void testAllowJavaSerializedObjectStillSendsTextAsItsBytes() {
+ Exchange out = template.send("direct:legacy", e ->
e.getIn().setBody("Hello World"));
+
+ assertNull(out.getException());
+ assertArrayEquals("Hello World".getBytes(StandardCharsets.UTF_8),
sent.get(0));
+ }
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ final CamelContext context = super.createCamelContext();
+
+ final TypedMessageBuilder<byte[]> messageBuilder =
mock(TypedMessageBuilder.class);
+ when(messageBuilder.value(any())).thenAnswer(invocation -> {
+ sent.add(invocation.getArgument(0));
+ return messageBuilder;
+ });
+
when(messageBuilder.sendAsync()).thenReturn(CompletableFuture.completedFuture(mock(MessageId.class)));
+
+ final Producer<byte[]> pulsarProducer = mock(Producer.class);
+ when(pulsarProducer.newMessage()).thenReturn(messageBuilder);
+
+ final ProducerBuilder<byte[]> producerBuilder =
mock(ProducerBuilder.class, RETURNS_SELF);
+ when(producerBuilder.create()).thenReturn(pulsarProducer);
+
+ final PulsarClient pulsarClient = mock(PulsarClient.class);
+ when(pulsarClient.newProducer()).thenReturn(producerBuilder);
+
+ final PulsarComponent component = new PulsarComponent(context);
+ component.setPulsarClient(pulsarClient);
+ context.addComponent("pulsar", component);
+
+ return context;
+ }
+
+ @Override
+ protected RoutesBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:start")
+
.to("pulsar:persistent://public/default/camel-body-test");
+ from("direct:legacy")
+
.to("pulsar:persistent://public/default/camel-body-legacy?allowJavaSerializedObject=true");
+ }
+ };
+ }
+
+ public record Order(int id) implements Serializable {
+ }
+}
diff --git
a/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/integration/PulsarProducerInIT.java
b/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/integration/PulsarProducerInIT.java
index 678606bd5f20..f322ee471f34 100644
---
a/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/integration/PulsarProducerInIT.java
+++
b/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/integration/PulsarProducerInIT.java
@@ -99,7 +99,7 @@ public class PulsarProducerInIT extends PulsarITSupport {
producerTemplate.sendBody("Hello ");
producerTemplate.sendBody("World ");
- producerTemplate.sendBody(10);
+ producerTemplate.sendBody("10");
MockEndpoint.assertIsSatisfied(10, TimeUnit.SECONDS, to);
}
diff --git
a/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/integration/PulsarProducerURIClientIT.java
b/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/integration/PulsarProducerURIClientIT.java
index a5d62d549eea..a0cee5aaef49 100644
---
a/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/integration/PulsarProducerURIClientIT.java
+++
b/components/camel-pulsar/src/test/java/org/apache/camel/component/pulsar/integration/PulsarProducerURIClientIT.java
@@ -68,7 +68,7 @@ public class PulsarProducerURIClientIT extends
PulsarITSupport {
producerTemplate.sendBody("Hello ");
producerTemplate.sendBody("World ");
- producerTemplate.sendBody(10);
+ producerTemplate.sendBody("10");
MockEndpoint.assertIsSatisfied(10, TimeUnit.SECONDS, to);
}
diff --git
a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
index 511d1600f11c..e896a8b1cadd 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/SecurityUtils.java
@@ -144,6 +144,7 @@ public final class SecurityUtils {
"component:http",
"component:https",
"component:jetty",
+ "component:pulsar",
"component:servlet",
"component:vertxhttp"));
owners.put("allowlocalwebhookurls", Set.of(
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index db656af4cbd1..df465eba457a 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -4735,6 +4735,17 @@ in retry mode: 16 redeliveries and its default retry
letter and dead letter topi
`retryLetterTopic` and `deadLetterTopic` only apply when `maxRedeliverCount`
is set. The consumer logs a WARN when it
starts with one of these topics but no `maxRedeliverCount` (and for
`retryLetterTopic` without `enableRetry`).
+=== camel-pulsar - the producer no longer sends a body with Java serialization
+
+The `pulsar` producer sends the body as a `byte[]`. A body that does not
convert to one, such as a `Map`, a `List`, a
+number or a POJO, was sent with Java serialization, which only a Java client
that deserializes it can read, and no body
+was sent as the bytes of a serialized `null`. Such a body, and no body, now
fail with an `InvalidPayloadException`.
+Text, bytes, a stream and a file are sent as their content, as before.
+
+Marshal the body before the producer, for example with `marshal().json()`. To
keep the old behaviour for now, set the
+new option `allowJavaSerializedObject=true` on the endpoint or the component.
The option is deprecated from the start
+and will be removed in a future release.
+
=== camel-twitter - twitter-search applies its query options again
Since Camel 4.0 (the upgrade to Twitter4J 4.1, whose `Query` is immutable) the
`twitter-search` endpoint sent only the
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PulsarComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PulsarComponentBuilderFactory.java
index fe389a937346..dd9f03ef4a6b 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PulsarComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PulsarComponentBuilderFactory.java
@@ -901,6 +901,30 @@ public interface PulsarComponentBuilderFactory {
return this;
}
+
+ /**
+ * Whether the producer sends a body that does not convert to a byte
+ * array (such as a Map, a List, a number or a POJO) with Java
+ * serialization, as Camel did before 4.24. Such a message can only be
+ * read by a Java client that deserializes it. By default the producer
+ * fails such a body: marshal it first, for example to JSON.
Deprecation
+ * note: Java serialization of the body is kept only for compatibility,
+ * and will be removed: marshal the body before sending it.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: producer (advanced)
+ *
+ * @param allowJavaSerializedObject the value to set
+ * @return the dsl builder
+ */
+ @Deprecated
+ default PulsarComponentBuilder allowJavaSerializedObject(boolean
allowJavaSerializedObject) {
+ doSetProperty("allowJavaSerializedObject",
allowJavaSerializedObject);
+ return this;
+ }
+
/**
* The pulsar auto configuration.
*
@@ -1023,6 +1047,7 @@ public interface PulsarComponentBuilderFactory {
case "messageRoutingMode":
getOrCreateConfiguration((PulsarComponent)
component).setMessageRoutingMode((org.apache.pulsar.client.api.MessageRoutingMode)
value); return true;
case "producerName": getOrCreateConfiguration((PulsarComponent)
component).setProducerName((java.lang.String) value); return true;
case "sendTimeoutMs": getOrCreateConfiguration((PulsarComponent)
component).setSendTimeoutMs((int) value); return true;
+ case "allowJavaSerializedObject":
getOrCreateConfiguration((PulsarComponent)
component).setAllowJavaSerializedObject((boolean) value); return true;
case "autoConfiguration": ((PulsarComponent)
component).setAutoConfiguration((org.apache.camel.component.pulsar.utils.AutoConfiguration)
value); return true;
case "autowiredEnabled": ((PulsarComponent)
component).setAutowiredEnabled((boolean) value); return true;
case "pulsarClient": ((PulsarComponent)
component).setPulsarClient((org.apache.pulsar.client.api.PulsarClient) value);
return true;
diff --git
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PulsarEndpointBuilderFactory.java
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PulsarEndpointBuilderFactory.java
index 0d1106c79396..6f7460b4a776 100644
---
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PulsarEndpointBuilderFactory.java
+++
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PulsarEndpointBuilderFactory.java
@@ -1444,6 +1444,50 @@ public interface PulsarEndpointBuilderFactory {
return (PulsarEndpointProducerBuilder) this;
}
+ /**
+ * Whether the producer sends a body that does not convert to a byte
+ * array (such as a Map, a List, a number or a POJO) with Java
+ * serialization, as Camel did before 4.24. Such a message can only be
+ * read by a Java client that deserializes it. By default the producer
+ * fails such a body: marshal it first, for example to JSON.
Deprecation
+ * note: Java serialization of the body is kept only for compatibility,
+ * and will be removed: marshal the body before sending it.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: producer (advanced)
+ *
+ * @param allowJavaSerializedObject the value to set
+ * @return the dsl builder
+ */
+ @Deprecated
+ default AdvancedPulsarEndpointProducerBuilder
allowJavaSerializedObject(boolean allowJavaSerializedObject) {
+ doSetProperty("allowJavaSerializedObject",
allowJavaSerializedObject);
+ return this;
+ }
+ /**
+ * Whether the producer sends a body that does not convert to a byte
+ * array (such as a Map, a List, a number or a POJO) with Java
+ * serialization, as Camel did before 4.24. Such a message can only be
+ * read by a Java client that deserializes it. By default the producer
+ * fails such a body: marshal it first, for example to JSON.
Deprecation
+ * note: Java serialization of the body is kept only for compatibility,
+ * and will be removed: marshal the body before sending it.
+ *
+ * The option will be converted to a <code>boolean</code> type.
+ *
+ * Default: false
+ * Group: producer (advanced)
+ *
+ * @param allowJavaSerializedObject the value to set
+ * @return the dsl builder
+ */
+ @Deprecated
+ default AdvancedPulsarEndpointProducerBuilder
allowJavaSerializedObject(String allowJavaSerializedObject) {
+ doSetProperty("allowJavaSerializedObject",
allowJavaSerializedObject);
+ return this;
+ }
/**
* Whether the producer should be started lazy (on the first message).
* By starting lazy you can use this to allow CamelContext and routes
to