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 2023/01/25 14:49:25 UTC

[camel-quarkus] branch 2083/joor-language-native-support updated (766f046759 -> 115aab8d8d)

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

nfilotto pushed a change to branch 2083/joor-language-native-support
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


 discard 766f046759 Ref #2083: jOOR language native support
     new 115aab8d8d Ref #2083: jOOR language native support

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (766f046759)
            \
             N -- N -- N   refs/heads/2083/joor-language-native-support (115aab8d8d)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

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.


Summary of changes:
 docs/modules/ROOT/pages/reference/extensions/joor.adoc  | 2 +-
 extensions/joor/runtime/src/main/doc/configuration.adoc | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)


[camel-quarkus] 01/01: Ref #2083: jOOR language native support

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

nfilotto pushed a commit to branch 2083/joor-language-native-support
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit 115aab8d8dcba466253afc6cc4e8a59515ae11ad
Author: Nicolas Filotto <nf...@talend.com>
AuthorDate: Wed Jan 25 14:21:15 2023 +0100

    Ref #2083: jOOR language native support
---
 docs/modules/ROOT/examples/languages/joor.yml      |   6 +-
 .../ROOT/pages/reference/extensions/joor.adoc      |  50 ++++-
 .../component/joor/deployment/JoorProcessor.java   |  46 -----
 extensions-jvm/pom.xml                             |   1 -
 .../language/deployment/ExpressionBuildItem.java   |   8 +-
 .../deployment/LanguageSupportProcessor.java       |  16 +-
 ...pressionBuildItem.java => ScriptBuildItem.java} |  26 +--
 .../deployment/dm/DryModeComponentResolver.java    |  19 +-
 .../language/deployment/dm/DryModeInjector.java    |  31 ++-
 .../language/deployment/dm/DryModeLanguage.java    |  32 +++-
 .../deployment/dm/DryModeLanguageResolver.java     |  12 +-
 ...Resolver.java => DryModeScriptingLanguage.java} |  30 +--
 .../language/deployment/dm/ExpressionHolder.java   |  64 +++++++
 .../language/deployment/dm/ScriptHolder.java       |  58 ++++++
 .../support/language/runtime/ExpressionUID.java    |  54 ++++++
 .../support/language/runtime/ScriptUID.java        |  53 ++++++
 .../support/language/runtime/SourceCodeUID.java    |  94 +++++++++
 .../joor/deployment/pom.xml                        |   8 +
 .../deployment/JoorExpressionSourceBuildItem.java  |  68 +++++++
 .../component/joor/deployment/JoorProcessor.java   | 211 +++++++++++++++++++++
 {extensions-jvm => extensions}/joor/pom.xml        |   2 +-
 .../joor/runtime/pom.xml                           |   5 +
 .../joor/runtime/src/main/doc/configuration.adoc   |   3 +
 .../joor/runtime/JoorExpressionCompiler.java       |  64 +++++++
 .../joor/runtime/JoorExpressionConfig.java         |  40 ++--
 .../joor/runtime/JoorExpressionLanguage.java       |  80 ++++++++
 .../joor/runtime/JoorExpressionRecorder.java       |  77 ++++++++
 .../runtime/JoorExpressionScriptingCompiler.java   |  64 +++++++
 .../main/resources/META-INF/quarkus-extension.yaml |   3 +-
 extensions/pom.xml                                 |   1 +
 integration-tests-jvm/pom.xml                      |   1 -
 integration-tests/csimple/pom.xml                  |  34 ++++
 .../component/csimple/it/CSimpleResource.java      |  15 ++
 .../quarkus/component/csimple/it/CSimpleRoute.java |  16 +-
 .../META-INF/native-image/reflect-config.json      |   6 +
 .../quarkus/component/csimple/it/CSimpleTest.java  |  28 +++
 .../joor/pom.xml                                   |  78 ++++++++
 .../camel/quarkus/component/joor/it/JoorBean.java  |  18 +-
 .../quarkus/component/joor/it/JoorResource.java    |  29 +++
 .../quarkus/component/joor/it/JoorRoute.java}      |  26 ++-
 .../META-INF/native-image/reflect-config.json      |   6 +
 .../joor/src/main/resources/bean.joor              |   4 +
 .../camel/quarkus/component/joor/it/JoorIT.java}   |  13 +-
 .../camel/quarkus/component/joor/it/JoorTest.java  |  42 +++-
 integration-tests/pom.xml                          |   1 +
 tooling/scripts/test-categories.yaml               |   1 +
 46 files changed, 1386 insertions(+), 158 deletions(-)

diff --git a/docs/modules/ROOT/examples/languages/joor.yml b/docs/modules/ROOT/examples/languages/joor.yml
index c8e14799ef..480dbe4b31 100644
--- a/docs/modules/ROOT/examples/languages/joor.yml
+++ b/docs/modules/ROOT/examples/languages/joor.yml
@@ -2,11 +2,11 @@
 # This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page
 cqArtifactId: camel-quarkus-joor
 cqArtifactIdBase: joor
-cqNativeSupported: false
-cqStatus: Preview
+cqNativeSupported: true
+cqStatus: Stable
 cqDeprecated: false
 cqJvmSince: 2.0.0
-cqNativeSince: n/a
+cqNativeSince: 2.17.0
 cqCamelPartName: joor
 cqCamelPartTitle: jOOR
 cqCamelPartDescription: Evaluates a jOOR (Java compiled once at runtime) expression.
diff --git a/docs/modules/ROOT/pages/reference/extensions/joor.adoc b/docs/modules/ROOT/pages/reference/extensions/joor.adoc
index c924cc07c2..57851dd427 100644
--- a/docs/modules/ROOT/pages/reference/extensions/joor.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/joor.adoc
@@ -4,17 +4,17 @@
 = jOOR
 :linkattrs:
 :cq-artifact-id: camel-quarkus-joor
-:cq-native-supported: false
-:cq-status: Preview
-:cq-status-deprecation: Preview
+:cq-native-supported: true
+:cq-status: Stable
+:cq-status-deprecation: Stable
 :cq-description: Evaluate a jOOR (Java compiled once at runtime) expression language.
 :cq-deprecated: false
 :cq-jvm-since: 2.0.0
-:cq-native-since: n/a
+:cq-native-since: 2.17.0
 
 ifeval::[{doc-show-badges} == true]
 [.badges]
-[.badge-key]##JVM since##[.badge-supported]##2.0.0## [.badge-key]##Native##[.badge-unsupported]##unsupported##
+[.badge-key]##JVM since##[.badge-supported]##2.0.0## [.badge-key]##Native since##[.badge-supported]##2.17.0##
 endif::[]
 
 Evaluate a jOOR (Java compiled once at runtime) expression language.
@@ -29,6 +29,10 @@ Please refer to the above link for usage and configuration details.
 [id="extensions-joor-maven-coordinates"]
 == Maven coordinates
 
+https://{link-quarkus-code-generator}/?extension-search=camel-quarkus-joor[Create a new project with this extension on {link-quarkus-code-generator}, window="_blank"]
+
+Or add the coordinates to your existing project:
+
 [source,xml]
 ----
 <dependency>
@@ -39,3 +43,39 @@ Please refer to the above link for usage and configuration details.
 ifeval::[{doc-show-user-guide-link} == true]
 Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
 endif::[]
+
+[id="extensions-joor-additional-camel-quarkus-configuration"]
+== Additional Camel Quarkus configuration
+
+The expressions and scripts written using the jOOR language are extracted and compiled at build time, to do so the
+language needs to be instantiated and configured at build time in order to be able to generate the exact same source code as
+the one generated at runtime. For this purpose, the next configuration properties have been added:
+
+
+[width="100%",cols="80,5,15",options="header"]
+|===
+| Configuration property | Type | Default
+
+
+|icon:lock[title=Fixed at build time] [[quarkus.camel.joor.single-quotes]]`link:#quarkus.camel.joor.single-quotes[quarkus.camel.joor.single-quotes]`
+
+Indicates whether a jOOR expression can use single quotes instead of double quotes.
+| `boolean`
+| `true`
+
+|icon:lock[title=Fixed at build time] [[quarkus.camel.joor.config-resource]]`link:#quarkus.camel.joor.config-resource[quarkus.camel.joor.config-resource]`
+
+
+| `string`
+| 
+
+|icon:lock[title=Fixed at build time] [[quarkus.camel.joor.result-type]]`link:#quarkus.camel.joor.result-type[quarkus.camel.joor.result-type]`
+
+
+| `string`
+| 
+|===
+
+[.configuration-legend]
+{doc-link-icon-lock}[title=Fixed at build time] Configuration property fixed at build time. All other configuration properties are overridable at runtime.
+
diff --git a/extensions-jvm/joor/deployment/src/main/java/org/apache/camel/quarkus/component/joor/deployment/JoorProcessor.java b/extensions-jvm/joor/deployment/src/main/java/org/apache/camel/quarkus/component/joor/deployment/JoorProcessor.java
deleted file mode 100644
index f2a7a6f576..0000000000
--- a/extensions-jvm/joor/deployment/src/main/java/org/apache/camel/quarkus/component/joor/deployment/JoorProcessor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.quarkus.component.joor.deployment;
-
-import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.annotations.ExecutionTime;
-import io.quarkus.deployment.annotations.Record;
-import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.deployment.pkg.steps.NativeBuild;
-import org.apache.camel.quarkus.core.JvmOnlyRecorder;
-import org.jboss.logging.Logger;
-
-class JoorProcessor {
-
-    private static final Logger LOG = Logger.getLogger(JoorProcessor.class);
-    private static final String FEATURE = "camel-joor";
-
-    @BuildStep
-    FeatureBuildItem feature() {
-        return new FeatureBuildItem(FEATURE);
-    }
-
-    /**
-     * Remove this once this extension starts supporting the native mode.
-     */
-    @BuildStep(onlyIf = NativeBuild.class)
-    @Record(value = ExecutionTime.RUNTIME_INIT)
-    void warnJvmInNative(JvmOnlyRecorder recorder) {
-        JvmOnlyRecorder.warnJvmInNative(LOG, FEATURE); // warn at build time
-        recorder.warnJvmInNative(FEATURE); // warn at runtime
-    }
-}
diff --git a/extensions-jvm/pom.xml b/extensions-jvm/pom.xml
index e5fd9e0c3f..5053e11a2b 100644
--- a/extensions-jvm/pom.xml
+++ b/extensions-jvm/pom.xml
@@ -84,7 +84,6 @@
         <module>jgroups</module>
         <module>jgroups-raft</module>
         <module>jooq</module>
-        <module>joor</module>
         <module>json-patch</module>
         <module>jsonapi</module>
         <module>jt400</module>
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
index b3e7d52dae..bbb5242308 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
@@ -27,10 +27,12 @@ public final class ExpressionBuildItem extends MultiBuildItem {
     final String language;
     final String expression;
     final boolean predicate;
+    final Object[] properties;
 
-    public ExpressionBuildItem(String language, String expression, boolean predicate) {
+    public ExpressionBuildItem(String language, String expression, Object[] properties, boolean predicate) {
         this.language = language;
         this.expression = expression;
+        this.properties = properties;
         this.predicate = predicate;
     }
 
@@ -45,4 +47,8 @@ public final class ExpressionBuildItem extends MultiBuildItem {
     public boolean isPredicate() {
         return predicate;
     }
+
+    public Object[] getProperties() {
+        return properties;
+    }
 }
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/LanguageSupportProcessor.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/LanguageSupportProcessor.java
index f30fa129f2..3a5f88eaf0 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/LanguageSupportProcessor.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/LanguageSupportProcessor.java
@@ -27,6 +27,8 @@ import org.apache.camel.quarkus.core.CamelConfig;
 import org.apache.camel.quarkus.core.deployment.spi.CamelRoutesBuilderClassBuildItem;
 import org.apache.camel.quarkus.support.language.deployment.dm.DryModeLanguage;
 import org.apache.camel.quarkus.support.language.deployment.dm.DryModeMain;
+import org.apache.camel.quarkus.support.language.deployment.dm.ExpressionHolder;
+import org.apache.camel.quarkus.support.language.deployment.dm.ScriptHolder;
 import org.jboss.logging.Logger;
 
 class LanguageSupportProcessor {
@@ -36,7 +38,8 @@ class LanguageSupportProcessor {
     @BuildStep
     ExpressionExtractionResultBuildItem extractExpressions(CamelConfig config,
             List<CamelRoutesBuilderClassBuildItem> routesBuilderClasses,
-            BuildProducer<ExpressionBuildItem> producer) throws Exception {
+            BuildProducer<ExpressionBuildItem> expressions,
+            BuildProducer<ScriptBuildItem> scripts) throws Exception {
         if (config.expression.extractionEnabled) {
             final ClassLoader loader = Thread.currentThread().getContextClassLoader();
             if (!(loader instanceof QuarkusClassLoader)) {
@@ -60,11 +63,14 @@ class LanguageSupportProcessor {
                 main.run();
                 for (DryModeLanguage language : main.getLanguages()) {
                     final String name = language.getName();
-                    for (String exp : language.getPredicates()) {
-                        producer.produce(new ExpressionBuildItem(name, exp, true));
+                    for (ExpressionHolder holder : language.getPredicates()) {
+                        expressions.produce(new ExpressionBuildItem(name, holder.getContent(), holder.getProperties(), true));
                     }
-                    for (String exp : language.getExpressions()) {
-                        producer.produce(new ExpressionBuildItem(name, exp, false));
+                    for (ExpressionHolder holder : language.getExpressions()) {
+                        expressions.produce(new ExpressionBuildItem(name, holder.getContent(), holder.getProperties(), false));
+                    }
+                    for (ScriptHolder script : language.getScripts()) {
+                        scripts.produce(new ScriptBuildItem(name, script.getContent(), script.getBindings()));
                     }
                 }
                 return new ExpressionExtractionResultBuildItem(true);
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ScriptBuildItem.java
similarity index 64%
copy from extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
copy to extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ScriptBuildItem.java
index b3e7d52dae..da3c862560 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ScriptBuildItem.java
@@ -16,33 +16,35 @@
  */
 package org.apache.camel.quarkus.support.language.deployment;
 
+import java.util.Map;
+
 import io.quarkus.builder.item.MultiBuildItem;
 
 /**
- * {@code ExpressionBuildItem} represents an expression in a given language that has been extracted from the route
- * definitions.
+ * {@code ScriptBuildItem} represents a script and its binding context in a given language that has been extracted from
+ * the route definitions.
  */
-public final class ExpressionBuildItem extends MultiBuildItem {
+public final class ScriptBuildItem extends MultiBuildItem {
 
     final String language;
-    final String expression;
-    final boolean predicate;
+    final String content;
+    final Map<String, Object> bindings;
 
-    public ExpressionBuildItem(String language, String expression, boolean predicate) {
+    public ScriptBuildItem(String language, String content, Map<String, Object> bindings) {
         this.language = language;
-        this.expression = expression;
-        this.predicate = predicate;
+        this.content = content;
+        this.bindings = bindings;
     }
 
     public String getLanguage() {
         return language;
     }
 
-    public String getExpression() {
-        return expression;
+    public String getContent() {
+        return content;
     }
 
-    public boolean isPredicate() {
-        return predicate;
+    public Map<String, Object> getBindings() {
+        return bindings;
     }
 }
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeComponentResolver.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeComponentResolver.java
index 98dbce3311..3be90cbb24 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeComponentResolver.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeComponentResolver.java
@@ -16,17 +16,30 @@
  */
 package org.apache.camel.quarkus.support.language.deployment.dm;
 
+import java.util.Set;
+
 import org.apache.camel.CamelContext;
 import org.apache.camel.Component;
-import org.apache.camel.spi.ComponentResolver;
+import org.apache.camel.impl.engine.DefaultComponentResolver;
 
 /**
- * {@code DryModeComponentResolver} is used to resolve all components with {@link DryModeComponent} for a dry run.
+ * {@code DryModeComponentResolver} is used to resolve all non-accepted components with {@link DryModeComponent} for a
+ * dry run.
+ * The accepted components are safe to start and stop for a dry run and cannot be replaced with a
+ * {@link DryModeComponent}.
  */
-class DryModeComponentResolver implements ComponentResolver {
+class DryModeComponentResolver extends DefaultComponentResolver {
+
+    /**
+     * Name of components for which a mock component is not needed for the dry run.
+     */
+    private static final Set<String> ACCEPTED_NAMES = Set.of("bean", "class", "kamelet");
 
     @Override
     public Component resolveComponent(String name, CamelContext context) {
+        if (ACCEPTED_NAMES.contains(name)) {
+            return super.resolveComponent(name, context);
+        }
         return new DryModeComponent();
     }
 }
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeInjector.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeInjector.java
index 46d53c058f..7fc7e87251 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeInjector.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeInjector.java
@@ -16,15 +16,25 @@
  */
 package org.apache.camel.quarkus.support.language.deployment.dm;
 
+import java.util.Set;
+
 import org.apache.camel.Component;
 import org.apache.camel.spi.Injector;
 
 /**
- * {@code DryModeInjector} is used to replace instantiations of any component with an instantiation of
- * {@link DryModeComponent} for a dry run.
+ * {@code DryModeInjector} is used to replace instantiations of non-accepted components with an instantiation of
+ * {@link DryModeComponent} for a dry run. The accepted components are safe to start and stop for a dry run and cannot
+ * be replaced with a {@link DryModeComponent}.
  */
 class DryModeInjector implements Injector {
 
+    /**
+     * Name of components for which a mock component is not needed for the dry run.
+     */
+    private static final Set<String> ACCEPTED_NAMES = Set.of("org.apache.camel.component.bean.BeanComponent",
+            "org.apache.camel.component.beanclass.ClassComponent",
+            "org.apache.camel.component.kamelet.KameletComponent");
+
     private final Injector delegate;
 
     DryModeInjector(Injector delegate) {
@@ -34,7 +44,7 @@ class DryModeInjector implements Injector {
     @SuppressWarnings("unchecked")
     @Override
     public <T> T newInstance(Class<T> type) {
-        if (Component.class.isAssignableFrom(type)) {
+        if (mustBeReplaced(type)) {
             return (T) delegate.newInstance(DryModeComponent.class);
         }
         return delegate.newInstance(type);
@@ -43,7 +53,7 @@ class DryModeInjector implements Injector {
     @SuppressWarnings("unchecked")
     @Override
     public <T> T newInstance(Class<T> type, String factoryMethod) {
-        if (Component.class.isAssignableFrom(type)) {
+        if (mustBeReplaced(type)) {
             return (T) delegate.newInstance(DryModeComponent.class);
         }
         return delegate.newInstance(type, factoryMethod);
@@ -52,7 +62,7 @@ class DryModeInjector implements Injector {
     @SuppressWarnings("unchecked")
     @Override
     public <T> T newInstance(Class<T> type, boolean postProcessBean) {
-        if (Component.class.isAssignableFrom(type)) {
+        if (mustBeReplaced(type)) {
             return (T) delegate.newInstance(DryModeComponent.class);
         }
         return delegate.newInstance(type, postProcessBean);
@@ -62,4 +72,15 @@ class DryModeInjector implements Injector {
     public boolean supportsAutoWiring() {
         return delegate.supportsAutoWiring();
     }
+
+    /**
+     * Indicates whether the given type must be replaced by a mock component.
+     * 
+     * @param  type the type to check.
+     * @return      {@code true} if it should be replaced, {@code false} otherwise.
+     * @param  <T>  the type of the class to check.
+     */
+    private static <T> boolean mustBeReplaced(Class<T> type) {
+        return Component.class.isAssignableFrom(type) && !ACCEPTED_NAMES.contains(type.getName());
+    }
 }
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguage.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguage.java
index cee5ca0b84..e74a699cc2 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguage.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguage.java
@@ -35,7 +35,7 @@ public class DryModeLanguage implements Language {
     private final String name;
     private final Predicate defaultPredicate = new DryModePredicate();
     private final Expression defaultExpression = new DryModeExpression();
-    private final Map<Boolean, Set<String>> expressions = new ConcurrentHashMap<>();
+    private final Map<Boolean, Set<ExpressionHolder>> expressions = new ConcurrentHashMap<>();
 
     public DryModeLanguage(String name) {
         this.name = name;
@@ -45,23 +45,41 @@ public class DryModeLanguage implements Language {
         return name;
     }
 
-    public Set<String> getPredicates() {
+    public Set<ExpressionHolder> getPredicates() {
         return expressions.getOrDefault(Boolean.TRUE, Set.of());
     }
 
-    public Set<String> getExpressions() {
+    public Set<ExpressionHolder> getExpressions() {
         return expressions.getOrDefault(Boolean.FALSE, Set.of());
     }
 
+    public Set<ScriptHolder> getScripts() {
+        return Set.of();
+    }
+
     @Override
     public Predicate createPredicate(String expression) {
-        expressions.computeIfAbsent(Boolean.TRUE, mode -> ConcurrentHashMap.newKeySet()).add(expression);
+        expressions.computeIfAbsent(Boolean.TRUE, mode -> ConcurrentHashMap.newKeySet()).add(new ExpressionHolder(expression));
         return defaultPredicate;
     }
 
     @Override
     public Expression createExpression(String expression) {
-        expressions.computeIfAbsent(Boolean.FALSE, mode -> ConcurrentHashMap.newKeySet()).add(expression);
+        expressions.computeIfAbsent(Boolean.FALSE, mode -> ConcurrentHashMap.newKeySet()).add(new ExpressionHolder(expression));
+        return defaultExpression;
+    }
+
+    @Override
+    public Predicate createPredicate(String expression, Object[] properties) {
+        expressions.computeIfAbsent(Boolean.TRUE, mode -> ConcurrentHashMap.newKeySet())
+                .add(new ExpressionHolder(expression, properties));
+        return defaultPredicate;
+    }
+
+    @Override
+    public Expression createExpression(String expression, Object[] properties) {
+        expressions.computeIfAbsent(Boolean.FALSE, mode -> ConcurrentHashMap.newKeySet())
+                .add(new ExpressionHolder(expression, properties));
         return defaultExpression;
     }
 
@@ -85,9 +103,11 @@ public class DryModeLanguage implements Language {
 
     private static class DryModeExpression implements Expression {
 
+        @SuppressWarnings("unchecked")
         @Override
         public <T> T evaluate(Exchange exchange, Class<T> type) {
-            return null;
+            // A non-null value must be returned and the returned type is not really important for the dry mode
+            return (T) new Object();
         }
 
         @Override
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java
index ae1a91a237..1d2e1bfccb 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java
@@ -22,18 +22,24 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.NoSuchLanguageException;
+import org.apache.camel.impl.engine.DefaultLanguageResolver;
 import org.apache.camel.spi.Language;
-import org.apache.camel.spi.LanguageResolver;
+import org.apache.camel.spi.ScriptingLanguage;
 
 /**
- * {@code DryModeLanguageResolver} is used to resolve all languages with {@link DryModeLanguage} for a dry run.
+ * {@code DryModeLanguageResolver} is used to resolve all languages with {@link DryModeLanguage} and scripting languages
+ * with {@link DryModeScriptingLanguage} for a dry run.
  */
-class DryModeLanguageResolver implements LanguageResolver {
+class DryModeLanguageResolver extends DefaultLanguageResolver {
 
     private final Map<String, DryModeLanguage> languages = new ConcurrentHashMap<>();
 
     @Override
     public Language resolveLanguage(String name, CamelContext context) throws NoSuchLanguageException {
+        final Language language = super.resolveLanguage(name, context);
+        if (language instanceof ScriptingLanguage) {
+            return languages.computeIfAbsent(name, DryModeScriptingLanguage::new);
+        }
         return languages.computeIfAbsent(name, DryModeLanguage::new);
     }
 
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeScriptingLanguage.java
similarity index 51%
copy from extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java
copy to extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeScriptingLanguage.java
index ae1a91a237..5f9f938b2a 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeLanguageResolver.java
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/DryModeScriptingLanguage.java
@@ -16,28 +16,34 @@
  */
 package org.apache.camel.quarkus.support.language.deployment.dm;
 
-import java.util.Collection;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
-import org.apache.camel.CamelContext;
-import org.apache.camel.NoSuchLanguageException;
-import org.apache.camel.spi.Language;
-import org.apache.camel.spi.LanguageResolver;
+import org.apache.camel.spi.ScriptingLanguage;
 
 /**
- * {@code DryModeLanguageResolver} is used to resolve all languages with {@link DryModeLanguage} for a dry run.
+ * {@code DryModeScriptingLanguage} is a mock scripting language meant to collect all the expressions,
+ * predicates and scripts that are registered for a specific scripting language.
  */
-class DryModeLanguageResolver implements LanguageResolver {
+class DryModeScriptingLanguage extends DryModeLanguage implements ScriptingLanguage {
 
-    private final Map<String, DryModeLanguage> languages = new ConcurrentHashMap<>();
+    private final Set<ScriptHolder> scripts = ConcurrentHashMap.newKeySet();
+
+    public DryModeScriptingLanguage(String name) {
+        super(name);
+    }
 
     @Override
-    public Language resolveLanguage(String name, CamelContext context) throws NoSuchLanguageException {
-        return languages.computeIfAbsent(name, DryModeLanguage::new);
+    public Set<ScriptHolder> getScripts() {
+        return scripts;
     }
 
-    Collection<DryModeLanguage> getLanguages() {
-        return languages.values();
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T> T evaluate(String script, Map<String, Object> bindings, Class<T> resultType) {
+        scripts.add(new ScriptHolder(script, bindings));
+        // A non-null value must be returned and the returned type is not really important for the dry mode
+        return (T) new Object();
     }
 }
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ExpressionHolder.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ExpressionHolder.java
new file mode 100644
index 0000000000..45c80139eb
--- /dev/null
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ExpressionHolder.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.support.language.deployment.dm;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * {@code ExpressionHolder} represents an expression with its parameters that could be extracted during the dry run.
+ */
+public final class ExpressionHolder {
+
+    private final String content;
+
+    private final Object[] properties;
+
+    public ExpressionHolder(String content) {
+        this(content, null);
+    }
+
+    public ExpressionHolder(String content, Object[] properties) {
+        this.content = content;
+        this.properties = properties;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public Object[] getProperties() {
+        return properties;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        ExpressionHolder that = (ExpressionHolder) o;
+        return Objects.equals(content, that.content) && Arrays.equals(properties, that.properties);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Objects.hash(content);
+        result = 31 * result + Arrays.hashCode(properties);
+        return result;
+    }
+}
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ScriptHolder.java b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ScriptHolder.java
new file mode 100644
index 0000000000..fb99746d1a
--- /dev/null
+++ b/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/dm/ScriptHolder.java
@@ -0,0 +1,58 @@
+/*
+ * 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.quarkus.support.language.deployment.dm;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * {@code ScriptHolder} represents a script with its binding context that could be extracted during the dry run.
+ */
+public final class ScriptHolder {
+
+    private final String content;
+
+    private final Map<String, Object> bindings;
+
+    public ScriptHolder(String content, Map<String, Object> bindings) {
+        this.content = content;
+        this.bindings = bindings;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public Map<String, Object> getBindings() {
+        return bindings;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+        ScriptHolder script = (ScriptHolder) o;
+        return Objects.equals(content, script.content) && Objects.equals(bindings, script.bindings);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(content, bindings);
+    }
+}
diff --git a/extensions-support/language/runtime/src/main/java/org/apache/camel/quarkus/support/language/runtime/ExpressionUID.java b/extensions-support/language/runtime/src/main/java/org/apache/camel/quarkus/support/language/runtime/ExpressionUID.java
new file mode 100644
index 0000000000..1f079d367f
--- /dev/null
+++ b/extensions-support/language/runtime/src/main/java/org/apache/camel/quarkus/support/language/runtime/ExpressionUID.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.support.language.runtime;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * {@code ExpressionUID} represents the unique identifier of a simple expression and its arguments.
+ */
+public final class ExpressionUID extends SourceCodeUID {
+
+    private final String expression;
+    private final String[] arguments;
+
+    public ExpressionUID(String expression) {
+        super("Expression");
+        this.expression = expression;
+        this.arguments = null;
+    }
+
+    public ExpressionUID(String expression, Object... arguments) {
+        super("Expression");
+        this.expression = expression;
+        this.arguments = arguments == null || arguments.length == 0 ? null
+                : Arrays.stream(arguments).map(Objects::toString).toArray(String[]::new);
+    }
+
+    @Override
+    protected byte[] asBytes() {
+        StringBuilder source = new StringBuilder();
+        source.append(expression);
+        source.append('.');
+        if (arguments != null) {
+            source.append(Arrays.toString(arguments));
+        }
+        source.append('.');
+        return source.toString().getBytes();
+    }
+}
diff --git a/extensions-support/language/runtime/src/main/java/org/apache/camel/quarkus/support/language/runtime/ScriptUID.java b/extensions-support/language/runtime/src/main/java/org/apache/camel/quarkus/support/language/runtime/ScriptUID.java
new file mode 100644
index 0000000000..a6b2b418a2
--- /dev/null
+++ b/extensions-support/language/runtime/src/main/java/org/apache/camel/quarkus/support/language/runtime/ScriptUID.java
@@ -0,0 +1,53 @@
+/*
+ * 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.quarkus.support.language.runtime;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * {@code ScriptUID} represents the unique identifier of a script, its binding context and its arguments.
+ */
+public final class ScriptUID extends SourceCodeUID {
+
+    private final String content;
+    private final String[] bindings;
+    private final Object[] arguments;
+
+    public ScriptUID(String content, Map<String, Object> bindings, Object... arguments) {
+        super("Script");
+        this.content = content;
+        this.bindings = bindings == null || bindings.isEmpty() ? null : bindings.keySet().toArray(new String[0]);
+        this.arguments = arguments;
+    }
+
+    @Override
+    protected byte[] asBytes() {
+        final StringBuilder source = new StringBuilder();
+        source.append(content);
+        source.append('.');
+        if (bindings != null) {
+            source.append(Arrays.toString(bindings));
+        }
+        source.append('.');
+        if (arguments != null) {
+            source.append(Arrays.toString(arguments));
+        }
+        source.append('.');
+        return source.toString().getBytes();
+    }
+}
diff --git a/extensions-support/language/runtime/src/main/java/org/apache/camel/quarkus/support/language/runtime/SourceCodeUID.java b/extensions-support/language/runtime/src/main/java/org/apache/camel/quarkus/support/language/runtime/SourceCodeUID.java
new file mode 100644
index 0000000000..563775dbd7
--- /dev/null
+++ b/extensions-support/language/runtime/src/main/java/org/apache/camel/quarkus/support/language/runtime/SourceCodeUID.java
@@ -0,0 +1,94 @@
+/*
+ * 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.quarkus.support.language.runtime;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+
+/**
+ * {@code SourceCodeUID} is the root class of all implementations of a unique identifier of a source code expressed
+ * in a given language.
+ * <p>
+ * To be able to retrieve a generated class thanks to its source code, an algorithm is applied to the source code to
+ * get a unique name that can be used as simple class name of the generated class.
+ * <p>
+ * The current algorithm, hashes first the source code to avoid having an identifier too long, then the result is
+ * encoded in base 64 to ensure that all characters are easy to read and finally converted in
+ * such way that it can be used as a Java identifier such as a class name.
+ */
+public abstract class SourceCodeUID {
+
+    /**
+     * The prefix of the Java identifier.
+     */
+    private final String prefix;
+
+    protected SourceCodeUID(String prefix) {
+        this.prefix = prefix;
+    }
+
+    /**
+     * @return the source code as bytes.
+     */
+    protected abstract byte[] asBytes();
+
+    /**
+     * @return the hash of the source code.
+     */
+    private byte[] asHash() {
+        try {
+            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
+            messageDigest.update(asBytes());
+            return messageDigest.digest();
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * @return the hash of the source code encoded in base 64.
+     */
+    private byte[] asHashInBase64() {
+        return Base64.getEncoder().encode(asHash());
+    }
+
+    /**
+     * @return the source code converted as a Java identifier.
+     */
+    public String asJavaIdentifier() {
+        final StringBuilder sb = new StringBuilder(prefix);
+        final String str = new String(asHashInBase64());
+        for (int i = 0, length = str.length(); i < length; i++) {
+            char c = str.charAt(i);
+            if (i > 0 && Character.isJavaIdentifierPart(c)) {
+                sb.append(c);
+            } else {
+                sb.append((int) c);
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * @return the value of {@link #asJavaIdentifier()}.
+     */
+    @Override
+    public final String toString() {
+        return asJavaIdentifier();
+    }
+}
diff --git a/extensions-jvm/joor/deployment/pom.xml b/extensions/joor/deployment/pom.xml
similarity index 88%
rename from extensions-jvm/joor/deployment/pom.xml
rename to extensions/joor/deployment/pom.xml
index b3a240f7ba..296711c080 100644
--- a/extensions-jvm/joor/deployment/pom.xml
+++ b/extensions/joor/deployment/pom.xml
@@ -34,10 +34,18 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-core-deployment</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-support-language-deployment</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-joor</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-java-joor-dsl</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/extensions/joor/deployment/src/main/java/org/apache/camel/quarkus/component/joor/deployment/JoorExpressionSourceBuildItem.java b/extensions/joor/deployment/src/main/java/org/apache/camel/quarkus/component/joor/deployment/JoorExpressionSourceBuildItem.java
new file mode 100644
index 0000000000..74b1bd8db3
--- /dev/null
+++ b/extensions/joor/deployment/src/main/java/org/apache/camel/quarkus/component/joor/deployment/JoorExpressionSourceBuildItem.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.quarkus.component.joor.deployment;
+
+import io.quarkus.builder.item.MultiBuildItem;
+import org.apache.camel.quarkus.support.language.runtime.ScriptUID;
+import org.apache.camel.quarkus.support.language.runtime.SourceCodeUID;
+
+/**
+ * A {@link MultiBuildItem} bearing info about a jOOR language expression that needs to get compiled.
+ */
+public final class JoorExpressionSourceBuildItem extends MultiBuildItem {
+
+    private final String sourceCode;
+    private final String className;
+    private final String id;
+    private final boolean script;
+
+    public JoorExpressionSourceBuildItem(SourceCodeUID id, String className, String sourceCode) {
+        this.id = id.asJavaIdentifier();
+        this.script = id instanceof ScriptUID;
+        this.className = className;
+        this.sourceCode = sourceCode;
+    }
+
+    /**
+     * @return the unique identifier of the expression.
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * @return {@code true} if it represents a script, otherwise it represents a simple expression.
+     */
+    public boolean isScript() {
+        return script;
+    }
+
+    /**
+     * @return the expression source code to compile
+     */
+    public String getSourceCode() {
+        return sourceCode;
+    }
+
+    /**
+     * @return a fully qualified class name that the compiler may use as a base for the name of the class into which it
+     *         compiles the source code returned by {@link #getSourceCode()}
+     */
+    public String getClassName() {
+        return className;
+    }
+}
diff --git a/extensions/joor/deployment/src/main/java/org/apache/camel/quarkus/component/joor/deployment/JoorProcessor.java b/extensions/joor/deployment/src/main/java/org/apache/camel/quarkus/component/joor/deployment/JoorProcessor.java
new file mode 100644
index 0000000000..938855be4d
--- /dev/null
+++ b/extensions/joor/deployment/src/main/java/org/apache/camel/quarkus/component/joor/deployment/JoorProcessor.java
@@ -0,0 +1,211 @@
+/*
+ * 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.quarkus.component.joor.deployment;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import io.quarkus.bootstrap.model.ApplicationModel;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.Consume;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.GeneratedClassBuildItem;
+import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
+import io.quarkus.deployment.recording.RecorderContext;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.paths.PathCollection;
+import io.quarkus.runtime.RuntimeValue;
+import org.apache.camel.CamelContext;
+import org.apache.camel.dsl.java.joor.CompilationUnit;
+import org.apache.camel.dsl.java.joor.MultiCompile;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.language.joor.JoorCompiler;
+import org.apache.camel.language.joor.JoorExpression;
+import org.apache.camel.language.joor.JoorScriptingCompiler;
+import org.apache.camel.quarkus.component.joor.runtime.JoorExpressionCompiler;
+import org.apache.camel.quarkus.component.joor.runtime.JoorExpressionConfig;
+import org.apache.camel.quarkus.component.joor.runtime.JoorExpressionLanguage;
+import org.apache.camel.quarkus.component.joor.runtime.JoorExpressionRecorder;
+import org.apache.camel.quarkus.component.joor.runtime.JoorExpressionScriptingCompiler;
+import org.apache.camel.quarkus.core.deployment.spi.CamelBeanBuildItem;
+import org.apache.camel.quarkus.core.deployment.spi.CamelContextBuildItem;
+import org.apache.camel.quarkus.support.language.deployment.ExpressionBuildItem;
+import org.apache.camel.quarkus.support.language.deployment.ExpressionExtractionResultBuildItem;
+import org.apache.camel.quarkus.support.language.deployment.ScriptBuildItem;
+import org.apache.camel.quarkus.support.language.runtime.ExpressionUID;
+import org.apache.camel.quarkus.support.language.runtime.ScriptUID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.camel.quarkus.component.joor.runtime.JoorExpressionLanguage.PACKAGE_NAME;
+
+class JoorProcessor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JoorProcessor.class);
+    private static final String FEATURE = "camel-joor";
+
+    @BuildStep
+    FeatureBuildItem feature() {
+        return new FeatureBuildItem(FEATURE);
+    }
+
+    @BuildStep
+    void collectExpressions(JoorExpressionConfig config,
+            ExpressionExtractionResultBuildItem result,
+            List<ExpressionBuildItem> expressions,
+            List<ScriptBuildItem> scripts,
+            BuildProducer<JoorExpressionSourceBuildItem> producer) throws Exception {
+        if (result.isSuccess()) {
+            List<ExpressionBuildItem> joorExpressions = expressions.stream()
+                    .filter(exp -> "joor".equals(exp.getLanguage()))
+                    .collect(Collectors.toList());
+            List<ScriptBuildItem> joorScripts = scripts.stream()
+                    .filter(exp -> "joor".equals(exp.getLanguage()))
+                    .collect(Collectors.toList());
+            if (joorExpressions.isEmpty() && joorScripts.isEmpty()) {
+                return;
+            }
+            // Don't close it as it won't be started and some log entries are added on close/stop
+            CamelContext ctx = new DefaultCamelContext();
+            try (JoorExpressionLanguage language = new JoorExpressionLanguage()) {
+                language.setCamelContext(ctx);
+                language.setSingleQuotes(config.singleQuotes);
+                config.configResource.ifPresent(language::setConfigResource);
+                language.setPreCompile(false);
+                language.init();
+                JoorCompiler compiler = language.getJoorCompiler();
+                for (ExpressionBuildItem expression : joorExpressions) {
+                    JoorExpression exp = (JoorExpression) language.createExpression(expression.getExpression(),
+                            expression.getProperties());
+                    ExpressionUID id = new ExpressionUID(expression.getExpression(), exp.isSingleQuotes());
+                    String name = String.format("%s.%s", PACKAGE_NAME, id);
+                    String content = evalCode(compiler, ctx, name, expression.getExpression(), exp.isSingleQuotes());
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Compiling expression:\n\n{}\n", content);
+                    }
+                    producer.produce(new JoorExpressionSourceBuildItem(id, name, content));
+                }
+                JoorScriptingCompiler scriptingCompiler = language.getJoorScriptingCompiler();
+                for (ScriptBuildItem script : joorScripts) {
+                    ScriptUID id = new ScriptUID(script.getContent(), script.getBindings(), language.isSingleQuotes());
+                    String name = String.format("%s.%s", PACKAGE_NAME, id);
+                    String content = scriptingCompiler.evalCode(ctx, name, script.getContent(), script.getBindings(),
+                            language.isSingleQuotes());
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Compiling script:\n\n{}\n", content);
+                    }
+                    producer.produce(new JoorExpressionSourceBuildItem(id, name, content));
+                }
+            }
+        }
+    }
+
+    @BuildStep
+    void compileExpressions(CurateOutcomeBuildItem curateOutcomeBuildItem,
+            List<JoorExpressionSourceBuildItem> sources,
+            BuildProducer<GeneratedClassBuildItem> generatedClass) {
+        if (sources.isEmpty()) {
+            return;
+        }
+        CompilationUnit unit = CompilationUnit.input();
+        for (JoorExpressionSourceBuildItem source : sources) {
+            unit.addClass(source.getClassName(), source.getSourceCode());
+        }
+        // Temporary workaround until being able to provide the classpath somehow to the method MultiCompile.compileUnit
+        // https://issues.apache.org/jira/browse/CAMEL-18860
+        String previousCP = System.getProperty("java.class.path");
+        try {
+            ApplicationModel model = curateOutcomeBuildItem.getApplicationModel();
+            List<ResolvedDependency> dependencies = new ArrayList<>(model.getDependencies());
+            dependencies.add(model.getAppArtifact());
+            String cp = dependencies.stream()
+                    .map(ResolvedDependency::getResolvedPaths)
+                    .flatMap(PathCollection::stream)
+                    .map(Objects::toString)
+                    .collect(Collectors.joining(System.getProperty("path.separator")));
+            System.setProperty("java.class.path", cp);
+            LOG.debug("Compiling unit: {}", unit);
+            CompilationUnit.Result compilationResult = MultiCompile.compileUnit(unit);
+            for (String className : compilationResult.getClassNames()) {
+                generatedClass
+                        .produce(
+                                new GeneratedClassBuildItem(true, className, compilationResult.getByteCode(className)));
+            }
+        } finally {
+            // Restore the CP
+            System.setProperty("java.class.path", previousCP);
+        }
+    }
+
+    @Record(ExecutionTime.STATIC_INIT)
+    @BuildStep
+    @Consume(CamelContextBuildItem.class)
+    CamelBeanBuildItem configureLanguage(
+            JoorExpressionConfig config,
+            RecorderContext recorderContext,
+            JoorExpressionRecorder recorder,
+            CamelContextBuildItem context,
+            ExpressionExtractionResultBuildItem result,
+            List<JoorExpressionSourceBuildItem> sources) {
+
+        if (result.isSuccess() && !sources.isEmpty()) {
+            final RuntimeValue<JoorExpressionCompiler.Builder> expressionCompilerBuilder = recorder
+                    .expressionCompilerBuilder();
+            final RuntimeValue<JoorExpressionScriptingCompiler.Builder> expressionScriptingCompilerBuilder = recorder
+                    .expressionScriptingCompilerBuilder();
+            RuntimeValue<CamelContext> camelContext = context.getCamelContext();
+            for (JoorExpressionSourceBuildItem source : sources) {
+                if (source.isScript()) {
+                    recorder.addScript(expressionScriptingCompilerBuilder, camelContext, source.getId(),
+                            recorderContext.classProxy(source.getClassName()));
+                } else {
+                    recorder.addExpression(expressionCompilerBuilder, camelContext, source.getId(),
+                            recorderContext.classProxy(source.getClassName()));
+                }
+            }
+            final RuntimeValue<JoorExpressionLanguage> language = recorder.languageNewInstance(config);
+            config.resultType.ifPresent(c -> recorder.setResultType(language, recorderContext.classProxy(c)));
+            recorder.setJoorCompiler(language, expressionCompilerBuilder);
+            recorder.setJoorScriptingCompiler(language, expressionScriptingCompilerBuilder);
+            return new CamelBeanBuildItem("joor", JoorExpressionLanguage.class.getName(), language);
+        }
+        return null;
+    }
+
+    /**
+     * @return the code generated by the {@link JoorCompiler} to compile.
+     */
+    private String evalCode(JoorCompiler compiler, CamelContext camelContext, String fqn, String script, boolean singleQuotes) {
+        // Use reflection as temporary workaround since it is not yet possible
+        // Will be fixed by https://issues.apache.org/jira/browse/CAMEL-18977
+        try {
+            Method m = JoorCompiler.class.getDeclaredMethod("evalCode", CamelContext.class, String.class, String.class,
+                    boolean.class);
+            m.setAccessible(true);
+            return (String) m.invoke(compiler, camelContext, fqn, script, singleQuotes);
+        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+            throw new RuntimeException("Cannot extract the generated code from the compiler", e);
+        }
+    }
+}
diff --git a/extensions-jvm/joor/pom.xml b/extensions/joor/pom.xml
similarity index 96%
rename from extensions-jvm/joor/pom.xml
rename to extensions/joor/pom.xml
index f6fff9c0c5..16150b6644 100644
--- a/extensions-jvm/joor/pom.xml
+++ b/extensions/joor/pom.xml
@@ -21,7 +21,7 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.camel.quarkus</groupId>
-        <artifactId>camel-quarkus-extensions-jvm</artifactId>
+        <artifactId>camel-quarkus-extensions</artifactId>
         <version>2.17.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
diff --git a/extensions-jvm/joor/runtime/pom.xml b/extensions/joor/runtime/pom.xml
similarity index 94%
rename from extensions-jvm/joor/runtime/pom.xml
rename to extensions/joor/runtime/pom.xml
index 757f156566..d396d4c041 100644
--- a/extensions-jvm/joor/runtime/pom.xml
+++ b/extensions/joor/runtime/pom.xml
@@ -32,6 +32,7 @@
 
     <properties>
         <camel.quarkus.jvmSince>2.0.0</camel.quarkus.jvmSince>
+        <camel.quarkus.nativeSince>2.17.0</camel.quarkus.nativeSince>
     </properties>
 
     <dependencies>
@@ -39,6 +40,10 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-support-language</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-joor</artifactId>
diff --git a/extensions/joor/runtime/src/main/doc/configuration.adoc b/extensions/joor/runtime/src/main/doc/configuration.adoc
new file mode 100644
index 0000000000..da6bd881a5
--- /dev/null
+++ b/extensions/joor/runtime/src/main/doc/configuration.adoc
@@ -0,0 +1,3 @@
+The expressions and scripts written using the jOOR language are extracted and compiled at build time, to do so the
+language needs to be instantiated and configured at build time in order to be able to generate the exact same source code as
+the one generated at runtime. For this purpose, the next configuration properties have been added:
diff --git a/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionCompiler.java b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionCompiler.java
new file mode 100644
index 0000000000..258f799267
--- /dev/null
+++ b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionCompiler.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.joor.runtime;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.language.joor.JoorCompiler;
+import org.apache.camel.language.joor.JoorMethod;
+import org.apache.camel.quarkus.support.language.runtime.ExpressionUID;
+
+/**
+ * {@code JoorExpressionCompiler} is a jOOR compiler with all the {@link JoorMethod}s defined ahead of time and ready to
+ * use at runtime.
+ * <p>
+ * In case a requested expression is unknown, the compilation is delegated to the parent class which implies that it
+ * will only work in JVM mode.
+ */
+public class JoorExpressionCompiler extends JoorCompiler {
+
+    private final Map<String, JoorMethod> methods;
+
+    private JoorExpressionCompiler(Map<String, JoorMethod> methods) {
+        this.methods = Collections.unmodifiableMap(methods);
+    }
+
+    @Override
+    public JoorMethod compile(CamelContext camelContext, String script, boolean singleQuotes) {
+        final JoorMethod method = methods.get(new ExpressionUID(script, singleQuotes).toString());
+        if (method == null) {
+            return super.compile(camelContext, script, singleQuotes);
+        }
+        return method;
+    }
+
+    public static class Builder {
+
+        private final Map<String, JoorMethod> methods = new HashMap<>();
+
+        public void addExpression(String id, JoorMethod method) {
+            methods.put(id, method);
+        }
+
+        public JoorExpressionCompiler build() {
+            return new JoorExpressionCompiler(methods);
+        }
+    }
+}
diff --git a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionConfig.java
similarity index 50%
copy from extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
copy to extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionConfig.java
index b3e7d52dae..62f7d2ad3c 100644
--- a/extensions-support/language/deployment/src/main/java/org/apache/camel/quarkus/support/language/deployment/ExpressionBuildItem.java
+++ b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionConfig.java
@@ -14,35 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.quarkus.support.language.deployment;
+package org.apache.camel.quarkus.component.joor.runtime;
 
-import io.quarkus.builder.item.MultiBuildItem;
+import java.util.Optional;
+
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
 
 /**
- * {@code ExpressionBuildItem} represents an expression in a given language that has been extracted from the route
- * definitions.
+ * Build time configuration options for the Camel jOOR language.
  */
-public final class ExpressionBuildItem extends MultiBuildItem {
-
-    final String language;
-    final String expression;
-    final boolean predicate;
-
-    public ExpressionBuildItem(String language, String expression, boolean predicate) {
-        this.language = language;
-        this.expression = expression;
-        this.predicate = predicate;
-    }
+@ConfigRoot(name = "camel.joor", phase = ConfigPhase.BUILD_TIME)
+public class JoorExpressionConfig {
 
-    public String getLanguage() {
-        return language;
-    }
+    /** Indicates whether a jOOR expression can use single quotes instead of double quotes. */
+    @ConfigItem(defaultValue = "true")
+    public boolean singleQuotes;
 
-    public String getExpression() {
-        return expression;
-    }
+    /** The specific location of the configuration of the jOOR language. */
+    public Optional<String> configResource;
 
-    public boolean isPredicate() {
-        return predicate;
-    }
+    /** The specific default result type of an expression expressed in jOOR language. */
+    public Optional<String> resultType;
 }
diff --git a/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionLanguage.java b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionLanguage.java
new file mode 100644
index 0000000000..69a15d7e1e
--- /dev/null
+++ b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionLanguage.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.quarkus.component.joor.runtime;
+
+import java.lang.reflect.Field;
+
+import org.apache.camel.language.joor.JoorCompiler;
+import org.apache.camel.language.joor.JoorLanguage;
+import org.apache.camel.language.joor.JoorScriptingCompiler;
+
+/**
+ * {@code JoorExpressionLanguage} is a jOOR language which uses a specific jOOR compiler and jOOR scripting compiler
+ * that can be preloaded during the static initialization phase.
+ */
+public class JoorExpressionLanguage extends JoorLanguage {
+
+    public static final String PACKAGE_NAME = "org.apache.camel.quarkus.component.joor.generated";
+
+    public JoorCompiler getJoorCompiler() {
+        // Use reflection as temporary workaround since it is not yet possible
+        // Will be fixed by https://issues.apache.org/jira/browse/CAMEL-18977
+        try {
+            Field f = JoorLanguage.class.getDeclaredField("compiler");
+            f.setAccessible(true);
+            return (JoorCompiler) f.get(this);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new RuntimeException("Cannot extract the compiler from the language", e);
+        }
+    }
+
+    public void setJoorCompiler(JoorCompiler compiler) {
+        // Use reflection as temporary workaround since it is not yet possible
+        // Will be fixed by https://issues.apache.org/jira/browse/CAMEL-18977
+        try {
+            Field f = JoorLanguage.class.getDeclaredField("compiler");
+            f.setAccessible(true);
+            f.set(this, compiler);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new RuntimeException("Cannot set the compiler to the language", e);
+        }
+    }
+
+    public JoorScriptingCompiler getJoorScriptingCompiler() {
+        // Use reflection as temporary workaround since it is not yet possible
+        // Will be fixed by https://issues.apache.org/jira/browse/CAMEL-18977
+        try {
+            Field f = JoorLanguage.class.getDeclaredField("scriptingCompiler");
+            f.setAccessible(true);
+            return (JoorScriptingCompiler) f.get(this);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new RuntimeException("Cannot extract the scripting compiler from the language", e);
+        }
+    }
+
+    public void setJoorScriptingCompiler(JoorScriptingCompiler compiler) {
+        // Use reflection as temporary workaround since it is not yet possible
+        // Will be fixed by https://issues.apache.org/jira/browse/CAMEL-18977
+        try {
+            Field f = JoorLanguage.class.getDeclaredField("scriptingCompiler");
+            f.setAccessible(true);
+            f.set(this, compiler);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            throw new RuntimeException("Cannot set the scripting compiler to the language", e);
+        }
+    }
+}
diff --git a/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionRecorder.java b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionRecorder.java
new file mode 100644
index 0000000000..3d0b301fae
--- /dev/null
+++ b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionRecorder.java
@@ -0,0 +1,77 @@
+/*
+ * 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.quarkus.component.joor.runtime;
+
+import io.quarkus.runtime.RuntimeValue;
+import io.quarkus.runtime.annotations.Recorder;
+import org.apache.camel.CamelContext;
+import org.apache.camel.language.joor.JoorMethod;
+import org.apache.camel.language.joor.JoorScriptingMethod;
+
+@Recorder
+public class JoorExpressionRecorder {
+
+    public RuntimeValue<JoorExpressionLanguage> languageNewInstance(JoorExpressionConfig config) {
+        RuntimeValue<JoorExpressionLanguage> language = new RuntimeValue<>(new JoorExpressionLanguage());
+        language.getValue().setSingleQuotes(config.singleQuotes);
+        config.configResource.ifPresent(language.getValue()::setConfigResource);
+        return language;
+    }
+
+    public void setResultType(RuntimeValue<JoorExpressionLanguage> language, Class<?> resultType) {
+        language.getValue().setResultType(resultType);
+    }
+
+    public RuntimeValue<JoorExpressionCompiler.Builder> expressionCompilerBuilder() {
+        return new RuntimeValue<>(new JoorExpressionCompiler.Builder());
+    }
+
+    public RuntimeValue<JoorExpressionScriptingCompiler.Builder> expressionScriptingCompilerBuilder() {
+        return new RuntimeValue<>(new JoorExpressionScriptingCompiler.Builder());
+    }
+
+    public void addExpression(RuntimeValue<JoorExpressionCompiler.Builder> builder, RuntimeValue<CamelContext> ctx, String id,
+            Class<?> clazz) {
+        try {
+            builder.getValue().addExpression(id,
+                    (JoorMethod) clazz.getConstructor(CamelContext.class).newInstance(ctx.getValue()));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void addScript(RuntimeValue<JoorExpressionScriptingCompiler.Builder> builder, RuntimeValue<CamelContext> ctx,
+            String id,
+            Class<?> clazz) {
+        try {
+            builder.getValue().addScript(id,
+                    (JoorScriptingMethod) clazz.getConstructor(CamelContext.class).newInstance(ctx.getValue()));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public void setJoorCompiler(RuntimeValue<JoorExpressionLanguage> language,
+            RuntimeValue<JoorExpressionCompiler.Builder> builder) {
+        language.getValue().setJoorCompiler(builder.getValue().build());
+    }
+
+    public void setJoorScriptingCompiler(RuntimeValue<JoorExpressionLanguage> language,
+            RuntimeValue<JoorExpressionScriptingCompiler.Builder> builder) {
+        language.getValue().setJoorScriptingCompiler(builder.getValue().build());
+    }
+}
diff --git a/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionScriptingCompiler.java b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionScriptingCompiler.java
new file mode 100644
index 0000000000..3cab6f584c
--- /dev/null
+++ b/extensions/joor/runtime/src/main/java/org/apache/camel/quarkus/component/joor/runtime/JoorExpressionScriptingCompiler.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.joor.runtime;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.language.joor.JoorScriptingCompiler;
+import org.apache.camel.language.joor.JoorScriptingMethod;
+import org.apache.camel.quarkus.support.language.runtime.ScriptUID;
+
+/**
+ * {@code JoorExpressionScriptingCompiler} is a jOOR scripting compiler with all the {@link JoorScriptingMethod}s
+ * defined ahead of time and ready to use at runtime.
+ * <p>
+ * In case a requested script is unknown, the compilation is delegated to the parent class which implies that it will
+ * only work in JVM mode.
+ */
+public class JoorExpressionScriptingCompiler extends JoorScriptingCompiler {
+
+    private final Map<String, JoorScriptingMethod> methods;
+
+    private JoorExpressionScriptingCompiler(Map<String, JoorScriptingMethod> methods) {
+        this.methods = Collections.unmodifiableMap(methods);
+    }
+
+    @Override
+    public JoorScriptingMethod compile(CamelContext camelContext, String script, Map<String, Object> bindings,
+            boolean singleQuotes) {
+        final JoorScriptingMethod method = methods.get(new ScriptUID(script, bindings, singleQuotes).toString());
+        if (method == null) {
+            return super.compile(camelContext, script, bindings, singleQuotes);
+        }
+        return method;
+    }
+
+    public static class Builder {
+        private final Map<String, JoorScriptingMethod> methods = new HashMap<>();
+
+        public void addScript(String id, JoorScriptingMethod method) {
+            methods.put(id, method);
+        }
+
+        public JoorExpressionScriptingCompiler build() {
+            return new JoorExpressionScriptingCompiler(methods);
+        }
+    }
+}
diff --git a/extensions-jvm/joor/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/joor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
similarity index 97%
rename from extensions-jvm/joor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
rename to extensions/joor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
index 24be3edff1..bed440b47e 100644
--- a/extensions-jvm/joor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
+++ b/extensions/joor/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -24,9 +24,8 @@
 name: "Camel jOOR"
 description: "Evaluate a jOOR (Java compiled once at runtime) expression language"
 metadata:
-  unlisted: true
   guide: "https://camel.apache.org/camel-quarkus/latest/reference/extensions/joor.html"
   categories:
   - "integration"
   status:
-  - "preview"
+  - "stable"
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 73e2e2eb07..fdce02e667 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -140,6 +140,7 @@
         <module>jms</module>
         <module>johnzon</module>
         <module>jolt</module>
+        <module>joor</module>
         <module>jpa</module>
         <module>jq</module>
         <module>js-dsl</module>
diff --git a/integration-tests-jvm/pom.xml b/integration-tests-jvm/pom.xml
index 600ed65140..8780201fb1 100644
--- a/integration-tests-jvm/pom.xml
+++ b/integration-tests-jvm/pom.xml
@@ -83,7 +83,6 @@
         <module>jgroups</module>
         <module>jgroups-raft</module>
         <module>jooq</module>
-        <module>joor</module>
         <module>json-patch</module>
         <module>jsonapi</module>
         <module>jt400</module>
diff --git a/integration-tests/csimple/pom.xml b/integration-tests/csimple/pom.xml
index e519b1676b..f03f7936c9 100644
--- a/integration-tests/csimple/pom.xml
+++ b/integration-tests/csimple/pom.xml
@@ -51,6 +51,14 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-yaml-dsl</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-kamelet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-bean</artifactId>
+        </dependency>
 
         <!-- test dependencies -->
         <dependency>
@@ -102,6 +110,19 @@
             </activation>
             <dependencies>
                 <!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-bean-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
                 <dependency>
                     <groupId>org.apache.camel.quarkus</groupId>
                     <artifactId>camel-quarkus-csimple-deployment</artifactId>
@@ -128,6 +149,19 @@
                         </exclusion>
                     </exclusions>
                 </dependency>
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-kamelet-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
                 <dependency>
                     <groupId>org.apache.camel.quarkus</groupId>
                     <artifactId>camel-quarkus-xml-io-dsl-deployment</artifactId>
diff --git a/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleResource.java b/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleResource.java
index f836df6792..da2168f574 100644
--- a/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleResource.java
+++ b/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleResource.java
@@ -19,6 +19,7 @@ package org.apache.camel.quarkus.component.csimple.it;
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
 import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
@@ -41,6 +42,12 @@ public class CSimpleResource {
         return producerTemplate.requestBody("direct:csimple-hello", body, String.class);
     }
 
+    @GET
+    @Path("/csimple-hi")
+    public String hi() {
+        return producerTemplate.requestBody("direct:csimple-hi", null, String.class);
+    }
+
     @Path("/csimple-xml-dsl")
     @POST
     @Consumes(MediaType.TEXT_PLAIN)
@@ -56,4 +63,12 @@ public class CSimpleResource {
     public String csimpleYamlDsl(String body) {
         return producerTemplate.requestBody("direct:csimple-yaml-dsl", body, String.class);
     }
+
+    @POST
+    @Path("/predicate")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String predicate(String message) {
+        return producerTemplate.requestBody("direct:predicate", message, String.class);
+    }
 }
diff --git a/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java b/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java
index 10b76c445b..4c6d4c3878 100644
--- a/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java
+++ b/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java
@@ -21,9 +21,23 @@ import org.apache.camel.builder.RouteBuilder;
 public class CSimpleRoute extends RouteBuilder {
 
     @Override
-    public void configure() throws Exception {
+    public void configure() {
+        routeTemplate("whereTo")
+                .templateParameter("bar")
+                .templateBean("myBar", String.class, "csimple", "Hi")
+                .from("kamelet:source")
+                .to("bean:{{myBar}}?method=toString")
+                .setBody().csimple("${body} {{bar}}");
+        from("direct:csimple-hi")
+                .kamelet("whereTo?bar=Bill");
         from("direct:csimple-hello")
                 .setBody().csimple("Hello ${body}");
+        from("direct:predicate")
+                .choice()
+                .when().csimple("${body} > 10")
+                .setBody().constant("High").endChoice()
+                .otherwise()
+                .setBody().constant("Low").endChoice();
     }
 
 }
diff --git a/integration-tests/csimple/src/main/resources/META-INF/native-image/reflect-config.json b/integration-tests/csimple/src/main/resources/META-INF/native-image/reflect-config.json
new file mode 100644
index 0000000000..fafb144bfe
--- /dev/null
+++ b/integration-tests/csimple/src/main/resources/META-INF/native-image/reflect-config.json
@@ -0,0 +1,6 @@
+[
+  {
+    "name" : "java.lang.String",
+    "allPublicMethods" : true
+  }
+]
diff --git a/integration-tests/csimple/src/test/java/org/apache/camel/quarkus/component/csimple/it/CSimpleTest.java b/integration-tests/csimple/src/test/java/org/apache/camel/quarkus/component/csimple/it/CSimpleTest.java
index 1a4fd2e94d..056c4482aa 100644
--- a/integration-tests/csimple/src/test/java/org/apache/camel/quarkus/component/csimple/it/CSimpleTest.java
+++ b/integration-tests/csimple/src/test/java/org/apache/camel/quarkus/component/csimple/it/CSimpleTest.java
@@ -19,6 +19,7 @@ package org.apache.camel.quarkus.component.csimple.it;
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
 import io.restassured.http.ContentType;
+import org.hamcrest.CoreMatchers;
 import org.junit.jupiter.api.Test;
 
 import static org.hamcrest.Matchers.is;
@@ -36,6 +37,14 @@ class CSimpleTest {
                 .body(is("Hello Joe"));
     }
 
+    @Test
+    void csimpleHi() {
+        RestAssured.given()
+                .get("/csimple/csimple-hi")
+                .then()
+                .body(is("Hi Bill"));
+    }
+
     @Test
     void csimpleXml() {
         RestAssured.given()
@@ -56,4 +65,23 @@ class CSimpleTest {
                 .body(is("Bonjour John"));
     }
 
+    @Test
+    void csimpleHigh() {
+        RestAssured.given()
+                .body("15")
+                .post("/csimple/predicate")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("High"));
+    }
+
+    @Test
+    void csimpleLow() {
+        RestAssured.given()
+                .body("3")
+                .post("/csimple/predicate")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("Low"));
+    }
 }
diff --git a/integration-tests-jvm/joor/pom.xml b/integration-tests/joor/pom.xml
similarity index 51%
rename from integration-tests-jvm/joor/pom.xml
rename to integration-tests/joor/pom.xml
index 0f363ecbc7..3dd6a0d8c6 100644
--- a/integration-tests-jvm/joor/pom.xml
+++ b/integration-tests/joor/pom.xml
@@ -35,6 +35,18 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-joor</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-direct</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-kamelet</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-bean</artifactId>
+        </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-resteasy</artifactId>
@@ -63,6 +75,32 @@
             </activation>
             <dependencies>
                 <!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-bean-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-direct-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
                 <dependency>
                     <groupId>org.apache.camel.quarkus</groupId>
                     <artifactId>camel-quarkus-joor-deployment</artifactId>
@@ -76,7 +114,47 @@
                         </exclusion>
                     </exclusions>
                 </dependency>
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-kamelet-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
             </dependencies>
         </profile>
+        <profile>
+            <id>native</id>
+            <activation>
+                <property>
+                    <name>native</name>
+                </property>
+            </activation>
+            <properties>
+                <quarkus.package.type>native</quarkus.package.type>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
 </project>
diff --git a/integration-tests-jvm/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorTest.java b/integration-tests/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorBean.java
similarity index 71%
copy from integration-tests-jvm/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorTest.java
copy to integration-tests/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorBean.java
index 674a5b88ac..76e4ade47d 100644
--- a/integration-tests-jvm/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorTest.java
+++ b/integration-tests/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorBean.java
@@ -16,19 +16,15 @@
  */
 package org.apache.camel.quarkus.component.joor.it;
 
-import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.RestAssured;
-import org.junit.jupiter.api.Test;
+public class JoorBean {
 
-@QuarkusTest
-class JoorTest {
+    private String bar;
 
-    @Test
-    public void loadLanguageJoor() {
-        /* A simple autogenerated test */
-        RestAssured.get("/joor/load/language/joor")
-                .then()
-                .statusCode(200);
+    public void setBar(String bar) {
+        this.bar = bar;
     }
 
+    public String where(String name) {
+        return "Hi " + name + " we are going to " + bar;
+    }
 }
diff --git a/integration-tests-jvm/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorResource.java b/integration-tests/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorResource.java
similarity index 68%
rename from integration-tests-jvm/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorResource.java
rename to integration-tests/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorResource.java
index c472c74baf..0d82db413a 100644
--- a/integration-tests-jvm/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorResource.java
+++ b/integration-tests/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorResource.java
@@ -18,13 +18,16 @@ package org.apache.camel.quarkus.component.joor.it;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
+import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
+import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
 import org.apache.camel.CamelContext;
+import org.apache.camel.ProducerTemplate;
 import org.jboss.logging.Logger;
 
 @Path("/joor")
@@ -36,6 +39,8 @@ public class JoorResource {
     private static final String LANGUAGE_JOOR = "joor";
     @Inject
     CamelContext context;
+    @Inject
+    ProducerTemplate producerTemplate;
 
     @Path("/load/language/joor")
     @GET
@@ -48,4 +53,28 @@ public class JoorResource {
         LOG.warnf("Could not load [%s] from the Camel context", LANGUAGE_JOOR);
         return Response.status(500, LANGUAGE_JOOR + " could not be loaded from the Camel context").build();
     }
+
+    @POST
+    @Path("/hello")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String hello(String message) {
+        return producerTemplate.requestBody("direct:joorHello", message, String.class);
+    }
+
+    @POST
+    @Path("/hi")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String hi(String message) {
+        return producerTemplate.requestBody("direct:joorHi", message, String.class);
+    }
+
+    @POST
+    @Path("/predicate")
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String predicate(String message) {
+        return producerTemplate.requestBody("direct:predicate", Integer.valueOf(message), String.class);
+    }
 }
diff --git a/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java b/integration-tests/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorRoute.java
similarity index 52%
copy from integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java
copy to integration-tests/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorRoute.java
index 10b76c445b..801e29aeb2 100644
--- a/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java
+++ b/integration-tests/joor/src/main/java/org/apache/camel/quarkus/component/joor/it/JoorRoute.java
@@ -14,16 +14,30 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.quarkus.component.csimple.it;
+package org.apache.camel.quarkus.component.joor.it;
 
 import org.apache.camel.builder.RouteBuilder;
 
-public class CSimpleRoute extends RouteBuilder {
+public class JoorRoute extends RouteBuilder {
 
     @Override
-    public void configure() throws Exception {
-        from("direct:csimple-hello")
-                .setBody().csimple("Hello ${body}");
-    }
+    public void configure() {
+        routeTemplate("whereTo")
+                .templateParameter("bar")
+                .templateBean("myBar", "joor", "resource:classpath:bean.joor")
+                .from("kamelet:source")
+                .to("bean:{{myBar}}");
+
+        from("direct:joorHi")
+                .kamelet("whereTo?bar=Shamrock");
 
+        from("direct:joorHello")
+                .transform().joor("'Hello ' + body + ' from jOOR!'");
+        from("direct:predicate")
+                .choice()
+                .when().joor("((int) body) / 2 > 10")
+                .setBody().constant("High").endChoice()
+                .otherwise()
+                .setBody().constant("Low").endChoice();
+    }
 }
diff --git a/integration-tests/joor/src/main/resources/META-INF/native-image/reflect-config.json b/integration-tests/joor/src/main/resources/META-INF/native-image/reflect-config.json
new file mode 100644
index 0000000000..b094205e09
--- /dev/null
+++ b/integration-tests/joor/src/main/resources/META-INF/native-image/reflect-config.json
@@ -0,0 +1,6 @@
+[
+  {
+    "name" : "org.apache.camel.quarkus.component.joor.it.JoorBean",
+    "allPublicMethods" : true
+  }
+]
diff --git a/integration-tests/joor/src/main/resources/bean.joor b/integration-tests/joor/src/main/resources/bean.joor
new file mode 100644
index 0000000000..b0ec3042a0
--- /dev/null
+++ b/integration-tests/joor/src/main/resources/bean.joor
@@ -0,0 +1,4 @@
+var bean = new org.apache.camel.quarkus.component.joor.it.JoorBean();
+// rtc is RouteTemplateContext
+bean.setBar(rtc.getProperty('bar', String.class));
+return bean;
diff --git a/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java b/integration-tests/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorIT.java
similarity index 72%
copy from integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java
copy to integration-tests/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorIT.java
index 10b76c445b..7892e0f0e4 100644
--- a/integration-tests/csimple/src/main/java/org/apache/camel/quarkus/component/csimple/it/CSimpleRoute.java
+++ b/integration-tests/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorIT.java
@@ -14,16 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.quarkus.component.csimple.it;
+package org.apache.camel.quarkus.component.joor.it;
 
-import org.apache.camel.builder.RouteBuilder;
+import io.quarkus.test.junit.QuarkusIntegrationTest;
 
-public class CSimpleRoute extends RouteBuilder {
-
-    @Override
-    public void configure() throws Exception {
-        from("direct:csimple-hello")
-                .setBody().csimple("Hello ${body}");
-    }
+@QuarkusIntegrationTest
+class JoorIT extends JoorTest {
 
 }
diff --git a/integration-tests-jvm/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorTest.java b/integration-tests/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorTest.java
similarity index 52%
rename from integration-tests-jvm/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorTest.java
rename to integration-tests/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorTest.java
index 674a5b88ac..90846296d0 100644
--- a/integration-tests-jvm/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorTest.java
+++ b/integration-tests/joor/src/test/java/org/apache/camel/quarkus/component/joor/it/JoorTest.java
@@ -18,17 +18,57 @@ package org.apache.camel.quarkus.component.joor.it;
 
 import io.quarkus.test.junit.QuarkusTest;
 import io.restassured.RestAssured;
+import org.hamcrest.CoreMatchers;
 import org.junit.jupiter.api.Test;
 
 @QuarkusTest
 class JoorTest {
 
     @Test
-    public void loadLanguageJoor() {
+    void loadLanguageJoor() {
         /* A simple autogenerated test */
         RestAssured.get("/joor/load/language/joor")
                 .then()
                 .statusCode(200);
     }
 
+    @Test
+    void joorHello() {
+        RestAssured.given()
+                .body("Bruce Smith")
+                .post("/joor/hello")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("Hello Bruce Smith from jOOR!"));
+    }
+
+    @Test
+    void joorHi() {
+        RestAssured.given()
+                .body("Jack")
+                .post("/joor/hi")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("Hi Jack we are going to Shamrock"));
+    }
+
+    @Test
+    void joorHigh() {
+        RestAssured.given()
+                .body("45")
+                .post("/joor/predicate")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("High"));
+    }
+
+    @Test
+    void joorLow() {
+        RestAssured.given()
+                .body("13")
+                .post("/joor/predicate")
+                .then()
+                .statusCode(200)
+                .body(CoreMatchers.is("Low"));
+    }
 }
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index d1915df7ef..cd44de181a 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -123,6 +123,7 @@
         <module>jms-artemis-client</module>
         <module>jms-qpid-amqp-client</module>
         <module>jolt</module>
+        <module>joor</module>
         <module>jpa</module>
         <module>jq</module>
         <module>js-dsl</module>
diff --git a/tooling/scripts/test-categories.yaml b/tooling/scripts/test-categories.yaml
index 304ace2eed..c49f08e346 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -184,6 +184,7 @@ group-11:
 group-12:
   - aws2-grouped
   - csimple
+  - joor
   - quartz-clustered
   - knative
   - knative-channel-consumer