You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/01/02 12:11:13 UTC

(camel) 01/02: CAMEL-20288: camel-core - Convert header and variable To another name

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

davsclaus pushed a commit to branch toname
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 7d1920327ae0bf481762c400f8d1bfcc6d541f19
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Jan 2 12:55:14 2024 +0100

    CAMEL-20288: camel-core - Convert header and variable To another name
---
 .../camel/catalog/models/convertHeaderTo.json      |  5 ++-
 .../modules/eips/pages/convertHeaderTo-eip.adoc    | 44 ++++++++++++++++++++++
 .../org/apache/camel/model/convertHeaderTo.json    |  5 ++-
 .../camel/model/ConvertHeaderDefinition.java       | 24 ++++++++++++
 .../apache/camel/model/ProcessorDefinition.java    | 13 +++++++
 .../apache/camel/reifier/ConvertHeaderReifier.java | 14 ++++++-
 .../processor/converter/ConvertHeaderTest.java     | 14 +++++++
 .../mbean/ManagedConvertHeaderMBean.java           |  3 ++
 .../management/mbean/ManagedConvertHeader.java     |  5 +++
 .../support/processor/ConvertHeaderProcessor.java  | 14 ++++++-
 .../java/org/apache/camel/xml/in/ModelParser.java  |  1 +
 .../java/org/apache/camel/xml/out/ModelWriter.java |  1 +
 .../org/apache/camel/yaml/out/ModelWriter.java     |  1 +
 .../dsl/yaml/deserializers/ModelDeserializers.java |  6 +++
 .../generated/resources/schema/camelYamlDsl.json   |  5 +++
 .../apache/camel/dsl/yaml/ConvertHeaderTest.groovy | 36 ++++++++++++++++++
 16 files changed, 184 insertions(+), 7 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/convertHeaderTo.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/convertHeaderTo.json
index 8567cc09065..0e2e103a2f2 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/convertHeaderTo.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/convertHeaderTo.json
@@ -17,7 +17,8 @@
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "name": { "index": 3, "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of message header to convert its value The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used." },
     "type": { "index": 4, "kind": "attribute", "displayName": "Type", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The java type to convert to" },
-    "mandatory": { "index": 5, "kind": "attribute", "displayName": "Mandatory", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "When mandatory then the conversion must return a value (cannot be null), if this is not possible then NoTypeConversionAvailableException is thrown. Setting this to false could mean conversion is not possible and the value is [...]
-    "charset": { "index": 6, "kind": "attribute", "displayName": "Charset", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To use a specific charset when converting" }
+    "toName": { "index": 5, "kind": "attribute", "displayName": "To Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To use another header to store the result. By default, the result is stored in the same header. This option allows to use another header. The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used." },
+    "mandatory": { "index": 6, "kind": "attribute", "displayName": "Mandatory", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "When mandatory then the conversion must return a value (cannot be null), if this is not possible then NoTypeConversionAvailableException is thrown. Setting this to false could mean conversion is not possible and the value is [...]
+    "charset": { "index": 7, "kind": "attribute", "displayName": "Charset", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To use a specific charset when converting" }
   }
 }
diff --git a/core/camel-core-engine/src/main/docs/modules/eips/pages/convertHeaderTo-eip.adoc b/core/camel-core-engine/src/main/docs/modules/eips/pages/convertHeaderTo-eip.adoc
index 659e7c8eb87..df04a1ac43b 100644
--- a/core/camel-core-engine/src/main/docs/modules/eips/pages/convertHeaderTo-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/modules/eips/pages/convertHeaderTo-eip.adoc
@@ -57,6 +57,50 @@ YAML::
 ----
 ====
 
+=== Convert to another header
+
+By default, the converted value is replaced in the existing header. However, you can tell Camel to store the result into another header,
+such as shown below where the value is stored in the `bar` header:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("seda:foo")
+  .convertHeaderTo("foo", "bar", String.class)
+  .log("The header content: ${header.bar}");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+  <from uri="seda:foo"/>
+  <convertHeaderTo name="foo" toName="bar" type="String"/>
+  <log message="The header content: ${header.bar}"/>
+</route>
+----
+
+YAML::
++
+[source,yaml]
+----
+- from:
+    uri: seda:foo
+    steps:
+      - convertHeaderTo:
+          name: foo
+          toName: bar
+          type: String
+      - log:
+          message: "The header content: ${header.bar}"
+----
+====
+
+
 === Dynamic header name
 
 The ConvertHeaderTo supports using xref:components:languages:simple-language.adoc[Simple] language for dynamic header name.
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/convertHeaderTo.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/convertHeaderTo.json
index 8567cc09065..0e2e103a2f2 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/convertHeaderTo.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/convertHeaderTo.json
@@ -17,7 +17,8 @@
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "name": { "index": 3, "kind": "attribute", "displayName": "Name", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of message header to convert its value The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used." },
     "type": { "index": 4, "kind": "attribute", "displayName": "Type", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The java type to convert to" },
-    "mandatory": { "index": 5, "kind": "attribute", "displayName": "Mandatory", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "When mandatory then the conversion must return a value (cannot be null), if this is not possible then NoTypeConversionAvailableException is thrown. Setting this to false could mean conversion is not possible and the value is [...]
-    "charset": { "index": 6, "kind": "attribute", "displayName": "Charset", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To use a specific charset when converting" }
+    "toName": { "index": 5, "kind": "attribute", "displayName": "To Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To use another header to store the result. By default, the result is stored in the same header. This option allows to use another header. The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used." },
+    "mandatory": { "index": 6, "kind": "attribute", "displayName": "Mandatory", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "When mandatory then the conversion must return a value (cannot be null), if this is not possible then NoTypeConversionAvailableException is thrown. Setting this to false could mean conversion is not possible and the value is [...]
+    "charset": { "index": 7, "kind": "attribute", "displayName": "Charset", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To use a specific charset when converting" }
   }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/ConvertHeaderDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/ConvertHeaderDefinition.java
index 6839c1268e4..89dab3ddb63 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/ConvertHeaderDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/ConvertHeaderDefinition.java
@@ -40,6 +40,8 @@ public class ConvertHeaderDefinition extends NoOutputDefinition<ConvertHeaderDef
     @XmlAttribute(required = true)
     private String type;
     @XmlAttribute
+    private String toName;
+    @XmlAttribute
     @Metadata(label = "advanced", javaType = "java.lang.Boolean", defaultValue = "true")
     private String mandatory;
     @XmlAttribute
@@ -60,6 +62,13 @@ public class ConvertHeaderDefinition extends NoOutputDefinition<ConvertHeaderDef
         setType(typeClass.getCanonicalName());
     }
 
+    public ConvertHeaderDefinition(String name, String toName, Class<?> typeClass) {
+        setName(name);
+        setToName(toName);
+        setTypeClass(typeClass);
+        setType(typeClass.getCanonicalName());
+    }
+
     public ConvertHeaderDefinition(String name, Class<?> typeClass, boolean mandatory) {
         setName(name);
         setTypeClass(typeClass);
@@ -103,6 +112,21 @@ public class ConvertHeaderDefinition extends NoOutputDefinition<ConvertHeaderDef
         return name;
     }
 
+    public String getToName() {
+        return toName;
+    }
+
+    /**
+     * To use another header to store the result. By default, the result is stored in the same header. This option
+     * allows to use another header.
+     * <p/>
+     * The <tt>simple</tt> language can be used to define a dynamic evaluated header name to be used. Otherwise a
+     * constant name will be used.
+     */
+    public void setToName(String toName) {
+        this.toName = toName;
+    }
+
     public String getType() {
         return type;
     }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
index 46dee7fa71e..798ac1caaba 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
@@ -2832,6 +2832,19 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
         return asType();
     }
 
+    /**
+     * Converts the IN message header to the specified type
+     *
+     * @param  name   the header name
+     * @param  toName to use another header to store the result
+     * @param  type   the type to convert to
+     * @return        the builder
+     */
+    public Type convertHeaderTo(String name, String toName, Class<?> type) {
+        addOutput(new ConvertHeaderDefinition(name, toName, type));
+        return asType();
+    }
+
     /**
      * Converts the IN message header to the specified type
      *
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ConvertHeaderReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ConvertHeaderReifier.java
index 6e971b1092a..f184409b4fa 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ConvertHeaderReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ConvertHeaderReifier.java
@@ -43,13 +43,25 @@ public class ConvertHeaderReifier extends ProcessorReifier<ConvertHeaderDefiniti
             nameExpr = camelContext.resolveLanguage("constant").createExpression(key);
         }
         nameExpr.init(camelContext);
+
+        String toKey = parseString(definition.getToName());
+        Expression toNameExpr = null;
+        if (toKey != null) {
+            if (LanguageSupport.hasSimpleFunction(toKey)) {
+                toNameExpr = camelContext.resolveLanguage("simple").createExpression(toKey);
+            } else {
+                toNameExpr = camelContext.resolveLanguage("constant").createExpression(toKey);
+            }
+            toNameExpr.init(camelContext);
+        }
+
         Class<?> typeClass = parse(Class.class, or(definition.getTypeClass(), parseString(definition.getType())));
         String charset = validateCharset(parseString(definition.getCharset()));
         boolean mandatory = true;
         if (definition.getMandatory() != null) {
             mandatory = parseBoolean(definition.getMandatory(), true);
         }
-        return new ConvertHeaderProcessor(key, nameExpr, typeClass, charset, mandatory);
+        return new ConvertHeaderProcessor(key, nameExpr, toKey, toNameExpr, typeClass, charset, mandatory);
     }
 
     public static String validateCharset(String charset) throws UnsupportedCharsetException {
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertHeaderTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertHeaderTest.java
index c3a5be38fcc..0680c6f6be0 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertHeaderTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/converter/ConvertHeaderTest.java
@@ -100,6 +100,19 @@ public class ConvertHeaderTest extends ContextTestSupport {
         assertMockEndpointsSatisfied();
     }
 
+    @Test
+    public void testConvertToName() throws Exception {
+        MockEndpoint result = getMockEndpoint("mock:result");
+        result.expectedHeaderReceived("foo", "11");
+        result.expectedHeaderReceived("bar", 11);
+        result.message(0).header("foo").isInstanceOf(String.class);
+        result.message(0).header("bar").isInstanceOf(Integer.class);
+
+        template.sendBodyAndHeader("direct:bar", null, "foo", "11");
+
+        assertMockEndpointsSatisfied();
+    }
+
     @Test
     public void testConvertToIntegerNotMandatory() throws Exception {
         // mandatory should fail
@@ -209,6 +222,7 @@ public class ConvertHeaderTest extends ContextTestSupport {
                 from("direct:charset").convertHeaderTo("foo", byte[].class, "iso-8859-1").to("mock:result");
                 from("direct:charset2").convertHeaderTo("foo", byte[].class, "utf-16").to("mock:result");
                 from("direct:charset3").convertHeaderTo("foo", String.class, "utf-16").to("mock:result");
+                from("direct:bar").convertHeaderTo("foo", "bar", Integer.class).to("mock:result");
             }
         };
     }
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedConvertHeaderMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedConvertHeaderMBean.java
index a2f558e7aae..fdc0acf36a9 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedConvertHeaderMBean.java
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedConvertHeaderMBean.java
@@ -23,6 +23,9 @@ public interface ManagedConvertHeaderMBean extends ManagedProcessorMBean {
     @ManagedAttribute(description = "The header name")
     String getName();
 
+    @ManagedAttribute(description = "If the result should be stored in another header")
+    String getToName();
+
     @ManagedAttribute(description = "The java type to convert to")
     String getType();
 
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedConvertHeader.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedConvertHeader.java
index 03797f8fd3a..82b1d500eb8 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedConvertHeader.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedConvertHeader.java
@@ -36,6 +36,11 @@ public class ManagedConvertHeader extends ManagedProcessor implements ManagedCon
         return processor.getName();
     }
 
+    @Override
+    public String getToName() {
+        return processor.getToName();
+    }
+
     @Override
     public String getType() {
         return processor.getType().getCanonicalName();
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/processor/ConvertHeaderProcessor.java b/core/camel-support/src/main/java/org/apache/camel/support/processor/ConvertHeaderProcessor.java
index 2b7c25a6a5d..705ac589fbd 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/processor/ConvertHeaderProcessor.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/processor/ConvertHeaderProcessor.java
@@ -40,15 +40,20 @@ public class ConvertHeaderProcessor extends ServiceSupport implements AsyncProce
     private String routeId;
     private final String name;
     private final Expression headerName;
+    private final String toName;
+    private final Expression toHeaderName;
     private final Class<?> type;
     private final String charset;
     private final boolean mandatory;
 
-    public ConvertHeaderProcessor(String name, Expression headerName, Class<?> type, String charset, boolean mandatory) {
+    public ConvertHeaderProcessor(String name, Expression headerName, String toName, Expression toHeaderName,
+                                  Class<?> type, String charset, boolean mandatory) {
         ObjectHelper.notNull(headerName, "headerName");
         ObjectHelper.notNull(type, "type", this);
         this.name = name;
         this.headerName = headerName;
+        this.toName = toName;
+        this.toHeaderName = toHeaderName;
         this.type = type;
         this.charset = IOHelper.normalizeCharset(charset);
         this.mandatory = mandatory;
@@ -85,6 +90,7 @@ public class ConvertHeaderProcessor extends ServiceSupport implements AsyncProce
 
         // what is the header name
         String name = headerName.evaluate(exchange, String.class);
+        String targetName = toHeaderName != null ? toHeaderName.evaluate(exchange, String.class) : name;
 
         if (old.getHeader(name) == null) {
             // only convert if there is a header
@@ -114,7 +120,7 @@ public class ConvertHeaderProcessor extends ServiceSupport implements AsyncProce
         } else {
             value = exchange.getContext().getTypeConverter().convertTo(type, exchange, value);
         }
-        old.setHeader(name, value);
+        old.setHeader(targetName, value);
 
         // remove or restore charset when we are done as we should not propagate that,
         // as that can lead to double converting later on
@@ -149,6 +155,10 @@ public class ConvertHeaderProcessor extends ServiceSupport implements AsyncProce
         return name;
     }
 
+    public String getToName() {
+        return toName;
+    }
+
     public Class<?> getType() {
         return type;
     }
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index 29bbc496d4f..8bb83fd7070 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -318,6 +318,7 @@ public class ModelParser extends BaseParser {
                 case "charset": def.setCharset(val); break;
                 case "mandatory": def.setMandatory(val); break;
                 case "name": def.setName(val); break;
+                case "toName": def.setToName(val); break;
                 case "type": def.setType(val); break;
                 default: return processorDefinitionAttributeHandler().accept(def, key, val);
             }
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
index 29576e4c78e..3a838680d24 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
@@ -1188,6 +1188,7 @@ public class ModelWriter extends BaseWriter {
         startElement(name);
         doWriteProcessorDefinitionAttributes(def);
         doWriteAttribute("charset", def.getCharset());
+        doWriteAttribute("toName", def.getToName());
         doWriteAttribute("name", def.getName());
         doWriteAttribute("type", def.getType());
         doWriteAttribute("mandatory", def.getMandatory());
diff --git a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
index eb43c07425c..4dadf86af71 100644
--- a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
+++ b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
@@ -1188,6 +1188,7 @@ public class ModelWriter extends BaseWriter {
         startElement(name);
         doWriteProcessorDefinitionAttributes(def);
         doWriteAttribute("charset", def.getCharset());
+        doWriteAttribute("toName", def.getToName());
         doWriteAttribute("name", def.getName());
         doWriteAttribute("type", def.getType());
         doWriteAttribute("mandatory", def.getMandatory());
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index 3984352312e..d74e84bd92d 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -2583,6 +2583,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     @YamlProperty(name = "inheritErrorHandler", type = "boolean"),
                     @YamlProperty(name = "mandatory", type = "boolean", description = "When mandatory then the conversion must return a value (cannot be null), if this is not possible then NoTypeConversionAvailableException is thrown. Setting this to false could mean conversion is not possible and the value is null.", displayName = "Mandatory"),
                     @YamlProperty(name = "name", type = "string", required = true, description = "Name of message header to convert its value The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used.", displayName = "Name"),
+                    @YamlProperty(name = "toName", type = "string", description = "To use another header to store the result. By default, the result is stored in the same header. This option allows to use another header. The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used.", displayName = "To Name"),
                     @YamlProperty(name = "type", type = "string", required = true, description = "The java type to convert to", displayName = "Type")
             }
     )
@@ -2626,6 +2627,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     target.setName(val);
                     break;
                 }
+                case "toName": {
+                    String val = asText(node);
+                    target.setToName(val);
+                    break;
+                }
                 case "type": {
                     String val = asText(node);
                     target.setType(val);
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
index 420ef377c91..2a1fb08c1cd 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
@@ -847,6 +847,11 @@
             "title" : "Name",
             "description" : "Name of message header to convert its value The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used."
           },
+          "toName" : {
+            "type" : "string",
+            "title" : "To Name",
+            "description" : "To use another header to store the result. By default, the result is stored in the same header. This option allows to use another header. The simple language can be used to define a dynamic evaluated header name to be used. Otherwise a constant name will be used."
+          },
           "type" : {
             "type" : "string",
             "title" : "Type",
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/ConvertHeaderTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/ConvertHeaderTest.groovy
index e920c5c8a46..bf58edd4d8a 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/ConvertHeaderTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/ConvertHeaderTest.groovy
@@ -57,6 +57,42 @@ class ConvertHeaderTest extends YamlTestSupport {
             MockEndpoint.assertIsSatisfied(context)
     }
 
+    def "convert-header-another-to"() {
+        setup:
+        loadRoutes '''
+                - from:
+                    uri: "direct:start"
+                    steps:    
+                      - convertHeaderTo:
+                          name: foo
+                          toName: bar  
+                          type: "java.lang.String"
+                          charset: "UTF8"
+                      - to: "mock:result"
+            '''
+
+        withMock('mock:result') {
+            expectedHeaderReceived("bar", 'test')
+        }
+        when:
+        context.start()
+
+        withTemplate {
+            to('direct:start').withHeader("foo", 'test'.bytes).send()
+        }
+        then:
+        context.routeDefinitions.size() == 1
+
+        with(context.routeDefinitions[0].outputs[0], ConvertHeaderDefinition) {
+            name == 'foo'
+            toName == 'bar'
+            type == 'java.lang.String'
+            charset == 'UTF8'
+        }
+
+        MockEndpoint.assertIsSatisfied(context)
+    }
+
     def "Error: kebab-case: convert-header-to"() {
         when:
         var route = '''