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 913a20871af9 CAMEL-23534: URL-decode schema properties in Jackson 
Avro/Protobuf components (#23270)
913a20871af9 is described below

commit 913a20871af9277066d458b54e3976773753bb8f
Author: Tom Cunningham <[email protected]>
AuthorDate: Mon May 18 11:51:31 2026 -0400

    CAMEL-23534: URL-decode schema properties in Jackson Avro/Protobuf 
components (#23270)
    
    Schema properties are URL-encoded when passed from Pipe to Kamelet via
    YamlRoutesBuilderLoader.createQueryString(), but were never decoded
    before reaching the schema resolvers. This caused parser errors when
    schemas contained special characters like quotes, equals signs, or
    brackets.
    
    This fix adds URL decoding to:
    - AvroSchemaResolver (Jackson and Jackson3)
    - ProtobufSchemaResolver (Jackson and Jackson3)
    - MimeType.of() method
    
    Added comprehensive tests for each component to verify URL-encoded
    schemas are properly decoded and parsed.
    
    Co-authored-by: Claude Sonnet 4.5 <[email protected]>
---
 .../jackson/avro/transform/AvroSchemaResolver.java |  6 ++-
 .../avro/transform/AvroSchemaResolverTest.java     | 43 ++++++++++++++++++++++
 .../protobuf/transform/ProtobufSchemaResolver.java |  6 ++-
 .../transform/ProtobufSchemaResolverTest.java      | 39 ++++++++++++++++++++
 .../avro/transform/AvroSchemaResolver.java         |  6 ++-
 .../avro/transform/AvroSchemaResolverTest.java     | 43 ++++++++++++++++++++++
 .../protobuf/transform/ProtobufSchemaResolver.java |  6 ++-
 .../transform/ProtobufSchemaResolverTest.java      | 39 ++++++++++++++++++++
 .../component/kamelet/utils/format/MimeType.java   |  7 +++-
 9 files changed, 190 insertions(+), 5 deletions(-)

diff --git 
a/components/camel-jackson-avro/src/main/java/org/apache/camel/component/jackson/avro/transform/AvroSchemaResolver.java
 
b/components/camel-jackson-avro/src/main/java/org/apache/camel/component/jackson/avro/transform/AvroSchemaResolver.java
index 2e7082f82adf..3f6f366e2dbc 100644
--- 
a/components/camel-jackson-avro/src/main/java/org/apache/camel/component/jackson/avro/transform/AvroSchemaResolver.java
+++ 
b/components/camel-jackson-avro/src/main/java/org/apache/camel/component/jackson/avro/transform/AvroSchemaResolver.java
@@ -17,6 +17,8 @@
 package org.apache.camel.component.jackson.avro.transform;
 
 import java.io.InputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.Locale;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -65,7 +67,9 @@ public class AvroSchemaResolver implements SchemaResolver, 
Processor {
 
     public void setSchema(String schema) {
         if (ObjectHelper.isNotEmpty(schema)) {
-            this.schema = new AvroSchema(new 
Schema.Parser(NameValidator.UTF_VALIDATOR).parse(schema));
+            // URL-decode the schema in case it was encoded
+            String decodedSchema = URLDecoder.decode(schema, 
StandardCharsets.UTF_8);
+            this.schema = new AvroSchema(new 
Schema.Parser(NameValidator.UTF_VALIDATOR).parse(decodedSchema));
         } else {
             this.schema = null;
         }
diff --git 
a/components/camel-jackson-avro/src/test/java/org/apache/camel/component/jackson/avro/transform/AvroSchemaResolverTest.java
 
b/components/camel-jackson-avro/src/test/java/org/apache/camel/component/jackson/avro/transform/AvroSchemaResolverTest.java
index 4ef630a3b13b..13f888c10d0e 100644
--- 
a/components/camel-jackson-avro/src/test/java/org/apache/camel/component/jackson/avro/transform/AvroSchemaResolverTest.java
+++ 
b/components/camel-jackson-avro/src/test/java/org/apache/camel/component/jackson/avro/transform/AvroSchemaResolverTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.camel.component.jackson.avro.transform;
 
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
 import com.fasterxml.jackson.dataformat.avro.AvroSchema;
 import org.apache.avro.NameValidator;
 import org.apache.avro.Schema;
@@ -89,4 +92,44 @@ class AvroSchemaResolverTest {
         Assertions.assertEquals(SchemaType.AVRO.type(), 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA_TYPE));
         Assertions.assertEquals(Person.class.getName(), 
exchange.getProperty(SchemaHelper.CONTENT_CLASS));
     }
+
+    @Test
+    void shouldDecodeUrlEncodedSchemaFromSetter() throws Exception {
+        // CAMEL-23534: Schema properties are URL-encoded when passed from 
Pipe to Kamelet
+        String schemaString = """
+                {
+                  "type": "record",
+                  "name": "Person",
+                  "fields": [
+                    {"name": "name", "type": "string"},
+                    {"name": "age", "type": "int"}
+                  ]
+                }
+                """;
+
+        // Simulate URL encoding that happens when properties are passed from 
Pipe to Kamelet
+        String urlEncodedSchema = URLEncoder.encode(schemaString, 
StandardCharsets.UTF_8);
+
+        // The encoded schema should contain URL-encoded characters like %22 
for ", %7B for {, etc.
+        Assertions.assertTrue(urlEncodedSchema.contains("%22"), "Schema should 
be URL-encoded");
+        Assertions.assertTrue(urlEncodedSchema.contains("%7B"), "Schema should 
be URL-encoded");
+
+        // Create resolver and set the URL-encoded schema via the setter method
+        AvroSchemaResolver schemaResolver = new AvroSchemaResolver();
+
+        // This should not throw an exception - the resolver should decode the 
schema
+        Assertions.assertDoesNotThrow(() -> 
schemaResolver.setSchema(urlEncodedSchema),
+                "URL-encoded schema should be decoded and parsed 
successfully");
+
+        // Verify the schema was parsed correctly
+        Exchange exchange = new DefaultExchange(camelContext);
+        exchange.setProperty(SchemaHelper.CONTENT_CLASS, 
Person.class.getName());
+        exchange.getMessage().setBody(person);
+
+        schemaResolver.process(exchange);
+
+        
Assertions.assertNotNull(exchange.getProperty(SchemaHelper.CONTENT_SCHEMA));
+        Assertions.assertEquals(AvroSchema.class, 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA).getClass());
+        Assertions.assertEquals(SchemaType.AVRO.type(), 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA_TYPE));
+    }
 }
diff --git 
a/components/camel-jackson-protobuf/src/main/java/org/apache/camel/component/jackson/protobuf/transform/ProtobufSchemaResolver.java
 
b/components/camel-jackson-protobuf/src/main/java/org/apache/camel/component/jackson/protobuf/transform/ProtobufSchemaResolver.java
index 030e6505d8c5..a859867346d2 100644
--- 
a/components/camel-jackson-protobuf/src/main/java/org/apache/camel/component/jackson/protobuf/transform/ProtobufSchemaResolver.java
+++ 
b/components/camel-jackson-protobuf/src/main/java/org/apache/camel/component/jackson/protobuf/transform/ProtobufSchemaResolver.java
@@ -18,6 +18,8 @@ package org.apache.camel.component.jackson.protobuf.transform;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.Locale;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -65,7 +67,9 @@ public class ProtobufSchemaResolver implements 
SchemaResolver, Processor {
     public void setSchema(String schema) {
         if (ObjectHelper.isNotEmpty(schema)) {
             try {
-                this.schema = ProtobufSchemaLoader.std.parse(schema);
+                // URL-decode the schema in case it was encoded
+                String decodedSchema = URLDecoder.decode(schema, 
StandardCharsets.UTF_8);
+                this.schema = ProtobufSchemaLoader.std.parse(decodedSchema);
             } catch (IOException e) {
                 throw new RuntimeCamelException("Failed tp parse Protobuf 
schema", e);
             }
diff --git 
a/components/camel-jackson-protobuf/src/test/java/org/apache/camel/component/jackson/protobuf/transform/ProtobufSchemaResolverTest.java
 
b/components/camel-jackson-protobuf/src/test/java/org/apache/camel/component/jackson/protobuf/transform/ProtobufSchemaResolverTest.java
index d1626aa7e7ce..999d54fffa9f 100644
--- 
a/components/camel-jackson-protobuf/src/test/java/org/apache/camel/component/jackson/protobuf/transform/ProtobufSchemaResolverTest.java
+++ 
b/components/camel-jackson-protobuf/src/test/java/org/apache/camel/component/jackson/protobuf/transform/ProtobufSchemaResolverTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.camel.component.jackson.protobuf.transform;
 
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
 import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchema;
 import com.fasterxml.jackson.dataformat.protobuf.schema.ProtobufSchemaLoader;
 import org.apache.camel.Exchange;
@@ -87,4 +90,40 @@ class ProtobufSchemaResolverTest {
         Assertions.assertEquals(SchemaType.PROTOBUF.type(), 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA_TYPE));
         Assertions.assertEquals(Person.class.getName(), 
exchange.getProperty(SchemaHelper.CONTENT_CLASS));
     }
+
+    @Test
+    void shouldDecodeUrlEncodedSchemaFromSetter() throws Exception {
+        // CAMEL-23534: Schema properties are URL-encoded when passed from 
Pipe to Kamelet
+        // Use proto2 syntax which matches the existing Person.proto test 
resource
+        String schemaString = """
+                message Person {
+                   required string name = 1;
+                   optional int32 age = 2;
+                }
+                """;
+
+        // Simulate URL encoding that happens when properties are passed from 
Pipe to Kamelet
+        String urlEncodedSchema = URLEncoder.encode(schemaString, 
StandardCharsets.UTF_8);
+
+        // The encoded schema should contain URL-encoded characters like %3D 
for =, %22 for ", etc.
+        Assertions.assertTrue(urlEncodedSchema.contains("%3D"), "Schema should 
be URL-encoded");
+
+        // Create resolver and set the URL-encoded schema via the setter method
+        ProtobufSchemaResolver schemaResolver = new ProtobufSchemaResolver();
+
+        // This should not throw an exception - the resolver should decode the 
schema
+        Assertions.assertDoesNotThrow(() -> 
schemaResolver.setSchema(urlEncodedSchema),
+                "URL-encoded schema should be decoded and parsed 
successfully");
+
+        // Verify the schema was parsed correctly
+        Exchange exchange = new DefaultExchange(camelContext);
+        exchange.setProperty(SchemaHelper.CONTENT_CLASS, 
Person.class.getName());
+        exchange.getMessage().setBody(person);
+
+        schemaResolver.process(exchange);
+
+        
Assertions.assertNotNull(exchange.getProperty(SchemaHelper.CONTENT_SCHEMA));
+        Assertions.assertEquals(ProtobufSchema.class, 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA).getClass());
+        Assertions.assertEquals(SchemaType.PROTOBUF.type(), 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA_TYPE));
+    }
 }
diff --git 
a/components/camel-jackson3-avro/src/main/java/org/apache/camel/component/jackson3/avro/transform/AvroSchemaResolver.java
 
b/components/camel-jackson3-avro/src/main/java/org/apache/camel/component/jackson3/avro/transform/AvroSchemaResolver.java
index d49204d9e4fb..19a6b50ef7bf 100644
--- 
a/components/camel-jackson3-avro/src/main/java/org/apache/camel/component/jackson3/avro/transform/AvroSchemaResolver.java
+++ 
b/components/camel-jackson3-avro/src/main/java/org/apache/camel/component/jackson3/avro/transform/AvroSchemaResolver.java
@@ -17,6 +17,8 @@
 package org.apache.camel.component.jackson3.avro.transform;
 
 import java.io.InputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.Locale;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -65,7 +67,9 @@ public class AvroSchemaResolver implements SchemaResolver, 
Processor {
 
     public void setSchema(String schema) {
         if (ObjectHelper.isNotEmpty(schema)) {
-            this.schema = new AvroSchema(new 
Schema.Parser(NameValidator.UTF_VALIDATOR).parse(schema));
+            // URL-decode the schema in case it was encoded
+            String decodedSchema = URLDecoder.decode(schema, 
StandardCharsets.UTF_8);
+            this.schema = new AvroSchema(new 
Schema.Parser(NameValidator.UTF_VALIDATOR).parse(decodedSchema));
         } else {
             this.schema = null;
         }
diff --git 
a/components/camel-jackson3-avro/src/test/java/org/apache/camel/component/jackson3/avro/transform/AvroSchemaResolverTest.java
 
b/components/camel-jackson3-avro/src/test/java/org/apache/camel/component/jackson3/avro/transform/AvroSchemaResolverTest.java
index 045d21ee4e10..3a9c5ceb2ac5 100644
--- 
a/components/camel-jackson3-avro/src/test/java/org/apache/camel/component/jackson3/avro/transform/AvroSchemaResolverTest.java
+++ 
b/components/camel-jackson3-avro/src/test/java/org/apache/camel/component/jackson3/avro/transform/AvroSchemaResolverTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.camel.component.jackson3.avro.transform;
 
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
 import org.apache.avro.NameValidator;
 import org.apache.avro.Schema;
 import org.apache.camel.Exchange;
@@ -89,4 +92,44 @@ class AvroSchemaResolverTest {
         Assertions.assertEquals(SchemaType.AVRO.type(), 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA_TYPE));
         Assertions.assertEquals(Person.class.getName(), 
exchange.getProperty(SchemaHelper.CONTENT_CLASS));
     }
+
+    @Test
+    void shouldDecodeUrlEncodedSchemaFromSetter() throws Exception {
+        // CAMEL-23534: Schema properties are URL-encoded when passed from 
Pipe to Kamelet
+        String schemaString = """
+                {
+                  "type": "record",
+                  "name": "Person",
+                  "fields": [
+                    {"name": "name", "type": "string"},
+                    {"name": "age", "type": "int"}
+                  ]
+                }
+                """;
+
+        // Simulate URL encoding that happens when properties are passed from 
Pipe to Kamelet
+        String urlEncodedSchema = URLEncoder.encode(schemaString, 
StandardCharsets.UTF_8);
+
+        // The encoded schema should contain URL-encoded characters like %22 
for ", %7B for {, etc.
+        Assertions.assertTrue(urlEncodedSchema.contains("%22"), "Schema should 
be URL-encoded");
+        Assertions.assertTrue(urlEncodedSchema.contains("%7B"), "Schema should 
be URL-encoded");
+
+        // Create resolver and set the URL-encoded schema via the setter method
+        AvroSchemaResolver schemaResolver = new AvroSchemaResolver();
+
+        // This should not throw an exception - the resolver should decode the 
schema
+        Assertions.assertDoesNotThrow(() -> 
schemaResolver.setSchema(urlEncodedSchema),
+                "URL-encoded schema should be decoded and parsed 
successfully");
+
+        // Verify the schema was parsed correctly
+        Exchange exchange = new DefaultExchange(camelContext);
+        exchange.setProperty(SchemaHelper.CONTENT_CLASS, 
Person.class.getName());
+        exchange.getMessage().setBody(person);
+
+        schemaResolver.process(exchange);
+
+        
Assertions.assertNotNull(exchange.getProperty(SchemaHelper.CONTENT_SCHEMA));
+        Assertions.assertEquals(AvroSchema.class, 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA).getClass());
+        Assertions.assertEquals(SchemaType.AVRO.type(), 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA_TYPE));
+    }
 }
diff --git 
a/components/camel-jackson3-protobuf/src/main/java/org/apache/camel/component/jackson3/protobuf/transform/ProtobufSchemaResolver.java
 
b/components/camel-jackson3-protobuf/src/main/java/org/apache/camel/component/jackson3/protobuf/transform/ProtobufSchemaResolver.java
index 41e33e9ce04f..6a5052e92819 100644
--- 
a/components/camel-jackson3-protobuf/src/main/java/org/apache/camel/component/jackson3/protobuf/transform/ProtobufSchemaResolver.java
+++ 
b/components/camel-jackson3-protobuf/src/main/java/org/apache/camel/component/jackson3/protobuf/transform/ProtobufSchemaResolver.java
@@ -18,6 +18,8 @@ package 
org.apache.camel.component.jackson3.protobuf.transform;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.Locale;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -65,7 +67,9 @@ public class ProtobufSchemaResolver implements 
SchemaResolver, Processor {
     public void setSchema(String schema) {
         if (ObjectHelper.isNotEmpty(schema)) {
             try {
-                this.schema = ProtobufSchemaLoader.std.parse(schema);
+                // URL-decode the schema in case it was encoded
+                String decodedSchema = URLDecoder.decode(schema, 
StandardCharsets.UTF_8);
+                this.schema = ProtobufSchemaLoader.std.parse(decodedSchema);
             } catch (IOException e) {
                 throw new RuntimeCamelException("Failed tp parse Protobuf 
schema", e);
             }
diff --git 
a/components/camel-jackson3-protobuf/src/test/java/org/apache/camel/component/jackson3/protobuf/transform/ProtobufSchemaResolverTest.java
 
b/components/camel-jackson3-protobuf/src/test/java/org/apache/camel/component/jackson3/protobuf/transform/ProtobufSchemaResolverTest.java
index 8c0adf2ecbb3..3e895ae69568 100644
--- 
a/components/camel-jackson3-protobuf/src/test/java/org/apache/camel/component/jackson3/protobuf/transform/ProtobufSchemaResolverTest.java
+++ 
b/components/camel-jackson3-protobuf/src/test/java/org/apache/camel/component/jackson3/protobuf/transform/ProtobufSchemaResolverTest.java
@@ -17,6 +17,9 @@
 
 package org.apache.camel.component.jackson3.protobuf.transform;
 
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
 import org.apache.camel.Exchange;
 import org.apache.camel.component.jackson3.SchemaHelper;
 import org.apache.camel.component.jackson3.SchemaType;
@@ -87,4 +90,40 @@ class ProtobufSchemaResolverTest {
         Assertions.assertEquals(SchemaType.PROTOBUF.type(), 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA_TYPE));
         Assertions.assertEquals(Person.class.getName(), 
exchange.getProperty(SchemaHelper.CONTENT_CLASS));
     }
+
+    @Test
+    void shouldDecodeUrlEncodedSchemaFromSetter() throws Exception {
+        // CAMEL-23534: Schema properties are URL-encoded when passed from 
Pipe to Kamelet
+        // Use proto2 syntax which matches the existing Person.proto test 
resource
+        String schemaString = """
+                message Person {
+                   required string name = 1;
+                   optional int32 age = 2;
+                }
+                """;
+
+        // Simulate URL encoding that happens when properties are passed from 
Pipe to Kamelet
+        String urlEncodedSchema = URLEncoder.encode(schemaString, 
StandardCharsets.UTF_8);
+
+        // The encoded schema should contain URL-encoded characters like %3D 
for =, %22 for ", etc.
+        Assertions.assertTrue(urlEncodedSchema.contains("%3D"), "Schema should 
be URL-encoded");
+
+        // Create resolver and set the URL-encoded schema via the setter method
+        ProtobufSchemaResolver schemaResolver = new ProtobufSchemaResolver();
+
+        // This should not throw an exception - the resolver should decode the 
schema
+        Assertions.assertDoesNotThrow(() -> 
schemaResolver.setSchema(urlEncodedSchema),
+                "URL-encoded schema should be decoded and parsed 
successfully");
+
+        // Verify the schema was parsed correctly
+        Exchange exchange = new DefaultExchange(camelContext);
+        exchange.setProperty(SchemaHelper.CONTENT_CLASS, 
Person.class.getName());
+        exchange.getMessage().setBody(person);
+
+        schemaResolver.process(exchange);
+
+        
Assertions.assertNotNull(exchange.getProperty(SchemaHelper.CONTENT_SCHEMA));
+        Assertions.assertEquals(ProtobufSchema.class, 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA).getClass());
+        Assertions.assertEquals(SchemaType.PROTOBUF.type(), 
exchange.getProperty(SchemaHelper.CONTENT_SCHEMA_TYPE));
+    }
 }
diff --git 
a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/utils/format/MimeType.java
 
b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/utils/format/MimeType.java
index aa16d5300c02..24cad6142f5b 100644
--- 
a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/utils/format/MimeType.java
+++ 
b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/utils/format/MimeType.java
@@ -17,6 +17,8 @@
 
 package org.apache.camel.component.kamelet.utils.format;
 
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.Objects;
 
 public enum MimeType {
@@ -44,8 +46,11 @@ public enum MimeType {
     }
 
     public static MimeType of(String type) {
+        // URL-decode the type in case it was encoded
+        String decodedType = URLDecoder.decode(type, StandardCharsets.UTF_8);
+
         for (MimeType mt : VALUES) {
-            if (Objects.equals(type, mt.type)) {
+            if (Objects.equals(decodedType, mt.type)) {
                 return mt;
             }
         }

Reply via email to