You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by cd...@apache.org on 2023/07/04 11:56:47 UTC

[camel] branch main updated (ae4213b73dd -> bc1d1c10632)

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

cdeppisch pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


    from ae4213b73dd Add .sdkmanrc to select the recommended Maven and Java versions if the user uses SDKMAN
     new 55191eca46a CAMEL-18698 Add support for multiple input/output data types on components
     new 2d8812eefe9 CAMEL-18698 Enhance YAML DSL loader to support input/output data types
     new bc1d1c10632 CAMEL-18698 Enhance transform EIP and transformer documentation

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/apache/camel/catalog/models/transform.json |   8 +-
 .../apache/camel/catalog/models/transformers.json  |   2 +-
 .../apache/camel/catalog/schemas/camel-spring.xsd  |  29 +++
 components/camel-aws/camel-aws2-s3/pom.xml         |   8 +
 .../AWS2S3CloudEventDataTypeTransformer.java       |  54 ++++++
 .../transformer/aws2-s3-application-cloudevents    |  18 ++
 .../AWS2S3CloudEventDataTypeTransformerTest.java   |  69 +++++++
 .../transform/AWS2S3TransformCloudEventsTest.java  |  82 +++++++++
 components/camel-cloudevents/pom.xml               |   7 +
 .../camel/component/cloudevents/CloudEvent.java    |  16 ++
 .../CloudEventHttpDataTypeTransformer.java         |  69 +++++++
 .../CloudEventJsonDataTypeTransformer.java         |  88 +++++++++
 .../transformer/application-cloudevents-json       |  18 ++
 .../transformer/http-application-cloudevents       |  18 ++
 .../CloudEventHttpDataTypeTransformerTest.java     | 110 ++++++++++++
 .../CloudEventJsonDataTypeTransformerTest.java     | 103 +++++++++++
 .../transformer/SpringTransformerRouteTest.xml     |  18 +-
 .../main/java/org/apache/camel/CamelContext.java   |  14 +-
 .../main/java/org/apache/camel/spi/DataType.java   |  57 ++++--
 .../org/apache/camel/spi/DataTypeTransformer.java  |  60 +++++++
 .../java/org/apache/camel/spi/Transformer.java     |  62 ++++++-
 .../org/apache/camel/spi/TransformerLoader.java}   |  20 ++-
 .../org/apache/camel/spi/TransformerResolver.java  |  54 ++++++
 .../camel/impl/engine/AbstractCamelContext.java    |   4 +-
 .../impl/engine/DefaultTransformerRegistry.java    | 121 +++++++++++--
 .../impl/engine/DefaultTransformerResolver.java    |  65 +++++++
 .../impl/engine/DefaultValidatorRegistry.java      |   2 +-
 .../apache/camel/impl/engine/TransformerKey.java   |  46 +++--
 .../docs/modules/eips/pages/transform-eip.adoc     |  43 +++++
 .../org/apache/camel/impl/DefaultCamelContext.java |  12 +-
 .../org/apache/camel/model/transform.json          |   8 +-
 .../org/apache/camel/model/transformer/jaxb.index  |   1 +
 .../camel/model/transformer/transformers.json      |   2 +-
 .../apache/camel/builder/TransformerBuilder.java   |  55 +++++-
 .../apache/camel/model/ProcessorDefinition.java    |  28 +++
 .../apache/camel/model/TransformDefinition.java    |  50 ++++++
 .../transformer/LoadTransformerDefinition.java     |  64 +++++++
 .../model/transformer/TransformerDefinition.java   |  31 +++-
 .../model/transformer/TransformersDefinition.java  |   1 +
 .../org/apache/camel/processor/ContractAdvice.java |  45 +++--
 .../transformer/AnnotationTransformerLoader.java   | 198 +++++++++++++++++++++
 .../transformer/ByteArrayDataTypeTransformer.java} |  31 ++--
 .../transformer/DataFormatTransformer.java         |  16 +-
 .../processor/transformer/DataTypeProcessor.java   | 120 +++++++++++++
 .../transformer/DefaultTransformerLoader.java      |  48 +++++
 .../transformer/ProcessorTransformer.java          |   7 +-
 .../transformer/StringDataTypeTransformer.java     |  46 +++++
 .../transformer/TypeConverterTransformer.java      |  80 +++++++++
 .../datatype/transformer/application-octet-stream  |  18 ++
 .../apache/camel/datatype/transformer/plain-text   |  18 ++
 .../org/apache/camel/reifier/TransformReifier.java |  10 ++
 .../transformer/CustomTransformerReifier.java      |   5 +-
 .../transformer/DataFormatTransformerReifier.java  |   3 +-
 .../transformer/EndpointTransformerReifier.java    |   2 +-
 ...merReifier.java => LoadTransformerReifier.java} |  25 +--
 .../reifier/transformer/TransformerReifier.java    |   3 +
 .../core/xml/AbstractCamelContextFactoryBean.java  |  12 +-
 .../camel/builder/TransformerBuilderTest.java      |   2 +-
 .../engine/DefaultTransformerRegistryTest.java     |  47 +++++
 .../engine/DefaultTransformerResolverTest.java     |  75 ++++++++
 .../impl/engine/LowercaseDataTypeTransformer.java} |  19 +-
 .../impl/engine/UppercaseDataTypeTransformer.java} |  19 +-
 .../processor/TransformDataTypeProcessorTest.java  |  45 +++++
 .../ByteArrayDataTypeTransformerTest.java          | 101 +++++++++++
 .../transformer/DataTypeProcessorTest.java         |  79 ++++++++
 .../transformer/StringDataTypeTransformerTest.java |  89 +++++++++
 .../transformer/TransformerRouteTest.java          |  19 +-
 .../custom/CustomDataTypeTransformer.java}         |  19 +-
 .../org/apache/camel/datatype/transformer/foo-json |  18 ++
 .../apache/camel/datatype/transformer/lowercase    |  18 ++
 .../apache/camel/datatype/transformer/uppercase    |  18 ++
 .../api/management/mbean/CamelOpenMBeanTypes.java  |   6 +-
 .../management/mbean/ManagedTransformMBean.java    |   6 +
 .../DefaultManagementObjectStrategy.java           |   5 +-
 .../camel/management/mbean/ManagedTransformer.java |  16 +-
 .../mbean/ManagedTransformerRegistry.java          |  10 +-
 .../management/ManagedTransformerRegistryTest.java |  16 +-
 .../java/org/apache/camel/xml/in/ModelParser.java  |  22 ++-
 .../java/org/apache/camel/xml/out/ModelWriter.java |  14 ++
 .../org/apache/camel/yaml/out/ModelWriter.java     |  14 ++
 .../modules/ROOT/pages/transformer.adoc            | 184 +++++++++++++++----
 .../dsl/yaml/deserializers/ModelDeserializers.java | 110 +++++++++++-
 .../deserializers/ModelDeserializersResolver.java  |   1 +
 .../deserializers/RouteDefinitionDeserializer.java |  12 ++
 .../generated/resources/schema/camel-yaml-dsl.json |  47 +++++
 .../generated/resources/schema/camelYamlDsl.json   |  47 +++++
 .../camel/dsl/yaml/YamlRoutesBuilderLoader.java    |  26 +++
 .../camel/dsl/yaml/KameletBindingLoaderTest.groovy |  97 ++++++++++
 .../org/apache/camel/dsl/yaml/RoutesTest.groovy    |  27 +++
 .../org/apache/camel/dsl/yaml/TransformTest.groovy |  51 ++++++
 90 files changed, 3240 insertions(+), 243 deletions(-)
 create mode 100644 components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformer.java
 create mode 100644 components/camel-aws/camel-aws2-s3/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/aws2-s3-application-cloudevents
 create mode 100644 components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformerTest.java
 create mode 100644 components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3TransformCloudEventsTest.java
 create mode 100644 components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformer.java
 create mode 100644 components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformer.java
 create mode 100644 components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-cloudevents-json
 create mode 100644 components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/http-application-cloudevents
 create mode 100644 components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformerTest.java
 create mode 100644 components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformerTest.java
 create mode 100644 core/camel-api/src/main/java/org/apache/camel/spi/DataTypeTransformer.java
 copy core/{camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java => camel-api/src/main/java/org/apache/camel/spi/TransformerLoader.java} (65%)
 create mode 100644 core/camel-api/src/main/java/org/apache/camel/spi/TransformerResolver.java
 create mode 100644 core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerResolver.java
 create mode 100644 core/camel-core-model/src/main/java/org/apache/camel/model/transformer/LoadTransformerDefinition.java
 create mode 100644 core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/AnnotationTransformerLoader.java
 copy core/{camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java => camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformer.java} (50%)
 create mode 100644 core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataTypeProcessor.java
 create mode 100644 core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DefaultTransformerLoader.java
 create mode 100644 core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/StringDataTypeTransformer.java
 create mode 100644 core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/TypeConverterTransformer.java
 create mode 100644 core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-octet-stream
 create mode 100644 core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/plain-text
 copy core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/{DataFormatTransformerReifier.java => LoadTransformerReifier.java} (53%)
 create mode 100644 core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerRegistryTest.java
 create mode 100644 core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerResolverTest.java
 copy core/{camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java => camel-core/src/test/java/org/apache/camel/impl/engine/LowercaseDataTypeTransformer.java} (63%)
 copy core/{camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java => camel-core/src/test/java/org/apache/camel/impl/engine/UppercaseDataTypeTransformer.java} (63%)
 create mode 100644 core/camel-core/src/test/java/org/apache/camel/processor/TransformDataTypeProcessorTest.java
 create mode 100644 core/camel-core/src/test/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformerTest.java
 create mode 100644 core/camel-core/src/test/java/org/apache/camel/processor/transformer/DataTypeProcessorTest.java
 create mode 100644 core/camel-core/src/test/java/org/apache/camel/processor/transformer/StringDataTypeTransformerTest.java
 copy core/{camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java => camel-core/src/test/java/org/apache/camel/processor/transformer/custom/CustomDataTypeTransformer.java} (63%)
 create mode 100644 core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/foo-json
 create mode 100644 core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/lowercase
 create mode 100644 core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/uppercase
 create mode 100644 dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/TransformTest.groovy


[camel] 01/03: CAMEL-18698 Add support for multiple input/output data types on components

Posted by cd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 55191eca46a46ced9f73eb82751a5eca7d599f14
Author: Christoph Deppisch <cd...@redhat.com>
AuthorDate: Wed Jun 28 08:54:44 2023 +0200

    CAMEL-18698 Add support for multiple input/output data types on components
    
    - Add data type to transform EIP resulting in a transformation from given type to target type using a matching transformer implementation
    - Enhance data type transformer resolving mechanism as follows:
    - Add lazy loading of transformer implementations via resource path factory finder
    - Add annotation based transformer loader (adds possibility to load transformer implementations with classpath scan)
    - Add possibility to configure preloading of default Camel transformer implementations
    - Add default Camel transformer implementations for String and byte[]
    - Add CloudEvents transformer implementation to transform any Camel Exchange into CloudEvent Http or Json binding
    - Add AWS S3 CloudEvents transformer implementation to transform getObject response into proper CloudEvent
---
 .../org/apache/camel/catalog/models/transform.json |   8 +-
 .../apache/camel/catalog/models/transformers.json  |   2 +-
 .../apache/camel/catalog/schemas/camel-spring.xsd  |  29 +++
 components/camel-aws/camel-aws2-s3/pom.xml         |   8 +
 .../AWS2S3CloudEventDataTypeTransformer.java       |  54 ++++++
 .../transformer/aws2-s3-application-cloudevents    |  18 ++
 .../AWS2S3CloudEventDataTypeTransformerTest.java   |  69 +++++++
 .../transform/AWS2S3TransformCloudEventsTest.java  |  82 +++++++++
 components/camel-cloudevents/pom.xml               |   7 +
 .../camel/component/cloudevents/CloudEvent.java    |  16 ++
 .../CloudEventHttpDataTypeTransformer.java         |  69 +++++++
 .../CloudEventJsonDataTypeTransformer.java         |  88 +++++++++
 .../transformer/application-cloudevents-json       |  18 ++
 .../transformer/http-application-cloudevents       |  18 ++
 .../CloudEventHttpDataTypeTransformerTest.java     | 110 ++++++++++++
 .../CloudEventJsonDataTypeTransformerTest.java     | 103 +++++++++++
 .../transformer/SpringTransformerRouteTest.xml     |  18 +-
 .../main/java/org/apache/camel/CamelContext.java   |  14 +-
 .../main/java/org/apache/camel/spi/DataType.java   |  57 ++++--
 .../org/apache/camel/spi/DataTypeTransformer.java  |  60 +++++++
 .../java/org/apache/camel/spi/Transformer.java     |  62 ++++++-
 .../org/apache/camel/spi/TransformerLoader.java}   |  20 ++-
 .../org/apache/camel/spi/TransformerResolver.java  |  54 ++++++
 .../camel/impl/engine/AbstractCamelContext.java    |   4 +-
 .../impl/engine/DefaultTransformerRegistry.java    | 121 +++++++++++--
 .../impl/engine/DefaultTransformerResolver.java    |  65 +++++++
 .../impl/engine/DefaultValidatorRegistry.java      |   2 +-
 .../apache/camel/impl/engine/TransformerKey.java   |  46 +++--
 .../org/apache/camel/impl/DefaultCamelContext.java |  12 +-
 .../org/apache/camel/model/transform.json          |   8 +-
 .../org/apache/camel/model/transformer/jaxb.index  |   1 +
 .../camel/model/transformer/transformers.json      |   2 +-
 .../apache/camel/builder/TransformerBuilder.java   |  55 +++++-
 .../apache/camel/model/ProcessorDefinition.java    |  28 +++
 .../apache/camel/model/TransformDefinition.java    |  50 ++++++
 .../transformer/LoadTransformerDefinition.java     |  64 +++++++
 .../model/transformer/TransformerDefinition.java   |  31 +++-
 .../model/transformer/TransformersDefinition.java  |   1 +
 .../org/apache/camel/processor/ContractAdvice.java |  45 +++--
 .../transformer/AnnotationTransformerLoader.java   | 198 +++++++++++++++++++++
 .../transformer/ByteArrayDataTypeTransformer.java} |  31 ++--
 .../transformer/DataFormatTransformer.java         |  16 +-
 .../processor/transformer/DataTypeProcessor.java   | 120 +++++++++++++
 .../transformer/DefaultTransformerLoader.java      |  48 +++++
 .../transformer/ProcessorTransformer.java          |   7 +-
 .../transformer/StringDataTypeTransformer.java     |  46 +++++
 .../transformer/TypeConverterTransformer.java      |  80 +++++++++
 .../datatype/transformer/application-octet-stream  |  18 ++
 .../apache/camel/datatype/transformer/plain-text   |  18 ++
 .../org/apache/camel/reifier/TransformReifier.java |  10 ++
 .../transformer/CustomTransformerReifier.java      |   5 +-
 .../transformer/DataFormatTransformerReifier.java  |   3 +-
 .../transformer/EndpointTransformerReifier.java    |   2 +-
 ...merReifier.java => LoadTransformerReifier.java} |  25 +--
 .../reifier/transformer/TransformerReifier.java    |   3 +
 .../core/xml/AbstractCamelContextFactoryBean.java  |  12 +-
 .../camel/builder/TransformerBuilderTest.java      |   2 +-
 .../engine/DefaultTransformerRegistryTest.java     |  47 +++++
 .../engine/DefaultTransformerResolverTest.java     |  75 ++++++++
 .../impl/engine/LowercaseDataTypeTransformer.java} |  19 +-
 .../impl/engine/UppercaseDataTypeTransformer.java} |  19 +-
 .../processor/TransformDataTypeProcessorTest.java  |  45 +++++
 .../ByteArrayDataTypeTransformerTest.java          | 101 +++++++++++
 .../transformer/DataTypeProcessorTest.java         |  79 ++++++++
 .../transformer/StringDataTypeTransformerTest.java |  89 +++++++++
 .../transformer/TransformerRouteTest.java          |  19 +-
 .../custom/CustomDataTypeTransformer.java}         |  19 +-
 .../org/apache/camel/datatype/transformer/foo-json |  18 ++
 .../apache/camel/datatype/transformer/lowercase    |  18 ++
 .../apache/camel/datatype/transformer/uppercase    |  18 ++
 .../api/management/mbean/CamelOpenMBeanTypes.java  |   6 +-
 .../management/mbean/ManagedTransformMBean.java    |   6 +
 .../DefaultManagementObjectStrategy.java           |   5 +-
 .../camel/management/mbean/ManagedTransformer.java |  16 +-
 .../mbean/ManagedTransformerRegistry.java          |  10 +-
 .../management/ManagedTransformerRegistryTest.java |  16 +-
 .../java/org/apache/camel/xml/in/ModelParser.java  |  22 ++-
 .../java/org/apache/camel/xml/out/ModelWriter.java |  14 ++
 .../org/apache/camel/yaml/out/ModelWriter.java     |  14 ++
 .../dsl/yaml/deserializers/ModelDeserializers.java | 110 +++++++++++-
 .../deserializers/ModelDeserializersResolver.java  |   1 +
 .../generated/resources/schema/camel-yaml-dsl.json |  47 +++++
 .../generated/resources/schema/camelYamlDsl.json   |  47 +++++
 83 files changed, 2831 insertions(+), 212 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transform.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transform.json
index 5e37dc5dd65..85e827be37f 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transform.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transform.json
@@ -13,8 +13,10 @@
   },
   "properties": {
     "expression": { "index": 0, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": fa [...]
-    "disabled": { "index": 1, "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." },
-    "id": { "index": 2, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
-    "description": { "index": 3, "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
+    "fromType": { "index": 1, "kind": "attribute", "displayName": "From Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "From type used in data type transformation." },
+    "toType": { "index": 2, "kind": "attribute", "displayName": "To Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To type used as a target data type in the transformation." },
+    "disabled": { "index": 3, "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." },
+    "id": { "index": 4, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "index": 5, "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transformers.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transformers.json
index af5d7902054..1f2ae2ab00a 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transformers.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transformers.json
@@ -12,6 +12,6 @@
     "output": false
   },
   "properties": {
-    "transformers": { "index": 0, "kind": "element", "displayName": "Transformers", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.transformer.TransformerDefinition>", "oneOf": [ "customTransformer", "dataFormatTransformer", "endpointTransformer" ], "deprecated": false, "autowired": false, "secret": false, "description": "The configured transformers" }
+    "transformers": { "index": 0, "kind": "element", "displayName": "Transformers", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.transformer.TransformerDefinition>", "oneOf": [ "customTransformer", "dataFormatTransformer", "endpointTransformer", "loadTransformer" ], "deprecated": false, "autowired": false, "secret": false, "description": "The configured transformers" }
   }
 }
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 649a953edab..dc428d9a181 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -13262,6 +13262,24 @@ Sets a reference to use for lookup the policy in the registry.
           <xs:element ref="tns:xpath"/>
           <xs:element ref="tns:xquery"/>
         </xs:choice>
+        <xs:attribute name="fromType" type="xs:string">
+          <xs:annotation>
+            <xs:documentation xml:lang="en">
+<![CDATA[
+From type used in data type transformation.
+]]>
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="toType" type="xs:string">
+          <xs:annotation>
+            <xs:documentation xml:lang="en">
+<![CDATA[
+To type used as a target data type in the transformation.
+]]>
+            </xs:documentation>
+          </xs:annotation>
+        </xs:attribute>
       </xs:extension>
     </xs:complexContent>
   </xs:complexType>
@@ -16165,6 +16183,7 @@ Sets the component name that this definition will apply to.
   <xs:complexType abstract="true" name="transformer">
     <xs:sequence/>
     <xs:attribute name="scheme" type="xs:string"/>
+    <xs:attribute name="name" type="xs:string"/>
     <xs:attribute name="fromType" type="xs:string"/>
     <xs:attribute name="toType" type="xs:string"/>
   </xs:complexType>
@@ -16227,11 +16246,21 @@ Sets the component name that this definition will apply to.
       </xs:extension>
     </xs:complexContent>
   </xs:complexType>
+  <xs:complexType name="loadTransformer">
+    <xs:complexContent>
+      <xs:extension base="tns:transformer">
+        <xs:sequence/>
+        <xs:attribute name="packageScan" type="xs:string"/>
+        <xs:attribute name="defaults" type="xs:string"/>
+      </xs:extension>
+    </xs:complexContent>
+  </xs:complexType>
   <xs:complexType name="transformersDefinition">
     <xs:sequence>
       <xs:choice maxOccurs="unbounded" minOccurs="0">
         <xs:element name="dataFormatTransformer" type="tns:dataFormatTransformer"/>
         <xs:element name="endpointTransformer" type="tns:endpointTransformer"/>
+        <xs:element name="loadTransformer" type="tns:loadTransformer"/>
         <xs:element name="customTransformer" type="tns:customTransformer"/>
       </xs:choice>
     </xs:sequence>
diff --git a/components/camel-aws/camel-aws2-s3/pom.xml b/components/camel-aws/camel-aws2-s3/pom.xml
index 91b47ced72e..3b79056ec21 100644
--- a/components/camel-aws/camel-aws2-s3/pom.xml
+++ b/components/camel-aws/camel-aws2-s3/pom.xml
@@ -55,6 +55,14 @@
             <artifactId>camel-health</artifactId>
         </dependency>
 
+        <!-- optional CloudEvent support -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-cloudevents</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+
         <!-- for testing -->
         <dependency>
             <groupId>org.apache.camel</groupId>
diff --git a/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformer.java b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformer.java
new file mode 100644
index 00000000000..6d718d506a1
--- /dev/null
+++ b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.aws2.s3.transform;
+
+import java.util.Map;
+
+import org.apache.camel.Message;
+import org.apache.camel.component.aws2.s3.AWS2S3Constants;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Data type transformer converts AWS S3 get object response to CloudEvent v1_0 data format. The data type sets Camel
+ * specific CloudEvent headers with values extracted from AWS S3 get object response.
+ */
+@DataTypeTransformer(name = "aws2-s3:application-cloudevents")
+public class AWS2S3CloudEventDataTypeTransformer extends Transformer {
+
+    @Override
+    public void transform(Message message, DataType fromType, DataType toType) {
+        final Map<String, Object> headers = message.getHeaders();
+
+        CloudEvent cloudEvent = CloudEvents.v1_0;
+        headers.putIfAbsent(CloudEvent.CAMEL_CLOUD_EVENT_ID, message.getExchange().getExchangeId());
+        headers.putIfAbsent(CloudEvent.CAMEL_CLOUD_EVENT_VERSION, cloudEvent.version());
+        headers.put(CloudEvent.CAMEL_CLOUD_EVENT_TYPE, "org.apache.camel.event.aws.s3.getObject");
+
+        if (message.getHeaders().containsKey(AWS2S3Constants.BUCKET_NAME)) {
+            headers.put(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE,
+                    "aws.s3.bucket." + message.getHeader(AWS2S3Constants.BUCKET_NAME, String.class));
+        }
+
+        headers.put(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT, message.getHeader(AWS2S3Constants.KEY, String.class));
+        headers.put(CloudEvent.CAMEL_CLOUD_EVENT_TIME, cloudEvent.getEventTime(message.getExchange()));
+    }
+}
diff --git a/components/camel-aws/camel-aws2-s3/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/aws2-s3-application-cloudevents b/components/camel-aws/camel-aws2-s3/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/aws2-s3-application-cloudevents
new file mode 100644
index 00000000000..ec5793a97f6
--- /dev/null
+++ b/components/camel-aws/camel-aws2-s3/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/aws2-s3-application-cloudevents
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.aws2.s3.transform.AWS2S3CloudEventDataTypeTransformer
diff --git a/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformerTest.java b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformerTest.java
new file mode 100644
index 00000000000..89011c482ab
--- /dev/null
+++ b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformerTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.aws2.s3.transform;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.aws2.s3.AWS2S3Constants;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class AWS2S3CloudEventDataTypeTransformerTest {
+
+    private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+    private final AWS2S3CloudEventDataTypeTransformer transformer = new AWS2S3CloudEventDataTypeTransformer();
+
+    @Test
+    void shouldMapToCloudEvent() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader(AWS2S3Constants.KEY, "test1.txt");
+        exchange.getMessage().setHeader(AWS2S3Constants.BUCKET_NAME, "myBucket");
+        exchange.getMessage().setHeader(AWS2S3Constants.CONTENT_TYPE, "text/plain");
+        exchange.getMessage().setHeader(AWS2S3Constants.CONTENT_ENCODING, StandardCharsets.UTF_8.toString());
+        exchange.getMessage().setBody(new ByteArrayInputStream("Test1".getBytes(StandardCharsets.UTF_8)));
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        Assertions.assertTrue(exchange.getMessage().hasHeaders());
+        Assertions.assertTrue(exchange.getMessage().getHeaders().containsKey(AWS2S3Constants.KEY));
+        assertEquals("org.apache.camel.event.aws.s3.getObject",
+                exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE));
+        assertEquals("test1.txt", exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT));
+        assertEquals("aws.s3.bucket.myBucket", exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE));
+    }
+
+    @Test
+    public void shouldLookupDataTypeTransformer() throws Exception {
+        Transformer transformer = camelContext.getTransformerRegistry()
+                .resolveTransformer(new TransformerKey("aws2-s3:application-cloudevents"));
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(AWS2S3CloudEventDataTypeTransformer.class, transformer.getClass());
+
+    }
+}
diff --git a/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3TransformCloudEventsTest.java b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3TransformCloudEventsTest.java
new file mode 100644
index 00000000000..4069f885e4a
--- /dev/null
+++ b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3TransformCloudEventsTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.aws2.s3.transform;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.aws2.s3.AWS2S3Constants;
+import org.apache.camel.component.aws2.s3.AWS2S3Operations;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class AWS2S3TransformCloudEventsTest extends CamelTestSupport {
+    protected MockEndpoint resultEndpoint;
+
+    @Test
+    public void testCloudEventDataTypeTransformation() throws Exception {
+        resultEndpoint.expectedBodiesReceived("Hello World!");
+
+        Exchange exchange = template.request("direct:start", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getMessage().setHeader(AWS2S3Constants.BUCKET_NAME, "mycamel");
+                exchange.getMessage().setHeader(AWS2S3Constants.KEY, "camel.txt");
+                exchange.getMessage().setHeader(AWS2S3Constants.S3_OPERATION, AWS2S3Operations.getObject);
+                exchange.getMessage().setBody("Hello");
+            }
+        });
+
+        resultEndpoint.assertIsSatisfied();
+        CloudEvent cloudEvent = CloudEvents.v1_0;
+        Message received = exchange.getMessage();
+        Assertions.assertEquals("org.apache.camel.event.aws.s3.getObject",
+                received.getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).http()));
+        Assertions.assertEquals("aws.s3.bucket.mycamel",
+                received.getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).http()));
+        Assertions.assertEquals(cloudEvent.version(),
+                received.getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).http()));
+        Assertions.assertEquals("Hello World!", received.getBody());
+    }
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+
+        resultEndpoint = getMockEndpoint("mock:result");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start")
+                        .inputType("aws2-s3:application-cloudevents")
+                        .setBody(body().append(" World!"))
+                        .outputType("http:application-cloudevents")
+                        .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-cloudevents/pom.xml b/components/camel-cloudevents/pom.xml
index f61eba3a973..b1900cc229e 100644
--- a/components/camel-cloudevents/pom.xml
+++ b/components/camel-cloudevents/pom.xml
@@ -44,6 +44,13 @@
             <artifactId>camel-support</artifactId>
         </dependency>
 
+        <!-- testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-junit5</artifactId>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
 </project>
diff --git a/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/CloudEvent.java b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/CloudEvent.java
index 0193549d8f1..ba3fc3d430a 100644
--- a/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/CloudEvent.java
+++ b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/CloudEvent.java
@@ -16,6 +16,10 @@
  */
 package org.apache.camel.component.cloudevents;
 
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Collection;
 import java.util.Objects;
 import java.util.Optional;
@@ -36,6 +40,9 @@ public interface CloudEvent {
     String CAMEL_CLOUD_EVENT_EXTENSIONS = "CamelCloudEventExtensions";
     String CAMEL_CLOUD_EVENT_CONTENT_TYPE = Exchange.CONTENT_TYPE;
 
+    String DEFAULT_CAMEL_CLOUD_EVENT_TYPE = "org.apache.camel.event";
+    String DEFAULT_CAMEL_CLOUD_EVENT_SOURCE = "org.apache.camel";
+
     /**
      * The CloudEvent spec version.
      */
@@ -65,6 +72,15 @@ public interface CloudEvent {
                 .orElseThrow(() -> new IllegalArgumentException("Unable to find attribute with id: " + id));
     }
 
+    /**
+     * Construct event time from given Camel exchange.
+     */
+    default String getEventTime(Exchange exchange) {
+        final ZonedDateTime created
+                = ZonedDateTime.ofInstant(Instant.ofEpochMilli(exchange.getCreated()), ZoneId.systemDefault());
+        return DateTimeFormatter.ISO_INSTANT.format(created);
+    }
+
     /**
      * Mandatory find http attribute by id.
      */
diff --git a/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformer.java b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformer.java
new file mode 100644
index 00000000000..c52c9af460e
--- /dev/null
+++ b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformer.java
@@ -0,0 +1,69 @@
+/*
+ * 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.cloudevents.transformer;
+
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Data type represents a default Camel CloudEvent V1 Http binding. The data type reads Camel specific CloudEvent
+ * headers and transforms these to Http headers according to the CloudEvents Http binding specification. Sets default
+ * values for CloudEvent attributes such as the Http content type header, event source, event type.
+ */
+@DataTypeTransformer(name = "http:application-cloudevents")
+public class CloudEventHttpDataTypeTransformer extends Transformer {
+
+    @Override
+    public void transform(Message message, DataType fromType, DataType toType) {
+        final Map<String, Object> headers = message.getHeaders();
+
+        CloudEvent cloudEvent = CloudEvents.v1_0;
+        headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).http(),
+                headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_ID, message.getExchange().getExchangeId()));
+        headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).http(),
+                headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_VERSION, cloudEvent.version()));
+        headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).http(),
+                headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_TYPE, CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_TYPE));
+        headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).http(),
+                headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE, CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_SOURCE));
+
+        if (headers.containsKey(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT)) {
+            headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT).http(),
+                    headers.get(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT));
+        }
+
+        if (headers.containsKey(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE)) {
+            headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE).http(),
+                    headers.get(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE));
+        }
+
+        headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TIME).http(),
+                headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_TIME, cloudEvent.getEventTime(message.getExchange())));
+        headers.putIfAbsent(Exchange.CONTENT_TYPE,
+                headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_CONTENT_TYPE, "application/json"));
+
+        cloudEvent.attributes().stream().map(CloudEvent.Attribute::id).forEach(headers::remove);
+    }
+}
diff --git a/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformer.java b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformer.java
new file mode 100644
index 00000000000..1eef7d27fab
--- /dev/null
+++ b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformer.java
@@ -0,0 +1,88 @@
+/*
+ * 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.cloudevents.transformer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Data type represents a default Camel CloudEvent V1 Json format binding. The data type reads Camel specific CloudEvent
+ * headers and transforms these to a Json object representing the CloudEvents Json format specification. Sets default
+ * values for CloudEvent attributes such as the Http content type header, event source, event type.
+ */
+@DataTypeTransformer(name = "application-cloudevents+json")
+public class CloudEventJsonDataTypeTransformer extends Transformer {
+
+    @Override
+    public void transform(Message message, DataType fromType, DataType toType) {
+        final Map<String, Object> headers = message.getHeaders();
+
+        Map<String, Object> cloudEventAttributes = new HashMap<>();
+        CloudEvent cloudEvent = CloudEvents.v1_0;
+        for (CloudEvent.Attribute attribute : cloudEvent.attributes()) {
+            if (headers.containsKey(attribute.id())) {
+                cloudEventAttributes.put(attribute.json(), headers.get(attribute.id()));
+            }
+        }
+
+        cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).json(),
+                cloudEvent.version());
+        cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).json(),
+                message.getExchange().getExchangeId());
+        cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).json(),
+                CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_TYPE);
+        cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).json(),
+                CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_SOURCE);
+
+        cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TIME).json(),
+                cloudEvent.getEventTime(message.getExchange()));
+
+        cloudEventAttributes.putIfAbsent("data", message.getBody(String.class));
+        cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE).json(),
+                headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_CONTENT_TYPE, "application/json"));
+
+        headers.put(Exchange.CONTENT_TYPE, "application/cloudevents+json");
+
+        message.setBody(createCouldEventJsonObject(cloudEventAttributes));
+
+        cloudEvent.attributes().stream().map(CloudEvent.Attribute::id).forEach(headers::remove);
+    }
+
+    private String createCouldEventJsonObject(Map<String, Object> cloudEventAttributes) {
+        StringBuilder builder = new StringBuilder("{");
+
+        cloudEventAttributes.forEach((key, value) -> {
+            builder.append(" ").append("\"").append(key).append("\"").append(":").append("\"").append(value).append("\"")
+                    .append(",");
+        });
+
+        if (!cloudEventAttributes.isEmpty()) {
+            builder.deleteCharAt(builder.lastIndexOf(","));
+        }
+
+        return builder.append("}").toString();
+    }
+}
diff --git a/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-cloudevents-json b/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-cloudevents-json
new file mode 100644
index 00000000000..d380ef770b9
--- /dev/null
+++ b/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-cloudevents-json
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.cloudevents.transformer.CloudEventJsonDataTypeTransformer
diff --git a/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/http-application-cloudevents b/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/http-application-cloudevents
new file mode 100644
index 00000000000..ca4580b0f73
--- /dev/null
+++ b/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/http-application-cloudevents
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.cloudevents.transformer.CloudEventHttpDataTypeTransformer
diff --git a/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformerTest.java b/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformerTest.java
new file mode 100644
index 00000000000..d4a864a7f6a
--- /dev/null
+++ b/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformerTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.cloudevents.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CloudEventHttpDataTypeTransformerTest {
+
+    private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+    private final CloudEventHttpDataTypeTransformer transformer = new CloudEventHttpDataTypeTransformer();
+
+    @Test
+    void shouldMapToHttpCloudEvent() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT, "test1.txt");
+        exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE, "org.apache.camel.event.test");
+        exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE, "org.apache.camel.test");
+        exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_CONTENT_TYPE, "text/plain");
+        exchange.getMessage().setBody(new ByteArrayInputStream("Test1".getBytes(StandardCharsets.UTF_8)));
+
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        CloudEvent cloudEvent = CloudEvents.v1_0;
+        assertTrue(exchange.getMessage().hasHeaders());
+        assertEquals(exchange.getExchangeId(),
+                exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).http()));
+        assertEquals(cloudEvent.version(),
+                exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).http()));
+        assertEquals("org.apache.camel.event.test",
+                exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).http()));
+        assertEquals("test1.txt",
+                exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT).http()));
+        assertEquals("org.apache.camel.test",
+                exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).http()));
+        assertTrue(exchange.getMessage().getHeaders()
+                .containsKey(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TIME).http()));
+        assertEquals("text/plain", exchange.getMessage().getHeader(Exchange.CONTENT_TYPE));
+        assertEquals("Test1", exchange.getMessage().getBody(String.class));
+
+        assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE));
+        assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE));
+        assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT));
+    }
+
+    @Test
+    void shouldSetDefaultCloudEventAttributes() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setBody(new ByteArrayInputStream("{}".getBytes(StandardCharsets.UTF_8)));
+
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        CloudEvent cloudEvent = CloudEvents.v1_0;
+        assertTrue(exchange.getMessage().hasHeaders());
+        assertEquals(exchange.getExchangeId(),
+                exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).http()));
+        assertEquals(cloudEvent.version(),
+                exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).http()));
+        assertEquals(CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_TYPE,
+                exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).http()));
+        assertNull(exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT).http()));
+        assertEquals(CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_SOURCE,
+                exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).http()));
+        assertTrue(exchange.getMessage().getHeaders()
+                .containsKey(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TIME).http()));
+        assertEquals("application/json", exchange.getMessage().getHeader(Exchange.CONTENT_TYPE));
+        assertEquals("{}", exchange.getMessage().getBody(String.class));
+    }
+
+    @Test
+    public void shouldLookupTransformer() throws Exception {
+        Transformer transformer
+                = camelContext.getTransformerRegistry().resolveTransformer(new TransformerKey("http:application-cloudevents"));
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(CloudEventHttpDataTypeTransformer.class, transformer.getClass());
+    }
+}
diff --git a/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformerTest.java b/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformerTest.java
new file mode 100644
index 00000000000..02b223e10a1
--- /dev/null
+++ b/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformerTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.cloudevents.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CloudEventJsonDataTypeTransformerTest {
+
+    private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+    private final CloudEventJsonDataTypeTransformer transformer = new CloudEventJsonDataTypeTransformer();
+
+    @Test
+    void shouldMapToJsonCloudEventFormat() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT, "test1.txt");
+        exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE, "org.apache.camel.event.test");
+        exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE, "org.apache.camel.test");
+        exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_CONTENT_TYPE, "text/plain");
+        exchange.getMessage().setBody(new ByteArrayInputStream("Test1".getBytes(StandardCharsets.UTF_8)));
+
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        CloudEvent cloudEvent = CloudEvents.v1_0;
+        assertTrue(exchange.getMessage().hasHeaders());
+        assertEquals("application/cloudevents+json", exchange.getMessage().getHeader(Exchange.CONTENT_TYPE));
+        assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"%s\"",
+                cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).json(), exchange.getExchangeId())));
+        assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"org.apache.camel.event.test\"",
+                cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).json())));
+        assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"org.apache.camel.test\"",
+                cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).json())));
+        assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"text/plain\"",
+                cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE).json())));
+        assertTrue(exchange.getMessage().getBody(String.class).contains("\"data\":\"Test1\""));
+
+        assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE));
+        assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE));
+        assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT));
+    }
+
+    @Test
+    void shouldSetDefaultCloudEventAttributes() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setBody(new ByteArrayInputStream("Test".getBytes(StandardCharsets.UTF_8)));
+
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        CloudEvent cloudEvent = CloudEvents.v1_0;
+        assertTrue(exchange.getMessage().hasHeaders());
+        assertEquals("application/cloudevents+json", exchange.getMessage().getHeader(Exchange.CONTENT_TYPE));
+        assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"%s\"",
+                cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).json(), exchange.getExchangeId())));
+        assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"org.apache.camel.event\"",
+                cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).json())));
+        assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"org.apache.camel\"",
+                cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).json())));
+        assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"application/json\"",
+                cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE).json())));
+        assertTrue(exchange.getMessage().getBody(String.class).contains("\"data\":\"Test\""));
+    }
+
+    @Test
+    public void shouldLookupTransformer() throws Exception {
+        Transformer transformer
+                = camelContext.getTransformerRegistry().resolveTransformer(new TransformerKey("application-cloudevents+json"));
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(CloudEventJsonDataTypeTransformer.class, transformer.getClass());
+    }
+}
diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/impl/transformer/SpringTransformerRouteTest.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/impl/transformer/SpringTransformerRouteTest.xml
index 47ce89a6189..319600d9bfe 100644
--- a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/impl/transformer/SpringTransformerRouteTest.xml
+++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/impl/transformer/SpringTransformerRouteTest.xml
@@ -30,16 +30,18 @@
     <bean id="otherToXOrder" class="org.apache.camel.processor.transformer.TransformerRouteTest$OtherToXOrderTransformer"/>
     <bean id="xOrderResponseToOther" class="org.apache.camel.processor.transformer.TransformerRouteTest$XOrderResponseToOtherTransformer"/>
     <bean id="myMyDataTypeFormatDef" class="org.apache.camel.processor.transformer.TransformerRouteTest$MyDataFormatDefinition"/>
-    
+
     <camelContext xmlns="http://camel.apache.org/schema/spring">
-    
+
         <endpoint id="myXmlEndpoint" uri="direct:endpointXmlTransformer"/>
 
         <transformers>
+            <loadTransformer defaults="true"/>
+            <loadTransformer packageScan="org.apache.camel.processor.transformer.custom"/>
             <dataFormatTransformer scheme="json">
                 <custom ref="myJsonDataFormatDef"/>
             </dataFormatTransformer>
-            <dataFormatTransformer scheme="myDataType">
+            <dataFormatTransformer name="myDataType">
                 <custom ref="myMyDataTypeFormatDef"/>
             </dataFormatTransformer>
             <endpointTransformer ref="myXmlEndpoint" fromType="xml:XmlXOrder" toType="java:org.apache.camel.processor.transformer.TransformerRouteTest$XOrder"/>
@@ -74,26 +76,26 @@
             <setBody><constant>response</constant></setBody>
             <to uri="mock:xyzresult"/>
         </route>
-        
+
         <route>
             <from uri="direct:dataFormat"/>
             <inputType urn="json:JsonXOrder"/>
             <outputType urn="json:JsonXOrderResponse"/>
             <to uri="direct:xyz" pattern="InOut"/>
         </route>
-        
+
         <route>
             <from uri="direct:endpoint"/>
             <inputType urn="xml:XmlXOrder"/>
             <outputType urn="xml:XmlXOrderResponse"/>
             <to uri="direct:xyz" pattern="InOut"/>
         </route>
-        
+
         <route>
             <from uri="direct:endpointXmlTransformer"/>
             <process ref="myXmlProcessor"/>
         </route>
-        
+
         <route>
             <from uri="direct:custom"/>
             <inputType urn="other:OtherXOrder"/>
@@ -114,5 +116,5 @@
         </route>
 
     </camelContext>
-  
+
 </beans>
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 33cf3735b90..0a7464354ec 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -948,10 +948,10 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
     /**
      * Resolve a transformer given a scheme
      *
-     * @param  model data model name.
-     * @return       the resolved transformer, or <tt>null</tt> if not found
+     * @param  name the transformer name, usually a combination of some scheme and name.
+     * @return      the resolved transformer, or <tt>null</tt> if not found
      */
-    Transformer resolveTransformer(String model);
+    Transformer resolveTransformer(String name);
 
     /**
      * Resolve a transformer given from/to data type.
@@ -1408,8 +1408,8 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
     /**
      * Whether to enable using data type on Camel messages.
      * <p/>
-     * Data type are automatic turned on if one ore more routes has been explicit configured with input and output
-     * types. Otherwise data type is default off.
+     * Data type are automatic turned on if one or more routes has been explicit configured with input and output types.
+     * Otherwise, data type is default off.
      *
      * @return <tt>true</tt> if data type is enabled
      */
@@ -1418,8 +1418,8 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
     /**
      * Whether to enable using data type on Camel messages.
      * <p/>
-     * Data type are automatic turned on if one ore more routes has been explicit configured with input and output
-     * types. Otherwise data type is default off.
+     * Data type are automatic turned on if one or more routes has been explicit configured with input and output types.
+     * Otherwise, data type is default off.
      *
      * @param useDataType <tt>true</tt> to enable data type on Camel messages.
      */
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/DataType.java b/core/camel-api/src/main/java/org/apache/camel/spi/DataType.java
index d741a81d956..333c262b47f 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/DataType.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/DataType.java
@@ -24,10 +24,16 @@ import org.apache.camel.util.StringHelper;
  * Java class doesn't always explain the data type completely, for example XML and JSON data format is sometimes
  * serialized as a {@code String}, {@code InputStream} or etc. The {@link DataTypeAware} message stores the DataType as
  * a part of the message to carry those data type information even if it's marshaled, so that it could be leveraged to
- * detect required {@link Transformer} and {@link Validator}. DataType consists of two parts, 'model' and 'name'. Its
- * string representation is 'model:name' connected with colon. For example 'java:com.example.Order', 'xml:ABCOrder' or
- * 'json:XYZOrder'. These type name other than java class name allows the message to carry the name of the message data
- * structure even if it's marshaled.
+ * detect required {@link Transformer} and {@link Validator}. DataType URN consists of two parts, 'scheme' and 'name'.
+ *
+ * Its string representation is 'scheme:name' connected with colon. For example 'java:com.example.Order', 'xml:ABCOrder'
+ * or 'json:XYZOrder'. These type name other than java class name allows the message to carry the name of the message
+ * data structure even if it's marshaled.
+ * <p/>
+ * The scheme can also be used to associate the same DataType with different Camel components. For example
+ * `http:cloud-events` and `aws-s3:cloud-events` where the scheme relates to the respective component's scheme. This
+ * information could be leveraged to detect required {@link Transformer} and {@link Validator} implementations provided
+ * as part of these components.
  *
  * @see DataTypeAware
  * @see Transformer
@@ -35,9 +41,13 @@ import org.apache.camel.util.StringHelper;
  */
 public class DataType {
 
-    public static final String JAVA_TYPE_PREFIX = "java";
+    public static final String DEFAULT_SCHEME = "camel";
+    public static final String JAVA_TYPE_SCHEME = "java";
+
+    public static final String ANY_TYPE_URN = DEFAULT_SCHEME + ":any";
+    public static final DataType ANY = new DataType(ANY_TYPE_URN);
 
-    private String model;
+    private final String scheme;
     private String name;
     private boolean isJavaType;
     private String typeString;
@@ -45,28 +55,35 @@ public class DataType {
     public DataType(String urn) {
         if (urn != null) {
             String[] split = StringHelper.splitOnCharacter(urn, ":", 2);
-            model = split[0];
-            isJavaType = model.equals(JAVA_TYPE_PREFIX);
+            scheme = split[0];
+            isJavaType = scheme.equals(JAVA_TYPE_SCHEME);
             if (split.length > 1) {
                 name = split[1];
             }
+        } else {
+            scheme = DataType.ANY.scheme;
+            name = DataType.ANY.name;
         }
     }
 
     public DataType(Class<?> clazz) {
-        model = JAVA_TYPE_PREFIX;
+        scheme = JAVA_TYPE_SCHEME;
         isJavaType = true;
         name = clazz.getName();
     }
 
-    public String getModel() {
-        return model;
+    public String getScheme() {
+        return scheme;
     }
 
     public String getName() {
         return name;
     }
 
+    public String getFullName() {
+        return name != null && !name.isEmpty() ? scheme + ":" + name : scheme;
+    }
+
     public boolean isJavaType() {
         return isJavaType;
     }
@@ -74,23 +91,31 @@ public class DataType {
     @Override
     public String toString() {
         if (this.typeString == null) {
-            this.typeString = name != null && !name.isEmpty() ? model + ":" + name : model;
+            this.typeString = getFullName();
         }
         return this.typeString;
     }
 
+    public static boolean isAnyType(DataType dataType) {
+        return dataType == null || DataType.ANY.equals(dataType);
+    }
+
+    public static boolean isJavaType(DataType dataType) {
+        return dataType != null && dataType.isJavaType();
+    }
+
     @Override
     public boolean equals(Object target) {
         if (target instanceof DataType) {
             DataType targetdt = (DataType) target;
-            String targetModel = targetdt.getModel();
+            String targetScheme = targetdt.getScheme();
             String targetName = targetdt.getName();
-            if (targetModel == null) {
+            if (targetScheme == null) {
                 return false;
             } else if (targetName == null) {
-                return targetModel.equals(getModel()) && getName() == null;
+                return targetScheme.equals(getScheme()) && getName() == null;
             } else {
-                return targetModel.equals(getModel()) && targetName.equals(getName());
+                return targetScheme.equals(getScheme()) && targetName.equals(getName());
             }
         }
         return false;
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/DataTypeTransformer.java b/core/camel-api/src/main/java/org/apache/camel/spi/DataTypeTransformer.java
new file mode 100644
index 00000000000..b047ed367bd
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/DataTypeTransformer.java
@@ -0,0 +1,60 @@
+/*
+ * 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.spi;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to configure a data type transformer with either specifying its name or from/to data types.
+ * <p/>
+ * The annotation is used by specific classpath scanning data type loaders to automatically add the data types to a
+ * registry.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Target({ ElementType.TYPE })
+public @interface DataTypeTransformer {
+
+    /**
+     * Data type transformer name. Identifies the data type transformer. Should be unique in the Camel context. Can be a
+     * combination of scheme and name. Is used to detect/reference the transformer when specifying input/output data
+     * types on routes.
+     *
+     * @return the data type transformer name.
+     */
+    String name() default "";
+
+    /**
+     * Data type representing the input of the transformation. Also used to detect the transformer.
+     *
+     * @return
+     */
+    String fromType() default "";
+
+    /**
+     * Data type representing the result of the transformation. Also used to detect the transformer.
+     *
+     * @return
+     */
+    String toType() default "";
+
+}
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/Transformer.java b/core/camel-api/src/main/java/org/apache/camel/spi/Transformer.java
index 814143a0869..b730fe5af12 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/Transformer.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/Transformer.java
@@ -20,6 +20,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.CamelContextAware;
 import org.apache.camel.Message;
 import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.ObjectHelper;
 
 /**
  * <a href="http://camel.apache.org/transformer.html">Transformer</a> performs message transformation according to the
@@ -32,10 +33,31 @@ import org.apache.camel.support.service.ServiceSupport;
 public abstract class Transformer extends ServiceSupport implements CamelContextAware {
 
     private CamelContext camelContext;
-    private String model;
+    private String name;
     private DataType from;
     private DataType to;
 
+    public Transformer() {
+        if (this.getClass().isAnnotationPresent(DataTypeTransformer.class)) {
+            DataTypeTransformer annotation = this.getClass().getAnnotation(DataTypeTransformer.class);
+            if (ObjectHelper.isNotEmpty(annotation.name())) {
+                this.name = annotation.name();
+            }
+
+            if (ObjectHelper.isNotEmpty(annotation.fromType())) {
+                this.from = new DataType(annotation.fromType());
+            }
+
+            if (ObjectHelper.isNotEmpty(annotation.toType())) {
+                this.to = new DataType(annotation.toType());
+            }
+        }
+    }
+
+    public Transformer(String name) {
+        this.name = name;
+    }
+
     /**
      * Perform data transformation with specified from/to type.
      *
@@ -46,10 +68,12 @@ public abstract class Transformer extends ServiceSupport implements CamelContext
     public abstract void transform(Message message, DataType from, DataType to) throws Exception;
 
     /**
-     * Get a data model which is supported by this transformer.
+     * Get the transformer name that represents the supported data type model.
+     *
+     * @return
      */
-    public String getModel() {
-        return model;
+    public String getName() {
+        return name;
     }
 
     /**
@@ -67,12 +91,32 @@ public abstract class Transformer extends ServiceSupport implements CamelContext
     }
 
     /**
-     * Set data model.
+     * Set the name for this transformer. Usually a combination of scheme and name.
+     *
+     * @param name the transformer name
+     */
+    public Transformer setName(String name) {
+        this.name = name;
+        return this;
+    }
+
+    /**
+     * Set the scheme and/or name for this transformer. When using only a scheme the transformer applies to all
+     * transformations with that scheme.
      *
-     * @param model data model
+     * @param scheme supported data type scheme
+     * @param name   transformer name
      */
-    public Transformer setModel(String model) {
-        this.model = model;
+    public Transformer setName(String scheme, String name) {
+        if (ObjectHelper.isNotEmpty(scheme)) {
+            if (ObjectHelper.isNotEmpty(name)) {
+                this.name = scheme + ":" + name;
+            } else {
+                this.name = scheme;
+            }
+        } else {
+            this.name = name;
+        }
         return this;
     }
 
@@ -108,7 +152,7 @@ public abstract class Transformer extends ServiceSupport implements CamelContext
 
     @Override
     public String toString() {
-        return String.format("%s[scheme='%s', from='%s', to='%s']", this.getClass().getSimpleName(), model, from, to);
+        return String.format("%s[name='%s', from='%s', to='%s']", this.getClass().getSimpleName(), name, from, to);
     }
 
     @Override
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-api/src/main/java/org/apache/camel/spi/TransformerLoader.java
similarity index 65%
copy from core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
copy to core/camel-api/src/main/java/org/apache/camel/spi/TransformerLoader.java
index 23827554acc..16f46d5754a 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/TransformerLoader.java
@@ -14,16 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.api.management.mbean;
 
-import org.apache.camel.api.management.ManagedAttribute;
+package org.apache.camel.spi;
 
-public interface ManagedTransformMBean extends ManagedProcessorMBean {
-
-    @ManagedAttribute(description = "The language for the expression")
-    String getExpressionLanguage();
+/**
+ * A pluggable strategy to load data types into a {@link TransformerRegistry}. Loads one to many data type transformers
+ * to the given registry.
+ */
+public interface TransformerLoader {
 
-    @ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
-    String getExpression();
+    /**
+     * A pluggable strategy to load transformers into a given registry.
+     *
+     * @param registry the registry the transformers get added to.
+     */
+    void load(TransformerRegistry registry);
 
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/TransformerResolver.java b/core/camel-api/src/main/java/org/apache/camel/spi/TransformerResolver.java
new file mode 100644
index 00000000000..cf03dc13012
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/TransformerResolver.java
@@ -0,0 +1,54 @@
+/*
+ * 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.spi;
+
+import java.util.Locale;
+
+import org.apache.camel.CamelContext;
+
+/**
+ * Resolves data type transformers from given transformer key. This represents the opportunity to lazy load transformers
+ * via factory finder discovery mechanism.
+ */
+@FunctionalInterface
+public interface TransformerResolver<K> {
+
+    /**
+     * Attempts to resolve the transformer for the given key. Usually uses the factory finder URI to resolve the
+     * transformer by its name derived from the given key. Transformer names may use scheme and name as a combination in
+     * order to resolve component specific transformers. Usually implements a fallback resolving mechanism when no
+     * matching transformer is found (e.g. search for generic Camel transformers just using the name).
+     *
+     * @param  key          the transformer key.
+     * @param  camelContext the current Camel context.
+     * @return              data type transformer resolved via URI factory finder or null if not found.
+     */
+    Transformer resolve(K key, CamelContext camelContext);
+
+    /**
+     * Normalize transformer key to conform with factory finder resource path. Replaces all non supported characters
+     * such as slashes and colons to dashes.
+     *
+     * @param  key the transformer key
+     * @return     normalized String representation of the key
+     */
+    default String normalize(K key) {
+        return key.toString().replaceAll("[^A-Za-z0-9-]", "-").toLowerCase(Locale.US);
+    }
+
+}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index e22568d641e..a282225893c 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -3867,8 +3867,8 @@ public abstract class AbstractCamelContext extends BaseService
     }
 
     @Override
-    public Transformer resolveTransformer(String scheme) {
-        return getTransformerRegistry().resolveTransformer(new TransformerKey(scheme));
+    public Transformer resolveTransformer(String name) {
+        return getTransformerRegistry().resolveTransformer(new TransformerKey(name));
     }
 
     @Override
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerRegistry.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerRegistry.java
index 23000c889df..cf3f8942e03 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerRegistry.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerRegistry.java
@@ -20,12 +20,17 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
 import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerLoader;
 import org.apache.camel.spi.TransformerRegistry;
+import org.apache.camel.spi.TransformerResolver;
 import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Default implementation of {@link org.apache.camel.spi.TransformerRegistry}.
@@ -33,8 +38,12 @@ import org.apache.camel.util.ObjectHelper;
 public class DefaultTransformerRegistry extends AbstractDynamicRegistry<TransformerKey, Transformer>
         implements TransformerRegistry<TransformerKey> {
 
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultTransformerRegistry.class);
+
     private final Map<TransformerKey, TransformerKey> aliasMap;
 
+    private TransformerResolver<TransformerKey> transformerResolver;
+
     public DefaultTransformerRegistry(CamelContext context) {
         super(context, CamelContextHelper.getMaximumTransformerCacheSize(context));
         this.aliasMap = new ConcurrentHashMap<>();
@@ -42,41 +51,107 @@ public class DefaultTransformerRegistry extends AbstractDynamicRegistry<Transfor
 
     @Override
     public Transformer resolveTransformer(TransformerKey key) {
-        if (ObjectHelper.isEmpty(key.getScheme()) && key.getTo() == null) {
+        if (DataType.isAnyType(key.getFrom()) && DataType.isAnyType(key.getTo())) {
             return null;
         }
 
         // try exact match
         Transformer answer = get(aliasMap.getOrDefault(key, key));
-        if (answer != null || ObjectHelper.isNotEmpty(key.getScheme())) {
+        if (answer != null) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Found transformer {} for key {}", ObjectHelper.name(answer.getClass()), key);
+            }
+
             return answer;
         }
 
-        // try wildcard match for next - add an alias if matched
+        // try wildcard match for transformers with matching data type scheme - add an alias if matched
         TransformerKey alias = null;
-        if (key.getFrom() != null && ObjectHelper.isNotEmpty(key.getFrom().getName())) {
-            alias = new TransformerKey(new DataType(key.getFrom().getModel()), key.getTo());
+        if (!DataType.isAnyType(key.getFrom()) && ObjectHelper.isNotEmpty(key.getFrom().getName())) {
+            alias = new TransformerKey(new DataType(key.getFrom().getScheme()), key.getTo());
             answer = get(alias);
         }
         if (answer == null && ObjectHelper.isNotEmpty(key.getTo().getName())) {
-            alias = new TransformerKey(key.getFrom(), new DataType(key.getTo().getModel()));
+            alias = new TransformerKey(key.getFrom(), new DataType(key.getTo().getScheme()));
             answer = get(alias);
         }
-        if (answer == null && key.getFrom() != null && ObjectHelper.isNotEmpty(key.getFrom().getName())
+        if (answer == null && !DataType.isAnyType(key.getFrom()) && ObjectHelper.isNotEmpty(key.getFrom().getName())
                 && ObjectHelper.isNotEmpty(key.getTo().getName())) {
-            alias = new TransformerKey(new DataType(key.getFrom().getModel()), new DataType(key.getTo().getModel()));
+            alias = new TransformerKey(new DataType(key.getFrom().getScheme()), new DataType(key.getTo().getScheme()));
             answer = get(alias);
         }
-        if (answer == null && key.getFrom() != null) {
-            alias = new TransformerKey(key.getFrom().getModel());
+
+        if (answer == null && !DataType.isAnyType(key.getTo())) {
+            alias = new TransformerKey(key.getTo());
             answer = get(alias);
+
+            if (answer == null) {
+                alias = new TransformerKey(key.getTo().getScheme());
+                answer = get(alias);
+            }
         }
-        if (answer == null) {
-            alias = new TransformerKey(key.getTo().getModel());
+
+        if (answer == null && !DataType.isAnyType(key.getFrom())) {
+            alias = new TransformerKey(key.getFrom());
             answer = get(alias);
+
+            if (answer == null) {
+                alias = new TransformerKey(key.getFrom().getScheme());
+                answer = get(alias);
+            }
         }
+
         if (answer != null) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Found transformer {} for key {} using alias {}", ObjectHelper.name(answer.getClass()), key, alias);
+            }
+
             aliasMap.put(key, alias);
+            return answer;
+        }
+
+        if (!DataType.isJavaType(key.getTo())) {
+            answer = lazyLoadTransformer(new TransformerKey(key.getTo()));
+
+            if (answer != null) {
+                // Add lazy loaded transformer and an alias
+                TransformerKey transformerKey = TransformerKey.createFrom(answer);
+                put(transformerKey, answer);
+                if (!key.equals(transformerKey)) {
+                    aliasMap.put(key, transformerKey);
+                }
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Found transformer {} for key {}", ObjectHelper.name(answer.getClass()), key);
+                }
+            }
+        }
+
+        return answer;
+    }
+
+    /**
+     * Tra to lazy load transformer either from Camel context as bean reference or via transformer resolver mechanism,
+     * e.g. doing a resource path lookup.
+     *
+     * @param  key the transformer key.
+     * @return     lazy loaded transformer or null if not found.
+     */
+    private Transformer lazyLoadTransformer(TransformerKey key) {
+        // Looking for matching beans in Camel registry first
+        Transformer answer = CamelContextHelper.lookup(context, key.toString(), Transformer.class);
+
+        if (answer == null) {
+            if (transformerResolver == null) {
+                TransformerResolver<?> contextResolver = context.getRegistry().findSingleByType(TransformerResolver.class);
+                if (contextResolver != null) {
+                    transformerResolver = (TransformerResolver<TransformerKey>) contextResolver;
+                } else {
+                    transformerResolver = new DefaultTransformerResolver();
+                }
+            }
+
+            // Try to lazy load transformer via resolver, e.g. with resource path lookup
+            answer = transformerResolver.resolve(key, context);
         }
 
         return answer;
@@ -86,7 +161,27 @@ public class DefaultTransformerRegistry extends AbstractDynamicRegistry<Transfor
     public Transformer put(TransformerKey key, Transformer obj) {
         // ensure transformer is started before its being used
         ServiceHelper.startService(obj);
-        return super.put(key, obj);
+
+        if (obj instanceof TransformerLoader) {
+            ((TransformerLoader) obj).load(this);
+            return obj;
+        } else {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Adding transformer for key {}", key);
+            }
+
+            return super.put(key, obj);
+        }
+    }
+
+    @Override
+    public void init() {
+        // if applicable set Camel context on all transformers
+        values().forEach(t -> {
+            if (((CamelContextAware) t).getCamelContext() == null) {
+                CamelContextAware.trySetCamelContext(t, context);
+            }
+        });
     }
 
     @Override
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerResolver.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerResolver.java
new file mode 100644
index 00000000000..6099e79ca31
--- /dev/null
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerResolver.java
@@ -0,0 +1,65 @@
+/*
+ * 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.impl.engine;
+
+import java.util.Optional;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerResolver;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The default implementation of {@link org.apache.camel.spi.TransformerResolver} which tries to find components by
+ * using the URI scheme prefix and searching for a file of the URI scheme name in the
+ * <b>META-INF/services/org/apache/camel/datatype/transformer/</b> directory on the classpath.
+ */
+public class DefaultTransformerResolver implements TransformerResolver<TransformerKey> {
+
+    public static final String DATA_TYPE_TRANSFORMER_RESOURCE_PATH = "META-INF/services/org/apache/camel/datatype/transformer/";
+
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultTransformerResolver.class);
+
+    @Override
+    public Transformer resolve(TransformerKey key, CamelContext context) {
+        String normalizedKey = normalize(key);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Resolving data type transformer for key {} via: {}{}", key, DATA_TYPE_TRANSFORMER_RESOURCE_PATH,
+                    normalizedKey);
+        }
+
+        Optional<Transformer> transformer = findTransformer(normalizedKey, context);
+        if (LOG.isDebugEnabled() && transformer.isPresent()) {
+            LOG.debug("Found data type transformer for key {} via type: {} via: {}{}", key,
+                    ObjectHelper.name(transformer.getClass()), DATA_TYPE_TRANSFORMER_RESOURCE_PATH, normalizedKey);
+        }
+
+        transformer.ifPresent(t -> CamelContextAware.trySetCamelContext(t, context));
+
+        return transformer.orElse(null);
+    }
+
+    private Optional<Transformer> findTransformer(String key, CamelContext context) {
+        return context.getCamelContextExtension()
+                .getBootstrapFactoryFinder(DATA_TYPE_TRANSFORMER_RESOURCE_PATH)
+                .newInstance(key, Transformer.class);
+    }
+}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultValidatorRegistry.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultValidatorRegistry.java
index 1314e058166..ef114820264 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultValidatorRegistry.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultValidatorRegistry.java
@@ -38,7 +38,7 @@ public class DefaultValidatorRegistry extends AbstractDynamicRegistry<ValidatorK
     public Validator resolveValidator(ValidatorKey key) {
         Validator answer = get(key);
         if (answer == null && ObjectHelper.isNotEmpty(key.getType().getName())) {
-            answer = get(new ValidatorKey(new DataType(key.getType().getModel())));
+            answer = get(new ValidatorKey(new DataType(key.getType().getScheme())));
         }
         return answer;
     }
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/TransformerKey.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/TransformerKey.java
index 8ce756b7d65..a74724467ef 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/TransformerKey.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/TransformerKey.java
@@ -18,6 +18,7 @@ package org.apache.camel.impl.engine;
 
 import org.apache.camel.ValueHolder;
 import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
 import org.apache.camel.util.StringHelper;
 
 /**
@@ -26,14 +27,16 @@ import org.apache.camel.util.StringHelper;
  */
 public final class TransformerKey extends ValueHolder<String> {
 
-    private String scheme;
-    private DataType from;
-    private DataType to;
+    private final DataType from;
+    private final DataType to;
 
-    public TransformerKey(String scheme) {
-        super(scheme);
-        StringHelper.notEmpty(scheme, "scheme");
-        this.scheme = scheme;
+    public TransformerKey(String toType) {
+        this(DataType.ANY, new DataType(toType));
+        StringHelper.notEmpty(toType, "toType");
+    }
+
+    public TransformerKey(DataType to) {
+        this(DataType.ANY, to);
     }
 
     public TransformerKey(DataType from, DataType to) {
@@ -42,12 +45,35 @@ public final class TransformerKey extends ValueHolder<String> {
         this.to = to;
     }
 
+    /**
+     * Create the string that represents this transformer key. Either uses both full names of from/to data types in
+     * combination or only uses the toType data type full name in case fromType is not specified.
+     *
+     * @param  from
+     * @param  to
+     * @return
+     */
     private static String createKeyString(DataType from, DataType to) {
-        return from + "/" + to;
+        if (DataType.isAnyType(from)) {
+            return to.getFullName();
+        }
+
+        return from.getFullName() + "/" + to.getFullName();
     }
 
-    public String getScheme() {
-        return scheme;
+    /**
+     * Create the transformer key for the given transformer either using the transformer name or it's specified from/to
+     * data type name.
+     *
+     * @param  answer
+     * @return
+     */
+    public static TransformerKey createFrom(Transformer answer) {
+        if (!DataType.isAnyType(answer.getFrom()) && !DataType.isAnyType(answer.getTo())) {
+            return new TransformerKey(answer.getFrom(), answer.getTo());
+        }
+
+        return new TransformerKey(answer.getName());
     }
 
     public DataType getFrom() {
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index 7a38fe8f0b4..15a4a6165bb 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -922,9 +922,15 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame
     }
 
     private static ValueHolder<String> createTransformerKey(TransformerDefinition def) {
-        return ObjectHelper.isNotEmpty(def.getScheme())
-                ? new TransformerKey(def.getScheme())
-                : new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
+        if (ObjectHelper.isNotEmpty(def.getScheme())) {
+            return ObjectHelper.isNotEmpty(def.getName())
+                    ? new TransformerKey(def.getScheme() + ":" + def.getName()) : new TransformerKey(def.getScheme());
+        }
+        if (ObjectHelper.isNotEmpty(def.getName())) {
+            return new TransformerKey(def.getName());
+        } else {
+            return new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
+        }
     }
 
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json
index 5e37dc5dd65..85e827be37f 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json
@@ -13,8 +13,10 @@
   },
   "properties": {
     "expression": { "index": 0, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": fa [...]
-    "disabled": { "index": 1, "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." },
-    "id": { "index": 2, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
-    "description": { "index": 3, "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
+    "fromType": { "index": 1, "kind": "attribute", "displayName": "From Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "From type used in data type transformation." },
+    "toType": { "index": 2, "kind": "attribute", "displayName": "To Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To type used as a target data type in the transformation." },
+    "disabled": { "index": 3, "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." },
+    "id": { "index": 4, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+    "description": { "index": 5, "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
   }
 }
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/jaxb.index b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/jaxb.index
index af780ec37f0..73ef81d1fb4 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/jaxb.index
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/jaxb.index
@@ -2,5 +2,6 @@
 CustomTransformerDefinition
 DataFormatTransformerDefinition
 EndpointTransformerDefinition
+LoadTransformerDefinition
 TransformerDefinition
 TransformersDefinition
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/transformers.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/transformers.json
index af5d7902054..1f2ae2ab00a 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/transformers.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/transformers.json
@@ -12,6 +12,6 @@
     "output": false
   },
   "properties": {
-    "transformers": { "index": 0, "kind": "element", "displayName": "Transformers", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.transformer.TransformerDefinition>", "oneOf": [ "customTransformer", "dataFormatTransformer", "endpointTransformer" ], "deprecated": false, "autowired": false, "secret": false, "description": "The configured transformers" }
+    "transformers": { "index": 0, "kind": "element", "displayName": "Transformers", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.transformer.TransformerDefinition>", "oneOf": [ "customTransformer", "dataFormatTransformer", "endpointTransformer", "loadTransformer" ], "deprecated": false, "autowired": false, "secret": false, "description": "The configured transformers" }
   }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/TransformerBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/TransformerBuilder.java
index a1a9ec74b7d..026939d1af3 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/TransformerBuilder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/TransformerBuilder.java
@@ -22,9 +22,11 @@ import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.model.transformer.CustomTransformerDefinition;
 import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
 import org.apache.camel.model.transformer.EndpointTransformerDefinition;
+import org.apache.camel.model.transformer.LoadTransformerDefinition;
 import org.apache.camel.model.transformer.TransformerDefinition;
 import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.Transformer;
+import org.apache.camel.util.ObjectHelper;
 
 /**
  * A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is used to build a
@@ -35,16 +37,32 @@ import org.apache.camel.spi.Transformer;
 public class TransformerBuilder {
 
     private String scheme;
+    private String name;
     private String from;
     private String to;
     private String uri;
     private DataFormatDefinition dataFormat;
     private Class<? extends Transformer> clazz;
     private String beanRef;
+    private boolean defaults;
+    private String packageScan;
+
+    /**
+     * Set the transformer name under which the transformer gets referenced when specifying the input/output data type
+     * on routes. If you specify a transformer name that matches a data type scheme like 'csv' the transformer will be
+     * picked up for all of 'csv:*' from/to Java transformation. Note that the scheme matching is performed only when no
+     * exactly matched transformer exists.
+     *
+     * @param name transformer name
+     */
+    public TransformerBuilder name(String name) {
+        this.name = name;
+        return this;
+    }
 
     /**
      * Set the scheme name supported by the transformer. If you specify 'csv', the transformer will be picked up for all
-     * of 'csv' from/to Java transformation. Note that the scheme matching is performed only when no exactly matched
+     * of 'csv:*' from/to Java transformation. Note that the scheme matching is performed only when no exactly matched
      * transformer exists.
      *
      * @param scheme scheme name
@@ -136,11 +154,33 @@ public class TransformerBuilder {
         return this;
     }
 
+    /**
+     * Enables default transformers on the registry.
+     */
+    public TransformerBuilder withDefaults() {
+        resetType();
+        this.defaults = true;
+        return this;
+    }
+
+    /**
+     * Set the classpath location to scan for {@code Transformer} implementations. Usually these transformer
+     * implementations use {@code DataTypeTransformer} annotations to expose a transformer name and supported from/to
+     * data types.
+     */
+    public TransformerBuilder scan(String location) {
+        resetType();
+        this.packageScan = location;
+        return this;
+    }
+
     private void resetType() {
         this.uri = null;
         this.dataFormat = null;
         this.clazz = null;
         this.beanRef = null;
+        this.defaults = false;
+        this.packageScan = null;
     }
 
     /**
@@ -167,12 +207,23 @@ public class TransformerBuilder {
             CustomTransformerDefinition ctd = new CustomTransformerDefinition();
             ctd.setRef(beanRef);
             transformer = ctd;
+        } else if (defaults) {
+            LoadTransformerDefinition ltd = new LoadTransformerDefinition();
+            ltd.setDefaults("true");
+            transformer = ltd;
+        } else if (packageScan != null) {
+            LoadTransformerDefinition ltd = new LoadTransformerDefinition();
+            ltd.setPackageScan(packageScan);
+            transformer = ltd;
         } else {
             throw new IllegalArgumentException("No Transformer type was specified");
         }
 
-        if (scheme != null) {
+        if (ObjectHelper.isNotEmpty(scheme)) {
             transformer.setScheme(scheme);
+            transformer.setName(name);
+        } else if (ObjectHelper.isNotEmpty(name)) {
+            transformer.setName(name);
         } else {
             transformer.setFromType(from);
             transformer.setToType(to);
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 e766c76f42b..11ff1d8dced 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
@@ -62,6 +62,7 @@ import org.apache.camel.resume.ResumeStrategy;
 import org.apache.camel.spi.AsEndpointUri;
 import org.apache.camel.spi.AsPredicate;
 import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.IdempotentRepository;
 import org.apache.camel.spi.InterceptStrategy;
 import org.apache.camel.spi.Metadata;
@@ -2453,6 +2454,33 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
         return asType();
     }
 
+    /**
+     * <a href="http://camel.apache.org/message-translator.html">Message Translator EIP:</a> Adds a processor which sets
+     * the body on the OUT message according to a data type transformation.
+     *
+     * @param  fromType the data type representing the input of the transformation
+     * @param  toType   the data type representing the output of the transformation.
+     * @return          the builder
+     */
+    public Type transform(DataType fromType, DataType toType) {
+        TransformDefinition answer = new TransformDefinition(fromType, toType);
+        addOutput(answer);
+        return asType();
+    }
+
+    /**
+     * <a href="http://camel.apache.org/message-translator.html">Message Translator EIP:</a> Adds a processor which sets
+     * the body on the OUT message according to a data type transformation.
+     *
+     * @param  toType the data type representing the output of the transformation.
+     * @return        the builder
+     */
+    public Type transform(DataType toType) {
+        TransformDefinition answer = new TransformDefinition(DataType.ANY, toType);
+        addOutput(answer);
+        return asType();
+    }
+
     /**
      * <a href="http://camel.apache.org/message-translator.html">Message Translator EIP:</a> Adds a processor which sets
      * the body on the OUT message
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/TransformDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/TransformDefinition.java
index e53dea89b88..a6519b5de3c 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/TransformDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/TransformDefinition.java
@@ -18,10 +18,12 @@ package org.apache.camel.model;
 
 import jakarta.xml.bind.annotation.XmlAccessType;
 import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
 import jakarta.xml.bind.annotation.XmlRootElement;
 
 import org.apache.camel.Expression;
 import org.apache.camel.model.language.ExpressionDefinition;
+import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.Metadata;
 
 /**
@@ -32,6 +34,12 @@ import org.apache.camel.spi.Metadata;
 @XmlAccessorType(XmlAccessType.FIELD)
 public class TransformDefinition extends ExpressionNode {
 
+    @XmlAttribute
+    private String fromType;
+
+    @XmlAttribute
+    private String toType;
+
     public TransformDefinition() {
     }
 
@@ -39,8 +47,21 @@ public class TransformDefinition extends ExpressionNode {
         super(expression);
     }
 
+    public TransformDefinition(DataType fromType, DataType toType) {
+        this.fromType = fromType.getFullName();
+        this.toType = toType.getFullName();
+    }
+
     @Override
     public String toString() {
+        if (toType != null) {
+            if (fromType != null) {
+                return "Transform[" + fromType + ", " + toType + "]";
+            } else {
+                return "Transform[" + toType + "]";
+            }
+        }
+
         return "Transform[" + getExpression() + "]";
     }
 
@@ -51,6 +72,14 @@ public class TransformDefinition extends ExpressionNode {
 
     @Override
     public String getLabel() {
+        if (toType != null) {
+            if (fromType != null) {
+                return "transform[" + fromType + ", " + toType + "]";
+            } else {
+                return "transform[" + toType + "]";
+            }
+        }
+
         return "transform[" + getExpression() + "]";
     }
 
@@ -63,4 +92,25 @@ public class TransformDefinition extends ExpressionNode {
         super.setExpression(expression);
     }
 
+    /**
+     * From type used in data type transformation.
+     */
+    public void setFromType(String fromType) {
+        this.fromType = fromType;
+    }
+
+    public String getFromType() {
+        return fromType;
+    }
+
+    /**
+     * To type used as a target data type in the transformation.
+     */
+    public void setToType(String toType) {
+        this.toType = toType;
+    }
+
+    public String getToType() {
+        return toType;
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/LoadTransformerDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/LoadTransformerDefinition.java
new file mode 100644
index 00000000000..68a2630d392
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/LoadTransformerDefinition.java
@@ -0,0 +1,64 @@
+/*
+ * 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.model.transformer;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlType;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Loads one to many {@link org.apache.camel.spi.Transformer} via {@link org.apache.camel.spi.TransformerLoader}.
+ * Supports classpath scan to load transformer implementations configured for instance via annotation configuration.
+ */
+@Metadata(label = "transformation")
+@XmlType(name = "loadTransformer")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class LoadTransformerDefinition extends TransformerDefinition {
+
+    @XmlAttribute
+    private String packageScan;
+
+    @XmlAttribute
+    @Metadata(javaType = "java.lang.Boolean", defaultValue = "false")
+    private String defaults;
+
+    public String getDefaults() {
+        return defaults;
+    }
+
+    /**
+     * Enable loading of default transformers.
+     */
+    public void setDefaults(String defaults) {
+        this.defaults = defaults;
+    }
+
+    public String getPackageScan() {
+        return packageScan;
+    }
+
+    /**
+     * Set the classpath location to scan for annotated transformers.
+     */
+    public void setPackageScan(String packageScan) {
+        this.packageScan = packageScan;
+    }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java
index ef186710526..8006181630a 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java
@@ -32,8 +32,15 @@ import org.apache.camel.spi.Metadata;
  *
  * If you specify from='java:com.example.ABC' and to='xml:XYZ', the transformer will be picked up when current message
  * type is 'java:com.example.ABC' and expected message type is 'xml:XYZ'. If you specify from='java' to='xml', then it
- * will be picked up for all of Java to xml transformation. Also it's possible to specify scheme='xml' so that the
- * transformer will be picked up for all of Java to xml and xml to java transformation.
+ * will be picked up for all of Java to xml transformation.
+ *
+ * Also, it's possible to specify a transformer name that identifies the transformer. Usually the name is a combination
+ * of a scheme and a name that represents the supported data type name. The declared {@link InputTypeDefinition} and/or
+ * {@link OutputTypeDefinition} can then reference the transformer by its name.
+ *
+ * In case the transformer name should represent a data type scheme such as name='xml' that specific transformer will
+ * also be picked up for all of Java to xml and xml to Java transformation as a fallback when no matching transformer is
+ * found.
  */
 @Metadata(label = "transformation")
 @XmlType(name = "transformer")
@@ -43,6 +50,8 @@ public abstract class TransformerDefinition {
     @XmlAttribute
     private String scheme;
     @XmlAttribute
+    private String name;
+    @XmlAttribute
     private String fromType;
     @XmlAttribute
     private String toType;
@@ -56,12 +65,28 @@ public abstract class TransformerDefinition {
      * of 'csv' from/to Java transformation. Note that the scheme matching is performed only when no exactly matched
      * transformer exists.
      *
-     * @param scheme scheme name
+     * @param scheme the supported data type scheme
      */
     public void setScheme(String scheme) {
         this.scheme = scheme;
     }
 
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Set the transformer name under which the transformer gets referenced when specifying the input/output data type
+     * on routes. If you specify a transformer name that matches a data type scheme like 'csv' the transformer will be
+     * picked up for all of 'csv:*' from/to Java transformation. Note that the scheme matching is performed only when no
+     * exactly matched transformer exists.
+     *
+     * @param name transformer name
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
     public String getFromType() {
         return fromType;
     }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java
index fea9b233691..907fc405db5 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java
@@ -37,6 +37,7 @@ public class TransformersDefinition {
     @XmlElements({
             @XmlElement(name = "dataFormatTransformer", type = DataFormatTransformerDefinition.class),
             @XmlElement(name = "endpointTransformer", type = EndpointTransformerDefinition.class),
+            @XmlElement(name = "loadTransformer", type = LoadTransformerDefinition.class),
             @XmlElement(name = "customTransformer", type = CustomTransformerDefinition.class) })
     private List<TransformerDefinition> transformers;
 
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/ContractAdvice.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/ContractAdvice.java
index 7c5954fa24c..22cdc199be5 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/ContractAdvice.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/ContractAdvice.java
@@ -20,6 +20,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.apache.camel.ValidationException;
+import org.apache.camel.processor.transformer.TypeConverterTransformer;
 import org.apache.camel.spi.CamelInternalProcessorAdvice;
 import org.apache.camel.spi.Contract;
 import org.apache.camel.spi.DataType;
@@ -48,7 +49,7 @@ import org.slf4j.LoggerFactory;
 public class ContractAdvice implements CamelInternalProcessorAdvice {
     private static final Logger LOG = LoggerFactory.getLogger(ContractAdvice.class);
 
-    private Contract contract;
+    private final Contract contract;
 
     public ContractAdvice(Contract contract) {
         this.contract = contract;
@@ -117,7 +118,7 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
 
     private void doTransform(Message message, DataType from, DataType to) throws Exception {
         if (from == null) {
-            // If 'from' is null, only Java-Java convertion is performed.
+            // If 'from' is null, only Java-Java conversion is performed.
             // It means if 'to' is other than Java, it's assumed to be already in expected type.
             convertIfRequired(message, to);
             return;
@@ -127,7 +128,7 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
         convertIfRequired(message, from);
 
         if (applyMatchedTransformer(message, from, to)) {
-            // Found matched transformer. Java-Java transformer is also allowed.
+            // Found matched transformer. Java->Java transformer is also allowed.
             return;
         } else if (from.isJavaType()) {
             // Try TypeConverter as a fallback for Java->Java transformation
@@ -143,39 +144,35 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
         throw new IllegalArgumentException("No Transformer found for [from='" + from + "', to='" + to + "']");
     }
 
-    private boolean convertIfRequired(Message message, DataType type) throws Exception {
-        // TODO for better performance it may be better to add TypeConverterTransformer
-        // into transformer registry automatically to avoid unnecessary scan in transformer registry
-        if (type != null && type.isJavaType() && type.getName() != null && message != null && message.getBody() != null) {
-            CamelContext context = message.getExchange().getContext();
-            Class<?> typeJava = getClazz(type.getName(), context);
-            if (!typeJava.isAssignableFrom(message.getBody().getClass())) {
-                LOG.debug("Converting to '{}'", typeJava.getName());
-                message.setBody(message.getMandatoryBody(typeJava));
-                return true;
-            }
+    private void convertIfRequired(Message message, DataType type) throws Exception {
+        if (DataType.isAnyType(type) || !DataType.isJavaType(type) || type.getName() == null) {
+            return;
         }
-        return false;
-    }
 
-    private boolean applyTransformer(Transformer transformer, Message message, DataType from, DataType to) throws Exception {
+        CamelContext context = message.getExchange().getContext();
+        Transformer transformer = context.resolveTransformer(DataType.ANY, type);
         if (transformer != null) {
-            LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
-            transformer.transform(message, from, to);
-            return true;
+            transformer.transform(message, DataType.ANY, type);
+        } else {
+            new TypeConverterTransformer(type).transform(message, DataType.ANY, type);
         }
-        return false;
     }
 
     private boolean applyMatchedTransformer(Message message, DataType from, DataType to) throws Exception {
         Transformer transformer = message.getExchange().getContext().resolveTransformer(from, to);
-        return applyTransformer(transformer, message, from, to);
+        if (transformer == null) {
+            return false;
+        }
+
+        LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
+        transformer.transform(message, from, to);
+        return true;
     }
 
     private boolean applyTransformerChain(Message message, DataType from, DataType to) throws Exception {
         CamelContext context = message.getExchange().getContext();
-        Transformer fromTransformer = context.resolveTransformer(from.getModel());
-        Transformer toTransformer = context.resolveTransformer(to.getModel());
+        Transformer fromTransformer = context.resolveTransformer(DataType.ANY, from);
+        Transformer toTransformer = context.resolveTransformer(DataType.ANY, to);
         if (fromTransformer != null && toTransformer != null) {
             LOG.debug("Applying transformer 1/2: from='{}', to='{}', transformer='{}'", from, to, fromTransformer);
             fromTransformer.transform(message, from, new DataType(Object.class));
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/AnnotationTransformerLoader.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/AnnotationTransformerLoader.java
new file mode 100644
index 00000000000..77b23515cc8
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/AnnotationTransformerLoader.java
@@ -0,0 +1,198 @@
+/*
+ * 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.processor.transformer;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.Message;
+import org.apache.camel.TypeConverterLoaderException;
+import org.apache.camel.impl.engine.DefaultPackageScanClassResolver;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerLoader;
+import org.apache.camel.spi.TransformerRegistry;
+import org.apache.camel.support.PluginHelper;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Transformer loader scans packages for {@link org.apache.camel.spi.Transformer} classes annotated with
+ * {@link DataType} annotation.
+ */
+public class AnnotationTransformerLoader extends Transformer implements TransformerLoader, CamelContextAware {
+
+    public static final String META_INF_SERVICES = "META-INF/services/org/apache/camel/Transformer";
+
+    private static final Logger LOG = LoggerFactory.getLogger(AnnotationTransformerLoader.class);
+
+    private CamelContext camelContext;
+
+    private String packageName;
+
+    private PackageScanClassResolver resolver;
+
+    private final Set<Class<?>> visitedClasses = new HashSet<>();
+    private final Set<String> visitedURIs = new HashSet<>();
+
+    @Override
+    public void load(TransformerRegistry registry) {
+        ObjectHelper.notNull(camelContext, "camelContext");
+
+        if (resolver == null) {
+            if (camelContext instanceof ExtendedCamelContext) {
+                resolver = PluginHelper.getPackageScanClassResolver(camelContext);
+            } else {
+                resolver = new DefaultPackageScanClassResolver();
+            }
+        }
+
+        Set<String> packages = new HashSet<>();
+
+        if (packageName == null || packageName.equals("*")) {
+            LOG.trace("Searching for {} services", META_INF_SERVICES);
+            try {
+                ClassLoader ccl = Thread.currentThread().getContextClassLoader();
+                if (ccl != null) {
+                    findPackages(packages, ccl);
+                }
+                findPackages(packages, getClass().getClassLoader());
+                if (packages.isEmpty()) {
+                    LOG.debug("No package names found to be used for classpath scanning for annotated data types.");
+                    return;
+                }
+            } catch (Exception e) {
+                throw new TypeConverterLoaderException(
+                        "Cannot find package names to be used for classpath scanning for annotated data types.", e);
+            }
+        } else {
+            packages.add(packageName);
+        }
+
+        // scan packages and load annotated transformer classes
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Found data type packages to scan: {}", String.join(", ", packages));
+        }
+        Set<Class<?>> scannedClasses = resolver.findAnnotated(DataTypeTransformer.class, packages.toArray(new String[] {}));
+        if (!scannedClasses.isEmpty()) {
+            LOG.debug("Found {} packages with {} @DataType classes to load", packages.size(), scannedClasses.size());
+
+            // load all the found classes into the type data type registry
+            for (Class<?> type : scannedClasses) {
+                if (acceptClass(type)) {
+                    if (LOG.isTraceEnabled()) {
+                        LOG.trace("Loading data type annotation: {}", ObjectHelper.name(type));
+                    }
+                    registerTransformer(registry, type);
+                }
+            }
+        }
+
+        // now clear the maps so we do not hold references
+        visitedClasses.clear();
+        visitedURIs.clear();
+    }
+
+    private void registerTransformer(TransformerRegistry registry, Class<?> type) {
+        if (visitedClasses.contains(type)) {
+            return;
+        }
+        visitedClasses.add(type);
+
+        try {
+            if (Transformer.class.isAssignableFrom(type) && type.isAnnotationPresent(DataTypeTransformer.class)) {
+                DataTypeTransformer dt = type.getAnnotation(DataTypeTransformer.class);
+                Transformer transformer = (Transformer) camelContext.getInjector().newInstance(type);
+                if (!ObjectHelper.isEmpty(dt.name())) {
+                    registry.put(new TransformerKey(dt.name()), transformer);
+                }
+
+                if (!DataType.isAnyType(new DataType(dt.fromType())) || !DataType.isAnyType(new DataType(dt.toType()))) {
+                    registry.put(new TransformerKey(new DataType(dt.fromType()), new DataType(dt.toType())), transformer);
+                }
+            }
+        } catch (NoClassDefFoundError e) {
+            LOG.debug("Ignoring transformer type: {} as a dependent class could not be found: {}",
+                    type.getCanonicalName(), e, e);
+        }
+    }
+
+    protected boolean acceptClass(Class<?> type) {
+        return Transformer.class.isAssignableFrom(type) && type.isAnnotationPresent(DataTypeTransformer.class);
+    }
+
+    protected void findPackages(Set<String> packages, ClassLoader classLoader) throws IOException {
+        Enumeration<URL> resources = classLoader.getResources(META_INF_SERVICES);
+        while (resources.hasMoreElements()) {
+            URL url = resources.nextElement();
+            String path = url.getPath();
+            if (!visitedURIs.contains(path)) {
+                // remember we have visited this uri so we wont read it twice
+                visitedURIs.add(path);
+                LOG.debug("Loading file {} to retrieve list of packages, from url: {}", META_INF_SERVICES, url);
+                try (BufferedReader reader
+                        = IOHelper.buffered(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
+                    while (true) {
+                        String line = reader.readLine();
+                        if (line == null) {
+                            break;
+                        }
+                        line = line.trim();
+                        if (line.startsWith("#") || line.length() == 0) {
+                            continue;
+                        }
+                        packages.add(line);
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void transform(Message message, DataType from, DataType to) throws Exception {
+        // noop
+    }
+
+    public void setPackageName(String packageName) {
+        this.packageName = packageName;
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformer.java
similarity index 50%
copy from core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
copy to core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformer.java
index 4f7c4e1069e..d553d979ea1 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformer.java
@@ -14,24 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.reifier;
 
-import org.apache.camel.Expression;
-import org.apache.camel.Processor;
-import org.apache.camel.Route;
-import org.apache.camel.model.ProcessorDefinition;
-import org.apache.camel.model.TransformDefinition;
-import org.apache.camel.processor.TransformProcessor;
+package org.apache.camel.processor.transformer;
 
-public class TransformReifier extends ExpressionReifier<TransformDefinition> {
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
 
-    public TransformReifier(Route route, ProcessorDefinition<?> definition) {
-        super(route, (TransformDefinition) definition);
-    }
+/**
+ * Generic binary data type uses Camel message body converter mechanism to convert content to byte array representation.
+ */
+@DataTypeTransformer(name = "application-octet-stream")
+public class ByteArrayDataTypeTransformer extends Transformer {
+
+    private static final Transformer DELEGATE = new TypeConverterTransformer(byte[].class);
 
     @Override
-    public Processor createProcessor() throws Exception {
-        Expression expr = createExpression(definition.getExpression());
-        return new TransformProcessor(expr);
+    public void transform(Message message, DataType from, DataType to) throws Exception {
+        DELEGATE.transform(message, from, to);
+
+        message.setHeader(Exchange.CONTENT_TYPE, "application/octet-stream");
     }
 }
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java
index 64afbf8f78a..7e197d7c942 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java
@@ -42,6 +42,9 @@ public class DataFormatTransformer extends Transformer {
     private DataFormat dataFormat;
     private String transformerString;
 
+    public DataFormatTransformer() {
+    }
+
     public DataFormatTransformer(CamelContext context) {
         setCamelContext(context);
     }
@@ -59,10 +62,10 @@ public class DataFormatTransformer extends Transformer {
         CamelContext context = exchange.getContext();
 
         // Unmarshaling into Java Object
-        if ((to == null || to.isJavaType()) && (from.equals(getFrom()) || from.getModel().equals(getModel()))) {
+        if ((DataType.isAnyType(to) || to.isJavaType()) && (from.equals(getFrom()) || from.getScheme().equals(getName()))) {
             LOG.debug("Unmarshaling with: {}", dataFormat);
             Object answer = dataFormat.unmarshal(exchange, message.getBody(InputStream.class));
-            if (to != null && to.getName() != null) {
+            if (!DataType.isAnyType(to) && to.getName() != null) {
                 Class<?> toClass = context.getClassResolver().resolveClass(to.getName());
                 if (!toClass.isAssignableFrom(answer.getClass())) {
                     LOG.debug("Converting to: {}", toClass.getName());
@@ -72,9 +75,10 @@ public class DataFormatTransformer extends Transformer {
             message.setBody(answer);
 
             // Marshaling from Java Object
-        } else if ((from == null || from.isJavaType()) && (to.equals(getTo()) || to.getModel().equals(getModel()))) {
+        } else if ((DataType.isAnyType(from) || from.isJavaType())
+                && (to.equals(getTo()) || to.getScheme().equals(getName()))) {
             Object input = message.getBody();
-            if (from != null && from.getName() != null) {
+            if (!DataType.isAnyType(from) && from.getName() != null) {
                 Class<?> fromClass = context.getClassResolver().resolveClass(from.getName());
                 if (!fromClass.isAssignableFrom(input.getClass())) {
                     LOG.debug("Converting to: {}", fromClass.getName());
@@ -105,8 +109,8 @@ public class DataFormatTransformer extends Transformer {
     @Override
     public String toString() {
         if (transformerString == null) {
-            transformerString = String.format("DataFormatTransformer[scheme='%s', from='%s', to='%s', dataFormat='%s']",
-                    getModel(), getFrom(), getTo(), dataFormat);
+            transformerString = String.format("DataFormatTransformer[name='%s', from='%s', to='%s', dataFormat='%s']",
+                    getName(), getFrom(), getTo(), dataFormat);
         }
         return transformerString;
     }
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataTypeProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataTypeProcessor.java
new file mode 100644
index 00000000000..a7f9212bead
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataTypeProcessor.java
@@ -0,0 +1,120 @@
+/*
+ * 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.processor.transformer;
+
+import java.util.Optional;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeAware;
+import org.apache.camel.spi.Transformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Processor applies data type conversion based on given format name. Searches for matching data type transformer in
+ * context and applies its logic.
+ */
+public class DataTypeProcessor implements Processor {
+
+    public static final String DATA_TYPE_PROPERTY = "CamelDataType";
+
+    private static final Logger LOG = LoggerFactory.getLogger(DataTypeProcessor.class);
+
+    private String fromType;
+    private String toType;
+
+    private boolean ignoreMissingDataType;
+
+    private Transformer transformer;
+
+    public DataTypeProcessor() {
+    }
+
+    public DataTypeProcessor(String fromType, String toType) {
+        this.fromType = fromType;
+        this.toType = toType;
+    }
+
+    @Override
+    public void process(Exchange exchange) throws Exception {
+        if (toType == null && exchange.hasProperties() && exchange.getProperties().containsKey(DATA_TYPE_PROPERTY)) {
+            toType = exchange.getProperty(DATA_TYPE_PROPERTY, String.class);
+        }
+
+        if (toType == null || toType.isEmpty()) {
+            return;
+        }
+
+        Message message = exchange.getMessage();
+
+        DataType toDataType = new DataType(toType);
+        DataType fromDataType = DataType.ANY;
+        if (fromType != null) {
+            fromDataType = new DataType(fromType);
+        } else if (message instanceof DataTypeAware) {
+            fromDataType = ((DataTypeAware) message).getDataType();
+        }
+
+        Optional<Transformer> dataTypeTransformer = doLookupTransformer(exchange.getContext(), fromDataType, toDataType);
+        if (dataTypeTransformer.isPresent()) {
+            dataTypeTransformer.get().transform(message, fromDataType, toDataType);
+        } else if (ignoreMissingDataType) {
+            LOG.debug("Unable to find  data type transformer from {} to type {}", fromDataType, toDataType);
+        } else {
+            throw new CamelExecutionException(
+                    String.format("Missing data type transformer from %s to type %s", fromDataType, toDataType), exchange);
+        }
+    }
+
+    private Optional<Transformer> doLookupTransformer(CamelContext context, DataType fromType, DataType toType) {
+        if (transformer != null) {
+            return Optional.of(transformer);
+        }
+
+        Transformer maybeTransformer
+                = context.getTransformerRegistry().resolveTransformer(new TransformerKey(fromType, toType));
+        if (maybeTransformer != null) {
+            this.transformer = maybeTransformer;
+            return Optional.of(maybeTransformer);
+        }
+
+        return Optional.empty();
+    }
+
+    public void setFromType(String fromType) {
+        this.fromType = fromType;
+    }
+
+    public void setToType(String toType) {
+        this.toType = toType;
+    }
+
+    public void setTransformer(Transformer transformer) {
+        this.transformer = transformer;
+    }
+
+    public void setIgnoreMissingDataType(boolean ignoreMissingDataType) {
+        this.ignoreMissingDataType = ignoreMissingDataType;
+    }
+}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DefaultTransformerLoader.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DefaultTransformerLoader.java
new file mode 100644
index 00000000000..aaf8d6adcf4
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DefaultTransformerLoader.java
@@ -0,0 +1,48 @@
+/*
+ * 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.processor.transformer;
+
+import org.apache.camel.Message;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerLoader;
+import org.apache.camel.spi.TransformerRegistry;
+
+/**
+ * Transformer loader loads known default {@link Transformer} implementations.
+ */
+public class DefaultTransformerLoader extends Transformer implements TransformerLoader {
+
+    @Override
+    public void load(TransformerRegistry registry) {
+        Transformer[] defaultTransformers = new Transformer[] {
+                new ByteArrayDataTypeTransformer(),
+                new StringDataTypeTransformer()
+        };
+
+        for (Transformer defaultTransformer : defaultTransformers) {
+            registry.put(TransformerKey.createFrom(defaultTransformer), defaultTransformer);
+        }
+    }
+
+    @Override
+    public void transform(Message message, DataType from, DataType to) throws Exception {
+        // noop
+    }
+}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ProcessorTransformer.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ProcessorTransformer.java
index 62455d9422f..e5ab53860e7 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ProcessorTransformer.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ProcessorTransformer.java
@@ -40,6 +40,9 @@ public class ProcessorTransformer extends Transformer {
     private Processor processor;
     private String transformerString;
 
+    public ProcessorTransformer() {
+    }
+
     public ProcessorTransformer(CamelContext context) {
         setCamelContext(context);
     }
@@ -101,8 +104,8 @@ public class ProcessorTransformer extends Transformer {
     @Override
     public String toString() {
         if (transformerString == null) {
-            transformerString = String.format("ProcessorTransformer[scheme='%s', from='%s', to='%s', processor='%s']",
-                    getModel(), getFrom(), getTo(), processor);
+            transformerString = String.format("ProcessorTransformer[name='%s', from='%s', to='%s', processor='%s']",
+                    getName(), getFrom(), getTo(), processor);
         }
         return transformerString;
     }
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/StringDataTypeTransformer.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/StringDataTypeTransformer.java
new file mode 100644
index 00000000000..02e53b2a06b
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/StringDataTypeTransformer.java
@@ -0,0 +1,46 @@
+/*
+ * 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.processor.transformer;
+
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePropertyKey;
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Generic String data type converts Exchange payload to String representation using the Camel message body converter
+ * mechanism. By default, uses UTF-8 charset as encoding.
+ */
+@DataTypeTransformer(name = "text-plain")
+public class StringDataTypeTransformer extends Transformer {
+
+    private static final Transformer DELEGATE = new TypeConverterTransformer(String.class);
+
+    @Override
+    public void transform(Message message, DataType from, DataType to) throws Exception {
+        message.getExchange().setProperty(ExchangePropertyKey.CHARSET_NAME, StandardCharsets.UTF_8.name());
+
+        DELEGATE.transform(message, from, to);
+
+        message.setHeader(Exchange.CONTENT_TYPE, "text/plain");
+    }
+}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/TypeConverterTransformer.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/TypeConverterTransformer.java
new file mode 100644
index 00000000000..bbd7917a357
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/TypeConverterTransformer.java
@@ -0,0 +1,80 @@
+/*
+ * 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.processor.transformer;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Data type converter receives a name and a target type in order to use traditional exchange body conversion mechanisms
+ * in order to transform the message body to a given type.
+ */
+public class TypeConverterTransformer extends Transformer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TypeConverterTransformer.class);
+
+    private DataType dataType;
+    private Class<?> type;
+
+    public TypeConverterTransformer(DataType type) {
+        super(type.getFullName());
+        this.dataType = type;
+    }
+
+    public TypeConverterTransformer(Class<?> type) {
+        super("java:" + type.getName());
+        this.type = type;
+    }
+
+    @Override
+    public void transform(Message message, DataType from, DataType to) {
+        if (message == null || message.getBody() == null) {
+            return;
+        }
+
+        try {
+            if (dataType != null) {
+                if (DataType.isJavaType(dataType) && dataType.getName() != null) {
+                    CamelContext context = message.getExchange().getContext();
+                    type = context.getClassResolver().resolveMandatoryClass(dataType.getName());
+                }
+            }
+
+            if (type != null && !type.isAssignableFrom(message.getBody().getClass())) {
+                LOG.debug("Converting to '{}'", type.getName());
+                message.setBody(message.getMandatoryBody(type));
+            }
+        } catch (InvalidPayloadException | ClassNotFoundException e) {
+            throw new CamelExecutionException(
+                    String.format("Failed to convert body to '%s' content using type conversion for %s",
+                            getName(), ObjectHelper.name(type)),
+                    message.getExchange(), e);
+        }
+    }
+
+    public Class<?> getType() {
+        return type;
+    }
+}
diff --git a/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-octet-stream b/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-octet-stream
new file mode 100644
index 00000000000..6d209870e44
--- /dev/null
+++ b/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-octet-stream
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.processor.transformer.ByteArrayDataTypeTransformer
diff --git a/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/plain-text b/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/plain-text
new file mode 100644
index 00000000000..a2347583375
--- /dev/null
+++ b/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/plain-text
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.processor.transformer.StringDataTypeTransformer
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
index 4f7c4e1069e..a8b7b41c55c 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
@@ -22,6 +22,7 @@ import org.apache.camel.Route;
 import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.model.TransformDefinition;
 import org.apache.camel.processor.TransformProcessor;
+import org.apache.camel.processor.transformer.DataTypeProcessor;
 
 public class TransformReifier extends ExpressionReifier<TransformDefinition> {
 
@@ -31,6 +32,15 @@ public class TransformReifier extends ExpressionReifier<TransformDefinition> {
 
     @Override
     public Processor createProcessor() throws Exception {
+        if (definition.getExpression() != null && definition.getToType() != null) {
+            throw new IllegalArgumentException(
+                    "Both expression and data type set on transform EIP - please choose only one of them");
+        }
+
+        if (definition.getToType() != null) {
+            return new DataTypeProcessor(definition.getFromType(), definition.getToType());
+        }
+
         Expression expr = createExpression(definition.getExpression());
         return new TransformProcessor(expr);
     }
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformerReifier.java
index 26ed5f1839d..7ab18da7177 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformerReifier.java
@@ -39,7 +39,7 @@ public class CustomTransformerReifier extends TransformerReifier<CustomTransform
             if (transformer == null) {
                 throw new IllegalArgumentException("Cannot find transformer with ref:" + definition.getRef());
             }
-            if (transformer.getModel() != null || transformer.getFrom() != null || transformer.getTo() != null) {
+            if (transformer.getName() != null || transformer.getFrom() != null || transformer.getTo() != null) {
                 throw new IllegalArgumentException(
                         String.format("Transformer '%s' is already in use. Please check if duplicate transformer exists.",
                                 definition.getRef()));
@@ -53,7 +53,8 @@ public class CustomTransformerReifier extends TransformerReifier<CustomTransform
             transformer = camelContext.getInjector().newInstance(transformerClass, false);
         }
         transformer.setCamelContext(camelContext);
-        return transformer.setModel(definition.getScheme()).setFrom(definition.getFromType()).setTo(definition.getToType());
+        return transformer.setName(definition.getScheme(), definition.getName()).setFrom(definition.getFromType())
+                .setTo(definition.getToType());
     }
 
 }
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
index 294a5c5ea29..261f1db553c 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
@@ -34,7 +34,8 @@ public class DataFormatTransformerReifier extends TransformerReifier<DataFormatT
     protected Transformer doCreateTransformer() {
         DataFormat dataFormat
                 = DataFormatReifier.getDataFormat(camelContext, definition.getDataFormatType());
-        return new DataFormatTransformer(camelContext).setDataFormat(dataFormat).setModel(definition.getScheme())
+        return new DataFormatTransformer(camelContext).setDataFormat(dataFormat)
+                .setName(definition.getScheme(), definition.getName())
                 .setFrom(definition.getFromType()).setTo(definition.getToType());
     }
 
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/EndpointTransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/EndpointTransformerReifier.java
index 9877f41eee2..2afdcf20f4a 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/EndpointTransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/EndpointTransformerReifier.java
@@ -38,7 +38,7 @@ public class EndpointTransformerReifier extends TransformerReifier<EndpointTrans
                 : lookupByNameAndType(parseString(definition.getRef()), Endpoint.class);
         SendProcessor processor = new SendProcessor(endpoint, ExchangePattern.InOut);
         return new ProcessorTransformer(camelContext).setProcessor(processor)
-                .setModel(parseString(definition.getScheme()))
+                .setName(parseString(definition.getScheme()), parseString(definition.getName()))
                 .setFrom(parseString(definition.getFromType()))
                 .setTo(parseString(definition.getToType()));
     }
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/LoadTransformerReifier.java
similarity index 53%
copy from core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
copy to core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/LoadTransformerReifier.java
index 294a5c5ea29..14a90802b30 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/LoadTransformerReifier.java
@@ -17,25 +17,28 @@
 package org.apache.camel.reifier.transformer;
 
 import org.apache.camel.CamelContext;
-import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
+import org.apache.camel.model.transformer.LoadTransformerDefinition;
 import org.apache.camel.model.transformer.TransformerDefinition;
-import org.apache.camel.processor.transformer.DataFormatTransformer;
-import org.apache.camel.reifier.dataformat.DataFormatReifier;
-import org.apache.camel.spi.DataFormat;
+import org.apache.camel.processor.transformer.AnnotationTransformerLoader;
+import org.apache.camel.processor.transformer.DefaultTransformerLoader;
 import org.apache.camel.spi.Transformer;
 
-public class DataFormatTransformerReifier extends TransformerReifier<DataFormatTransformerDefinition> {
+public class LoadTransformerReifier extends TransformerReifier<LoadTransformerDefinition> {
 
-    public DataFormatTransformerReifier(CamelContext camelContext, TransformerDefinition definition) {
-        super(camelContext, (DataFormatTransformerDefinition) definition);
+    public LoadTransformerReifier(CamelContext camelContext, TransformerDefinition definition) {
+        super(camelContext, (LoadTransformerDefinition) definition);
     }
 
     @Override
     protected Transformer doCreateTransformer() {
-        DataFormat dataFormat
-                = DataFormatReifier.getDataFormat(camelContext, definition.getDataFormatType());
-        return new DataFormatTransformer(camelContext).setDataFormat(dataFormat).setModel(definition.getScheme())
-                .setFrom(definition.getFromType()).setTo(definition.getToType());
+        if (definition.getDefaults() != null && parseBoolean(definition.getDefaults(), false)) {
+            return new DefaultTransformerLoader();
+        } else {
+            AnnotationTransformerLoader transformerLoader = new AnnotationTransformerLoader();
+            transformerLoader.setCamelContext(camelContext);
+            transformerLoader.setPackageName(definition.getPackageScan());
+            return transformerLoader;
+        }
     }
 
 }
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/TransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/TransformerReifier.java
index 63707ea4eaa..69a61a1ffc3 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/TransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/TransformerReifier.java
@@ -24,6 +24,7 @@ import org.apache.camel.CamelContext;
 import org.apache.camel.model.transformer.CustomTransformerDefinition;
 import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
 import org.apache.camel.model.transformer.EndpointTransformerDefinition;
+import org.apache.camel.model.transformer.LoadTransformerDefinition;
 import org.apache.camel.model.transformer.TransformerDefinition;
 import org.apache.camel.reifier.AbstractReifier;
 import org.apache.camel.spi.ReifierStrategy;
@@ -80,6 +81,8 @@ public abstract class TransformerReifier<T> extends AbstractReifier {
             return new DataFormatTransformerReifier(camelContext, definition);
         } else if (definition instanceof EndpointTransformerDefinition) {
             return new EndpointTransformerReifier(camelContext, definition);
+        } else if (definition instanceof LoadTransformerDefinition) {
+            return new LoadTransformerReifier(camelContext, definition);
         }
         return null;
     }
diff --git a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index 92a0d7963ca..fb2662db6b5 100644
--- a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -577,9 +577,15 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
     }
 
     private static ValueHolder<String> createTransformerKey(TransformerDefinition def) {
-        return org.apache.camel.util.ObjectHelper.isNotEmpty(def.getScheme())
-                ? new TransformerKey(def.getScheme())
-                : new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
+        if (org.apache.camel.util.ObjectHelper.isNotEmpty(def.getScheme())) {
+            return org.apache.camel.util.ObjectHelper.isNotEmpty(def.getName())
+                    ? new TransformerKey(def.getScheme() + ":" + def.getName()) : new TransformerKey(def.getScheme());
+        }
+        if (org.apache.camel.util.ObjectHelper.isNotEmpty(def.getName())) {
+            return new TransformerKey(def.getName());
+        } else {
+            return new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
+        }
     }
 
     private void initValidators() {
diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
index 38e34f17476..338d32dbfe2 100644
--- a/core/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
@@ -63,7 +63,7 @@ public class TransformerBuilderTest extends TestSupport {
         RouteBuilder builder = new RouteBuilder() {
             @Override
             public void configure() throws Exception {
-                transformer().scheme("other").withJava(MyTransformer.class);
+                transformer().name("other").withJava(MyTransformer.class);
                 from("direct:input").log("test");
             }
         };
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerRegistryTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerRegistryTest.java
new file mode 100644
index 00000000000..a7de0a24a40
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerRegistryTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.impl.engine;
+
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.processor.transformer.ByteArrayDataTypeTransformer;
+import org.apache.camel.processor.transformer.StringDataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class DefaultTransformerRegistryTest {
+
+    private final DefaultTransformerRegistry dataTypeRegistry = new DefaultTransformerRegistry(new DefaultCamelContext());
+
+    @Test
+    public void shouldLookupDefaultDataTypeConverters() throws Exception {
+        Transformer transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("plain-text"));
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(StringDataTypeTransformer.class, transformer.getClass());
+        transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("application-octet-stream"));
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(ByteArrayDataTypeTransformer.class, transformer.getClass());
+        transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("lowercase"));
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(LowercaseDataTypeTransformer.class, transformer.getClass());
+        transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("uppercase"));
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(UppercaseDataTypeTransformer.class, transformer.getClass());
+    }
+
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerResolverTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerResolverTest.java
new file mode 100644
index 00000000000..b7b17d9d354
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerResolverTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.impl.engine;
+
+import org.apache.camel.Message;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.processor.transformer.StringDataTypeTransformer;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class DefaultTransformerResolverTest {
+
+    private DefaultCamelContext camelContext;
+
+    private final DefaultTransformerResolver resolver = new DefaultTransformerResolver();
+
+    @BeforeEach
+    void setup() {
+        this.camelContext = new DefaultCamelContext();
+    }
+
+    @Test
+    public void shouldHandleUnresolvableDataTypeTransformers() throws Exception {
+        Transformer transformer = resolver.resolve(new TransformerKey("unknown"), camelContext);
+        Assertions.assertNull(transformer);
+
+        transformer = resolver.resolve(new TransformerKey(
+                new DataType("foo:fromType"),
+                new DataType("foo:toType")), camelContext);
+        Assertions.assertNull(transformer);
+    }
+
+    @Test
+    public void shouldResolveDataTypeTransformers() throws Exception {
+        Transformer transformer = resolver.resolve(new TransformerKey("plain-text"), camelContext);
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(StringDataTypeTransformer.class, transformer.getClass());
+
+        transformer = resolver.resolve(new TransformerKey("lowercase"), camelContext);
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(LowercaseDataTypeTransformer.class, transformer.getClass());
+
+        transformer = resolver.resolve(new TransformerKey(new DataType("foo"), new DataType("json")), camelContext);
+        Assertions.assertNotNull(transformer);
+        Assertions.assertEquals(FooDataTypeTransformer.class, transformer.getClass());
+    }
+
+    @DataTypeTransformer(name = "foo-json", fromType = "foo", toType = "json")
+    public static class FooDataTypeTransformer extends Transformer {
+
+        @Override
+        public void transform(Message message, DataType fromType, DataType toType) {
+            message.setBody("Foo");
+        }
+    }
+}
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/LowercaseDataTypeTransformer.java
similarity index 63%
copy from core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
copy to core/camel-core/src/test/java/org/apache/camel/impl/engine/LowercaseDataTypeTransformer.java
index 23827554acc..3cdf31ee232 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/LowercaseDataTypeTransformer.java
@@ -14,16 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.api.management.mbean;
 
-import org.apache.camel.api.management.ManagedAttribute;
+package org.apache.camel.impl.engine;
 
-public interface ManagedTransformMBean extends ManagedProcessorMBean {
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
 
-    @ManagedAttribute(description = "The language for the expression")
-    String getExpressionLanguage();
-
-    @ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
-    String getExpression();
+@DataTypeTransformer(name = "lowercase")
+public class LowercaseDataTypeTransformer extends Transformer {
 
+    @Override
+    public void transform(Message message, DataType fromType, DataType toType) {
+        message.setBody(message.getBody(String.class).toLowerCase());
+    }
 }
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/UppercaseDataTypeTransformer.java
similarity index 63%
copy from core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
copy to core/camel-core/src/test/java/org/apache/camel/impl/engine/UppercaseDataTypeTransformer.java
index 23827554acc..58cdd93eca7 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/UppercaseDataTypeTransformer.java
@@ -14,16 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.api.management.mbean;
 
-import org.apache.camel.api.management.ManagedAttribute;
+package org.apache.camel.impl.engine;
 
-public interface ManagedTransformMBean extends ManagedProcessorMBean {
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
 
-    @ManagedAttribute(description = "The language for the expression")
-    String getExpressionLanguage();
-
-    @ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
-    String getExpression();
+@DataTypeTransformer(name = "uppercase")
+public class UppercaseDataTypeTransformer extends Transformer {
 
+    @Override
+    public void transform(Message message, DataType fromType, DataType toType) {
+        message.setBody(message.getBody(String.class).toUpperCase());
+    }
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/TransformDataTypeProcessorTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/TransformDataTypeProcessorTest.java
new file mode 100644
index 00000000000..02ad6bec7ac
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/TransformDataTypeProcessorTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.processor;
+
+import org.apache.camel.Message;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+
+public class TransformDataTypeProcessorTest extends TransformViaDSLTest {
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                transformer().name("myDataType").withJava(MyDataTypeTransformer.class);
+                // START SNIPPET: example
+                from("direct:start").transform(new DataType("myDataType")).to("mock:result");
+                // END SNIPPET: example
+            }
+        };
+    }
+
+    public static class MyDataTypeTransformer extends Transformer {
+
+        @Override
+        public void transform(Message message, DataType from, DataType to) throws Exception {
+            message.setBody(message.getBody(String.class) + " World!");
+        }
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformerTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformerTest.java
new file mode 100644
index 00000000000..1f5f3011f24
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformerTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.processor.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.DefaultTransformerRegistry;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ByteArrayDataTypeTransformerTest {
+
+    private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+    private final ByteArrayDataTypeTransformer transformer = new ByteArrayDataTypeTransformer();
+
+    @Test
+    void shouldRetainBytesModel() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader("file", "test.txt");
+        exchange.getMessage().setBody("Test".getBytes(StandardCharsets.UTF_8));
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        Assertions.assertTrue(exchange.getMessage().hasHeaders());
+        assertBinaryBody(exchange, "test.txt", "Test");
+    }
+
+    @Test
+    void shouldTransformFromStringToBytesModel() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader("file", "test1.txt");
+        exchange.getMessage().setBody("Test1");
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        Assertions.assertTrue(exchange.getMessage().hasHeaders());
+        assertBinaryBody(exchange, "test1.txt", "Test1");
+    }
+
+    @Test
+    void shouldTransformFromBytesToBytesModel() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader("file", "test2.txt");
+        exchange.getMessage().setBody("Test2".getBytes(StandardCharsets.UTF_8));
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        Assertions.assertTrue(exchange.getMessage().hasHeaders());
+        assertBinaryBody(exchange, "test2.txt", "Test2");
+    }
+
+    @Test
+    void shouldTransformFromInputStreamToBytesModel() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader("file", "test3.txt");
+        exchange.getMessage().setBody(new ByteArrayInputStream("Test3".getBytes(StandardCharsets.UTF_8)));
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        Assertions.assertTrue(exchange.getMessage().hasHeaders());
+        assertBinaryBody(exchange, "test3.txt", "Test3");
+    }
+
+    @Test
+    public void shouldResolveTransformer() throws Exception {
+        DefaultTransformerRegistry transformerRegistry = new DefaultTransformerRegistry(camelContext);
+        Transformer transformer = transformerRegistry.resolveTransformer(new TransformerKey("application-octet-stream"));
+        Assertions.assertNotNull(transformer);
+    }
+
+    private static void assertBinaryBody(Exchange exchange, String key, String content) {
+        assertEquals(key, exchange.getMessage().getHeader("file"));
+
+        assertEquals(byte[].class, exchange.getMessage().getBody().getClass());
+        assertEquals(content, exchange.getMessage().getBody(String.class));
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/DataTypeProcessorTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/DataTypeProcessorTest.java
new file mode 100644
index 00000000000..065e148f088
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/DataTypeProcessorTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.processor.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class DataTypeProcessorTest {
+
+    private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+    private final DataTypeProcessor processor = new DataTypeProcessor();
+
+    @BeforeEach
+    void setup() {
+        CamelContextAware.trySetCamelContext(processor, camelContext);
+    }
+
+    @Test
+    public void shouldApplyDataTypeConverterFromAnnotationLookup() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setBody(new ByteArrayInputStream("Test".getBytes(StandardCharsets.UTF_8)));
+        processor.setToType("uppercase");
+        processor.process(exchange);
+
+        assertEquals(String.class, exchange.getMessage().getBody().getClass());
+        assertEquals("TEST", exchange.getMessage().getBody());
+    }
+
+    @Test
+    public void shouldApplyDataTypeConverterFromResourceLookup() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setBody(new ByteArrayInputStream("Test".getBytes(StandardCharsets.UTF_8)));
+        processor.setToType("lowercase");
+        processor.process(exchange);
+
+        assertEquals(String.class, exchange.getMessage().getBody().getClass());
+        assertEquals("test", exchange.getMessage().getBody());
+    }
+
+    @Test
+    public void shouldIgnoreUnknownDataType() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setBody(new ByteArrayInputStream("Test".getBytes(StandardCharsets.UTF_8)));
+        processor.setIgnoreMissingDataType(true);
+        processor.setToType("foo:unknown");
+        processor.process(exchange);
+
+        assertEquals(ByteArrayInputStream.class, exchange.getMessage().getBody().getClass());
+        assertEquals("Test", exchange.getMessage().getBody(String.class));
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/StringDataTypeTransformerTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/StringDataTypeTransformerTest.java
new file mode 100644
index 00000000000..25b70416c06
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/StringDataTypeTransformerTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.processor.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.DefaultTransformerRegistry;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class StringDataTypeTransformerTest {
+
+    private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+    private final StringDataTypeTransformer transformer = new StringDataTypeTransformer();
+
+    @Test
+    void shouldRetainStringModel() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader("file", "test.txt");
+        exchange.getMessage().setBody("Test");
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        Assertions.assertTrue(exchange.getMessage().hasHeaders());
+        assertStringBody(exchange, "test.txt", "Test");
+    }
+
+    @Test
+    void shouldMapFromBinaryToStringModel() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader("file", "test1.txt");
+        exchange.getMessage().setBody("Test1".getBytes(StandardCharsets.UTF_8));
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        Assertions.assertTrue(exchange.getMessage().hasHeaders());
+        assertStringBody(exchange, "test1.txt", "Test1");
+    }
+
+    @Test
+    void shouldMapFromInputStreamToStringModel() throws Exception {
+        Exchange exchange = new DefaultExchange(camelContext);
+
+        exchange.getMessage().setHeader("file", "test3.txt");
+        exchange.getMessage().setBody(new ByteArrayInputStream("Test3".getBytes(StandardCharsets.UTF_8)));
+        transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+        Assertions.assertTrue(exchange.getMessage().hasHeaders());
+        assertStringBody(exchange, "test3.txt", "Test3");
+    }
+
+    @Test
+    public void shouldLookupDataType() throws Exception {
+        DefaultTransformerRegistry dataTypeRegistry = new DefaultTransformerRegistry(camelContext);
+        Transformer transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("plain-text"));
+        Assertions.assertNotNull(transformer);
+    }
+
+    private static void assertStringBody(Exchange exchange, String key, String content) {
+        assertEquals(key, exchange.getMessage().getHeader("file"));
+
+        assertEquals(String.class, exchange.getMessage().getBody().getClass());
+        assertEquals(content, exchange.getMessage().getBody(String.class));
+    }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/TransformerRouteTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/TransformerRouteTest.java
index 8a3f850300d..1fdf129e747 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/TransformerRouteTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/TransformerRouteTest.java
@@ -64,7 +64,7 @@ public class TransformerRouteTest extends ContextTestSupport {
         abcresult.whenAnyExchangeReceived(new Processor() {
             @Override
             public void process(Exchange exchange) throws Exception {
-                LOG.info("Asserting String -> XOrderResponse convertion");
+                LOG.info("Asserting String -> XOrderResponse conversion");
                 assertEquals(XOrderResponse.class, exchange.getIn().getBody().getClass());
             }
 
@@ -75,7 +75,7 @@ public class TransformerRouteTest extends ContextTestSupport {
         xyzresult.whenAnyExchangeReceived(new Processor() {
             @Override
             public void process(Exchange exchange) throws Exception {
-                LOG.info("Asserting String -> XOrderResponse convertion is not yet performed");
+                LOG.info("Asserting String -> XOrderResponse conversion is not yet performed");
                 assertEquals("response", exchange.getIn().getBody());
             }
         });
@@ -97,7 +97,7 @@ public class TransformerRouteTest extends ContextTestSupport {
         xyzresult.whenAnyExchangeReceived(new Processor() {
             @Override
             public void process(Exchange exchange) throws Exception {
-                LOG.info("Asserting String -> XOrderResponse convertion is not yet performed");
+                LOG.info("Asserting String -> XOrderResponse conversion is not yet performed");
                 assertEquals("response", exchange.getIn().getBody());
             }
         });
@@ -119,7 +119,7 @@ public class TransformerRouteTest extends ContextTestSupport {
         xyzresult.whenAnyExchangeReceived(new Processor() {
             @Override
             public void process(Exchange exchange) throws Exception {
-                LOG.info("Asserting String -> XOrderResponse convertion is not yet performed");
+                LOG.info("Asserting String -> XOrderResponse conversion is not yet performed");
                 assertEquals("response", exchange.getIn().getBody());
             }
         });
@@ -141,7 +141,7 @@ public class TransformerRouteTest extends ContextTestSupport {
         xyzresult.whenAnyExchangeReceived(new Processor() {
             @Override
             public void process(Exchange exchange) throws Exception {
-                LOG.info("Asserting String -> XOrderResponse convertion is not yet performed");
+                LOG.info("Asserting String -> XOrderResponse conversion is not yet performed");
                 assertEquals("response", exchange.getIn().getBody());
             }
         });
@@ -178,14 +178,14 @@ public class TransformerRouteTest extends ContextTestSupport {
                 context.getTypeConverterRegistry().addTypeConverters(new MyTypeConverters());
                 from("direct:abc").inputType(AOrder.class).outputType(AOrderResponse.class).process(new Processor() {
                     public void process(Exchange exchange) throws Exception {
-                        LOG.info("Asserting input -> AOrder convertion");
+                        LOG.info("Asserting input -> AOrder conversion");
                         assertEquals(AOrder.class, exchange.getIn().getBody().getClass());
                     }
                 }).to(ExchangePattern.InOut, "direct:xyz").to("mock:abcresult");
 
                 from("direct:xyz").inputType(XOrder.class).outputType(XOrderResponse.class).process(new Processor() {
                     public void process(Exchange exchange) throws Exception {
-                        LOG.info("Asserting input -> XOrder convertion");
+                        LOG.info("Asserting input -> XOrder conversion");
                         assertEquals(XOrder.class, exchange.getIn().getBody().getClass());
                         exchange.getIn().setBody("response");
                     }
@@ -206,12 +206,15 @@ public class TransformerRouteTest extends ContextTestSupport {
                         .withJava(XOrderResponseToOtherTransformer.class);
                 from("direct:custom").inputType("other:OtherXOrder").outputType("other:OtherXOrderResponse")
                         .to(ExchangePattern.InOut, "direct:xyz");
-                transformer().scheme("myDataType").withDataFormat(new MyDataFormatDefinition());
+                transformer().name("myDataType").withDataFormat(new MyDataFormatDefinition());
                 from("direct:testDataType").inputTypeWithValidate("myDataType")
                         .to("direct:testDataTypeStep2");
                 from("direct:testDataTypeStep2").inputType(MyDataType.class)
                         .to("mock:testDataType");
                 validator().type("myDataType").withExpression(bodyAs(String.class).contains("fake"));
+
+                transformer().withDefaults();
+                transformer().scan("com.apache.camel.processor.transformer.custom");
             }
         };
     }
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/custom/CustomDataTypeTransformer.java
similarity index 63%
copy from core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
copy to core/camel-core/src/test/java/org/apache/camel/processor/transformer/custom/CustomDataTypeTransformer.java
index 23827554acc..3dc9339c69e 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/custom/CustomDataTypeTransformer.java
@@ -14,16 +14,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.api.management.mbean;
 
-import org.apache.camel.api.management.ManagedAttribute;
+package org.apache.camel.processor.transformer.custom;
 
-public interface ManagedTransformMBean extends ManagedProcessorMBean {
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
 
-    @ManagedAttribute(description = "The language for the expression")
-    String getExpressionLanguage();
-
-    @ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
-    String getExpression();
+@DataTypeTransformer(name = "custom")
+public class CustomDataTypeTransformer extends Transformer {
 
+    @Override
+    public void transform(Message message, DataType from, DataType to) throws Exception {
+        message.setBody("customized");
+    }
 }
diff --git a/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/foo-json b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/foo-json
new file mode 100644
index 00000000000..9b2546f6062
--- /dev/null
+++ b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/foo-json
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.impl.engine.DefaultTransformerResolverTest$FooDataTypeTransformer
diff --git a/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/lowercase b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/lowercase
new file mode 100644
index 00000000000..0ee439ca63b
--- /dev/null
+++ b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/lowercase
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.impl.engine.LowercaseDataTypeTransformer
diff --git a/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/uppercase b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/uppercase
new file mode 100644
index 00000000000..734ff7f25ed
--- /dev/null
+++ b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/uppercase
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.impl.engine.UppercaseDataTypeTransformer
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
index 991a0325d6f..93b01ebd60d 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
@@ -217,14 +217,14 @@ public final class CamelOpenMBeanTypes {
     public static TabularType listTransformersTabularType() throws OpenDataException {
         CompositeType ct = listTransformersCompositeType();
         return new TabularType(
-                "listTransformers", "Lists all the transformers in the registry", ct, new String[] { "scheme", "from", "to" });
+                "listTransformers", "Lists all the transformers in the registry", ct, new String[] { "name", "from", "to" });
     }
 
     public static CompositeType listTransformersCompositeType() throws OpenDataException {
         return new CompositeType(
                 "transformers", "Transformers",
-                new String[] { "scheme", "from", "to", "static", "dynamic", "description" },
-                new String[] { "Scheme", "From", "To", "Static", "Dynamic", "Description" },
+                new String[] { "name", "from", "to", "static", "dynamic", "description" },
+                new String[] { "Name", "From", "To", "Static", "Dynamic", "Description" },
                 new OpenType[] {
                         SimpleType.STRING, SimpleType.STRING, SimpleType.STRING,
                         SimpleType.BOOLEAN, SimpleType.BOOLEAN, SimpleType.STRING });
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
index 23827554acc..271319f9203 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
@@ -26,4 +26,10 @@ public interface ManagedTransformMBean extends ManagedProcessorMBean {
     @ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
     String getExpression();
 
+    @ManagedAttribute(description = "Data type used as defined input for the message transformation")
+    String getFromType();
+
+    @ManagedAttribute(description = "Data type representing the defined outcome of a data type transformation (the new message body to use)")
+    String getToType();
+
 }
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java
index 2338ad1bc89..773573228aa 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java
@@ -179,6 +179,7 @@ import org.apache.camel.processor.loadbalancer.RoundRobinLoadBalancer;
 import org.apache.camel.processor.loadbalancer.StickyLoadBalancer;
 import org.apache.camel.processor.loadbalancer.TopicLoadBalancer;
 import org.apache.camel.processor.loadbalancer.WeightedLoadBalancer;
+import org.apache.camel.processor.transformer.DataTypeProcessor;
 import org.apache.camel.spi.BrowsableEndpoint;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.ErrorHandler;
@@ -437,7 +438,9 @@ public class DefaultManagementObjectStrategy implements ManagementObjectStrategy
             } else if (target instanceof ThrowExceptionProcessor) {
                 answer = new ManagedThrowException(context, (ThrowExceptionProcessor) target, definition);
             } else if (target instanceof TransformProcessor) {
-                answer = new ManagedTransformer(context, (TransformProcessor) target, (TransformDefinition) definition);
+                answer = new ManagedTransformer(context, target, (TransformDefinition) definition);
+            } else if (target instanceof DataTypeProcessor) {
+                answer = new ManagedTransformer(context, target, (TransformDefinition) definition);
             } else if (target instanceof PredicateValidatingProcessor) {
                 answer = new ManagedValidate(context, (PredicateValidatingProcessor) target, (ValidateDefinition) definition);
             } else if (target instanceof WireTapProcessor) {
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformer.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformer.java
index 465387af416..00916eb866e 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformer.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformer.java
@@ -17,18 +17,16 @@
 package org.apache.camel.management.mbean;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.Processor;
 import org.apache.camel.api.management.ManagedResource;
 import org.apache.camel.api.management.mbean.ManagedTransformMBean;
 import org.apache.camel.model.TransformDefinition;
-import org.apache.camel.processor.TransformProcessor;
 
 @ManagedResource(description = "Managed Transformer")
 public class ManagedTransformer extends ManagedProcessor implements ManagedTransformMBean {
-    private final TransformProcessor processor;
 
-    public ManagedTransformer(CamelContext context, TransformProcessor processor, TransformDefinition definition) {
+    public ManagedTransformer(CamelContext context, Processor processor, TransformDefinition definition) {
         super(context, processor, definition);
-        this.processor = processor;
     }
 
     @Override
@@ -45,4 +43,14 @@ public class ManagedTransformer extends ManagedProcessor implements ManagedTrans
     public String getExpression() {
         return getDefinition().getExpression().getExpression();
     }
+
+    @Override
+    public String getFromType() {
+        return getDefinition().getFromType();
+    }
+
+    @Override
+    public String getToType() {
+        return getDefinition().getToType();
+    }
 }
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
index 8f9943f065f..79ac1ff8c3d 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
@@ -84,18 +84,18 @@ public class ManagedTransformerRegistry extends ManagedService implements Manage
             Collection<Transformer> transformers = transformerRegistry.values();
             for (Transformer transformer : transformers) {
                 CompositeType ct = CamelOpenMBeanTypes.listTransformersCompositeType();
-                String scheme = transformer.getModel();
+                String name = transformer.getName();
                 DataType from = transformer.getFrom();
                 DataType to = transformer.getTo();
                 String desc = transformer.toString();
                 boolean fromStatic
-                        = scheme != null ? transformerRegistry.isStatic(scheme) : transformerRegistry.isStatic(from, to);
+                        = name != null ? transformerRegistry.isStatic(name) : transformerRegistry.isStatic(from, to);
                 boolean fromDynamic
-                        = scheme != null ? transformerRegistry.isDynamic(scheme) : transformerRegistry.isDynamic(from, to);
+                        = name != null ? transformerRegistry.isDynamic(name) : transformerRegistry.isDynamic(from, to);
 
                 CompositeData data = new CompositeDataSupport(
-                        ct, new String[] { "scheme", "from", "to", "static", "dynamic", "description" },
-                        new Object[] { scheme, from.toString(), to.toString(), fromStatic, fromDynamic, desc });
+                        ct, new String[] { "name", "from", "to", "static", "dynamic", "description" },
+                        new Object[] { name, from.toString(), to.toString(), fromStatic, fromDynamic, desc });
                 answer.put(data);
             }
             return answer;
diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
index 104bfdffe68..6d5f01dee05 100644
--- a/core/camel-management/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
+++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
@@ -85,25 +85,25 @@ public class ManagedTransformerRegistryTest extends ManagementTestSupport {
         TabularData data = (TabularData) mbeanServer.invoke(on, "listTransformers", null, null);
         for (Object row : data.values()) {
             CompositeData composite = (CompositeData) row;
-            String scheme = (String) composite.get("scheme");
+            String name = (String) composite.get("name");
             String from = (String) composite.get("from");
             String to = (String) composite.get("to");
             String description = (String) composite.get("description");
             boolean isStatic = (boolean) composite.get("static");
             boolean isDynamic = (boolean) composite.get("dynamic");
-            LOG.info("[{}][{}][{}][{}][{}][{}]", scheme, from, to, isStatic, isDynamic, description);
+            LOG.info("[{}][{}][{}][{}][{}][{}]", name, from, to, isStatic, isDynamic, description);
             if (description.startsWith("ProcessorTransformer")) {
-                assertEquals(null, scheme);
+                assertEquals(null, name);
                 assertEquals("xml:foo", from);
                 assertEquals("json:bar", to);
             } else if (description.startsWith("DataFormatTransformer")) {
-                assertEquals(null, scheme);
+                assertEquals(null, name);
                 assertEquals("java:" + ManagedTransformerRegistryTest.class.getName(), from);
                 assertEquals("xml:test", to);
             } else if (description.startsWith("MyTransformer")) {
-                assertEquals("custom", scheme);
-                assertEquals(null, from);
-                assertEquals(null, to);
+                assertEquals("custom", name);
+                assertEquals("camel:any", from);
+                assertEquals("camel:any", to);
             } else {
                 fail("Unexpected transformer:" + description);
             }
@@ -121,7 +121,7 @@ public class ManagedTransformerRegistryTest extends ManagementTestSupport {
                         .toType("json:bar")
                         .withUri("direct:transformer");
                 transformer()
-                        .scheme("custom")
+                        .name("custom")
                         .withJava(MyTransformer.class);
 
                 from("direct:start").to("mock:result");
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 3acd8f38740..1438223c20f 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
@@ -1513,8 +1513,14 @@ public class ModelParser extends BaseParser {
         }, outputDefinitionElementHandler(), noValueHandler());
     }
     protected TransformDefinition doParseTransformDefinition() throws IOException, XmlPullParserException {
-        return doParse(new TransformDefinition(),
-            processorDefinitionAttributeHandler(), expressionNodeElementHandler(), noValueHandler());
+        return doParse(new TransformDefinition(), (def, key, val) -> {
+            switch (key) {
+                case "fromType": def.setFromType(val); break;
+                case "toType": def.setToType(val); break;
+                default: return processorDefinitionAttributeHandler().accept(def, key, val);
+            }
+            return true;
+        }, expressionNodeElementHandler(), noValueHandler());
     }
     protected TryDefinition doParseTryDefinition() throws IOException, XmlPullParserException {
         return doParse(new TryDefinition(),
@@ -3242,6 +3248,7 @@ public class ModelParser extends BaseParser {
         return (def, key, val) -> {
             switch (key) {
                 case "fromType": def.setFromType(val); break;
+                case "name": def.setName(val); break;
                 case "scheme": def.setScheme(val); break;
                 case "toType": def.setToType(val); break;
                 default: return false;
@@ -3270,12 +3277,23 @@ public class ModelParser extends BaseParser {
             return true;
         }, noElementHandler(), noValueHandler());
     }
+    protected LoadTransformerDefinition doParseLoadTransformerDefinition() throws IOException, XmlPullParserException {
+        return doParse(new LoadTransformerDefinition(), (def, key, val) -> {
+            switch (key) {
+                case "defaults": def.setDefaults(val); break;
+                case "packageScan": def.setPackageScan(val); break;
+                default: return transformerDefinitionAttributeHandler().accept(def, key, val);
+            }
+            return true;
+        }, noElementHandler(), noValueHandler());
+    }
     protected TransformersDefinition doParseTransformersDefinition() throws IOException, XmlPullParserException {
         return doParse(new TransformersDefinition(),
             noAttributeHandler(), (def, key) -> {
             switch (key) {
                 case "dataFormatTransformer": doAdd(doParseDataFormatTransformerDefinition(), def.getTransformers(), def::setTransformers); break;
                 case "endpointTransformer": doAdd(doParseEndpointTransformerDefinition(), def.getTransformers(), def::setTransformers); break;
+                case "loadTransformer": doAdd(doParseLoadTransformerDefinition(), def.getTransformers(), def::setTransformers); break;
                 case "customTransformer": doAdd(doParseCustomTransformerDefinition(), def.getTransformers(), def::setTransformers); break;
                 default: return false;
             }
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 2104066297c..ea0520d9d52 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
@@ -2381,6 +2381,8 @@ public class ModelWriter extends BaseWriter {
             throws IOException {
         startElement(name);
         doWriteProcessorDefinitionAttributes(def);
+        doWriteAttribute("toType", def.getToType());
+        doWriteAttribute("fromType", def.getFromType());
         doWriteExpressionNodeElements(def);
         endElement(name);
     }
@@ -4547,12 +4549,23 @@ public class ModelWriter extends BaseWriter {
         doWriteAttribute("uri", def.getUri());
         endElement(name);
     }
+    protected void doWriteLoadTransformerDefinition(
+            String name,
+            LoadTransformerDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteTransformerDefinitionAttributes(def);
+        doWriteAttribute("defaults", def.getDefaults());
+        doWriteAttribute("packageScan", def.getPackageScan());
+        endElement(name);
+    }
     protected void doWriteTransformerDefinitionAttributes(
             TransformerDefinition def)
             throws IOException {
         doWriteAttribute("toType", def.getToType());
         doWriteAttribute("fromType", def.getFromType());
         doWriteAttribute("scheme", def.getScheme());
+        doWriteAttribute("name", def.getName());
     }
     protected void doWriteTransformerDefinition(
             String name,
@@ -4571,6 +4584,7 @@ public class ModelWriter extends BaseWriter {
             switch (v.getClass().getSimpleName()) {
                 case "DataFormatTransformerDefinition" -> doWriteDataFormatTransformerDefinition("dataFormatTransformer", (DataFormatTransformerDefinition) v);
                 case "EndpointTransformerDefinition" -> doWriteEndpointTransformerDefinition("endpointTransformer", (EndpointTransformerDefinition) v);
+                case "LoadTransformerDefinition" -> doWriteLoadTransformerDefinition("loadTransformer", (LoadTransformerDefinition) v);
                 case "CustomTransformerDefinition" -> doWriteCustomTransformerDefinition("customTransformer", (CustomTransformerDefinition) v);
             }
         });
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 9b00f8064dc..b0d62b775d7 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
@@ -2381,6 +2381,8 @@ public class ModelWriter extends BaseWriter {
             throws IOException {
         startElement(name);
         doWriteProcessorDefinitionAttributes(def);
+        doWriteAttribute("toType", def.getToType());
+        doWriteAttribute("fromType", def.getFromType());
         doWriteExpressionNodeElements(def);
         endElement(name);
     }
@@ -4547,12 +4549,23 @@ public class ModelWriter extends BaseWriter {
         doWriteAttribute("uri", def.getUri());
         endElement(name);
     }
+    protected void doWriteLoadTransformerDefinition(
+            String name,
+            LoadTransformerDefinition def)
+            throws IOException {
+        startElement(name);
+        doWriteTransformerDefinitionAttributes(def);
+        doWriteAttribute("defaults", def.getDefaults());
+        doWriteAttribute("packageScan", def.getPackageScan());
+        endElement(name);
+    }
     protected void doWriteTransformerDefinitionAttributes(
             TransformerDefinition def)
             throws IOException {
         doWriteAttribute("toType", def.getToType());
         doWriteAttribute("fromType", def.getFromType());
         doWriteAttribute("scheme", def.getScheme());
+        doWriteAttribute("name", def.getName());
     }
     protected void doWriteTransformerDefinition(
             String name,
@@ -4571,6 +4584,7 @@ public class ModelWriter extends BaseWriter {
             switch (v.getClass().getSimpleName()) {
                 case "DataFormatTransformerDefinition" -> doWriteDataFormatTransformerDefinition("dataFormatTransformer", (DataFormatTransformerDefinition) v);
                 case "EndpointTransformerDefinition" -> doWriteEndpointTransformerDefinition("endpointTransformer", (EndpointTransformerDefinition) v);
+                case "LoadTransformerDefinition" -> doWriteLoadTransformerDefinition("loadTransformer", (LoadTransformerDefinition) v);
                 case "CustomTransformerDefinition" -> doWriteCustomTransformerDefinition("customTransformer", (CustomTransformerDefinition) v);
             }
         });
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 91b18829099..c0211030ffb 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
@@ -231,6 +231,7 @@ import org.apache.camel.model.rest.SecurityDefinition;
 import org.apache.camel.model.transformer.CustomTransformerDefinition;
 import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
 import org.apache.camel.model.transformer.EndpointTransformerDefinition;
+import org.apache.camel.model.transformer.LoadTransformerDefinition;
 import org.apache.camel.model.transformer.TransformersDefinition;
 import org.apache.camel.model.validator.CustomValidatorDefinition;
 import org.apache.camel.model.validator.EndpointValidatorDefinition;
@@ -2999,6 +3000,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
             properties = {
                     @YamlProperty(name = "class-name", type = "string"),
                     @YamlProperty(name = "from-type", type = "string"),
+                    @YamlProperty(name = "name", type = "string"),
                     @YamlProperty(name = "ref", type = "string"),
                     @YamlProperty(name = "scheme", type = "string"),
                     @YamlProperty(name = "to-type", type = "string")
@@ -3028,6 +3030,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     target.setFromType(val);
                     break;
                 }
+                case "name": {
+                    String val = asText(node);
+                    target.setName(val);
+                    break;
+                }
                 case "ref": {
                     String val = asText(node);
                     target.setRef(val);
@@ -3156,6 +3163,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     @YamlProperty(name = "json-api", type = "object:org.apache.camel.model.dataformat.JsonApiDataFormat"),
                     @YamlProperty(name = "lzf", type = "object:org.apache.camel.model.dataformat.LZFDataFormat"),
                     @YamlProperty(name = "mime-multipart", type = "object:org.apache.camel.model.dataformat.MimeMultipartDataFormat"),
+                    @YamlProperty(name = "name", type = "string"),
                     @YamlProperty(name = "parquet-avro", type = "object:org.apache.camel.model.dataformat.ParquetAvroDataFormat"),
                     @YamlProperty(name = "pgp", type = "object:org.apache.camel.model.dataformat.PGPDataFormat"),
                     @YamlProperty(name = "protobuf", type = "object:org.apache.camel.model.dataformat.ProtobufDataFormat"),
@@ -3402,6 +3410,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     target.setFromType(val);
                     break;
                 }
+                case "name": {
+                    String val = asText(node);
+                    target.setName(val);
+                    break;
+                }
                 case "scheme": {
                     String val = asText(node);
                     target.setScheme(val);
@@ -4623,6 +4636,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
             order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
             properties = {
                     @YamlProperty(name = "from-type", type = "string"),
+                    @YamlProperty(name = "name", type = "string"),
                     @YamlProperty(name = "ref", type = "string"),
                     @YamlProperty(name = "scheme", type = "string"),
                     @YamlProperty(name = "to-type", type = "string"),
@@ -4648,6 +4662,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     target.setFromType(val);
                     break;
                 }
+                case "name": {
+                    String val = asText(node);
+                    target.setName(val);
+                    break;
+                }
                 case "ref": {
                     String val = asText(node);
                     target.setRef(val);
@@ -8184,6 +8203,70 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
         }
     }
 
+    @YamlType(
+            types = org.apache.camel.model.transformer.LoadTransformerDefinition.class,
+            order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
+            properties = {
+                    @YamlProperty(name = "defaults", type = "boolean"),
+                    @YamlProperty(name = "from-type", type = "string"),
+                    @YamlProperty(name = "name", type = "string"),
+                    @YamlProperty(name = "package-scan", type = "string"),
+                    @YamlProperty(name = "scheme", type = "string"),
+                    @YamlProperty(name = "to-type", type = "string")
+            }
+    )
+    public static class LoadTransformerDefinitionDeserializer extends YamlDeserializerBase<LoadTransformerDefinition> {
+        public LoadTransformerDefinitionDeserializer() {
+            super(LoadTransformerDefinition.class);
+        }
+
+        @Override
+        protected LoadTransformerDefinition newInstance() {
+            return new LoadTransformerDefinition();
+        }
+
+        @Override
+        protected boolean setProperty(LoadTransformerDefinition target, String propertyKey,
+                String propertyName, Node node) {
+            switch(propertyKey) {
+                case "defaults": {
+                    String val = asText(node);
+                    target.setDefaults(val);
+                    break;
+                }
+                case "from-type": {
+                    String val = asText(node);
+                    target.setFromType(val);
+                    break;
+                }
+                case "name": {
+                    String val = asText(node);
+                    target.setName(val);
+                    break;
+                }
+                case "package-scan": {
+                    String val = asText(node);
+                    target.setPackageScan(val);
+                    break;
+                }
+                case "scheme": {
+                    String val = asText(node);
+                    target.setScheme(val);
+                    break;
+                }
+                case "to-type": {
+                    String val = asText(node);
+                    target.setToType(val);
+                    break;
+                }
+                default: {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
     @YamlType(
             nodes = "log",
             inline = true,
@@ -17074,8 +17157,10 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     @YamlProperty(name = "description", type = "string"),
                     @YamlProperty(name = "disabled", type = "boolean"),
                     @YamlProperty(name = "expression", type = "object:org.apache.camel.model.language.ExpressionDefinition"),
+                    @YamlProperty(name = "from-type", type = "string"),
                     @YamlProperty(name = "id", type = "string"),
-                    @YamlProperty(name = "inherit-error-handler", type = "boolean")
+                    @YamlProperty(name = "inherit-error-handler", type = "boolean"),
+                    @YamlProperty(name = "to-type", type = "string")
             }
     )
     public static class TransformDefinitionDeserializer extends YamlDeserializerBase<TransformDefinition> {
@@ -17102,11 +17187,21 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     target.setExpression(val);
                     break;
                 }
+                case "from-type": {
+                    String val = asText(node);
+                    target.setFromType(val);
+                    break;
+                }
                 case "inherit-error-handler": {
                     String val = asText(node);
                     target.setInheritErrorHandler(java.lang.Boolean.valueOf(val));
                     break;
                 }
+                case "to-type": {
+                    String val = asText(node);
+                    target.setToType(val);
+                    break;
+                }
                 case "id": {
                     String val = asText(node);
                     target.setId(val);
@@ -17141,7 +17236,8 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
             properties = {
                     @YamlProperty(name = "custom-transformer", type = "object:org.apache.camel.model.transformer.CustomTransformerDefinition"),
                     @YamlProperty(name = "data-format-transformer", type = "object:org.apache.camel.model.transformer.DataFormatTransformerDefinition"),
-                    @YamlProperty(name = "endpoint-transformer", type = "object:org.apache.camel.model.transformer.EndpointTransformerDefinition")
+                    @YamlProperty(name = "endpoint-transformer", type = "object:org.apache.camel.model.transformer.EndpointTransformerDefinition"),
+                    @YamlProperty(name = "load-transformer", type = "object:org.apache.camel.model.transformer.LoadTransformerDefinition")
             }
     )
     public static class TransformersDefinitionDeserializer extends YamlDeserializerBase<TransformersDefinition> {
@@ -17183,6 +17279,16 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     target.setTransformers(existing);
                     break;
                 }
+                case "load-transformer": {
+                    org.apache.camel.model.transformer.LoadTransformerDefinition val = asType(node, org.apache.camel.model.transformer.LoadTransformerDefinition.class);
+                    java.util.List<org.apache.camel.model.transformer.TransformerDefinition> existing = target.getTransformers();
+                    if (existing == null) {
+                        existing = new java.util.ArrayList<>();
+                    }
+                    existing.add(val);
+                    target.setTransformers(existing);
+                    break;
+                }
                 case "custom-transformer": {
                     org.apache.camel.model.transformer.CustomTransformerDefinition val = asType(node, org.apache.camel.model.transformer.CustomTransformerDefinition.class);
                     java.util.List<org.apache.camel.model.transformer.TransformerDefinition> existing = target.getTransformers();
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
index 3f512865fa4..960fdb05881 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
@@ -226,6 +226,7 @@ public final class ModelDeserializersResolver implements YamlDeserializerResolve
             case "load-balance": return new ModelDeserializers.LoadBalanceDefinitionDeserializer();
             case "loadBalance": return new ModelDeserializers.LoadBalanceDefinitionDeserializer();
             case "org.apache.camel.model.LoadBalanceDefinition": return new ModelDeserializers.LoadBalanceDefinitionDeserializer();
+            case "org.apache.camel.model.transformer.LoadTransformerDefinition": return new ModelDeserializers.LoadTransformerDefinitionDeserializer();
             case "log": return new ModelDeserializers.LogDefinitionDeserializer();
             case "org.apache.camel.model.LogDefinition": return new ModelDeserializers.LogDefinitionDeserializer();
             case "loop": return new ModelDeserializers.LoopDefinitionDeserializer();
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json
index 76e1cb9eef9..5d7127bcd0e 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json
@@ -2491,6 +2491,9 @@
           "id" : {
             "type" : "string"
           },
+          "input-type" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.InputTypeDefinition"
+          },
           "log-mask" : {
             "type" : "boolean"
           },
@@ -2500,6 +2503,9 @@
           "node-prefix-id" : {
             "type" : "string"
           },
+          "output-type" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.OutputTypeDefinition"
+          },
           "precondition" : {
             "type" : "string"
           },
@@ -3332,11 +3338,17 @@
           "expression" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.language.ExpressionDefinition"
           },
+          "from-type" : {
+            "type" : "string"
+          },
           "id" : {
             "type" : "string"
           },
           "inherit-error-handler" : {
             "type" : "boolean"
+          },
+          "to-type" : {
+            "type" : "string"
           }
         }
       },
@@ -8008,6 +8020,9 @@
           "from-type" : {
             "type" : "string"
           },
+          "name" : {
+            "type" : "string"
+          },
           "ref" : {
             "type" : "string"
           },
@@ -8091,6 +8106,9 @@
           "mime-multipart" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.dataformat.MimeMultipartDataFormat"
           },
+          "name" : {
+            "type" : "string"
+          },
           "parquet-avro" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.dataformat.ParquetAvroDataFormat"
           },
@@ -8159,6 +8177,9 @@
           "from-type" : {
             "type" : "string"
           },
+          "name" : {
+            "type" : "string"
+          },
           "ref" : {
             "type" : "string"
           },
@@ -8173,6 +8194,29 @@
           }
         }
       },
+      "org.apache.camel.model.transformer.LoadTransformerDefinition" : {
+        "type" : "object",
+        "properties" : {
+          "defaults" : {
+            "type" : "boolean"
+          },
+          "from-type" : {
+            "type" : "string"
+          },
+          "name" : {
+            "type" : "string"
+          },
+          "package-scan" : {
+            "type" : "string"
+          },
+          "scheme" : {
+            "type" : "string"
+          },
+          "to-type" : {
+            "type" : "string"
+          }
+        }
+      },
       "org.apache.camel.model.transformer.TransformersDefinition" : {
         "type" : "object",
         "properties" : {
@@ -8184,6 +8228,9 @@
           },
           "endpoint-transformer" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.transformer.EndpointTransformerDefinition"
+          },
+          "load-transformer" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.transformer.LoadTransformerDefinition"
           }
         }
       },
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 06c320f6d52..ed5bc50550e 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
@@ -2401,6 +2401,9 @@
           "id" : {
             "type" : "string"
           },
+          "inputType" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.InputTypeDefinition"
+          },
           "logMask" : {
             "type" : "boolean"
           },
@@ -2410,6 +2413,9 @@
           "nodePrefixId" : {
             "type" : "string"
           },
+          "outputType" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.OutputTypeDefinition"
+          },
           "precondition" : {
             "type" : "string"
           },
@@ -3242,11 +3248,17 @@
           "expression" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.language.ExpressionDefinition"
           },
+          "fromType" : {
+            "type" : "string"
+          },
           "id" : {
             "type" : "string"
           },
           "inheritErrorHandler" : {
             "type" : "boolean"
+          },
+          "toType" : {
+            "type" : "string"
           }
         }
       },
@@ -7915,6 +7927,9 @@
           "fromType" : {
             "type" : "string"
           },
+          "name" : {
+            "type" : "string"
+          },
           "ref" : {
             "type" : "string"
           },
@@ -7998,6 +8013,9 @@
           "mimeMultipart" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.dataformat.MimeMultipartDataFormat"
           },
+          "name" : {
+            "type" : "string"
+          },
           "parquetAvro" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.dataformat.ParquetAvroDataFormat"
           },
@@ -8066,6 +8084,9 @@
           "fromType" : {
             "type" : "string"
           },
+          "name" : {
+            "type" : "string"
+          },
           "ref" : {
             "type" : "string"
           },
@@ -8080,6 +8101,29 @@
           }
         }
       },
+      "org.apache.camel.model.transformer.LoadTransformerDefinition" : {
+        "type" : "object",
+        "properties" : {
+          "defaults" : {
+            "type" : "boolean"
+          },
+          "fromType" : {
+            "type" : "string"
+          },
+          "name" : {
+            "type" : "string"
+          },
+          "packageScan" : {
+            "type" : "string"
+          },
+          "scheme" : {
+            "type" : "string"
+          },
+          "toType" : {
+            "type" : "string"
+          }
+        }
+      },
       "org.apache.camel.model.transformer.TransformersDefinition" : {
         "type" : "object",
         "properties" : {
@@ -8091,6 +8135,9 @@
           },
           "endpointTransformer" : {
             "$ref" : "#/items/definitions/org.apache.camel.model.transformer.EndpointTransformerDefinition"
+          },
+          "loadTransformer" : {
+            "$ref" : "#/items/definitions/org.apache.camel.model.transformer.LoadTransformerDefinition"
           }
         }
       },


[camel] 02/03: CAMEL-18698 Enhance YAML DSL loader to support input/output data types

Posted by cd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 2d8812eefe92451ddb91179e7abe14d283a6acc4
Author: Christoph Deppisch <cd...@redhat.com>
AuthorDate: Wed Jun 28 08:56:04 2023 +0200

    CAMEL-18698 Enhance YAML DSL loader to support input/output data types
    
    - Enable users to specify input/output data types on route and KameletBinding
    - Automatically adds transformation steps and/or input/output data type specifications to the Camel route
---
 .../deserializers/RouteDefinitionDeserializer.java | 12 +++
 .../camel/dsl/yaml/YamlRoutesBuilderLoader.java    | 26 ++++++
 .../camel/dsl/yaml/KameletBindingLoaderTest.groovy | 97 ++++++++++++++++++++++
 .../org/apache/camel/dsl/yaml/RoutesTest.groovy    | 27 ++++++
 .../org/apache/camel/dsl/yaml/TransformTest.groovy | 51 ++++++++++++
 5 files changed, 213 insertions(+)

diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java
index 38ba442f082..3369c745d4d 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/main/java/org/apache/camel/dsl/yaml/deserializers/RouteDefinitionDeserializer.java
@@ -21,6 +21,8 @@ import org.apache.camel.dsl.yaml.common.YamlDeserializerBase;
 import org.apache.camel.dsl.yaml.common.YamlDeserializerResolver;
 import org.apache.camel.dsl.yaml.common.exception.UnsupportedFieldException;
 import org.apache.camel.model.FromDefinition;
+import org.apache.camel.model.InputTypeDefinition;
+import org.apache.camel.model.OutputTypeDefinition;
 import org.apache.camel.model.RouteDefinition;
 import org.apache.camel.spi.annotations.YamlIn;
 import org.apache.camel.spi.annotations.YamlProperty;
@@ -48,6 +50,8 @@ import org.snakeyaml.engine.v2.nodes.NodeTuple;
                   @YamlProperty(name = "message-history", type = "boolean"),
                   @YamlProperty(name = "log-mask", type = "boolean"),
                   @YamlProperty(name = "trace", type = "boolean"),
+                  @YamlProperty(name = "input-type", type = "object:org.apache.camel.model.InputTypeDefinition"),
+                  @YamlProperty(name = "output-type", type = "object:org.apache.camel.model.OutputTypeDefinition"),
                   @YamlProperty(name = "from", type = "object:org.apache.camel.model.FromDefinition", required = true)
           })
 public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefinition> {
@@ -119,6 +123,14 @@ public class RouteDefinitionDeserializer extends YamlDeserializerBase<RouteDefin
                 case "trace":
                     target.setTrace(asText(val));
                     break;
+                case "inputType":
+                case "input-type":
+                    target.setInputType(asType(val, InputTypeDefinition.class));
+                    break;
+                case "outputType":
+                case "output-type":
+                    target.setOutputType(asType(val, OutputTypeDefinition.class));
+                    break;
                 case "from":
                     val.setProperty(RouteDefinition.class.getName(), target);
                     target.setInput(asType(val, FromDefinition.class));
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
index 87eecb3f346..dd6a306aef7 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/main/java/org/apache/camel/dsl/yaml/YamlRoutesBuilderLoader.java
@@ -57,6 +57,7 @@ import org.apache.camel.model.rest.RestConfigurationDefinition;
 import org.apache.camel.model.rest.RestDefinition;
 import org.apache.camel.model.rest.VerbDefinition;
 import org.apache.camel.spi.CamelContextCustomizer;
+import org.apache.camel.spi.DataType;
 import org.apache.camel.spi.DependencyStrategy;
 import org.apache.camel.spi.Resource;
 import org.apache.camel.spi.annotations.RoutesLoader;
@@ -648,6 +649,19 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
                     }
                 }
 
+                MappingNode dataTypes = asMappingNode(nodeAt(source, "/dataTypes"));
+                if (dataTypes != null) {
+                    MappingNode in = asMappingNode(nodeAt(dataTypes, "/in"));
+                    if (in != null) {
+                        route.inputType(extractTupleValue(in.getValue(), "format"));
+                    }
+
+                    MappingNode out = asMappingNode(nodeAt(dataTypes, "/out"));
+                    if (out != null) {
+                        route.transform(new DataType(extractTupleValue(out.getValue(), "format")));
+                    }
+                }
+
                 // steps in the middle (optional)
                 Node steps = nodeAt(root, "/spec/steps");
                 if (steps != null) {
@@ -683,6 +697,18 @@ public class YamlRoutesBuilderLoader extends YamlRoutesBuilderLoaderSupport {
                 }
 
                 if (sink != null) {
+                    dataTypes = asMappingNode(nodeAt(sink, "/dataTypes"));
+                    if (dataTypes != null) {
+                        MappingNode in = asMappingNode(nodeAt(dataTypes, "/in"));
+                        if (in != null) {
+                            route.transform(new DataType(extractTupleValue(in.getValue(), "format")));
+                        }
+
+                        MappingNode out = asMappingNode(nodeAt(dataTypes, "/out"));
+                        if (out != null) {
+                            route.outputType(extractTupleValue(out.getValue(), "format"));
+                        }
+                    }
 
                     // sink is at the end (mandatory)
                     line = -1;
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletBindingLoaderTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletBindingLoaderTest.groovy
index 2a15541d526..30454f5c188 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletBindingLoaderTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/KameletBindingLoaderTest.groovy
@@ -22,6 +22,7 @@ import org.apache.camel.component.mock.MockEndpoint
 import org.apache.camel.dsl.yaml.support.YamlTestSupport
 import org.apache.camel.model.KameletDefinition
 import org.apache.camel.model.ToDefinition
+import org.apache.camel.model.TransformDefinition
 import org.apache.camel.model.errorhandler.DeadLetterChannelDefinition
 import org.apache.camel.model.errorhandler.DefaultErrorHandlerDefinition
 import org.apache.camel.model.errorhandler.NoErrorHandlerDefinition
@@ -657,4 +658,100 @@ class KameletBindingLoaderTest extends YamlTestSupport {
         }
     }
 
+    def "kamelet binding with input/output data types"() {
+        when:
+        loadBindings('''
+                apiVersion: camel.apache.org/v1alpha1
+                kind: KameletBinding
+                metadata:
+                  name: timer-event-source                  
+                spec:
+                  source:
+                    ref:
+                      kind: Kamelet
+                      apiVersion: camel.apache.org/v1
+                      name: timer-source
+                    dataTypes:
+                      in:
+                        format: plain/text
+                    properties:
+                      message: "Hello world!"
+                  sink:
+                    ref:
+                      kind: Kamelet
+                      apiVersion: camel.apache.org/v1
+                      name: log-sink
+                    dataTypes:
+                      out:
+                        format: application/octet-stream   
+            ''')
+        then:
+        context.routeDefinitions.size() == 3
+
+        with (context.routeDefinitions[0]) {
+            routeId == 'timer-event-source'
+            input.endpointUri == 'kamelet:timer-source?message=Hello+world%21'
+            input.lineNumber == 7
+            inputType.urn == 'plain/text'
+            outputType.urn == 'application/octet-stream'
+            outputs.size() == 1
+            with (outputs[0], ToDefinition) {
+                endpointUri == 'kamelet:log-sink'
+                lineNumber == 17
+            }
+        }
+    }
+
+    def "kamelet binding with data type transformation"() {
+        when:
+        loadBindings('''
+                apiVersion: camel.apache.org/v1alpha1
+                kind: KameletBinding
+                metadata:
+                  name: timer-event-source                  
+                spec:
+                  source:
+                    ref:
+                      kind: Kamelet
+                      apiVersion: camel.apache.org/v1
+                      name: timer-source
+                    dataTypes:
+                      out:
+                        format: application/octet-stream    
+                    properties:
+                      message: "Hello world!"
+                  sink:
+                    ref:
+                      kind: Kamelet
+                      apiVersion: camel.apache.org/v1
+                      name: log-sink
+                    dataTypes:
+                      in:
+                        format: plain/text
+            ''')
+        then:
+        context.routeDefinitions.size() == 3
+
+        with (context.routeDefinitions[0]) {
+            routeId == 'timer-event-source'
+            input.endpointUri == 'kamelet:timer-source?message=Hello+world%21'
+            input.lineNumber == 7
+            outputs.size() == 3
+            with (outputs[0], TransformDefinition) {
+                fromType == 'camel:any'
+                toType == 'application/octet-stream'
+                lineNumber == -1
+            }
+            with (outputs[1], TransformDefinition) {
+                fromType == 'camel:any'
+                toType == 'plain/text'
+                lineNumber == -1
+            }
+            with (outputs[2], ToDefinition) {
+                endpointUri == 'kamelet:log-sink'
+                lineNumber == 17
+            }
+        }
+    }
+
 }
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy
index 983782d5577..3bfe4494be4 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/RoutesTest.groovy
@@ -164,6 +164,33 @@ class RoutesTest extends YamlTestSupport {
             }
     }
 
+    def "load route with input/output types"() {
+        when:
+        loadRoutes '''
+                - route:
+                    inputType: 
+                      urn: "plain/text"
+                    outputType: 
+                      urn: "application/octet-stream"
+                    from: 
+                      uri: "direct:info"
+                      steps:
+                        - log: "message"
+            '''
+        then:
+        context.routeDefinitions.size() == 1
+
+        with(context.routeDefinitions[0], RouteDefinition) {
+            inputType.urn == 'plain/text'
+            outputType.urn == 'application/octet-stream'
+
+            input.endpointUri == 'direct:info'
+            with (outputs[0], LogDefinition) {
+                message == 'message'
+            }
+        }
+    }
+
     def "load route inlined"() {
         when:
         loadRoutes '''
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/TransformTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/TransformTest.groovy
new file mode 100644
index 00000000000..32fd939de05
--- /dev/null
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/TransformTest.groovy
@@ -0,0 +1,51 @@
+/*
+ * 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.dsl.yaml
+
+import org.apache.camel.dsl.yaml.support.YamlTestSupport
+import org.apache.camel.model.StepDefinition
+import org.apache.camel.model.ToDefinition
+import org.apache.camel.model.TransformDefinition
+
+class TransformTest extends YamlTestSupport {
+
+    def "transform with data types"() {
+        when:
+            loadRoutes '''
+                - from:
+                    uri: "direct:start"
+                    steps:    
+                      - step:
+                          steps:
+                            - transform:
+                                fromType: "plain-text"
+                                toType: "application-octet-stream"
+                      - to: "mock:result"    
+                             
+            '''
+        then:
+            with(context.routeDefinitions[0].outputs[0], StepDefinition) {
+                with(outputs[0], TransformDefinition) {
+                    fromType == 'plain-text'
+                    toType == 'application-octet-stream'
+                }
+            }
+            with(context.routeDefinitions[0].outputs[1], ToDefinition) {
+                endpointUri == 'mock:result'
+            }
+    }
+}


[camel] 03/03: CAMEL-18698 Enhance transform EIP and transformer documentation

Posted by cd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit bc1d1c1063260eca132f29ffef4f0ede3913cd44
Author: Christoph Deppisch <cd...@redhat.com>
AuthorDate: Wed Jun 28 18:47:26 2023 +0200

    CAMEL-18698 Enhance transform EIP and transformer documentation
---
 .../docs/modules/eips/pages/transform-eip.adoc     |  43 +++++
 .../modules/ROOT/pages/transformer.adoc            | 184 +++++++++++++++++----
 2 files changed, 196 insertions(+), 31 deletions(-)

diff --git a/core/camel-core-engine/src/main/docs/modules/eips/pages/transform-eip.adoc b/core/camel-core-engine/src/main/docs/modules/eips/pages/transform-eip.adoc
index 670f8d31c26..f0283430acc 100644
--- a/core/camel-core-engine/src/main/docs/modules/eips/pages/transform-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/modules/eips/pages/transform-eip.adoc
@@ -81,6 +81,49 @@ YAML::
 ----
 ====
 
+The xref:transform-eip.adoc[Transform] may also reference a given from/to data type (`org.apache.camel.spi.DataType`).
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("direct:cheese")
+    .transform(new DataType("myDataType"))
+    .to("log:hello");
+----
+
+XML::
++
+[source,xml]
+----
+<route>
+    <from uri="direct:cheese"/>
+    <transform toType="myDataType"/>
+    <to uri="log:hello"/>
+</route>
+----
+
+YAML::
++
+[source,yaml]
+----
+- from:
+    uri: direct:cheese
+    steps:
+      - transform:
+          to-type: myDataType
+      - to:
+          uri: log:hello
+----
+====
+
+The example above defines the xref:transform-eip.adoc[Transform] EIP that uses a target data type `myDataType`.
+The given data type may reference a xref:manual::transformer.adoc[Transformer] that is able to handle the data type transformation.
+
+Users may also specify `fromType` in order to reference a very specific transformation from a given data type to a given data type.
+
 === What is the difference between Transform and Set Body
 
 The Transform EIP always sets the result on the OUT message body.
diff --git a/docs/user-manual/modules/ROOT/pages/transformer.adoc b/docs/user-manual/modules/ROOT/pages/transformer.adoc
index b5a27cb69c6..3f97ed2c066 100644
--- a/docs/user-manual/modules/ROOT/pages/transformer.adoc
+++ b/docs/user-manual/modules/ROOT/pages/transformer.adoc
@@ -2,11 +2,11 @@
 
 Transformer (`org.apache.camel.spi.Transformer`) performs declarative transformation of the message according
 to the declared _Input Type_ and/or _Output Type_ on a route definition which declares
-the expected message type. The default camel Message implements `DataTypeAware`, which allows to hold the message type
+the expected message type. The default Camel Message implements `DataTypeAware`, which allows to hold the message type
 represented by `DataType`.
 
 If the input type and/or output type is declared by _Input Type_ and/or _Output Type_ in the route
-definition, and it is different from actual message type at runtime, camel internal processor
+definition, and in case it is different from actual message type at runtime, Camel internal processor
 looks for a `Transformer` which transforms from the current message type to the expected message
 type and apply. Once transform succeed or message is already in expected type, then the message
 data type is updated.
@@ -18,9 +18,10 @@ data type is updated.
 scheme:name
 ----
 
-where *scheme* is the type of data model like `java`, `xml` or `json`, and *name* is the individual
-data type name. If you only specify *scheme* then it hits all the data types which has that scheme like
-a wildcard.
+where *scheme* is the type of data model like `java`, `xml` or `json`, and *name* is the individual data type name.
+The scheme could also represent a Camel component scheme such as `http` or `aws2-s3` in order to reference component specific data types.
+When using the `java` scheme the data type name may be the qualified class name (e.g. `java:org.apache.camel.Foo`)
+If you only specify *scheme* then it hits all the data types which has that scheme like a wildcard.
 
 == Supported Transformers
 
@@ -30,20 +31,63 @@ a wildcard.
 | Data Format Transformer | Transform with using Data Format
 | Endpoint Transformer | Transform with using Endpoint
 | Custom Transformer | Transform with using custom transformer class. Transformer must be a subclass of `org.apache.camel.spi.Transformer`
+| Loading Transformer | Loads multiple transformer implementations (e.g. via annotation classpath scan). Also preloads known default Camel transformer implementations.
 |===
 
 === Common Options
 
-All transformers have following common options to specify which data type is supported by the transformer. `scheme` or both of `fromType` and `toType` must be specified.
+All transformers have following common options to specify which data type is supported by the transformer. `name` or both of `fromType` and `toType` must be specified.
 
 [width="100%",cols="25%,75%",options="header",]
 |===
 | Name | Description
-| scheme | Type of data model like `xml` or `json`. For example if `xml` is specified, the transformer is applied for all java -&gt; xml and xml -&gt; java transformation.
+| scheme | The supported data type scheme. It is possible to just reference a scheme like `xml` or `json`. For example if `xml` is specified, the transformer is applied for all java -&gt; xml and xml -&gt; java transformation.
+| name | The name of the transformer. If name is specified users may use a combination of a scheme and name (e.g. `xml:Order`) to reference the transformer in a route.
 | fromType | xref:transformer.adoc[Data type] to transform from.
 | toType | xref:transformer.adoc[Data type] to transform to.
 |===
 
+Transformer implementations may use `scheme:name` or the combination of `fromType/toType` as an identifier.
+
+When using the `scheme:name` identifier users may reference the transformer by its full name in a route.
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+from("direct:abc")
+    .inputType("myScheme:myTransformer")
+    .to("...");
+----
+
+XML::
++
+[source,xml]
+----
+<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
+    <route>
+        <from uri="direct:abc"/>
+        <inputType urn="myScheme:myTransformer"/>
+        <to uri="..."/>
+    </route>
+</camelContext>
+----
+====
+
+As mentioned earlier the transformer may also skip the name and just use a `scheme` (e.g. `xml`) in order to apply to
+all data type transformations of a given scheme (e.g. `xml:Order`, `xml:OrderResponse`, `xml:anything`)
+
+When using the combination of `fromType/toType` as an identifier the transformer gets matched automatically by the given
+data types used on the Camel route (e.g. inputType) and the given Exchange data type (specified by the Exchange message using `DataTypeAware` interface).
+
+In general, the transformer resolving mechanism tries to find the best match when searching for a proper transformation
+from a given data type to a given data type. The mechanism tries to find exact matches for `fromType` and `toType` first,
+then wildcard matches (using transformers for the given data type scheme only), then named transformers using `scheme:name` identifiers,
+then named transformers matching `scheme` only.
+
+If not already preloaded by the configuration the Transformer resolving mechanism also performs lazy loading of transformer implementations using the factory finder resource path lookup.
 
 === DataFormat Transformer Options
 
@@ -56,8 +100,10 @@ All transformers have following common options to specify which data type is sup
 
 Here is an example to specify xref:components:dataformats:bindy-dataformat.adoc[Bindy] DataFormat type:
 
-Java DSL:
-
+[tabs]
+====
+Java::
++
 [source,java]
 ----
 BindyDataFormat bindy = new BindyDataFormat();
@@ -69,14 +115,15 @@ transformer()
     .withDataFormat(bindy);
 ----
 
-XML DSL:
-
+XML::
++
 [source,xml]
 ----
 <dataFormatTransformer fromType="java:com.example.Order" toType="csv:CSVOrder">
     <bindy id="csvdf" type="Csv" classType="com.example.Order"/>
 </dataFormatTransformer>
 ----
+====
 
 == Endpoint Transformer Options
 
@@ -117,8 +164,10 @@ Note that Transformer must be a subclass of `org.apache.camel.spi.Transformer`
 
 Here is an example to specify custom Transformer class:
 
-Java DSL:
-
+[tabs]
+====
+Java::
++
 [source,java]
 ----
 transformer()
@@ -127,46 +176,118 @@ transformer()
     .withJava(com.example.MyCustomTransformer.class);
 ----
 
-XML DSL:
-
+XML::
++
 [source,xml]
 ----
 <customTransformer className="com.example.MyCustomTransformer" fromType="xml" toType="json"/>
 ----
+====
+
+== Load Transformer Options
+
+Users are able to preload known default transformers. Also users may load transformers via classpath scan.
+
+[width="100%",cols="25%,75%",options="header",]
+|===
+| Name | Description
+| defaults | Loads known default transformer implementations (e.g. plain-text, application-octet-stream)
+| location | Classpath location to scan for transformer implementations. Transformer implementations must use the `org.apache.camel.spi.DataTypeTransformer` annotation to get recognized by the scanner.
+|===
+
+Here is an example to load default Transformer classes:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+transformer()
+    .withDefaults()
+----
+
+XML::
++
+[source,xml]
+----
+<loadTransformer defaults="true"/>
+----
+====
+
+Here is an example to load Transformer classes via classpath scan:
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+transformer()
+    .scan("org.apache.camel.transformer.standard")
+----
+
+XML::
++
+[source,xml]
+----
+<loadTransformer packageScan="org.apache.camel.transformer.standard"/>
+----
+====
+
+The classpath scan looks for classes that use the `org.apache.camel.spi.DataTypeTransformer` annotation.
+The annotation defines the transformer name and/or the supported from/to data types.
+
+[source,java]
+----
+@DataTypeTransformer(name = "uppercase")
+public class UppercaseDataTypeTransformer extends Transformer {
+
+    @Override
+    public void transform(Message message, DataType fromType, DataType toType) {
+        message.setBody(message.getBody(String.class).toUpperCase());
+    }
+}
+----
 
 == Example
 
 For example to declare the Endpoint Transformer which uses
 xslt component to transform from `xml:ABCOrder` to `xml:XYZOrder`, we can do as follows:
 
-Java DSL:
-
+[tabs]
+====
+Java::
++
 [source,java]
--------------------------------------------------------------------
+----
 transformer()
     .fromType("xml:ABCOrder")
     .toType("xml:XYZOrder")
     .withUri("xslt:transform.xsl");
--------------------------------------------------------------------
-
-XML DSL:
+----
 
+XML::
++
 [source,xml]
--------------------------------------------------------------------
+----
 <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
     <transformers>
         <endpointTransformer uri="xslt:transform.xsl" fromType="xml:ABCOrder" toType="xml:XYZOrder"/>
     </transformers>
     ....
 </camelContext>
--------------------------------------------------------------------
+----
+====
 
 If you have following route definition, above transformer will be applied when `direct:abc` endpoint sends the message to `direct:xyz`:
 
-Java DSL:
-
+[tabs]
+====
+Java::
++
 [source,java]
--------------------------------------------------------------------
+----
 from("direct:abc")
     .inputType("xml:ABCOrder")
     .to("direct:xyz");
@@ -174,12 +295,12 @@ from("direct:abc")
 from("direct:xyz")
     .inputType("xml:XYZOrder")
     .to("somewhere:else");
--------------------------------------------------------------------
-
-XML DSL:
+----
 
+XML::
++
 [source,xml]
--------------------------------------------------------------------
+----
 <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
     <route>
         <from uri="direct:abc"/>
@@ -192,7 +313,8 @@ XML DSL:
         <to uri="somewhere:else"/>
     </route>
 </camelContext>
--------------------------------------------------------------------
+----
+====
 
 == See Also