You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2020/12/05 10:05:18 UTC

[camel] branch master updated: [CAMEL-15804] - DataSonnet Expression Language Support (#4561)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 892e225  [CAMEL-15804] - DataSonnet Expression Language Support (#4561)
892e225 is described below

commit 892e2259cc90ae8ffded74a7b7bc02b34f2ba9dc
Author: Jose Montoya <ja...@users.noreply.github.com>
AuthorDate: Sat Dec 5 04:04:49 2020 -0600

    [CAMEL-15804] - DataSonnet Expression Language Support (#4561)
    
    * datasonnet: adds language
    
    * sets up cml library
    
    * upgrade datasonnet mapper
    
    * formatting
    
    * refactors valuebuilder optional params
    
    * renames mimetype to mediatype
    
    also moves datasonnet builder to camel-datasonnet
    
    * Revert delegating ValueBuilder to camel-datasonnet
    
    This partially reverts commit d2202f7ee78daccacec2cec3f85925f4e8b8411e.
    
    * refactor headers and exchange properties to functions
    
    * defaults to output Document unless result specified
    
    * bump datasonnet-mapper ver
    
    * bump ds mapper version
    
    * add dep
    
    * fix scala directory
    
    * rebase 3.7.0-SNAPSHOT
    
    * fix cml library
    
    * adds docs
    
    * bump last ms3 ds version
    
    * Refactor reifier and language
    
    * adds ASF license where possible
    
    * uses parent/pom for dep versions
    
    * adds licenses in core-model
    
    * addresses checkstyle
    
    * align scala deps
    
    * uses parent/pom for dep versions
    
    * maven central mapper version
    
    * supportlevel preview
    
    * remvoe todos
    
    * Removed System print line in test
    
    * Replaced Spring DSL with XML DSL
    
    * Removed ms3inc repository from camel-datasonnet pom
    
    * clarify use of cml.properties in docs
    
    * fixes issues with mapper version
    
    * remove maven compiler properties
    
    * fix language test
    
    * moves classpath scanning to language
    
    * converts CML.scala to java
    
    * reverts scala deps changes
    
    * address checkstyle errors
    
    * fixed scala dep issue
    
    * move datasonnet expression builder
    
    * remove comment
    
    * bump ds mapper version
    
    Co-authored-by: Jake <jh...@ms3-inc.com>
---
 bom/camel-bom/pom.xml                              |   5 +
 camel-dependencies/pom.xml                         |   2 +
 components/camel-datasonnet/pom.xml                |  98 ++++++++
 .../src/main/docs/datasonnet-language.adoc         | 193 +++++++++++++++
 .../org/apache/camel/language/datasonnet/CML.java  | 115 +++++++++
 .../camel/language/datasonnet/Datasonnet.java      |  37 +++
 .../language/datasonnet/DatasonnetConstants.java   |  25 ++
 .../language/datasonnet/DatasonnetExpression.java  | 274 +++++++++++++++++++++
 .../language/datasonnet/DatasonnetLanguage.java    | 171 +++++++++++++
 .../language/datasonnet/CamelDatasonnetTest.java   | 164 ++++++++++++
 .../language/datasonnet/ExpressionsInJavaTest.java | 118 +++++++++
 .../apache/camel/language/datasonnet/Gizmo.java    | 114 +++++++++
 .../camel/language/datasonnet/Manufacturer.java    |  68 +++++
 .../camel/language/datasonnet/PropertiesTest.java  |  52 ++++
 .../camel-datasonnet/src/test/resources/dslibs.jar | Bin 0 -> 786 bytes
 .../src/test/resources/javaTest.json               |  15 ++
 .../test/resources/libraries/testlib4.libsonnet    |  21 ++
 .../src/test/resources/log4j2.properties           |  32 +++
 .../src/test/resources/namedImports.ds             |  28 +++
 .../src/test/resources/namedImportsFS.ds           |  24 ++
 .../src/test/resources/namedImports_result.json    |   1 +
 .../camel/language.datasonnet/camel-context.xml    | 172 +++++++++++++
 .../src/test/resources/payload.csv                 |   2 +
 .../src/test/resources/payload.xml                 |  22 ++
 .../src/test/resources/readCSVTest.ds              |  20 ++
 .../src/test/resources/readJavaTest.ds             |  30 +++
 .../src/test/resources/readXMLExtTest.ds           |  23 ++
 .../src/test/resources/readXMLExtTest.json         |  13 +
 .../src/test/resources/simpleMapping.ds            |  25 ++
 .../src/test/resources/simpleMapping_payload.json  |   4 +
 .../src/test/resources/simpleMapping_result.json   |   1 +
 .../src/test/resources/testlib3.libsonnet          |  21 ++
 .../src/test/resources/writeJavaTest.ds            |  30 +++
 components/pom.xml                                 |   1 +
 core/camel-allcomponents/pom.xml                   |   4 +
 .../org/apache/camel/builder/BuilderSupport.java   |  35 +++
 .../org/apache/camel/builder/ExpressionClause.java |  10 +
 .../camel/builder/ExpressionClauseSupport.java     |  17 +-
 .../camel/model/language/DatasonnetExpression.java | 111 +++++++++
 .../language/DatasonnetExpressionReifier.java      |  62 +++++
 .../camel/reifier/language/ExpressionReifier.java  |   3 +
 parent/pom.xml                                     |   8 +
 42 files changed, 2168 insertions(+), 3 deletions(-)

diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index b330711b..253aa81 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -624,6 +624,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-datasonnet</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-debezium-common</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/camel-dependencies/pom.xml b/camel-dependencies/pom.xml
index 8483389..b10538b 100644
--- a/camel-dependencies/pom.xml
+++ b/camel-dependencies/pom.xml
@@ -161,6 +161,7 @@
     <cxf.codegen.jvmArgs></cxf.codegen.jvmArgs>
     <cxf.codegenplugin.forkmode>once</cxf.codegenplugin.forkmode>
     <cxf.xjc.jvmArgs></cxf.xjc.jvmArgs>
+    <datasonnet-mapper-version>2.1.1</datasonnet-mapper-version>
     <debezium-mysql-connector-version>8.0.22</debezium-mysql-connector-version>
     <debezium-version>1.3.1.Final</debezium-version>
     <deltaspike-version>1.9.4</deltaspike-version>
@@ -492,6 +493,7 @@
     <rxjava2-version>2.2.20</rxjava2-version>
     <saxon-version>9.9.1-7</saxon-version>
     <scala-version>2.11.7</scala-version>
+    <scala-datasonnet-version>2.13.3</scala-datasonnet-version>
     <scribe-version>1.3.7</scribe-version>
     <servicemix-specs-version>2.9.0</servicemix-specs-version>
     <servlet-version-range>[3,4)</servlet-version-range>
diff --git a/components/camel-datasonnet/pom.xml b/components/camel-datasonnet/pom.xml
new file mode 100644
index 0000000..9187570
--- /dev/null
+++ b/components/camel-datasonnet/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>3.7.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-datasonnet</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Camel :: DataSonnet</name>
+    <description>Camel DataSonnet support</description>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <additionalClasspathElements>
+                        <additionalClasspathElement>${project.basedir}/src/test/resources/dslibs.jar</additionalClasspathElement>
+                    </additionalClasspathElements>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.scala-lang</groupId>
+            <artifactId>scala-library</artifactId>
+            <version>${scala-datasonnet-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-support</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.datasonnet</groupId>
+            <artifactId>datasonnet-mapper</artifactId>
+            <version>${datasonnet-mapper-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.github.classgraph</groupId>
+            <artifactId>classgraph</artifactId>
+            <version>${classgraph-version}</version>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-spring-junit5</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.skyscreamer</groupId>
+            <artifactId>jsonassert</artifactId>
+            <version>${jsonassert-version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/components/camel-datasonnet/src/main/docs/datasonnet-language.adoc b/components/camel-datasonnet/src/main/docs/datasonnet-language.adoc
new file mode 100644
index 0000000..5f2ea2d
--- /dev/null
+++ b/components/camel-datasonnet/src/main/docs/datasonnet-language.adoc
@@ -0,0 +1,193 @@
+[[datasonnet-language]]
+= DataSonnet Language
+:docTitle: DataSonnet
+:artifactId: camel-datasonnet
+:description: To use DataSonnet scripts in Camel expressions or predicates.
+:since: 3.7
+:supportLevel: Preview
+include::{cq-version}@camel-quarkus:ROOT:partial$reference/languages/datasonnet.adoc[opts=optional]
+
+*Since Camel {since}*
+
+Camel supports https://datasonnet.com/[DataSonnet] transformations to allow an Expression or Predicate to be used in the Java DSL or  xref:manual::xml-configuration.adoc[XML
+Configuration].
+
+To use a DataSonnet expression use the following Java code:
+[source,java]
+---------------------------------------
+... datasonnet("someDSExpression") ...
+---------------------------------------
+
+== Example
+
+Here is a simple example using a DataSonnet expression as a predicate in a Message Filter:
+
+[source,java]
+------------------------------------------------------------------------------------------------
+// lets route if a line item is over $100
+from("queue:foo")
+    .filter(datasonnet("ds.arrays.firstWith(body.lineItems, function(item) item > 100) != null"))
+    .to("queue:bar")
+------------------------------------------------------------------------------------------------
+
+And the XML DSL:
+
+[source,xml]
+-----------------------------------------------------------------------------
+<route>
+    <from uri="queue:foo"/>
+    <filter>
+        <datasonnet>ds.arrays.firstWith(body.lineItems, function(item) item > 100) != null</datasonnet>
+        <to uri="queue:bar"/>
+    </filter>
+</route>
+-----------------------------------------------------------------------------
+
+Here is an example of a simple DataSonnet expression as a transformation EIP. This example will transform an XML body with
+`lineItems` into JSON while filtering out lines that are under 100.
+
+[source,java]
+------------------------------------------------------------------------------------------------
+from("queue:foo")
+    .transform(datasonnet("ds.filter(body.lineItems, function(item) item > 100)", String.class)
+        .bodyMediaType("application/xml").outputMediaType("application/json")
+    )
+    .to("queue:bar")
+------------------------------------------------------------------------------------------------
+
+And the XML DSL:
+
+[source,xml]
+-----------------------------------------------------------------------------
+<route>
+    <from uri="queue:foo"/>
+    <filter>
+        <datasonnet bodyMediaType="application/xml" outputMediaType="application/json" resultTypeName="java.lang.String" >
+            ds.filter(body.lineItems, function(item) item > 100)
+        </datasonnet>
+        <to uri="queue:bar"/>
+    </filter>
+</route>
+-----------------------------------------------------------------------------
+
+== Setting result type
+
+The xref:datasonnet-language.adoc[DataSonnet] expression will return a `com.datasonnet.document.Document` by default. The
+document preserves the content type metadata along with the contents of the result of the transformation. In predicates,
+however, the Document will be automatically unwrapped and the boolean content will be returned. Similarly any times you
+want the content in a specific result type like a String. To do this you have to instruct the
+xref:datasonnet-language.adoc[DataSonnet] which result type to return.
+
+In Java DSL:
+
+[source,java]
+----
+datasonnet("body.foo", String.class)
+----
+
+In XML DSL you use the *resultType* attribute to provide a fully
+qualified classname:
+
+[source,xml]
+----
+<datasonnet resultType="java.lang.String">body.foo</datasonnet>
+----
+
+If the expression results in an array, or an object, you can instruct the expression to return you `List.class`
+or `Map.class`, respectively. However, you must also set the output media type to `application/x-java-object`.
+
+NOTE: The default `Document` object is useful in situations where there are intermediate transformation steps, and so
+retaining the content metadata through a route execution is valuable.
+
+== Specifying Media Types
+
+Traditionally the input and output media types are specified through the
+https://datasonnet.s3-us-west-2.amazonaws.com/docs-ci/primary/master/datasonnet/1.0-SNAPSHOT/headers.html[DataSonnet Header]
+The xref:datasonnet-language.adoc[DataSonnet] expression provides convenience options for specifying the body and output
+media types without the need for a Header, this is useful if the transformation is a one-liner, for example.
+
+The DataSonnet expression will look for a body media type in the following order:
+
+1. If the body is a `Document` it will use the metadata in the object
+2. If the convenience bodyMediaType method was used, it will use its value
+3. A "CamelDatasonnetBodyMediaType" exchange property
+4. A "Content-Type" message header
+5. The DataSonnet Header payload media type directive
+6. `application/x-java-object`
+
+And for output media type:
+
+1. If the convenience outputMediaType method was used, it will use its value
+2. A "CamelDatasonnetOutputMediaType" exchange property
+3. A "CamelDatasonnetOutputMediaType" message header
+4. The DataSonnet Header output media type directive
+5. `application/x-java-object`
+
+== Functions
+
+Camel adds the following DataSonnet functions that can be used to access the
+exchange:
+
+[width="100%",cols="10%,10%,10%,70%",options="header",]
+|===
+|Function |Argument |Type |Description
+
+|cml.properties |key for property |String |To lookup a property using the
+xref:ROOT:properties-component.adoc[Properties] component (property placeholders).
+
+|cml.header |the header name |String |Will return the message header.
+
+|cml.exchangeProperty |key for property |String |Will return the exchange property.
+|===
+
+Here's an example showing some of these functions in use:
+
+[source,java]
+------------------------------------------------------------------------------------------------
+from("direct:in")
+    .setBody(datasonnet("'hello, ' + cml.properties('toGreet')", String.class))
+    .to("mock:camel");
+------------------------------------------------------------------------------------------------
+
+And the XML DSL:
+
+[source,xml]
+-----------------------------------------------------------------------------
+<route>
+    <from uri="direct:in"/>
+    <setBody>
+        <datasonnet resultTypeName="java.lang.String">'hello, ' + cml.properties('toGreet')</datasonnet>
+    </setBody>
+    <to uri="mock:camel"/>
+</route>
+-----------------------------------------------------------------------------
+
+== Loading script from external resource
+
+You can externalize the script and have Camel load it from a resource
+such as `"classpath:"`, `"file:"`, or `"http:"`. +
+This is done using the following syntax: `"resource:scheme:location"`,
+eg to refer to a file on the classpath you can do:
+
+[source,java]
+-------------------------------------------------------------------
+.setHeader("myHeader").datasonnet("resource:classpath:mydatasonnet.ds")
+-------------------------------------------------------------------
+
+== Dependencies
+
+To use scripting languages in your camel routes you need to add a
+dependency on *camel-datasonnet*.
+
+If you use Maven you could just add the following to your `pom.xml`,
+substituting the version number for the latest and greatest release (see
+the download page for the latest versions).
+
+[source,xml]
+---------------------------------------
+<dependency>
+  <groupId>org.apache.camel</groupId>
+  <artifactId>camel-datasonnet</artifactId>
+  <version>x.x.x</version>
+</dependency>
+---------------------------------------
diff --git a/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/CML.java b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/CML.java
new file mode 100644
index 0000000..0716ff4
--- /dev/null
+++ b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/CML.java
@@ -0,0 +1,115 @@
+/*
+ * 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.language.datasonnet;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import com.datasonnet.document.DefaultDocument;
+import com.datasonnet.document.Document;
+import com.datasonnet.document.MediaTypes;
+import com.datasonnet.header.Header;
+import com.datasonnet.spi.DataFormatService;
+import com.datasonnet.spi.Library;
+import com.datasonnet.spi.PluginException;
+import org.apache.camel.Exchange;
+import sjsonnet.Materializer;
+import sjsonnet.Val;
+
+public final class CML extends Library {
+    private static final CML INSTANCE = new CML();
+    private final ThreadLocal<Exchange> exchange = new ThreadLocal<>();
+
+    private CML() {
+    }
+
+    public static CML getInstance() {
+        return INSTANCE;
+    }
+
+    public ThreadLocal<Exchange> getExchange() {
+        return exchange;
+    }
+
+    @Override
+    public String namespace() {
+        return "cml";
+    }
+
+    @Override
+    public Set<String> libsonnets() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Map<String, Val.Func> functions(DataFormatService dataFormats, Header header) {
+        Map<String, Val.Func> answer = new HashMap<>();
+        answer.put("properties", makeSimpleFunc(
+                Collections.singletonList("key"), //parameters list
+                params -> properties(params.get(0))));
+        answer.put("header", makeSimpleFunc(
+                Collections.singletonList("key"), //parameters list
+                params -> header(params.get(0), dataFormats)));
+        answer.put("exchangeProperty", makeSimpleFunc(
+                Collections.singletonList("key"), //parameters list
+                params -> exchangeProperty(params.get(0), dataFormats)));
+
+        return answer;
+    }
+
+    public Map<String, Val.Obj> modules(DataFormatService dataFormats, Header header) {
+        return Collections.emptyMap();
+    }
+
+    private Val properties(Val key) {
+        if (key instanceof Val.Str) {
+            return new Val.Str(exchange.get().getContext().resolvePropertyPlaceholders("{{" + ((Val.Str) key).value() + "}}"));
+        }
+        throw new IllegalArgumentException("Expected String got: " + key.prettyName());
+    }
+
+    private Val header(Val key, DataFormatService dataformats) {
+        if (key instanceof Val.Str) {
+            return valFrom(exchange.get().getMessage().getHeader(((Val.Str) key).value()), dataformats);
+        }
+        throw new IllegalArgumentException("Expected String got: " + key.prettyName());
+    }
+
+    private Val exchangeProperty(Val key, DataFormatService dataformats) {
+        if (key instanceof Val.Str) {
+            return valFrom(exchange.get().getProperty(((Val.Str) key).value()), dataformats);
+        }
+        throw new IllegalArgumentException("Expected String got: " + key.prettyName());
+    }
+
+    private Val valFrom(Object obj, DataFormatService dataformats) {
+        Document doc;
+        if (obj instanceof Document) {
+            doc = (Document) obj;
+        } else {
+            doc = new DefaultDocument(obj, MediaTypes.APPLICATION_JAVA);
+        }
+
+        try {
+            return Materializer.reverse(dataformats.mandatoryRead(doc));
+        } catch (PluginException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}
diff --git a/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/Datasonnet.java b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/Datasonnet.java
new file mode 100644
index 0000000..6e5de5f
--- /dev/null
+++ b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/Datasonnet.java
@@ -0,0 +1,37 @@
+/*
+ * 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.language.datasonnet;
+
+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;
+
+import org.apache.camel.support.language.LanguageAnnotation;
+
+/**
+ * Used to inject a DataSonnet expression into a field, property, method or parameter when using
+ * <a href="http://camel.apache.org/bean-integration.html">Bean Integration</a>.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
+@LanguageAnnotation(language = "datasonnet")
+public @interface Datasonnet {
+    String value();
+}
diff --git a/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/DatasonnetConstants.java b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/DatasonnetConstants.java
new file mode 100644
index 0000000..5ee7a7c
--- /dev/null
+++ b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/DatasonnetConstants.java
@@ -0,0 +1,25 @@
+/*
+ * 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.language.datasonnet;
+
+public final class DatasonnetConstants {
+    public static final String BODY_MEDIATYPE = "CamelDatasonnetBodyMediaType";
+    public static final String OUTPUT_MEDIATYPE = "CamelDatasonnetOutputMediaType";
+
+    private DatasonnetConstants() {
+    }
+}
diff --git a/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/DatasonnetExpression.java b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/DatasonnetExpression.java
new file mode 100644
index 0000000..1c1db0b
--- /dev/null
+++ b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/DatasonnetExpression.java
@@ -0,0 +1,274 @@
+/*
+ * 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.language.datasonnet;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import com.datasonnet.Mapper;
+import com.datasonnet.MapperBuilder;
+import com.datasonnet.document.DefaultDocument;
+import com.datasonnet.document.Document;
+import com.datasonnet.document.MediaType;
+import com.datasonnet.document.MediaTypes;
+import org.apache.camel.Exchange;
+import org.apache.camel.Expression;
+import org.apache.camel.RuntimeExpressionException;
+import org.apache.camel.spi.ExpressionResultTypeAware;
+import org.apache.camel.support.ExchangeHelper;
+import org.apache.camel.support.ExpressionAdapter;
+import org.apache.camel.support.MessageHelper;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DatasonnetExpression extends ExpressionAdapter implements ExpressionResultTypeAware {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DatasonnetExpression.class);
+
+    private String expression;
+    private Expression metaExpression;
+    private MediaType bodyMediaType;
+    private MediaType outputMediaType;
+    private Class<?> resultType;
+    private Collection<String> libraryPaths;
+
+    public DatasonnetExpression(String expression) {
+        this.expression = expression;
+    }
+
+    public DatasonnetExpression(Expression expression) {
+        this.metaExpression = expression;
+    }
+
+    public static DatasonnetExpression builder(String expression) {
+        DatasonnetExpression answer = new DatasonnetExpression(expression);
+        return answer;
+    }
+
+    public static DatasonnetExpression builder(Expression expression) {
+        DatasonnetExpression answer = new DatasonnetExpression(expression);
+        return answer;
+    }
+
+    public static DatasonnetExpression builder(String expression, Class<?> resultType) {
+        DatasonnetExpression answer = new DatasonnetExpression(expression);
+        answer.setResultType(resultType);
+        return answer;
+    }
+
+    public static DatasonnetExpression builder(Expression expression, Class<?> resultType) {
+        DatasonnetExpression answer = new DatasonnetExpression(expression);
+        answer.setResultType(resultType);
+        return answer;
+    }
+
+    @Override
+    public boolean matches(Exchange exchange) {
+        this.outputMediaType = MediaTypes.APPLICATION_JAVA;
+        return evaluate(exchange, Boolean.class);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T evaluate(Exchange exchange, Class<T> type) {
+        try {
+            if (metaExpression != null) {
+                expression = metaExpression.evaluate(exchange, String.class);
+            }
+
+            Objects.requireNonNull(expression, "String expression property must be set!");
+
+            Document<?> result = doEvaluate(exchange);
+            if (!type.equals(Object.class)) {
+                return ExchangeHelper.convertToType(exchange, type, result.getContent());
+            } else if (resultType == null || resultType.equals(Document.class)) {
+                return (T) result;
+            } else {
+                return (T) result.getContent();
+            }
+        } catch (Exception e) {
+            throw new RuntimeExpressionException("Unable to evaluate DataSonnet expression : " + expression, e);
+        } finally {
+            CML.getInstance().getExchange().remove();
+        }
+    }
+
+    private Document<?> doEvaluate(Exchange exchange) {
+        if (bodyMediaType == null) {
+            //Try to auto-detect input mime type if it was not explicitly set
+            String typeHeader = exchange.getProperty(DatasonnetConstants.BODY_MEDIATYPE,
+                    exchange.getIn().getHeader(Exchange.CONTENT_TYPE), String.class);
+            if (typeHeader != null) {
+                bodyMediaType = MediaType.valueOf(typeHeader);
+            }
+        }
+
+        Document<?> body;
+        if (exchange.getMessage().getBody() instanceof Document) {
+            body = (Document<?>) exchange.getMessage().getBody();
+        } else if (MediaTypes.APPLICATION_JAVA.equalsTypeAndSubtype(bodyMediaType)) {
+            body = new DefaultDocument<>(exchange.getMessage().getBody());
+        } else {
+            body = new DefaultDocument<>(MessageHelper.extractBodyAsString(exchange.getMessage()), bodyMediaType);
+        }
+
+        Map<String, Document<?>> inputs = Collections.singletonMap("body", body);
+
+        DatasonnetLanguage language = (DatasonnetLanguage) exchange.getContext().resolveLanguage("datasonnet");
+        Mapper mapper = language.computeIfMiss(expression, () -> new MapperBuilder(expression)
+                .withInputNames(inputs.keySet())
+                .withImports(resolveImports(language))
+                .withLibrary(CML.getInstance())
+                .withDefaultOutput(MediaTypes.APPLICATION_JAVA)
+                .build());
+
+        // pass exchange to CML lib using thread as context
+        CML.getInstance().getExchange().set(exchange);
+
+        if (outputMediaType == null) {
+            //Try to auto-detect output mime type if it was not explicitly set
+            String typeHeader = exchange.getProperty(DatasonnetConstants.OUTPUT_MEDIATYPE,
+                    exchange.getIn().getHeader(DatasonnetConstants.OUTPUT_MEDIATYPE), String.class);
+            if (typeHeader != null) {
+                outputMediaType = MediaType.valueOf(typeHeader);
+            } else {
+                outputMediaType = MediaTypes.ANY;
+            }
+        }
+
+        if (resultType == null || resultType.equals(Document.class)) {
+            return mapper.transform(body, inputs, outputMediaType, Object.class);
+        } else {
+            return mapper.transform(body, inputs, outputMediaType, resultType);
+        }
+    }
+
+    private Map<String, String> resolveImports(DatasonnetLanguage language) {
+        if (libraryPaths == null) {
+            return language.getClasspathImports();
+        }
+
+        Map<String, String> answer = new HashMap<>();
+        LOGGER.debug("Explicit library path is " + libraryPaths);
+        for (String nextPath : libraryPaths) {
+            final File nextLibDir = new File(nextPath);
+            if (nextLibDir.isDirectory()) {
+                try {
+                    Files.walkFileTree(nextLibDir.toPath(), new SimpleFileVisitor<Path>() {
+                        @Override
+                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                            File f = file.toFile();
+                            if (!f.isDirectory() && f.getName().toLowerCase().endsWith(".libsonnet")) {
+                                String content = IOUtils.toString(file.toUri());
+                                Path relative = nextLibDir.toPath().relativize(file);
+                                LOGGER.debug("Loading DataSonnet library: " + relative);
+                                answer.put(relative.toString(), content);
+                            }
+                            return FileVisitResult.CONTINUE;
+                        }
+                    });
+                } catch (IOException e) {
+                    LOGGER.error("Unable to load libraries from " + nextPath, e);
+                }
+            }
+        }
+
+        return answer;
+    }
+
+    // Getter/Setter methods
+    // -------------------------------------------------------------------------
+
+    public MediaType getBodyMediaType() {
+        return bodyMediaType;
+    }
+
+    /**
+     * The message's body MediaType
+     */
+    public void setBodyMediaType(MediaType inputMimeType) {
+        this.bodyMediaType = inputMimeType;
+    }
+
+    public MediaType getOutputMediaType() {
+        return outputMediaType;
+    }
+
+    /**
+     * The MediaType to output
+     */
+    public void setOutputMediaType(MediaType outputMimeType) {
+        this.outputMediaType = outputMimeType;
+    }
+
+    public Collection<String> getLibraryPaths() {
+        return libraryPaths;
+    }
+
+    /**
+     * The paths to search for .libsonnet files
+     */
+    public void setLibraryPaths(Collection<String> libraryPaths) {
+        this.libraryPaths = libraryPaths;
+    }
+
+    @Override
+    public String getExpressionText() {
+        return this.expression;
+    }
+
+    @Override
+    public Class<?> getResultType() {
+        return this.resultType;
+    }
+
+    /**
+     * Sets the class of the result type (type from output).
+     * <p/>
+     * The default result type is com.datasonnet.document.Document
+     */
+    public void setResultType(Class<?> targetType) {
+        this.resultType = targetType;
+    }
+
+    // Fluent builder methods
+    // -------------------------------------------------------------------------
+    public DatasonnetExpression bodyMediaType(MediaType bodyMediaType) {
+        setBodyMediaType(bodyMediaType);
+        return this;
+    }
+
+    public DatasonnetExpression outputMediaType(MediaType outputMediaType) {
+        setOutputMediaType(outputMediaType);
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return "datasonnet: " + expression;
+    }
+}
diff --git a/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/DatasonnetLanguage.java b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/DatasonnetLanguage.java
new file mode 100644
index 0000000..c7053f3
--- /dev/null
+++ b/components/camel-datasonnet/src/main/java/org/apache/camel/language/datasonnet/DatasonnetLanguage.java
@@ -0,0 +1,171 @@
+/*
+ * 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.language.datasonnet;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Supplier;
+
+import com.datasonnet.Mapper;
+import com.datasonnet.document.MediaType;
+import io.github.classgraph.ClassGraph;
+import io.github.classgraph.ScanResult;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.Predicate;
+import org.apache.camel.spi.PropertyConfigurer;
+import org.apache.camel.spi.annotations.Language;
+import org.apache.camel.support.LRUCacheFactory;
+import org.apache.camel.support.LanguageSupport;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Language("datasonnet")
+public class DatasonnetLanguage extends LanguageSupport implements PropertyConfigurer {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DatasonnetLanguage.class);
+
+    private static final Map<String, String> CLASSPATH_IMPORTS = new HashMap<>();
+
+    static {
+        LOGGER.debug("One time classpath search...");
+        try (ScanResult scanResult = new ClassGraph().whitelistPaths("/").scan()) {
+            scanResult.getResourcesWithExtension("libsonnet")
+                    .forEachByteArray((resource, bytes) -> {
+                        LOGGER.debug("Loading DataSonnet library: " + resource.getPath());
+                        CLASSPATH_IMPORTS.put(resource.getPath(), new String(bytes, StandardCharsets.UTF_8));
+                    });
+        }
+    }
+
+    // Cache used to stores the Mappers
+    // See: {@link GroovyLanguage}
+    private final Map<String, Mapper> mapperCache = LRUCacheFactory.newLRUSoftCache(16, 1000, true);
+
+    private MediaType bodyMediaType;
+    private MediaType outputMediaType;
+    private Class<?> resultType;
+    private Collection<String> libraryPaths;
+
+    @Override
+    public Predicate createPredicate(String expression) {
+        return createPredicate(expression, null);
+    }
+
+    @Override
+    public Expression createExpression(String expression) {
+        return createExpression(expression, null);
+    }
+
+    @Override
+    public Predicate createPredicate(String expression, Object[] properties) {
+        return (Predicate) createExpression(expression, properties);
+    }
+
+    @Override
+    public Expression createExpression(String expression, Object[] properties) {
+        expression = loadResource(expression);
+
+        DatasonnetExpression answer = new DatasonnetExpression(expression);
+        answer.setResultType(property(Class.class, properties, 0, resultType));
+
+        String stringBodyMediaType = property(String.class, properties, 1, null);
+        answer.setBodyMediaType(stringBodyMediaType != null ? MediaType.valueOf(stringBodyMediaType) : bodyMediaType);
+        String stringOutputMediaType = property(String.class, properties, 2, null);
+        answer.setOutputMediaType(stringOutputMediaType != null ? MediaType.valueOf(stringOutputMediaType) : outputMediaType);
+
+        return answer;
+    }
+
+    Optional<Mapper> lookup(String script) {
+        return Optional.ofNullable(mapperCache.get(script));
+    }
+
+    Mapper computeIfMiss(String script, Supplier<Mapper> mapperSupplier) {
+        return mapperCache.computeIfAbsent(script, k -> mapperSupplier.get());
+    }
+
+    public Map<String, String> getClasspathImports() {
+        return CLASSPATH_IMPORTS;
+    }
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object target, String name, Object value, boolean ignoreCase) {
+        if (target != this) {
+            throw new IllegalStateException("Can only configure our own instance !");
+        }
+
+        switch (ignoreCase ? name.toLowerCase() : name) {
+            case "bodyMediaType":
+            case "bodymediatype":
+                setBodyMediaType(PropertyConfigurerSupport.property(camelContext, String.class, value));
+                return true;
+            case "outputMediaType":
+            case "outputmediatype":
+                setOutputMediaType(PropertyConfigurerSupport.property(camelContext, String.class, value));
+                return true;
+            case "resultType":
+            case "resulttype":
+                setResultType(PropertyConfigurerSupport.property(camelContext, Class.class, value));
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    // Getter/Setter methods
+    // -------------------------------------------------------------------------
+
+    public MediaType getBodyMediaType() {
+        return bodyMediaType;
+    }
+
+    public void setBodyMediaType(MediaType bodyMediaType) {
+        this.bodyMediaType = bodyMediaType;
+    }
+
+    public void setBodyMediaType(String bodyMediaType) {
+        this.bodyMediaType = MediaType.valueOf(bodyMediaType);
+    }
+
+    public MediaType getOutputMediaType() {
+        return outputMediaType;
+    }
+
+    public void setOutputMediaType(MediaType outputMediaType) {
+        this.outputMediaType = outputMediaType;
+    }
+
+    public void setOutputMediaType(String outputMediaType) {
+        this.outputMediaType = MediaType.valueOf(outputMediaType);
+    }
+
+    public Collection<String> getLibraryPaths() {
+        return libraryPaths;
+    }
+
+    public void setLibraryPaths(Collection<String> libraryPaths) {
+        this.libraryPaths = libraryPaths;
+    }
+
+    public void setResultType(Class<?> targetType) {
+        this.resultType = targetType;
+    }
+}
diff --git a/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/CamelDatasonnetTest.java b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/CamelDatasonnetTest.java
new file mode 100644
index 0000000..a4f2938
--- /dev/null
+++ b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/CamelDatasonnetTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.language.datasonnet;
+
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.TimeZone;
+
+import com.datasonnet.document.Document;
+import org.apache.camel.Exchange;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.support.ExchangeHelper;
+import org.apache.camel.test.spring.junit5.CamelSpringTestSupport;
+import org.apache.commons.io.IOUtils;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class CamelDatasonnetTest extends CamelSpringTestSupport {
+    private MockEndpoint mock;
+
+    @Override
+    protected AbstractApplicationContext createApplicationContext() {
+        return new ClassPathXmlApplicationContext("org/apache/camel/language.datasonnet/camel-context.xml");
+    }
+
+    @Test
+    public void testTransform() throws Exception {
+        runCamelTest(loadResourceAsString("simpleMapping_payload.json"),
+                loadResourceAsString("simpleMapping_result.json"),
+                "direct:basicTransform");
+    }
+
+    @Test
+    public void testTransformXML() throws Exception {
+        runCamelTest(loadResourceAsString("payload.xml"),
+                loadResourceAsString("readXMLExtTest.json"),
+                "direct:transformXML");
+    }
+
+    @Test
+    public void testTransformCSV() throws Exception {
+        runCamelTest(loadResourceAsString("payload.csv"),
+                "{\"account\":\"123\"}",
+                "direct:transformCSV");
+    }
+
+    @Test
+    public void testDatasonnetScript() throws Exception {
+        runCamelTest(loadResourceAsString("simpleMapping_payload.json"),
+                loadResourceAsString("simpleMapping_result.json"),
+                "direct:datasonnetScript");
+    }
+
+    @Test
+    public void testNamedImports() throws Exception {
+        runCamelTest("{}",
+                loadResourceAsString("namedImports_result.json"),
+                "direct:namedImports");
+    }
+
+    @Test
+    public void testExpressionLanguage() throws Exception {
+        runCamelTest("World",
+                "{ \"test\":\"Hello, World\"}",
+                "direct:expressionLanguage");
+    }
+
+    @Test
+    public void testNullInput() throws Exception {
+        runCamelTest("",
+                "{ \"test\":\"Hello, World\"}",
+                "direct:nullInput");
+        runCamelTest(null,
+                "{ \"test\":\"Hello, World\"}",
+                "direct:nullInput");
+    }
+
+    @Test
+    public void testReadJava() throws Exception {
+        Gizmo theGizmo = new Gizmo();
+        theGizmo.setName("gizmo");
+        theGizmo.setQuantity(123);
+        theGizmo.setInStock(true);
+        theGizmo.setColors(Arrays.asList("red", "white", "blue"));
+
+        Manufacturer manufacturer = new Manufacturer();
+        manufacturer.setManufacturerName("ACME Corp.");
+        manufacturer.setManufacturerCode("ACME123");
+        theGizmo.setManufacturer(manufacturer);
+
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        theGizmo.setDate(df.parse("2020-01-06"));
+
+        runCamelTest(theGizmo,
+                loadResourceAsString("javaTest.json"),
+                "direct:readJava");
+    }
+
+    @Test
+    public void testWriteJava() throws Exception {
+        Gizmo theGizmo = new Gizmo();
+        theGizmo.setName("gizmo");
+        theGizmo.setQuantity(123);
+        theGizmo.setInStock(true);
+        theGizmo.setColors(Arrays.asList("red", "white", "blue"));
+
+        Manufacturer manufacturer = new Manufacturer();
+        manufacturer.setManufacturerName("ACME Corp.");
+        manufacturer.setManufacturerCode("ACME123");
+        theGizmo.setManufacturer(manufacturer);
+
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        df.setTimeZone(TimeZone.getTimeZone("UTC"));
+        theGizmo.setDate(df.parse("2020-01-06"));
+
+        String payload = loadResourceAsString("javaTest.json");
+
+        template.sendBody("direct:writeJava", payload);
+        mock = getMockEndpoint("mock:direct:end");
+        Exchange exchange = mock.assertExchangeReceived(mock.getReceivedCounter() - 1);
+        Object response = exchange.getIn().getBody();
+
+        assertEquals(theGizmo, response);
+    }
+
+    private void runCamelTest(Object payload, String expectedJson, String uri) throws Exception {
+        template.sendBody(uri, payload);
+        mock = getMockEndpoint("mock:direct:end");
+        Exchange exchange = mock.assertExchangeReceived(mock.getReceivedCounter() - 1);
+        Object body = exchange.getMessage().getBody();
+        String response;
+        if (body instanceof Document) {
+            response = ExchangeHelper.convertToMandatoryType(exchange, String.class, ((Document<?>) body).getContent());
+        } else {
+            response = exchange.getMessage().getBody(String.class);
+
+        }
+        JSONAssert.assertEquals(expectedJson, response, true);
+    }
+
+    private String loadResourceAsString(String name) throws Exception {
+        InputStream is = getClass().getClassLoader().getResourceAsStream(name);
+        return IOUtils.toString(is);
+    }
+}
diff --git a/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/ExpressionsInJavaTest.java b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/ExpressionsInJavaTest.java
new file mode 100644
index 0000000..6d843a3
--- /dev/null
+++ b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/ExpressionsInJavaTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.language.datasonnet;
+
+import java.util.Collections;
+import java.util.List;
+
+import com.datasonnet.document.MediaTypes;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.skyscreamer.jsonassert.JSONAssert;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ExpressionsInJavaTest extends CamelTestSupport {
+    @EndpointInject("mock:direct:response")
+    protected MockEndpoint endEndpoint;
+
+    @Produce("direct:expressionsInJava")
+    protected ProducerTemplate expressionsInJavaProducer;
+
+    @Produce("direct:chainExpressions")
+    protected ProducerTemplate chainExpressionsProducer;
+
+    @Produce("direct:fluentBuilder")
+    protected ProducerTemplate fluentBuilderProducer;
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:chainExpressions")
+                        .setHeader("ScriptHeader", constant("{ hello: \"World\"}"))
+                        .setBody(datasonnet(simple("${header.ScriptHeader}", String.class)))
+                        .to("mock:direct:response");
+
+                from("direct:expressionsInJava")
+                                .choice()
+                                    .when(datasonnet("payload == 'World'"))
+                                        .setBody(datasonnet("'Hello, ' + payload", String.class))
+                                    .otherwise()
+                                        .setBody(datasonnet("'Good bye, ' + payload", String.class))
+                                    .end()
+                                .to("mock:direct:response");
+
+                from("direct:fluentBuilder")
+                        // no optional params, look in header
+                        .setHeader(Exchange.CONTENT_TYPE, constant(MediaTypes.APPLICATION_JAVA_VALUE))
+                        .setBody(DatasonnetExpression.builder("payload"))
+                        .removeHeader(Exchange.CONTENT_TYPE)
+
+                        // override output
+                        .transform(DatasonnetExpression.builder("payload", String.class)
+                                .outputMediaType(MediaTypes.APPLICATION_JSON))
+
+                        // override input
+                        .transform(
+                                DatasonnetExpression.builder("payload", List.class).bodyMediaType(MediaTypes.APPLICATION_JSON))
+
+                        // override both
+                        .setHeader(Exchange.CONTENT_TYPE, constant(MediaTypes.APPLICATION_JSON_VALUE))
+                        .setBody(constant("<root>some-value</root>"))
+                        .transform(DatasonnetExpression.builder("payload.root['$']", String.class)
+                                .bodyMediaType(MediaTypes.APPLICATION_XML)
+                                .outputMediaType(MediaTypes.APPLICATION_JSON))
+                        .to("mock:direct:response");
+            }
+        };
+    }
+
+    @Test
+    public void testExpressionLanguageInJava() throws Exception {
+        endEndpoint.expectedMessageCount(1);
+        expressionsInJavaProducer.sendBody("World");
+        Exchange exchange = endEndpoint.assertExchangeReceived(endEndpoint.getReceivedCounter() - 1);
+        String response = exchange.getIn().getBody().toString();
+        assertEquals("Hello, World", response);
+    }
+
+    @Test
+    public void testChainExpressions() throws Exception {
+        endEndpoint.expectedMessageCount(1);
+        chainExpressionsProducer.sendBody("{}");
+        Exchange exchange = endEndpoint.assertExchangeReceived(endEndpoint.getReceivedCounter() - 1);
+        String response = exchange.getIn().getBody().toString();
+        JSONAssert.assertEquals("{\"hello\":\"World\"}", response, true);
+    }
+
+    @Test
+    public void testFluentBuilder() throws Exception {
+        endEndpoint.expectedMessageCount(1);
+        fluentBuilderProducer.sendBody(Collections.singletonList("datasonnet"));
+        Exchange exchange = endEndpoint.assertExchangeReceived(endEndpoint.getReceivedCounter() - 1);
+        String response = exchange.getMessage().getBody(String.class);
+        assertEquals("\"some-value\"", response);
+    }
+}
diff --git a/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/Gizmo.java b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/Gizmo.java
new file mode 100644
index 0000000..743320e
--- /dev/null
+++ b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/Gizmo.java
@@ -0,0 +1,114 @@
+/*
+ * 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.language.datasonnet;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+
+public class Gizmo {
+    private String name;
+    private int quantity;
+    private List<String> colors;
+    private boolean inStock;
+    private Manufacturer manufacturer;
+    private Date date;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public int getQuantity() {
+        return quantity;
+    }
+
+    public void setQuantity(int quantity) {
+        this.quantity = quantity;
+    }
+
+    public List<String> getColors() {
+        return colors;
+    }
+
+    public void setColors(List<String> colors) {
+        this.colors = colors;
+    }
+
+    public boolean isInStock() {
+        return inStock;
+    }
+
+    public void setInStock(boolean inStock) {
+        this.inStock = inStock;
+    }
+
+    public Manufacturer getManufacturer() {
+        return manufacturer;
+    }
+
+    public void setManufacturer(Manufacturer manufacturer) {
+        this.manufacturer = manufacturer;
+    }
+
+    public Date getDate() {
+        return date;
+    }
+
+    public void setDate(Date date) {
+        this.date = date;
+    }
+
+    @Override
+    public String toString() {
+        return "Gizmo{" +
+               "name='" + name + '\'' +
+               ", quantity=" + quantity +
+               ", colors=" + colors +
+               ", inStock=" + inStock +
+               ", manufacturer=" + manufacturer +
+               ", date=" + date +
+               '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        Gizmo gizmo = (Gizmo) o;
+        return getQuantity() == gizmo.getQuantity() &&
+                isInStock() == gizmo.isInStock() &&
+                Objects.equals(getName(), gizmo.getName()) &&
+                Objects.equals(getColors(), gizmo.getColors()) &&
+                Objects.equals(date, gizmo.getDate()) &&
+                Objects.equals(getManufacturer(), gizmo.getManufacturer());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getName(), getQuantity(), getColors(), isInStock(), getManufacturer(), getDate());
+    }
+}
diff --git a/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/Manufacturer.java b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/Manufacturer.java
new file mode 100644
index 0000000..c903041
--- /dev/null
+++ b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/Manufacturer.java
@@ -0,0 +1,68 @@
+/*
+ * 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.language.datasonnet;
+
+import java.util.Objects;
+
+public class Manufacturer {
+    private String manufacturerName;
+    private String manufacturerCode;
+
+    public String getManufacturerName() {
+        return manufacturerName;
+    }
+
+    public void setManufacturerName(String manufacturerName) {
+        this.manufacturerName = manufacturerName;
+    }
+
+    public String getManufacturerCode() {
+        return manufacturerCode;
+    }
+
+    public void setManufacturerCode(String manufacturerCode) {
+        this.manufacturerCode = manufacturerCode;
+    }
+
+    @Override
+    public String toString() {
+        return "Manufacturer{" +
+               "manufacturerName='" + manufacturerName + '\'' +
+               ", manufacturerCode='" + manufacturerCode + '\'' +
+               '}';
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        Manufacturer that = (Manufacturer) o;
+        return Objects.equals(getManufacturerName(), that.getManufacturerName()) &&
+                Objects.equals(getManufacturerCode(), that.getManufacturerCode());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getManufacturerName(), getManufacturerCode());
+    }
+}
diff --git a/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/PropertiesTest.java b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/PropertiesTest.java
new file mode 100644
index 0000000..be61462
--- /dev/null
+++ b/components/camel-datasonnet/src/test/java/org/apache/camel/language/datasonnet/PropertiesTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.language.datasonnet;
+
+import java.util.Properties;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.support.DefaultExchange;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+public class PropertiesTest extends CamelTestSupport {
+    @Test
+    public void testPropertiesBuiltin() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:camel");
+        mock.expectedBodiesReceived("bar");
+
+        template.send("direct:in", new DefaultExchange(context));
+
+        mock.assertIsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                Properties prop = new Properties();
+                prop.setProperty("foo", "bar");
+                context.getPropertiesComponent().setInitialProperties(prop);
+
+                from("direct:in")
+                        .setBody(datasonnet("cml.properties('foo')", String.class))
+                        .to("mock:camel");
+            }
+        };
+    }
+}
diff --git a/components/camel-datasonnet/src/test/resources/dslibs.jar b/components/camel-datasonnet/src/test/resources/dslibs.jar
new file mode 100644
index 0000000..64c90c8
Binary files /dev/null and b/components/camel-datasonnet/src/test/resources/dslibs.jar differ
diff --git a/components/camel-datasonnet/src/test/resources/javaTest.json b/components/camel-datasonnet/src/test/resources/javaTest.json
new file mode 100644
index 0000000..2dffc04
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/javaTest.json
@@ -0,0 +1,15 @@
+{
+  "pojoColors": [
+    "red",
+    "white",
+    "blue"
+  ],
+  "pojoInStock": true,
+  "pojoManufacturer": {
+    "manufacturerCode": "ACME123",
+    "manufacturerName": "ACME Corp."
+  },
+  "pojoName": "gizmo",
+  "pojoQuantity": 123,
+  "pojoDate": "2020-01-06"
+}
diff --git a/components/camel-datasonnet/src/test/resources/libraries/testlib4.libsonnet b/components/camel-datasonnet/src/test/resources/libraries/testlib4.libsonnet
new file mode 100644
index 0000000..d6fdda1
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/libraries/testlib4.libsonnet
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+{
+    sayBye(name)::
+        "Bye, " + name + " : TestLib4"
+}
\ No newline at end of file
diff --git a/components/camel-datasonnet/src/test/resources/log4j2.properties b/components/camel-datasonnet/src/test/resources/log4j2.properties
new file mode 100644
index 0000000..8f2e7bb
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/log4j2.properties
@@ -0,0 +1,32 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-datasonnet-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n
+logger.springframework.name = org.springframework
+logger.springframework.level = WARN
+logger.datasonnet.name=org.apache.camel.language.datasonnet
+logger.datasonnet.level=DEBUG
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file
diff --git a/components/camel-datasonnet/src/test/resources/namedImports.ds b/components/camel-datasonnet/src/test/resources/namedImports.ds
new file mode 100644
index 0000000..dbf0a4f
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/namedImports.ds
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+local testlib1 = import 'testlib.libsonnet';
+local testlib2 = import 'libraries/testlib2.libsonnet';
+local testlib3 = import 'testlib3.libsonnet';
+local testlib4 = import 'libraries/testlib4.libsonnet';
+
+{
+    "Lib1JAR": testlib1.sayHello("World"),
+    "Lib2JAR": testlib2.sayBye("World"),
+    "Lib3FS": testlib3.sayHello("World"),
+    "Lib4FS": testlib4.sayBye("World")
+}
\ No newline at end of file
diff --git a/components/camel-datasonnet/src/test/resources/namedImportsFS.ds b/components/camel-datasonnet/src/test/resources/namedImportsFS.ds
new file mode 100644
index 0000000..be16794
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/namedImportsFS.ds
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+local testlib3 = import 'testlib3.libsonnet';
+local testlib4 = import 'libraries/testlib4.libsonnet';
+
+{
+    "Lib3FS": testlib3.sayHello("World"),
+    "Lib4FS": testlib4.sayBye("World")
+}
\ No newline at end of file
diff --git a/components/camel-datasonnet/src/test/resources/namedImports_result.json b/components/camel-datasonnet/src/test/resources/namedImports_result.json
new file mode 100644
index 0000000..56fcae1
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/namedImports_result.json
@@ -0,0 +1 @@
+{"Lib1JAR":"Hello, World","Lib2JAR":"Bye, World","Lib3FS":"Hello, World : TestLib3","Lib4FS":"Bye, World : TestLib4"}
\ No newline at end of file
diff --git a/components/camel-datasonnet/src/test/resources/org/apache/camel/language.datasonnet/camel-context.xml b/components/camel-datasonnet/src/test/resources/org/apache/camel/language.datasonnet/camel-context.xml
new file mode 100644
index 0000000..0a9cac1
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/org/apache/camel/language.datasonnet/camel-context.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<!-- Configures the Camel Context-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+">
+
+    <camelContext id="main" xmlns="http://camel.apache.org/schema/spring">
+        <route id="basicTransform">
+            <from uri="direct:basicTransform"/>
+
+            <setProperty name="test">
+                <constant>HelloWorld</constant>
+            </setProperty>
+            <setProperty name="count">
+                <simple resultType="java.lang.Integer">1</simple>
+            </setProperty>
+            <setProperty name="isActive">
+                <simple resultType="java.lang.Boolean">true</simple>
+            </setProperty>
+            <setProperty name="1. Full Name">
+                <constant>DataSonnet</constant>
+            </setProperty>
+
+            <transform>
+                <datasonnet bodyMediaType="application/json" outputMediaType="application/json"
+                    resultType="java.lang.String">resource:classpath:simpleMapping.ds</datasonnet>
+            </transform>
+            <to uri="mock:direct:end"/>
+        </route>
+
+        <route id="transformXML">
+            <from uri="direct:transformXML"/>
+            <transform>
+                <datasonnet bodyMediaType="application/xml" outputMediaType="application/json"
+                            resultType="java.lang.String">resource:classpath:readXMLExtTest.ds</datasonnet>
+            </transform>
+            <to uri="mock:direct:end"/>
+        </route>
+
+        <route id="transformCSV">
+            <from uri="direct:transformCSV"/>
+            <transform>
+                <datasonnet bodyMediaType="application/csv" outputMediaType="application/json"
+                            resultType="java.lang.String">resource:classpath:readCSVTest.ds</datasonnet>
+            </transform>
+            <to uri="mock:direct:end"/>
+        </route>
+
+        <route id="datasonnetScript">
+            <from uri="direct:datasonnetScript"/>
+
+            <setProperty name="test">
+                <simple>HelloWorld</simple>
+            </setProperty>
+            <setProperty name="count">
+                <simple resultType="java.lang.Integer">1</simple>
+            </setProperty>
+            <setProperty name="isActive">
+                <simple resultType="java.lang.Boolean">true</simple>
+            </setProperty>
+            <setProperty name="1. Full Name">
+                <constant>DataSonnet</constant>
+            </setProperty>
+
+            <transform>
+                <datasonnet bodyMediaType="application/json" outputMediaType="application/json"
+                            resultType="java.lang.String"><![CDATA[
+{
+    "uid": payload.userId,
+    "uname": payload.name,
+    "testVar": cml.exchangeProperty('test'),
+    "isActive": cml.exchangeProperty('isActive'),
+    "count": cml.exchangeProperty('count'),
+    "fullName": cml.exchangeProperty('1. Full Name')
+}
+]]>
+                </datasonnet>
+            </transform>
+
+                    <to uri="mock:direct:end"/>
+                </route>
+
+                <route id="namedImports">
+            <from uri="direct:namedImports"/>
+            <transform>
+                <datasonnet bodyMediaType="application/json" outputMediaType="application/json"
+                            resultType="java.lang.String">resource:classpath:namedImports.ds</datasonnet>
+            </transform>
+            <to uri="mock:direct:end"/>
+        </route>
+
+        <route id="readJava">
+            <from uri="direct:readJava"/>
+            <transform>
+                <datasonnet bodyMediaType="application/x-java-object" outputMediaType="application/json"
+                            resultType="java.lang.String">resource:classpath:readJavaTest.ds</datasonnet>
+            </transform>
+            <to uri="mock:direct:end"/>
+        </route>
+
+        <route id="writeJava">
+            <from uri="direct:writeJava"/>
+            <transform>
+                <datasonnet bodyMediaType="application/json" outputMediaType="application/x-java-object"
+                    resultType="org.apache.camel.language.datasonnet.Gizmo">resource:classpath:writeJavaTest.ds</datasonnet>
+            </transform>
+            <to uri="mock:direct:end"/>
+        </route>
+
+        <route id="expressionLanguage">
+            <from uri="direct:expressionLanguage"/>
+
+            <setHeader name="CamelDatasonnetOutputMediaType">
+                <constant>text/plain</constant>
+            </setHeader>
+            <setHeader name="HelloHeader">
+                <language language="datasonnet">"Hello, " + payload</language>
+            </setHeader>
+
+            <setHeader name="CamelDatasonnetOutputMediaType">
+                <constant>application/json</constant>
+            </setHeader>
+            <setBody>
+                <language language="datasonnet">
+                    <![CDATA[
+                    {
+                        test: cml.header('HelloHeader')
+                    }
+                    ]]>
+                </language>
+            </setBody>
+
+            <to uri="mock:direct:end"/>
+        </route>
+
+        <route id="nullInput">
+            <from uri="direct:nullInput"/>
+            <setBody>
+                <datasonnet outputMediaType="application/json" resultType="java.lang.String">
+                    {
+                        test: "Hello, World"
+                    }
+                </datasonnet>
+            </setBody>
+
+            <to uri="mock:direct:end"/>
+        </route>
+
+    </camelContext>
+
+</beans>
diff --git a/components/camel-datasonnet/src/test/resources/payload.csv b/components/camel-datasonnet/src/test/resources/payload.csv
new file mode 100644
index 0000000..75676b4
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/payload.csv
@@ -0,0 +1,2 @@
+account,firstName,lastName
+123,Joe,Doe
diff --git a/components/camel-datasonnet/src/test/resources/payload.xml b/components/camel-datasonnet/src/test/resources/payload.xml
new file mode 100644
index 0000000..f65ee14
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/payload.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<test:root xmlns:test="http://www.modusbox.com">
+    <test:datasonnet version="1.0">Hello World</test:datasonnet>
+</test:root>
diff --git a/components/camel-datasonnet/src/test/resources/readCSVTest.ds b/components/camel-datasonnet/src/test/resources/readCSVTest.ds
new file mode 100644
index 0000000..4d908e3
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/readCSVTest.ds
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+{
+    account: payload[0]["account"]
+}
diff --git a/components/camel-datasonnet/src/test/resources/readJavaTest.ds b/components/camel-datasonnet/src/test/resources/readJavaTest.ds
new file mode 100644
index 0000000..9150608
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/readJavaTest.ds
@@ -0,0 +1,30 @@
+/** DataSonnet
+version=2.0
+input payload application/x-java-object; DateFormat=yyyy-MM-dd
+*/
+
+/*
+ * 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.
+ */
+
+{
+    "pojoName": payload.name,
+    "pojoQuantity": payload.quantity,
+    "pojoInStock": payload.inStock,
+    "pojoColors": payload.colors,
+    "pojoManufacturer": payload.manufacturer,
+    "pojoDate": payload.date
+}
diff --git a/components/camel-datasonnet/src/test/resources/readXMLExtTest.ds b/components/camel-datasonnet/src/test/resources/readXMLExtTest.ds
new file mode 100644
index 0000000..3b4a4de
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/readXMLExtTest.ds
@@ -0,0 +1,23 @@
+/** DataSonnet
+version=2.0
+input payload application/xml; NamespaceSeparator=%; TextValueKey=__text; AttributeCharacter=*
+*/
+
+/*
+ * 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.
+ */
+
+payload
diff --git a/components/camel-datasonnet/src/test/resources/readXMLExtTest.json b/components/camel-datasonnet/src/test/resources/readXMLExtTest.json
new file mode 100644
index 0000000..0e4ca56
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/readXMLExtTest.json
@@ -0,0 +1,13 @@
+{
+  "test%root": {
+    "*xmlns": {
+      "test": "http://www.modusbox.com"
+    },
+    "test%datasonnet": {
+      "*version": "1.0",
+      "__text": "Hello World",
+      "~": 1
+    },
+    "~": 1
+  }
+}
diff --git a/components/camel-datasonnet/src/test/resources/simpleMapping.ds b/components/camel-datasonnet/src/test/resources/simpleMapping.ds
new file mode 100644
index 0000000..a1faf25
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/simpleMapping.ds
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+{
+    "uid": payload.userId,
+    "uname": payload.name,
+    "testVar": cml.exchangeProperty('test'),
+    "isActive": cml.exchangeProperty('isActive'),
+    "count": cml.exchangeProperty('count'),
+    "fullName": cml.exchangeProperty('1. Full Name')
+}
\ No newline at end of file
diff --git a/components/camel-datasonnet/src/test/resources/simpleMapping_payload.json b/components/camel-datasonnet/src/test/resources/simpleMapping_payload.json
new file mode 100644
index 0000000..1ab6bf4
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/simpleMapping_payload.json
@@ -0,0 +1,4 @@
+{
+  "userId": 123,
+  "name": "JavaDuke"
+}
\ No newline at end of file
diff --git a/components/camel-datasonnet/src/test/resources/simpleMapping_result.json b/components/camel-datasonnet/src/test/resources/simpleMapping_result.json
new file mode 100644
index 0000000..e9489bd
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/simpleMapping_result.json
@@ -0,0 +1 @@
+{"count":1,"isActive":true,"testVar":"HelloWorld","uid":123,"uname":"JavaDuke","fullName": "DataSonnet"}
\ No newline at end of file
diff --git a/components/camel-datasonnet/src/test/resources/testlib3.libsonnet b/components/camel-datasonnet/src/test/resources/testlib3.libsonnet
new file mode 100644
index 0000000..38878b3
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/testlib3.libsonnet
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+{
+    sayHello(name)::
+        "Hello, " + name + " : TestLib3"
+}
\ No newline at end of file
diff --git a/components/camel-datasonnet/src/test/resources/writeJavaTest.ds b/components/camel-datasonnet/src/test/resources/writeJavaTest.ds
new file mode 100644
index 0000000..d1e98b7
--- /dev/null
+++ b/components/camel-datasonnet/src/test/resources/writeJavaTest.ds
@@ -0,0 +1,30 @@
+/** DataSonnet
+version=2.0
+output application/x-java-object; DateFormat=yyyy-MM-dd
+*/
+
+/*
+ * 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.
+ */
+
+{
+    "name": payload.pojoName,
+    "quantity": payload.pojoQuantity,
+    "inStock": payload.pojoInStock,
+    "colors": payload.pojoColors,
+    "manufacturer": payload.pojoManufacturer,
+    "date": payload.pojoDate
+}
diff --git a/components/pom.xml b/components/pom.xml
index 29770f7..b77caf8 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -175,6 +175,7 @@
         <module>camel-crypto</module>
         <module>camel-csimple-joor</module>
         <module>camel-csv</module>
+        <module>camel-datasonnet</module>
         <module>camel-debezium-common</module>
         <module>camel-debezium-mongodb</module>
         <module>camel-debezium-mysql</module>
diff --git a/core/camel-allcomponents/pom.xml b/core/camel-allcomponents/pom.xml
index 62183f5..dba0b8e 100644
--- a/core/camel-allcomponents/pom.xml
+++ b/core/camel-allcomponents/pom.xml
@@ -400,6 +400,10 @@
 		</dependency>
 		<dependency>
 			<groupId>org.apache.camel</groupId>
+			<artifactId>camel-datasonnet</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.camel</groupId>
 			<artifactId>camel-debezium-mongodb</artifactId>
 		</dependency>
 		<dependency>
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
index ec041bb..fd25daa 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/BuilderSupport.java
@@ -26,6 +26,7 @@ import org.apache.camel.Expression;
 import org.apache.camel.NoSuchEndpointException;
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.model.language.CSimpleExpression;
+import org.apache.camel.model.language.DatasonnetExpression;
 import org.apache.camel.model.language.ExchangePropertyExpression;
 import org.apache.camel.model.language.HeaderExpression;
 import org.apache.camel.model.language.JoorExpression;
@@ -150,6 +151,40 @@ public abstract class BuilderSupport {
     }
 
     /**
+     * Returns a Datasonnet expression value builder
+     */
+    public ValueBuilder datasonnet(String value) {
+        DatasonnetExpression exp = new DatasonnetExpression(value);
+        return new ValueBuilder(exp);
+    }
+
+    /**
+     * Returns a Datasonnet expression value builder
+     */
+    public ValueBuilder datasonnet(Expression value) {
+        DatasonnetExpression exp = new DatasonnetExpression(value);
+        return new ValueBuilder(exp);
+    }
+
+    /**
+     * Returns a Datasonnet expression value builder
+     */
+    public ValueBuilder datasonnet(String value, Class<?> resultType) {
+        DatasonnetExpression exp = new DatasonnetExpression(value);
+        exp.setResultType(resultType);
+        return new ValueBuilder(exp);
+    }
+
+    /**
+     * Returns a Datasonnet expression value builder
+     */
+    public ValueBuilder datasonnet(Expression value, Class<?> resultType) {
+        DatasonnetExpression exp = new DatasonnetExpression(value);
+        exp.setResultType(resultType);
+        return new ValueBuilder(exp);
+    }
+
+    /**
      * Returns a simple expression value builder
      */
     public SimpleBuilder simple(String value) {
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java
index 0dacb5e..b8bdbc5 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClause.java
@@ -344,6 +344,16 @@ public class ExpressionClause<T> implements Expression, Predicate {
     }
 
     /**
+     * Evaluates a <a href="http://camel.apache.org/datasonnet.html">Datasonnet expression</a>
+     *
+     * @param  text the expression to be evaluated
+     * @return      the builder to continue processing the DSL
+     */
+    public T datasonnet(String text) {
+        return delegate.datasonnet(text);
+    }
+
+    /**
      * Evaluates a <a href="http://camel.apache.org/jsonpath.html">Json Path expression</a>
      *
      * @param  text the expression to be evaluated
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
index b496134..2c84ab2 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
@@ -24,6 +24,7 @@ import org.apache.camel.Expression;
 import org.apache.camel.ExpressionFactory;
 import org.apache.camel.model.language.CSimpleExpression;
 import org.apache.camel.model.language.ConstantExpression;
+import org.apache.camel.model.language.DatasonnetExpression;
 import org.apache.camel.model.language.ExchangePropertyExpression;
 import org.apache.camel.model.language.GroovyExpression;
 import org.apache.camel.model.language.HeaderExpression;
@@ -326,6 +327,16 @@ public class ExpressionClauseSupport<T> implements ExpressionFactoryAware {
     }
 
     /**
+     * Evaluates a <a href="http://camel.apache.org/datasonnet.html">Datasonnet expression</a>
+     *
+     * @param  text the expression to be evaluated
+     * @return      the builder to continue processing the DSL
+     */
+    public T datasonnet(String text) {
+        return expression(new DatasonnetExpression(text));
+    }
+
+    /**
      * Evaluates a <a href="http://camel.apache.org/jsonpath.html">Json Path expression</a>
      *
      * @param  text the expression to be evaluated
@@ -803,7 +814,7 @@ public class ExpressionClauseSupport<T> implements ExpressionFactoryAware {
 
     /**
      * Evaluates an XML token expression on the message body with XML content
-     * 
+     *
      * @param  path       the xpath like path notation specifying the child nodes to tokenize
      * @param  mode       one of 'i', 'w', or 'u' to inject the namespaces to the token, to wrap the token with its
      *                    ancestor contet, or to unwrap to its element child
@@ -836,7 +847,7 @@ public class ExpressionClauseSupport<T> implements ExpressionFactoryAware {
     /**
      * Evaluates an <a href="http://camel.apache.org/xpath.html">XPath expression</a> on the supplied header name's
      * contents
-     * 
+     *
      * @param  text       the expression to be evaluated
      * @param  headerName the name of the header to apply the expression to
      * @return            the builder to continue processing the DSL
@@ -965,7 +976,7 @@ public class ExpressionClauseSupport<T> implements ExpressionFactoryAware {
 
     /**
      * Evaluates an <a href="http://camel.apache.org/xquery.html">XQuery expression</a>
-     * 
+     *
      * @param  text       the expression to be evaluated
      * @param  headerName the name of the header to apply the expression to
      * @return            the builder to continue processing the DSL
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/DatasonnetExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/DatasonnetExpression.java
new file mode 100644
index 0000000..a08d768
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/DatasonnetExpression.java
@@ -0,0 +1,111 @@
+/*
+ * 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.language;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+import org.apache.camel.Expression;
+import org.apache.camel.spi.Metadata;
+
+/**
+ * To use DataSonnet scripts in Camel expressions or predicates.
+ */
+@Metadata(firstVersion = "3.7.0", label = "language,script", title = "DataSonnet")
+@XmlRootElement(name = "datasonnet")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class DatasonnetExpression extends ExpressionDefinition {
+
+    @XmlAttribute(name = "bodyMediaType")
+    private String bodyMediaType;
+
+    @XmlAttribute(name = "outputMediaType")
+    private String outputMediaType;
+
+    @XmlAttribute(name = "resultType")
+    private String resultTypeName;
+
+    @XmlTransient
+    private Class<?> resultType;
+
+    public DatasonnetExpression() {
+    }
+
+    public DatasonnetExpression(String expression) {
+        super(expression);
+    }
+
+    public DatasonnetExpression(Expression expression) {
+        super(expression);
+    }
+
+    @Override
+    public String getLanguage() {
+        return "datasonnet";
+    }
+
+    public String getBodyMediaType() {
+        return bodyMediaType;
+    }
+
+    /**
+     * The String representation of the message's body MediaType
+     */
+    public void setBodyMediaType(String bodyMediaType) {
+        this.bodyMediaType = bodyMediaType;
+    }
+
+    public String getOutputMediaType() {
+        return outputMediaType;
+    }
+
+    /**
+     * The String representation of the MediaType to output
+     */
+    public void setOutputMediaType(String outputMediaType) {
+        this.outputMediaType = outputMediaType;
+    }
+
+    public Class<?> getResultType() {
+        return resultType;
+    }
+
+    /**
+     * Sets the class of the result type (type from output).
+     * <p/>
+     * The default result type is com.datasonnet.document.Document
+     */
+    public void setResultType(Class<?> resultType) {
+        this.resultType = resultType;
+    }
+
+    public String getResultTypeName() {
+        return resultTypeName;
+    }
+
+    /**
+     * Sets the class name of the result type (type from output)
+     * <p/>
+     * The default result type is com.datasonnet.document.Document
+     */
+    public void setResultTypeName(String resultTypeName) {
+        this.resultTypeName = resultTypeName;
+    }
+}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/DatasonnetExpressionReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/DatasonnetExpressionReifier.java
new file mode 100644
index 0000000..904ff16
--- /dev/null
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/DatasonnetExpressionReifier.java
@@ -0,0 +1,62 @@
+/*
+ * 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.reifier.language;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.Predicate;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.model.language.DatasonnetExpression;
+import org.apache.camel.model.language.ExpressionDefinition;
+import org.apache.camel.spi.Language;
+
+public class DatasonnetExpressionReifier extends ExpressionReifier<DatasonnetExpression> {
+
+    public DatasonnetExpressionReifier(CamelContext camelContext, ExpressionDefinition definition) {
+        super(camelContext, (DatasonnetExpression) definition);
+    }
+
+    @Override
+    protected void configureLanguage(Language language) {
+        if (definition.getResultType() == null && definition.getResultTypeName() != null) {
+            try {
+                Class<?> clazz = camelContext.getClassResolver().resolveMandatoryClass(definition.getResultTypeName());
+                definition.setResultType(clazz);
+            } catch (ClassNotFoundException e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
+            }
+        }
+    }
+
+    @Override
+    protected Expression createExpression(Language language, String exp) {
+        return language.createExpression(exp, createProperties());
+    }
+
+    @Override
+    protected Predicate createPredicate(Language language, String exp) {
+        return language.createPredicate(exp, createProperties());
+    }
+
+    private Object[] createProperties() {
+        Object[] properties = new Object[3];
+        properties[0] = definition.getResultType();
+        properties[1] = parseString(definition.getBodyMediaType());
+        properties[2] = parseString(definition.getOutputMediaType());
+        return properties;
+    }
+}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java
index 5d1c918..dd775a1 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/language/ExpressionReifier.java
@@ -29,6 +29,7 @@ import org.apache.camel.Predicate;
 import org.apache.camel.model.ExpressionSubElementDefinition;
 import org.apache.camel.model.language.CSimpleExpression;
 import org.apache.camel.model.language.ConstantExpression;
+import org.apache.camel.model.language.DatasonnetExpression;
 import org.apache.camel.model.language.ExchangePropertyExpression;
 import org.apache.camel.model.language.ExpressionDefinition;
 import org.apache.camel.model.language.GroovyExpression;
@@ -111,6 +112,8 @@ public class ExpressionReifier<T extends ExpressionDefinition> extends AbstractR
             return new ExpressionReifier<>(camelContext, definition);
         } else if (definition instanceof CSimpleExpression) {
             return new CSimpleExpressionReifier(camelContext, definition);
+        } else if (definition instanceof DatasonnetExpression) {
+            return new DatasonnetExpressionReifier(camelContext, definition);
         } else if (definition instanceof ExchangePropertyExpression) {
             return new ExpressionReifier<>(camelContext, definition);
         } else if (definition instanceof GroovyExpression) {
diff --git a/parent/pom.xml b/parent/pom.xml
index 8cc4d48..ce287b6 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -105,6 +105,7 @@
         <cglib-version>3.2.12</cglib-version>
         <chunk-templates-version>3.5.0</chunk-templates-version>
         <citrus-version>2.8.0</citrus-version>
+        <classgraph-version>4.8.52</classgraph-version>
         <cmis-version>1.1.0</cmis-version>
         <cometd-java-client-version>4.0.4</cometd-java-client-version>
         <cometd-java-server>4.0.4</cometd-java-server>
@@ -142,6 +143,7 @@
         <!-- cxf-xjc is not released as often -->
         <cxf-xjc-plugin-version>3.3.1</cxf-xjc-plugin-version>
         <cxf-xjc-utils-version>3.3.1</cxf-xjc-utils-version>
+        <datasonnet-mapper-version>2.1.1</datasonnet-mapper-version>
         <deltaspike-version>1.9.4</deltaspike-version>
         <depends-maven-plugin-version>1.4.0</depends-maven-plugin-version>
         <derby-version>10.14.2.0</derby-version>
@@ -480,6 +482,7 @@
         <rxjava2-version>2.2.20</rxjava2-version>
         <saxon-version>9.9.1-7</saxon-version>
         <scala-version>2.11.7</scala-version>
+        <scala-datasonnet-version>2.13.3</scala-datasonnet-version>
         <scribe-version>1.3.7</scribe-version>
         <servicemix-specs-version>2.9.0</servicemix-specs-version>
         <servlet-version-range>[3,4)</servlet-version-range>
@@ -1242,6 +1245,11 @@
 			</dependency>
 			<dependency>
 				<groupId>org.apache.camel</groupId>
+				<artifactId>camel-datasonnet</artifactId>
+				<version>${project.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.apache.camel</groupId>
 				<artifactId>camel-debezium-common</artifactId>
 				<version>${project.version}</version>
 			</dependency>