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;
}
}