You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2022/11/08 14:37:03 UTC

[camel] branch CAMEL-18697/languages-java-dsl created (now de8677119af)

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

nfilotto pushed a change to branch CAMEL-18697/languages-java-dsl
in repository https://gitbox.apache.org/repos/asf/camel.git


      at de8677119af CAMEL-18697: camel-core - Propose a DSL for languages

This branch includes the following new commits:

     new de8677119af CAMEL-18697: camel-core - Propose a DSL for languages

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



[camel] 01/01: CAMEL-18697: camel-core - Propose a DSL for languages

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

nfilotto pushed a commit to branch CAMEL-18697/languages-java-dsl
in repository https://gitbox.apache.org/repos/asf/camel.git

commit de8677119afc69fe50d54cce3c89689c5cc78d86
Author: Nicolas Filotto <nf...@talend.com>
AuthorDate: Tue Nov 8 15:36:31 2022 +0100

    CAMEL-18697: camel-core - Propose a DSL for languages
---
 .../org/apache/camel/builder/BuilderSupport.java   |   7 +
 .../LanguageBuilder.java}                          |  31 ++--
 .../camel/builder/LanguageBuilderFactory.java      | 200 +++++++++++++++++++++
 .../org/apache/camel/builder/RouteBuilder.java     |  24 +++
 .../camel/model/dataformat/FhirDataformat.java     |   2 +-
 .../dataformat/UniVocityAbstractDataFormat.java    |   2 +-
 .../camel/model/language/CSimpleExpression.java    |  36 ++++
 .../camel/model/language/ConstantExpression.java   |  36 ++++
 .../camel/model/language/DatasonnetExpression.java |  61 +++++++
 .../model/language/ExchangePropertyExpression.java |  17 ++
 .../camel/model/language/ExpressionDefinition.java |  59 ++++++
 .../camel/model/language/GroovyExpression.java     |  17 ++
 .../camel/model/language/HeaderExpression.java     |  17 ++
 .../camel/model/language/Hl7TerserExpression.java  |  17 ++
 .../camel/model/language/JoorExpression.java       |  76 ++++++++
 .../apache/camel/model/language/JqExpression.java  |  61 +++++++
 .../camel/model/language/JsonPathExpression.java   | 146 +++++++++++++++
 .../camel/model/language/LanguageExpression.java   |  28 +++
 .../camel/model/language/MethodCallExpression.java |  91 ++++++++++
 .../camel/model/language/MvelExpression.java       |  17 ++
 .../model/language/NamespaceAwareExpression.java   |  36 ++++
 .../camel/model/language/OgnlExpression.java       |  17 ++
 .../camel/model/language/PythonExpression.java     |  17 ++
 .../apache/camel/model/language/RefExpression.java |  16 ++
 .../camel/model/language/SimpleExpression.java     |  36 ++++
 .../camel/model/language/SpELExpression.java       |  17 ++
 .../camel/model/language/TokenizerExpression.java  | 162 +++++++++++++++++
 .../model/language/XMLTokenizerExpression.java     |  61 +++++++
 .../camel/model/language/XPathExpression.java      | 196 ++++++++++++++++++++
 .../camel/model/language/XQueryExpression.java     |  74 ++++++++
 .../camel/impl/LanguageFluentSyntaxTest.java       |  80 +++++++++
 .../modules/ROOT/pages/dataformat-dsl.adoc         |   2 +-
 docs/user-manual/modules/ROOT/pages/index.adoc     |   1 +
 .../modules/ROOT/pages/language-dsl.adoc           |  69 +++++++
 34 files changed, 1705 insertions(+), 24 deletions(-)

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 1b8036a6bd9..9c0c99dbd8d 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
@@ -54,6 +54,13 @@ public abstract class BuilderSupport implements CamelContextAware {
     // Builder methods
     // -------------------------------------------------------------------------
 
+    /**
+     * Returns a value builder for the given expression
+     */
+    public ValueBuilder expression(Expression exp) {
+        return new ValueBuilder(exp);
+    }
+
     /**
      * Returns a value builder for the given header
      */
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/MvelExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilder.java
similarity index 55%
copy from core/camel-core-model/src/main/java/org/apache/camel/model/language/MvelExpression.java
copy to core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilder.java
index 0d1cb316723..69ac3f5e775 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/MvelExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilder.java
@@ -14,31 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.model.language;
+package org.apache.camel.builder;
 
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlRootElement;
-
-import org.apache.camel.spi.Metadata;
+import org.apache.camel.model.language.ExpressionDefinition;
 
 /**
- * Evaluates a MVEL template.
+ * {@code LanguageBuilder} defines the contract of an expression builder.
  */
-@Metadata(firstVersion = "2.0.0", label = "language,java", title = "MVEL")
-@XmlRootElement(name = "mvel")
-@XmlAccessorType(XmlAccessType.FIELD)
-public class MvelExpression extends ExpressionDefinition {
-
-    public MvelExpression() {
-    }
+public interface LanguageBuilder<T extends ExpressionDefinition> {
 
-    public MvelExpression(String expression) {
-        super(expression);
-    }
+    /**
+     * Ends the build of an expression.
+     *
+     * @return the expression fully built.
+     */
+    T end();
 
-    @Override
-    public String getLanguage() {
-        return "mvel";
-    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilderFactory.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilderFactory.java
new file mode 100644
index 00000000000..789d9d94f22
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/LanguageBuilderFactory.java
@@ -0,0 +1,200 @@
+/*
+ * 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.builder;
+
+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;
+import org.apache.camel.model.language.Hl7TerserExpression;
+import org.apache.camel.model.language.JoorExpression;
+import org.apache.camel.model.language.JqExpression;
+import org.apache.camel.model.language.JsonPathExpression;
+import org.apache.camel.model.language.LanguageExpression;
+import org.apache.camel.model.language.MethodCallExpression;
+import org.apache.camel.model.language.MvelExpression;
+import org.apache.camel.model.language.OgnlExpression;
+import org.apache.camel.model.language.PythonExpression;
+import org.apache.camel.model.language.RefExpression;
+import org.apache.camel.model.language.SimpleExpression;
+import org.apache.camel.model.language.SpELExpression;
+import org.apache.camel.model.language.TokenizerExpression;
+import org.apache.camel.model.language.XMLTokenizerExpression;
+import org.apache.camel.model.language.XPathExpression;
+import org.apache.camel.model.language.XQueryExpression;
+
+/**
+ * {@code LanguageBuilderFactory} is a factory class of builder of all supported languages.
+ */
+public final class LanguageBuilderFactory {
+
+    /**
+     * Uses the Constant language
+     */
+    public ConstantExpression.Builder constant() {
+        return new ConstantExpression.Builder();
+    }
+
+    /**
+     * Uses the CSimple language
+     */
+    public CSimpleExpression.Builder csimple() {
+        return new CSimpleExpression.Builder();
+    }
+
+    /**
+     * Uses the Datasonnet language
+     */
+    public DatasonnetExpression.Builder datasonnet() {
+        return new DatasonnetExpression.Builder();
+    }
+
+    /**
+     * Uses the ExchangeProperty language
+     */
+    public ExchangePropertyExpression.Builder exchangeProperty() {
+        return new ExchangePropertyExpression.Builder();
+    }
+
+    /**
+     * Uses the Groovy language
+     */
+    public GroovyExpression.Builder groovy() {
+        return new GroovyExpression.Builder();
+    }
+
+    /**
+     * Uses the Header language
+     */
+    public HeaderExpression.Builder header() {
+        return new HeaderExpression.Builder();
+    }
+
+    /**
+     * Uses the Hl7Terser language
+     */
+    public Hl7TerserExpression.Builder hl7terser() {
+        return new Hl7TerserExpression.Builder();
+    }
+
+    /**
+     * Uses the Joor language
+     */
+    public JoorExpression.Builder joor() {
+        return new JoorExpression.Builder();
+    }
+
+    /**
+     * Uses the Jq language
+     */
+    public JqExpression.Builder jq() {
+        return new JqExpression.Builder();
+    }
+
+    /**
+     * Uses the JsonPath language
+     */
+    public JsonPathExpression.Builder jsonpath() {
+        return new JsonPathExpression.Builder();
+    }
+
+    /**
+     * Uses a custom language
+     */
+    public LanguageExpression.Builder language() {
+        return new LanguageExpression.Builder();
+    }
+
+    /**
+     * Uses the MethodCall language
+     */
+    public MethodCallExpression.Builder bean() {
+        return new MethodCallExpression.Builder();
+    }
+
+    /**
+     * Uses the Mvel language
+     */
+    public MvelExpression.Builder mvel() {
+        return new MvelExpression.Builder();
+    }
+
+    /**
+     * Uses the Ognl language
+     */
+    public OgnlExpression.Builder ognl() {
+        return new OgnlExpression.Builder();
+    }
+
+    /**
+     * Uses the Python language
+     */
+    public PythonExpression.Builder python() {
+        return new PythonExpression.Builder();
+    }
+
+    /**
+     * Uses the Ref language
+     */
+    public RefExpression.Builder ref() {
+        return new RefExpression.Builder();
+    }
+
+    /**
+     * Uses the Simple language
+     */
+    public SimpleExpression.Builder simple() {
+        return new SimpleExpression.Builder();
+    }
+
+    /**
+     * Uses the SpEL language
+     */
+    public SpELExpression.Builder spel() {
+        return new SpELExpression.Builder();
+    }
+
+    /**
+     * Uses the Tokenizer language
+     */
+    public TokenizerExpression.Builder tokenize() {
+        return new TokenizerExpression.Builder();
+    }
+
+    /**
+     * Uses the XMLTokenizer language
+     */
+    public XMLTokenizerExpression.Builder xtokenize() {
+        return new XMLTokenizerExpression.Builder();
+    }
+
+    /**
+     * Uses the XPath language
+     */
+    public XPathExpression.Builder xpath() {
+        return new XPathExpression.Builder();
+    }
+
+    /**
+     * Uses the XQuery language
+     */
+    public XQueryExpression.Builder xquery() {
+        return new XQueryExpression.Builder();
+    }
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
index 99e43c34dd2..9aa0025548e 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/RouteBuilder.java
@@ -236,6 +236,8 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
      *             .end()
      *     )
      *     .to("file:data");
+     * }
+     * </pre>
      *
      * @return an entry point to the builder of all supported data formats.
      */
@@ -243,6 +245,28 @@ public abstract class RouteBuilder extends BuilderSupport implements RoutesBuild
         return new DataFormatBuilderFactory();
     }
 
+    /**
+     * A utility method allowing to build any language using a fluent syntax as shown in the next example:
+     *
+     * <pre>
+     * {@code
+     * from("file:data")
+     *     .split(
+     *         expression()
+     *             .tokenize()
+     *                 .token("\n")
+     *             .end()
+     *     )
+     *     .process("processEntry");
+     * }
+     * </pre>
+     *
+     * @return an entry point to the builder of all supported languages.
+     */
+    public LanguageBuilderFactory expression() {
+        return new LanguageBuilderFactory();
+    }
+
     /**
      * Configures the REST services
      *
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/FhirDataformat.java b/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/FhirDataformat.java
index 8f4a6e03f07..e317ab76cfe 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/FhirDataformat.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/FhirDataformat.java
@@ -395,7 +395,7 @@ public abstract class FhirDataformat extends DataFormatDefinition implements Con
     }
 
     /**
-     * {@code Builder} is a specific builder for {@link FhirDataformat}.
+     * {@code AbstractBuilder} is the base builder for {@link FhirDataformat}.
      */
     @XmlTransient
     @SuppressWarnings("unchecked")
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/UniVocityAbstractDataFormat.java b/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/UniVocityAbstractDataFormat.java
index e2e55bb6aa3..6648b669aac 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/UniVocityAbstractDataFormat.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/dataformat/UniVocityAbstractDataFormat.java
@@ -283,7 +283,7 @@ public abstract class UniVocityAbstractDataFormat extends DataFormatDefinition {
     }
 
     /**
-     * {@code Builder} is a specific builder for {@link UniVocityAbstractDataFormat}.
+     * {@code AbstractBuilder} is the base builder for {@link UniVocityAbstractDataFormat}.
      */
     @XmlTransient
     @SuppressWarnings("unchecked")
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/CSimpleExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/CSimpleExpression.java
index b19c936ef2e..24f03d4a572 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/CSimpleExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/CSimpleExpression.java
@@ -44,6 +44,12 @@ public class CSimpleExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private CSimpleExpression(Builder builder) {
+        super(builder);
+        this.resultTypeName = builder.resultTypeName;
+        this.resultType = builder.resultType;
+    }
+
     @Override
     public String getLanguage() {
         return "csimple";
@@ -71,4 +77,34 @@ public class CSimpleExpression extends ExpressionDefinition {
         this.resultTypeName = resultTypeName;
     }
 
+    /**
+     * {@code Builder} is a specific builder for {@link CSimpleExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, CSimpleExpression> {
+
+        private String resultTypeName;
+        private Class<?> resultType;
+
+        /**
+         * Sets the class of the result type (type from output)
+         */
+        public Builder resultType(Class<?> resultType) {
+            this.resultType = resultType;
+            return this;
+        }
+
+        /**
+         * Sets the class name of the result type (type from output)
+         */
+        public Builder resultTypeName(String resultTypeName) {
+            this.resultTypeName = resultTypeName;
+            return this;
+        }
+
+        @Override
+        public CSimpleExpression end() {
+            return new CSimpleExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/ConstantExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/ConstantExpression.java
index 5754d654988..26d12d82589 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/ConstantExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/ConstantExpression.java
@@ -44,6 +44,12 @@ public class ConstantExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private ConstantExpression(Builder builder) {
+        super(builder);
+        this.resultTypeName = builder.resultTypeName;
+        this.resultType = builder.resultType;
+    }
+
     @Override
     public String getLanguage() {
         return "constant";
@@ -71,4 +77,34 @@ public class ConstantExpression extends ExpressionDefinition {
         this.resultTypeName = resultTypeName;
     }
 
+    /**
+     * {@code Builder} is a specific builder for {@link ConstantExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, ConstantExpression> {
+
+        private String resultTypeName;
+        private Class<?> resultType;
+
+        /**
+         * Sets the class of the constant type
+         */
+        public Builder resultType(Class<?> resultType) {
+            this.resultType = resultType;
+            return this;
+        }
+
+        /**
+         * Sets the class name of the constant type
+         */
+        public Builder resultTypeName(String resultTypeName) {
+            this.resultTypeName = resultTypeName;
+            return this;
+        }
+
+        @Override
+        public ConstantExpression end() {
+            return new ConstantExpression(this);
+        }
+    }
 }
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
index 6a9616a01e7..d21368be89a 100644
--- 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
@@ -53,6 +53,14 @@ public class DatasonnetExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private DatasonnetExpression(Builder builder) {
+        super(builder);
+        this.bodyMediaType = builder.bodyMediaType;
+        this.outputMediaType = builder.outputMediaType;
+        this.resultTypeName = builder.resultTypeName;
+        this.resultType = builder.resultType;
+    }
+
     @Override
     public String getLanguage() {
         return "datasonnet";
@@ -105,4 +113,57 @@ public class DatasonnetExpression extends ExpressionDefinition {
     public void setResultTypeName(String resultTypeName) {
         this.resultTypeName = resultTypeName;
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link DatasonnetExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, DatasonnetExpression> {
+
+        private String bodyMediaType;
+        private String outputMediaType;
+        private String resultTypeName;
+        private Class<?> resultType;
+
+        /**
+         * The String representation of the message's body MediaType
+         */
+        public Builder bodyMediaType(String bodyMediaType) {
+            this.bodyMediaType = bodyMediaType;
+            return this;
+        }
+
+        /**
+         * The String representation of the MediaType to output
+         */
+        public Builder outputMediaType(String outputMediaType) {
+            this.outputMediaType = outputMediaType;
+            return this;
+        }
+
+        /**
+         * Sets the class of the result type (type from output).
+         * <p/>
+         * The default result type is com.datasonnet.document.Document
+         */
+        public Builder resultType(Class<?> resultType) {
+            this.resultType = resultType;
+            return this;
+        }
+
+        /**
+         * Sets the class name of the result type (type from output)
+         * <p/>
+         * The default result type is com.datasonnet.document.Document
+         */
+        public Builder resultTypeName(String resultTypeName) {
+            this.resultTypeName = resultTypeName;
+            return this;
+        }
+
+        @Override
+        public DatasonnetExpression end() {
+            return new DatasonnetExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/ExchangePropertyExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/ExchangePropertyExpression.java
index 95d69d9955f..5c3b2e62918 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/ExchangePropertyExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/ExchangePropertyExpression.java
@@ -19,6 +19,7 @@ package org.apache.camel.model.language;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.spi.Metadata;
 
@@ -37,8 +38,24 @@ public class ExchangePropertyExpression extends ExpressionDefinition {
         super(name);
     }
 
+    private ExchangePropertyExpression(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public String getLanguage() {
         return "exchangeProperty";
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link ExchangePropertyExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, ExchangePropertyExpression> {
+
+        @Override
+        public ExchangePropertyExpression end() {
+            return new ExchangePropertyExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/ExpressionDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/ExpressionDefinition.java
index e755c76b073..b3274b000a1 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/ExpressionDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/ExpressionDefinition.java
@@ -34,6 +34,7 @@ import org.apache.camel.Expression;
 import org.apache.camel.ExpressionFactory;
 import org.apache.camel.Predicate;
 import org.apache.camel.PredicateFactory;
+import org.apache.camel.builder.LanguageBuilder;
 import org.apache.camel.model.HasExpressionType;
 import org.apache.camel.model.ModelCamelContext;
 import org.apache.camel.spi.ExpressionFactoryAware;
@@ -85,6 +86,13 @@ public class ExpressionDefinition
         this.expressionValue = expression;
     }
 
+    protected ExpressionDefinition(AbstractBuilder<?, ?> builder) {
+        this.id = builder.id;
+        this.expression = builder.expression;
+        this.trim = builder.trim;
+        this.predicate = builder.predicate;
+    }
+
     public static String getLabel(List<ExpressionDefinition> expressions) {
         StringJoiner buffer = new StringJoiner(", ");
         for (ExpressionDefinition expression : expressions) {
@@ -260,4 +268,55 @@ public class ExpressionDefinition
             predicate = createPredicate(context);
         }
     }
+
+    /**
+     * {@code AbstractBuilder} is the base expression builder.
+     */
+    @XmlTransient
+    @SuppressWarnings("unchecked")
+    abstract static class AbstractBuilder<T extends AbstractBuilder<T, E>, E extends ExpressionDefinition>
+            implements LanguageBuilder<E> {
+
+        private String id;
+        private String expression;
+        private String trim;
+        private Predicate predicate;
+
+        /**
+         * Sets the id of this node
+         */
+        public T id(String id) {
+            this.id = id;
+            return (T) this;
+        }
+
+        /**
+         * Whether to trim the value to remove leading and trailing whitespaces and line breaks
+         */
+        public T trim(String trim) {
+            this.trim = trim;
+            return (T) this;
+        }
+
+        /**
+         * Whether to trim the value to remove leading and trailing whitespaces and line breaks
+         */
+        public T trim(boolean trim) {
+            this.trim = Boolean.toString(trim);
+            return (T) this;
+        }
+
+        /**
+         * The expression value in your chosen language syntax
+         */
+        public T expression(String expression) {
+            this.expression = expression;
+            return (T) this;
+        }
+
+        public T predicate(Predicate predicate) {
+            this.predicate = predicate;
+            return (T) this;
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/GroovyExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/GroovyExpression.java
index 5a42f35c938..84b6606fd77 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/GroovyExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/GroovyExpression.java
@@ -19,6 +19,7 @@ package org.apache.camel.model.language;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.spi.Metadata;
 
@@ -37,8 +38,24 @@ public class GroovyExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private GroovyExpression(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public String getLanguage() {
         return "groovy";
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link GroovyExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, GroovyExpression> {
+
+        @Override
+        public GroovyExpression end() {
+            return new GroovyExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/HeaderExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/HeaderExpression.java
index 4e7937edc88..89fb7dfa155 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/HeaderExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/HeaderExpression.java
@@ -19,6 +19,7 @@ package org.apache.camel.model.language;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.spi.Metadata;
 
@@ -37,8 +38,24 @@ public class HeaderExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private HeaderExpression(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public String getLanguage() {
         return "header";
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link HeaderExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, HeaderExpression> {
+
+        @Override
+        public HeaderExpression end() {
+            return new HeaderExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/Hl7TerserExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/Hl7TerserExpression.java
index dd00d0daa4d..a65cb4457ce 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/Hl7TerserExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/Hl7TerserExpression.java
@@ -19,6 +19,7 @@ package org.apache.camel.model.language;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.spi.Metadata;
 
@@ -37,8 +38,24 @@ public class Hl7TerserExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private Hl7TerserExpression(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public String getLanguage() {
         return "hl7terser";
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link Hl7TerserExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, Hl7TerserExpression> {
+
+        @Override
+        public Hl7TerserExpression end() {
+            return new Hl7TerserExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/JoorExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/JoorExpression.java
index fba17d4dff8..12d8e6e9466 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/JoorExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/JoorExpression.java
@@ -50,6 +50,14 @@ public class JoorExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private JoorExpression(Builder builder) {
+        super(builder);
+        this.preCompile = builder.preCompile;
+        this.singleQuotes = builder.singleQuotes;
+        this.resultTypeName = builder.resultTypeName;
+        this.resultType = builder.resultType;
+    }
+
     @Override
     public String getLanguage() {
         return "joor";
@@ -101,4 +109,72 @@ public class JoorExpression extends ExpressionDefinition {
         this.resultTypeName = resultTypeName;
     }
 
+    /**
+     * {@code Builder} is a specific builder for {@link JoorExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, JoorExpression> {
+
+        private String preCompile;
+        private String singleQuotes;
+        private String resultTypeName;
+        private Class<?> resultType;
+
+        /**
+         * Whether the expression should be pre compiled once during initialization phase. If this is turned off, then
+         * the expression is reloaded and compiled on each evaluation.
+         */
+        public Builder preCompile(String preCompile) {
+            this.preCompile = preCompile;
+            return this;
+        }
+
+        /**
+         * Whether the expression should be pre compiled once during initialization phase. If this is turned off, then
+         * the expression is reloaded and compiled on each evaluation.
+         */
+        public Builder preCompile(boolean preCompile) {
+            this.preCompile = Boolean.toString(preCompile);
+            return this;
+        }
+
+        /**
+         * Whether single quotes can be used as replacement for double quotes. This is convenient when you need to work
+         * with strings inside strings.
+         */
+        public Builder singleQuotes(String singleQuotes) {
+            this.singleQuotes = singleQuotes;
+            return this;
+        }
+
+        /**
+         * Whether single quotes can be used as replacement for double quotes. This is convenient when you need to work
+         * with strings inside strings.
+         */
+        public Builder singleQuotes(boolean singleQuotes) {
+            this.singleQuotes = Boolean.toString(singleQuotes);
+            return this;
+        }
+
+        /**
+         * Sets the class of the result type (type from output)
+         */
+        public Builder resultType(Class<?> resultType) {
+            this.resultType = resultType;
+            return this;
+        }
+
+        /**
+         * Sets the class name of the result type (type from output)
+         */
+        public Builder resultTypeName(String resultTypeName) {
+            this.resultTypeName = resultTypeName;
+            return this;
+        }
+
+        @Override
+        public JoorExpression end() {
+            return new JoorExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/JqExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/JqExpression.java
index ee8a1b95bcf..13db5d36f12 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/JqExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/JqExpression.java
@@ -48,6 +48,14 @@ public class JqExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private JqExpression(Builder builder) {
+        super(builder);
+        this.resultTypeName = builder.resultTypeName;
+        this.resultType = builder.resultType;
+        this.headerName = builder.headerName;
+        this.propertyName = builder.propertyName;
+    }
+
     @Override
     public String getLanguage() {
         return "jq";
@@ -100,4 +108,57 @@ public class JqExpression extends ExpressionDefinition {
     public void setPropertyName(String propertyName) {
         this.propertyName = propertyName;
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link JqExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, JqExpression> {
+
+        private String resultTypeName;
+        private Class<?> resultType;
+        private String headerName;
+        private String propertyName;
+
+        /**
+         * Sets the class name of the result type (type from output)
+         */
+        public Builder resultType(Class<?> resultType) {
+            this.resultType = resultType;
+            return this;
+        }
+
+        /**
+         * Sets the class of the result type (type from output)
+         */
+        public Builder resultTypeName(String resultTypeName) {
+            this.resultTypeName = resultTypeName;
+            return this;
+        }
+
+        /**
+         * Name of header to use as input, instead of the message body
+         * </p>
+         * It has as higher precedent than the propertyName if both are set.
+         */
+        public Builder headerName(String headerName) {
+            this.headerName = headerName;
+            return this;
+        }
+
+        /**
+         * Name of property to use as input, instead of the message body.
+         * </p>
+         * It has a lower precedent than the headerName if both are set.
+         */
+        public Builder propertyName(String propertyName) {
+            this.propertyName = propertyName;
+            return this;
+        }
+
+        @Override
+        public JqExpression end() {
+            return new JqExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/JsonPathExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/JsonPathExpression.java
index 5a675b3b455..540759c11b5 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/JsonPathExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/JsonPathExpression.java
@@ -66,6 +66,19 @@ public class JsonPathExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private JsonPathExpression(Builder builder) {
+        super(builder);
+        this.resultTypeName = builder.resultTypeName;
+        this.resultType = builder.resultType;
+        this.suppressExceptions = builder.suppressExceptions;
+        this.allowSimple = builder.allowSimple;
+        this.allowEasyPredicate = builder.allowEasyPredicate;
+        this.writeAsString = builder.writeAsString;
+        this.unpackArray = builder.unpackArray;
+        this.headerName = builder.headerName;
+        this.option = builder.option;
+    }
+
     public String getResultTypeName() {
         return resultTypeName;
     }
@@ -170,4 +183,137 @@ public class JsonPathExpression extends ExpressionDefinition {
         return "jsonpath";
     }
 
+    /**
+     * {@code Builder} is a specific builder for {@link JsonPathExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, JsonPathExpression> {
+
+        private String resultTypeName;
+        private Class<?> resultType;
+        private String suppressExceptions;
+        private String allowSimple;
+        private String allowEasyPredicate;
+        private String writeAsString;
+        private String unpackArray;
+        private String headerName;
+        private String option;
+
+        /**
+         * Sets the class of the result type (type from output)
+         */
+        public Builder resultType(Class<?> resultType) {
+            this.resultType = resultType;
+            return this;
+        }
+
+        /**
+         * Sets the class name of the result type (type from output)
+         */
+        public Builder resultTypeName(String resultTypeName) {
+            this.resultTypeName = resultTypeName;
+            return this;
+        }
+
+        /**
+         * Whether to suppress exceptions such as PathNotFoundException.
+         */
+        public Builder suppressExceptions(String suppressExceptions) {
+            this.suppressExceptions = suppressExceptions;
+            return this;
+        }
+
+        /**
+         * Whether to suppress exceptions such as PathNotFoundException.
+         */
+        public Builder suppressExceptions(boolean suppressExceptions) {
+            this.suppressExceptions = Boolean.toString(suppressExceptions);
+            return this;
+        }
+
+        /**
+         * Whether to allow in inlined Simple exceptions in the JSONPath expression
+         */
+        public Builder allowSimple(String allowSimple) {
+            this.allowSimple = allowSimple;
+            return this;
+        }
+
+        /**
+         * Whether to allow in inlined Simple exceptions in the JSONPath expression
+         */
+        public Builder allowSimple(boolean allowSimple) {
+            this.allowSimple = Boolean.toString(allowSimple);
+            return this;
+        }
+
+        /**
+         * Whether to allow using the easy predicate parser to pre-parse predicates.
+         */
+        public Builder allowEasyPredicate(String allowEasyPredicate) {
+            this.allowEasyPredicate = allowEasyPredicate;
+            return this;
+        }
+
+        /**
+         * Whether to allow using the easy predicate parser to pre-parse predicates.
+         */
+        public Builder allowEasyPredicate(boolean allowEasyPredicate) {
+            this.allowEasyPredicate = Boolean.toString(allowEasyPredicate);
+            return this;
+        }
+
+        /**
+         * Whether to write the output of each row/element as a JSON String value instead of a Map/POJO value.
+         */
+        public Builder writeAsString(String writeAsString) {
+            this.writeAsString = writeAsString;
+            return this;
+        }
+
+        /**
+         * Whether to write the output of each row/element as a JSON String value instead of a Map/POJO value.
+         */
+        public Builder writeAsString(boolean writeAsString) {
+            this.writeAsString = Boolean.toString(writeAsString);
+            return this;
+        }
+
+        /**
+         * Whether to unpack a single element json-array into an object.
+         */
+        public Builder unpackArray(String unpackArray) {
+            this.unpackArray = unpackArray;
+            return this;
+        }
+
+        /**
+         * Whether to unpack a single element json-array into an object.
+         */
+        public Builder unpackArray(boolean unpackArray) {
+            this.unpackArray = Boolean.toString(unpackArray);
+            return this;
+        }
+
+        /**
+         * Name of header to use as input, instead of the message body
+         */
+        public Builder headerName(String headerName) {
+            this.headerName = headerName;
+            return this;
+        }
+
+        /**
+         * To configure additional options on JSONPath. Multiple values can be separated by comma.
+         */
+        public Builder option(String option) {
+            this.option = option;
+            return this;
+        }
+
+        @Override
+        public JsonPathExpression end() {
+            return new JsonPathExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/LanguageExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/LanguageExpression.java
index 32c8df3071a..f638676aa7b 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/LanguageExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/LanguageExpression.java
@@ -20,6 +20,7 @@ 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.spi.Metadata;
 
@@ -42,6 +43,11 @@ public class LanguageExpression extends ExpressionDefinition {
         setExpression(expression);
     }
 
+    private LanguageExpression(Builder builder) {
+        super(builder);
+        this.language = builder.language;
+    }
+
     @Override
     public String getLanguage() {
         return language;
@@ -53,4 +59,26 @@ public class LanguageExpression extends ExpressionDefinition {
     public void setLanguage(String language) {
         this.language = language;
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link LanguageExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, LanguageExpression> {
+
+        private String language;
+
+        /**
+         * The name of the language to use
+         */
+        public Builder language(String language) {
+            this.language = language;
+            return this;
+        }
+
+        @Override
+        public LanguageExpression end() {
+            return new LanguageExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/MethodCallExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/MethodCallExpression.java
index 7cbcb05ef9b..cebce5ab291 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/MethodCallExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/MethodCallExpression.java
@@ -88,6 +88,16 @@ public class MethodCallExpression extends ExpressionDefinition {
         setMethod(method);
     }
 
+    private MethodCallExpression(Builder builder) {
+        super(builder);
+        this.beanType = builder.beanType;
+        this.instance = builder.instance;
+        this.ref = builder.ref;
+        this.method = builder.method;
+        this.beanTypeName = builder.beanTypeName;
+        this.scope = builder.scope;
+    }
+
     @Override
     public String getLanguage() {
         return "bean";
@@ -192,4 +202,85 @@ public class MethodCallExpression extends ExpressionDefinition {
         return "bean[" + name + (method != null ? " method:" + method : "") + "]";
     }
 
+    /**
+     * {@code Builder} is a specific builder for {@link MethodCallExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, MethodCallExpression> {
+
+        private Class<?> beanType;
+        private Object instance;
+        private String ref;
+        private String method;
+        private String beanTypeName;
+        private String scope;
+
+        /**
+         * Name of method to call
+         */
+        public Builder method(String method) {
+            this.method = method;
+            return this;
+        }
+
+        /**
+         * Reference to an existing bean (bean id) to lookup in the registry
+         */
+        public Builder ref(String ref) {
+            this.ref = ref;
+            return this;
+        }
+
+        public Builder instance(Object instance) {
+            // people may by mistake pass in a class type as the instance
+            if (instance instanceof Class) {
+                this.beanType = (Class<?>) instance;
+                this.instance = null;
+            } else {
+                this.beanType = null;
+                this.instance = instance;
+            }
+            return this;
+        }
+
+        public Builder beanType(Class<?> beanType) {
+            this.beanType = beanType;
+            this.instance = null;
+            return this;
+        }
+
+        /**
+         * Class name (fully qualified) of the bean to use
+         *
+         * Will lookup in registry and if there is a single instance of the same type, then the existing bean is used,
+         * otherwise a new bean is created (requires a default no-arg constructor).
+         */
+        public Builder beanTypeName(String beanTypeName) {
+            this.beanTypeName = beanTypeName;
+            return this;
+        }
+
+        /**
+         * Scope of bean.
+         *
+         * When using singleton scope (default) the bean is created or looked up only once and reused for the lifetime
+         * of the endpoint. The bean should be thread-safe in case concurrent threads is calling the bean at the same
+         * time. When using request scope the bean is created or looked up once per request (exchange). This can be used
+         * if you want to store state on a bean while processing a request and you want to call the same bean instance
+         * multiple times while processing the request. The bean does not have to be thread-safe as the instance is only
+         * called from the same request. When using prototype scope, then the bean will be looked up or created per
+         * call. However in case of lookup then this is delegated to the bean registry such as Spring or CDI (if in
+         * use), which depends on their configuration can act as either singleton or prototype scope. So when using
+         * prototype scope then this depends on the bean registry implementation.
+         */
+        public Builder scope(String scope) {
+            this.scope = scope;
+            return this;
+        }
+
+        @Override
+        public MethodCallExpression end() {
+            return new MethodCallExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/MvelExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/MvelExpression.java
index 0d1cb316723..66aa146e3cc 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/MvelExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/MvelExpression.java
@@ -19,6 +19,7 @@ package org.apache.camel.model.language;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.spi.Metadata;
 
@@ -37,8 +38,24 @@ public class MvelExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private MvelExpression(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public String getLanguage() {
         return "mvel";
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link MvelExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, MvelExpression> {
+
+        @Override
+        public MvelExpression end() {
+            return new MvelExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/NamespaceAwareExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/NamespaceAwareExpression.java
index c6fb6399886..2e663fa63e4 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/NamespaceAwareExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/NamespaceAwareExpression.java
@@ -49,6 +49,12 @@ public abstract class NamespaceAwareExpression extends ExpressionDefinition impl
         super(expression);
     }
 
+    protected NamespaceAwareExpression(AbstractNamespaceAwareBuilder<?, ?> builder) {
+        super(builder);
+        this.namespace = builder.namespace;
+        this.namespaces = builder.namespaces;
+    }
+
     @Override
     public Map<String, String> getNamespaces() {
         return getNamespaceAsMap();
@@ -87,4 +93,34 @@ public abstract class NamespaceAwareExpression extends ExpressionDefinition impl
         return namespaces;
     }
 
+    /**
+     * {@code NamespaceAwareBuilder} is the base namespace aware expression builder.
+     */
+    @XmlTransient
+    @SuppressWarnings("unchecked")
+    abstract static class AbstractNamespaceAwareBuilder<
+            T extends AbstractNamespaceAwareBuilder<T, E>, E extends ExpressionDefinition>
+            extends AbstractBuilder<T, E> {
+
+        private List<PropertyDefinition> namespace;
+        private Map<String, String> namespaces;
+
+        /**
+         * Injects the XML Namespaces of prefix -> uri mappings
+         *
+         * @param namespaces the XML namespaces with the key of prefixes and the value the URIs
+         */
+        public T namespaces(Map<String, String> namespaces) {
+            this.namespaces = namespaces;
+            return (T) this;
+        }
+
+        /**
+         * Injects the XML Namespaces of prefix -> uri mappings
+         */
+        public T namespace(List<PropertyDefinition> namespace) {
+            this.namespace = namespace;
+            return (T) this;
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/OgnlExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/OgnlExpression.java
index fe6b09d0a97..bddede57951 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/OgnlExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/OgnlExpression.java
@@ -19,6 +19,7 @@ package org.apache.camel.model.language;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.spi.Metadata;
 
@@ -37,8 +38,24 @@ public class OgnlExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private OgnlExpression(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public String getLanguage() {
         return "ognl";
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link OgnlExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, OgnlExpression> {
+
+        @Override
+        public OgnlExpression end() {
+            return new OgnlExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/PythonExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/PythonExpression.java
index 90d7404b4f8..ccdacd7cb37 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/PythonExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/PythonExpression.java
@@ -19,6 +19,7 @@ package org.apache.camel.model.language;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.spi.Metadata;
 
@@ -37,8 +38,24 @@ public class PythonExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private PythonExpression(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public String getLanguage() {
         return "python";
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link PythonExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, PythonExpression> {
+
+        @Override
+        public PythonExpression end() {
+            return new PythonExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/RefExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/RefExpression.java
index 2f61a297a01..8f575ce92d9 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/RefExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/RefExpression.java
@@ -19,6 +19,7 @@ package org.apache.camel.model.language;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.spi.Metadata;
 
@@ -37,9 +38,24 @@ public class RefExpression extends ExpressionDefinition {
         super(ref);
     }
 
+    private RefExpression(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public String getLanguage() {
         return "ref";
     }
 
+    /**
+     * {@code Builder} is a specific builder for {@link RefExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, RefExpression> {
+
+        @Override
+        public RefExpression end() {
+            return new RefExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/SimpleExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/SimpleExpression.java
index 5760d224327..89408037d69 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/SimpleExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/SimpleExpression.java
@@ -49,6 +49,12 @@ public class SimpleExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private SimpleExpression(Builder builder) {
+        super(builder);
+        this.resultTypeName = builder.resultTypeName;
+        this.resultType = builder.resultType;
+    }
+
     @Override
     public String getLanguage() {
         return "simple";
@@ -76,4 +82,34 @@ public class SimpleExpression extends ExpressionDefinition {
         this.resultTypeName = resultTypeName;
     }
 
+    /**
+     * {@code Builder} is a specific builder for {@link SimpleExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, SimpleExpression> {
+
+        private String resultTypeName;
+        private Class<?> resultType;
+
+        /**
+         * Sets the class of the result type (type from output)
+         */
+        public Builder resultType(Class<?> resultType) {
+            this.resultType = resultType;
+            return this;
+        }
+
+        /**
+         * Sets the class name of the result type (type from output)
+         */
+        public Builder resultTypeName(String resultTypeName) {
+            this.resultTypeName = resultTypeName;
+            return this;
+        }
+
+        @Override
+        public SimpleExpression end() {
+            return new SimpleExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/SpELExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/SpELExpression.java
index e8bcdf93e87..2dac641e99d 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/SpELExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/SpELExpression.java
@@ -19,6 +19,7 @@ package org.apache.camel.model.language;
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
 
 import org.apache.camel.spi.Metadata;
 
@@ -37,8 +38,24 @@ public class SpELExpression extends ExpressionDefinition {
         super(expression);
     }
 
+    private SpELExpression(Builder builder) {
+        super(builder);
+    }
+
     @Override
     public String getLanguage() {
         return "spel";
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link SpELExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, SpELExpression> {
+
+        @Override
+        public SpELExpression end() {
+            return new SpELExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/TokenizerExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
index e74dacd7265..3cea1fe10db 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
@@ -20,6 +20,7 @@ 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.spi.Metadata;
 
@@ -67,6 +68,20 @@ public class TokenizerExpression extends ExpressionDefinition {
         this.token = token;
     }
 
+    private TokenizerExpression(Builder builder) {
+        super(builder);
+        this.token = builder.token;
+        this.endToken = builder.endToken;
+        this.inheritNamespaceTagName = builder.inheritNamespaceTagName;
+        this.headerName = builder.headerName;
+        this.regex = builder.regex;
+        this.xml = builder.xml;
+        this.includeTokens = builder.includeTokens;
+        this.group = builder.group;
+        this.groupDelimiter = builder.groupDelimiter;
+        this.skipFirst = builder.skipFirst;
+    }
+
     @Override
     public String getLanguage() {
         return "tokenize";
@@ -198,4 +213,151 @@ public class TokenizerExpression extends ExpressionDefinition {
             return "tokenize{" + (headerName != null ? "header: " + headerName : "body()") + " using token: " + token + "}";
         }
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link TokenizerExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractBuilder<Builder, TokenizerExpression> {
+
+        private String token;
+        private String endToken;
+        private String inheritNamespaceTagName;
+        private String headerName;
+        private String regex;
+        private String xml;
+        private String includeTokens;
+        private String group;
+        private String groupDelimiter;
+        private String skipFirst;
+
+        /**
+         * The (start) token to use as tokenizer, for example you can use the new line token. You can use simple
+         * language as the token to support dynamic tokens.
+         */
+        public Builder token(String token) {
+            this.token = token;
+            return this;
+        }
+
+        /**
+         * The end token to use as tokenizer if using start/end token pairs. You can use simple language as the token to
+         * support dynamic tokens.
+         */
+        public Builder endToken(String endToken) {
+            this.endToken = endToken;
+            return this;
+        }
+
+        /**
+         * To inherit namespaces from a root/parent tag name when using XML You can use simple language as the tag name
+         * to support dynamic names.
+         */
+        public Builder inheritNamespaceTagName(String inheritNamespaceTagName) {
+            this.inheritNamespaceTagName = inheritNamespaceTagName;
+            return this;
+        }
+
+        /**
+         * Name of header to tokenize instead of using the message body.
+         */
+        public Builder headerName(String headerName) {
+            this.headerName = headerName;
+            return this;
+        }
+
+        /**
+         * If the token is a regular expression pattern.
+         * <p/>
+         * The default value is false
+         */
+        public Builder regex(String regex) {
+            this.regex = regex;
+            return this;
+        }
+
+        /**
+         * If the token is a regular expression pattern.
+         * <p/>
+         * The default value is false
+         */
+        public Builder regex(boolean regex) {
+            this.regex = Boolean.toString(regex);
+            return this;
+        }
+
+        /**
+         * Whether the input is XML messages. This option must be set to true if working with XML payloads.
+         */
+        public Builder xml(String xml) {
+            this.xml = xml;
+            return this;
+        }
+
+        /**
+         * Whether the input is XML messages. This option must be set to true if working with XML payloads.
+         */
+        public Builder xml(boolean xml) {
+            this.xml = Boolean.toString(xml);
+            return this;
+        }
+
+        /**
+         * Whether to include the tokens in the parts when using pairs
+         * <p/>
+         * The default value is false
+         */
+        public Builder includeTokens(String includeTokens) {
+            this.includeTokens = includeTokens;
+            return this;
+        }
+
+        /**
+         * Whether to include the tokens in the parts when using pairs
+         * <p/>
+         * The default value is false
+         */
+        public Builder includeTokens(boolean includeTokens) {
+            this.includeTokens = Boolean.toString(includeTokens);
+            return this;
+        }
+
+        /**
+         * To group N parts together, for example to split big files into chunks of 1000 lines. You can use simple
+         * language as the group to support dynamic group sizes.
+         */
+        public Builder group(String group) {
+            this.group = group;
+            return this;
+        }
+
+        /**
+         * Sets the delimiter to use when grouping. If this has not been set then token will be used as the delimiter.
+         */
+        public Builder groupDelimiter(String groupDelimiter) {
+            this.groupDelimiter = groupDelimiter;
+            return this;
+        }
+
+        /**
+         * To skip the very first element
+         */
+        public Builder skipFirst(String skipFirst) {
+            this.skipFirst = skipFirst;
+            return this;
+        }
+
+        /**
+         * To skip the very first element
+         */
+        public Builder skipFirst(boolean skipFirst) {
+            this.skipFirst = Boolean.toString(skipFirst);
+            return this;
+        }
+
+        @Override
+        public TokenizerExpression end() {
+            return new TokenizerExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/XMLTokenizerExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/XMLTokenizerExpression.java
index ac588b10f96..487cc288bfd 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/XMLTokenizerExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/XMLTokenizerExpression.java
@@ -20,6 +20,7 @@ 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.spi.Metadata;
 
@@ -48,6 +49,13 @@ public class XMLTokenizerExpression extends NamespaceAwareExpression {
         super(expression);
     }
 
+    private XMLTokenizerExpression(Builder builder) {
+        super(builder);
+        this.headerName = builder.headerName;
+        this.mode = builder.mode;
+        this.group = builder.group;
+    }
+
     @Override
     public String getLanguage() {
         return "xtokenize";
@@ -92,4 +100,57 @@ public class XMLTokenizerExpression extends NamespaceAwareExpression {
         this.group = group;
     }
 
+    /**
+     * {@code Builder} is a specific builder for {@link XMLTokenizerExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractNamespaceAwareBuilder<Builder, XMLTokenizerExpression> {
+
+        private String headerName;
+        private String mode;
+        private String group;
+
+        /**
+         * Name of header to tokenize instead of using the message body.
+         */
+        public Builder headerName(String headerName) {
+            this.headerName = headerName;
+            return this;
+        }
+
+        /**
+         * The extraction mode. The available extraction modes are:
+         * <ul>
+         * <li>i - injecting the contextual namespace bindings into the extracted token (default)</li>
+         * <li>w - wrapping the extracted token in its ancestor context</li>
+         * <li>u - unwrapping the extracted token to its child content</li>
+         * <li>t - extracting the text content of the specified element</li>
+         * </ul>
+         */
+        public Builder mode(String mode) {
+            this.mode = mode;
+            return this;
+        }
+
+        /**
+         * To group N parts together
+         */
+        public Builder group(String group) {
+            this.group = group;
+            return this;
+        }
+
+        /**
+         * To group N parts together
+         */
+        public Builder group(int group) {
+            this.group = Integer.toString(group);
+            return this;
+        }
+
+        @Override
+        public XMLTokenizerExpression end() {
+            return new XMLTokenizerExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/XPathExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/XPathExpression.java
index f463db284bf..983e75b528f 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/XPathExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/XPathExpression.java
@@ -80,6 +80,22 @@ public class XPathExpression extends NamespaceAwareExpression {
         setExpressionValue(expression);
     }
 
+    private XPathExpression(Builder builder) {
+        super(builder);
+        this.documentType = builder.documentType;
+        this.resultType = builder.resultType;
+        this.xpathFactory = builder.xpathFactory;
+        this.documentTypeName = builder.documentTypeName;
+        this.resultTypeName = builder.resultTypeName;
+        this.saxon = builder.saxon;
+        this.factoryRef = builder.factoryRef;
+        this.objectModel = builder.objectModel;
+        this.logNamespaces = builder.logNamespaces;
+        this.headerName = builder.headerName;
+        this.threadSafety = builder.threadSafety;
+        this.preCompile = builder.preCompile;
+    }
+
     @Override
     public String getLanguage() {
         return "xpath";
@@ -232,4 +248,184 @@ public class XPathExpression extends NamespaceAwareExpression {
     public void setPreCompile(String preCompile) {
         this.preCompile = preCompile;
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link XPathExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractNamespaceAwareBuilder<Builder, XPathExpression> {
+
+        private Class<?> documentType;
+        private Class<?> resultType;
+        private XPathFactory xpathFactory;
+        private String documentTypeName;
+        private String resultTypeName;
+        private String saxon;
+        private String factoryRef;
+        private String objectModel;
+        private String logNamespaces;
+        private String headerName;
+        private String threadSafety;
+        private String preCompile;
+
+        /**
+         * Class for document type to use
+         * <p/>
+         * The default value is org.w3c.dom.Document
+         */
+        public Builder documentType(Class<?> documentType) {
+            this.documentType = documentType;
+            return this;
+        }
+
+        /**
+         * Sets the class of the result type (type from output).
+         * <p/>
+         * The default result type is NodeSet
+         */
+        public Builder resultType(Class<?> resultType) {
+            this.resultType = resultType;
+            return this;
+        }
+
+        public Builder xpathFactory(XPathFactory xpathFactory) {
+            this.xpathFactory = xpathFactory;
+            return this;
+        }
+
+        /**
+         * Name of class for document type
+         * <p/>
+         * The default value is org.w3c.dom.Document
+         */
+        public Builder documentTypeName(String documentTypeName) {
+            this.documentTypeName = documentTypeName;
+            return this;
+        }
+
+        /**
+         * Sets the class name of the result type (type from output)
+         * <p/>
+         * The default result type is NodeSet
+         */
+        public Builder resultTypeName(String resultTypeName) {
+            this.resultTypeName = resultTypeName;
+            return this;
+        }
+
+        /**
+         * Whether to use Saxon.
+         */
+        public Builder saxon(String saxon) {
+            this.saxon = saxon;
+            return this;
+        }
+
+        /**
+         * Whether to use Saxon.
+         */
+        public Builder saxon(boolean saxon) {
+            this.saxon = Boolean.toString(saxon);
+            return this;
+        }
+
+        /**
+         * References to a custom XPathFactory to lookup in the registry
+         */
+        public Builder factoryRef(String factoryRef) {
+            this.factoryRef = factoryRef;
+            return this;
+        }
+
+        /**
+         * The XPath object model to use
+         */
+        public Builder objectModel(String objectModel) {
+            this.objectModel = objectModel;
+            return this;
+        }
+
+        /**
+         * Whether to log namespaces which can assist during troubleshooting
+         */
+        public Builder logNamespaces(String logNamespaces) {
+            this.logNamespaces = logNamespaces;
+            return this;
+        }
+
+        /**
+         * Whether to log namespaces which can assist during troubleshooting
+         */
+        public Builder logNamespaces(boolean logNamespaces) {
+            this.logNamespaces = Boolean.toString(logNamespaces);
+            return this;
+        }
+
+        /**
+         * Name of header to use as input, instead of the message body
+         */
+        public Builder headerName(String headerName) {
+            this.headerName = headerName;
+            return this;
+        }
+
+        /**
+         * Whether to enable thread-safety for the returned result of the xpath expression. This applies to when using
+         * NODESET as the result type, and the returned set has multiple elements. In this situation there can be
+         * thread-safety issues if you process the NODESET concurrently such as from a Camel Splitter EIP in parallel
+         * processing mode. This option prevents concurrency issues by doing defensive copies of the nodes.
+         * <p/>
+         * It is recommended to turn this option on if you are using camel-saxon or Saxon in your application. Saxon has
+         * thread-safety issues which can be prevented by turning this option on.
+         */
+        public Builder threadSafety(String threadSafety) {
+            this.threadSafety = threadSafety;
+            return this;
+        }
+
+        /**
+         * Whether to enable thread-safety for the returned result of the xpath expression. This applies to when using
+         * NODESET as the result type, and the returned set has multiple elements. In this situation there can be
+         * thread-safety issues if you process the NODESET concurrently such as from a Camel Splitter EIP in parallel
+         * processing mode. This option prevents concurrency issues by doing defensive copies of the nodes.
+         * <p/>
+         * It is recommended to turn this option on if you are using camel-saxon or Saxon in your application. Saxon has
+         * thread-safety issues which can be prevented by turning this option on.
+         */
+        public Builder threadSafety(boolean threadSafety) {
+            this.threadSafety = Boolean.toString(threadSafety);
+            return this;
+        }
+
+        /**
+         * Whether to enable pre-compiling the xpath expression during initialization phase. pre-compile is enabled by
+         * default.
+         *
+         * This can be used to turn off, for example in cases the compilation phase is desired at the starting phase,
+         * such as if the application is ahead of time compiled (for example with camel-quarkus) which would then load
+         * the xpath factory of the built operating system, and not a JVM runtime.
+         */
+        public Builder preCompile(String preCompile) {
+            this.preCompile = preCompile;
+            return this;
+        }
+
+        /**
+         * Whether to enable pre-compiling the xpath expression during initialization phase. pre-compile is enabled by
+         * default.
+         *
+         * This can be used to turn off, for example in cases the compilation phase is desired at the starting phase,
+         * such as if the application is ahead of time compiled (for example with camel-quarkus) which would then load
+         * the xpath factory of the built operating system, and not a JVM runtime.
+         */
+        public Builder preCompile(boolean preCompile) {
+            this.preCompile = Boolean.toString(preCompile);
+            return this;
+        }
+
+        @Override
+        public XPathExpression end() {
+            return new XPathExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/language/XQueryExpression.java b/core/camel-core-model/src/main/java/org/apache/camel/model/language/XQueryExpression.java
index dfb7260ff9e..1d88a6f6128 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/language/XQueryExpression.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/language/XQueryExpression.java
@@ -53,6 +53,15 @@ public class XQueryExpression extends NamespaceAwareExpression {
         super(expression);
     }
 
+    private XQueryExpression(Builder builder) {
+        super(builder);
+        this.resultType = builder.resultType;
+        this.configuration = builder.configuration;
+        this.type = builder.type;
+        this.headerName = builder.headerName;
+        this.configurationRef = builder.configurationRef;
+    }
+
     @Override
     public String getLanguage() {
         return "xquery";
@@ -119,4 +128,69 @@ public class XQueryExpression extends NamespaceAwareExpression {
     public void setConfiguration(Object configuration) {
         this.configuration = configuration;
     }
+
+    /**
+     * {@code Builder} is a specific builder for {@link XQueryExpression}.
+     */
+    @XmlTransient
+    public static class Builder extends AbstractNamespaceAwareBuilder<Builder, XQueryExpression> {
+
+        private Class<?> resultType;
+        private Object configuration;
+        private String type;
+        private String headerName;
+        private String configurationRef;
+
+        /**
+         * Sets the class of the result type (type from output).
+         * <p/>
+         * The default result type is NodeSet
+         */
+        public Builder resultType(Class<?> resultType) {
+            this.resultType = resultType;
+            return this;
+        }
+
+        /**
+         * Custom saxon configuration (requires camel-saxon). This may be needed to add custom functions to a saxon
+         * configuration, so these custom functions can be used in xquery expressions.
+         */
+        public Builder configuration(Object configuration) {
+            this.configuration = configuration;
+            return this;
+        }
+
+        /**
+         * Sets the class name of the result type (type from output)
+         * <p/>
+         * The default result type is NodeSet
+         */
+        public Builder type(String type) {
+            this.type = type;
+            return this;
+        }
+
+        /**
+         * Name of header to use as input, instead of the message body
+         */
+        public Builder headerName(String headerName) {
+            this.headerName = headerName;
+            return this;
+        }
+
+        /**
+         * Reference to a saxon configuration instance in the registry to use for xquery (requires camel-saxon). This
+         * may be needed to add custom functions to a saxon configuration, so these custom functions can be used in
+         * xquery expressions.
+         */
+        public Builder configurationRef(String configurationRef) {
+            this.configurationRef = configurationRef;
+            return this;
+        }
+
+        @Override
+        public XQueryExpression end() {
+            return new XQueryExpression(this);
+        }
+    }
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/LanguageFluentSyntaxTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/LanguageFluentSyntaxTest.java
new file mode 100644
index 00000000000..239122910a2
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/LanguageFluentSyntaxTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.impl;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+/**
+ * A unit test class ensuring that the fluent syntax to create language works as expected.
+ */
+class LanguageFluentSyntaxTest extends ContextTestSupport {
+
+    @Test
+    void testAsSplitExpression() throws Exception {
+        getMockEndpoint("mock:a").expectedBodiesReceived("A", "B");
+
+        template.sendBody("direct:a", "A\nB");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    void testAsOuterExpression() throws Exception {
+        getMockEndpoint("mock:b").expectedBodiesReceived("Hello World Out");
+
+        template.sendBody("direct:b", "foo");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    void testAsInnerExpression() throws Exception {
+        getMockEndpoint("mock:c").expectedBodiesReceived("Hello World In");
+
+        template.sendBody("direct:c", "bar");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    void testAsFiler() throws Exception {
+        getMockEndpoint("mock:d").expectedBodiesReceived("Hello World");
+
+        template.sendBodyAndHeader("direct:d", "Hello World", "foo", "bar");
+        template.sendBodyAndHeader("direct:d", "Bye World", "foo", "other");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:a").split(
+                    expression().tokenize().token("\n").end()
+                ).to("mock:a");
+
+                from("direct:b").setBody().expression(expression().simple().expression("Hello World Out").end()).to("mock:b");
+                from("direct:c").setBody(expression().simple().expression("Hello World In").end()).to("mock:c");
+                from("direct:d").filter(expression(expression().header().expression("foo").end()).isEqualTo("bar")).to("mock:d");
+            }
+        };
+    }
+}
diff --git a/docs/user-manual/modules/ROOT/pages/dataformat-dsl.adoc b/docs/user-manual/modules/ROOT/pages/dataformat-dsl.adoc
index 31aef5f0196..67440b08b24 100644
--- a/docs/user-manual/modules/ROOT/pages/dataformat-dsl.adoc
+++ b/docs/user-manual/modules/ROOT/pages/dataformat-dsl.adoc
@@ -1,7 +1,7 @@
 = Data Format DSL
 
 The Data Format DSL is a builder API that allows using type safe construction of
-Camel xref:data-format.adoc[Data Format].
+Camel xref:data-format.adoc[Data Formats].
 
 The Data Format DSL is exclusively available as part of the Java DSL.
 
diff --git a/docs/user-manual/modules/ROOT/pages/index.adoc b/docs/user-manual/modules/ROOT/pages/index.adoc
index af00807288a..8b0b23e366e 100644
--- a/docs/user-manual/modules/ROOT/pages/index.adoc
+++ b/docs/user-manual/modules/ROOT/pages/index.adoc
@@ -35,6 +35,7 @@ For a deeper and better understanding of Apache Camel, an xref:faq:what-is-camel
 * xref:component-dsl.adoc[Component DSL]
 * xref:Endpoint-dsl.adoc[Endpoint DSL]
 * xref:dataformat-dsl.adoc[DataFormat DSL]
+* xref:language-dsl.adoc[Language DSL]
 * xref:dsl.adoc[DSL]
 * xref:components::index.adoc[Components]
 * xref:components:dataformats:index.adoc[Data Formats]
diff --git a/docs/user-manual/modules/ROOT/pages/language-dsl.adoc b/docs/user-manual/modules/ROOT/pages/language-dsl.adoc
new file mode 100644
index 00000000000..066196ed8e6
--- /dev/null
+++ b/docs/user-manual/modules/ROOT/pages/language-dsl.adoc
@@ -0,0 +1,69 @@
+= Language DSL
+
+The Language DSL is a builder API that allows using type safe construction of
+Camel xref:languages.adoc[Languages].
+
+The Language DSL is exclusively available as part of the Java DSL.
+
+The DSL can be accessed directly from the `RouteBuilder` thanks to the method `expression()`.
+
+== Using Language DSL
+
+In the following example, a `TokenizerExpression` is created using the legacy approach where the expression is instantiated explicitly and configured using setters:
+
+[source,java]
+----
+public class MyRoutes extends RouteBuilder {
+    @Override
+    public void configure() {
+        TokenizerExpression expression = new TokenizerExpression("(\\W+)\\s*"); // <1>
+        expression.setRegex(true); // <2>
+        from("file:data")
+            .split(expression) // <3>
+            .process("processEntry");
+    }
+}
+----
+<1> Instantiate the expected expression
+<2> Configure the expression according to the needs
+<3> Affect the expression with the expected configuration
+
+The previous code could be simplified using the utility methods available directly from the `ExpressionClause` corresponding to the type returned by several existing methods such as `split()`, `setBody()`, `setHeader(String)`, `aggregate()`, etc.:
+
+[source,java]
+----
+public class MyRoutes extends RouteBuilder {
+    @Override
+    public void configure() {
+        from("file:data")
+            .split()
+            .tokenize("(\\W+)\\s*", true) // <1>
+            .process("processEntry");
+    }
+}
+----
+<1> Select the `tokenize` language with a specific regular expression
+
+This approach is suitable for very basic configuration, but as there are only limited utility methods for each supported language, for more complex configuration, we can quickly face situations where the utility method for our expected configuration doesn't exist. In this situation, you can either use the legacy approach or the language DSL like in the next code snippet:
+
+[source,java]
+----
+public class MyRoutes extends RouteBuilder {
+    @Override
+    public void configure() {
+        from("file:data")
+            .split(
+                expression() // <1>
+                    .tokenize() // <2>
+                        .token("(\\W+)\\s*") // <3>
+                        .regex(true) // <3>
+                    .end() // <4>
+            )
+            .process("processEntry");
+    }
+}
+----
+<1> Give access to all the supported languages
+<2> Select the `tokenize` language
+<3> Configure the expression according to the needs
+<4> Build the expression with the expected configuration