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

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


The following commit(s) were added to refs/heads/main by this push:
     new bd4549977db6 CAMEL-22894: Extract Simple functions into dedicated 
factories
bd4549977db6 is described below

commit bd4549977db65dc4cb928e7cce978eef2dce6e41
Author: Adriano Machado <[email protected]>
AuthorDate: Wed May 27 02:12:16 2026 -0400

    CAMEL-22894: Extract Simple functions into dedicated factories
    
    Extract six more function families from the monolithic
    SimpleFunctionExpression into dedicated SimpleLanguageFunctionFactory
    implementations: SystemFunctionFactory (sys/env), DateFunctionFactory,
    PropertiesFunctionFactory (properties/ref), TypeFunctionFactory,
    MessageFunctionFactory, and OutputFunctionFactory (pretty/toJson).
    Remove unused deprecated tryCreate() and tryCreateCode() methods.
    Tests moved to per-factory test classes.
    
    Closes #23544
---
 .../language/simple/SimpleFunctionDispatcher.java  |  40 +--
 .../simple/ast/SimpleFunctionExpression.java       | 239 ------------------
 .../simple/functions/DateFunctionFactory.java      |  87 +++++++
 .../simple/functions/MessageFunctionFactory.java   |  58 +++++
 .../simple/functions/OutputFunctionFactory.java    |  71 ++++++
 .../functions/PropertiesFunctionFactory.java       |  85 +++++++
 .../simple/functions/SystemFunctionFactory.java    |  80 ++++++
 .../simple/functions/TypeFunctionFactory.java      |  64 +++++
 core/camel-core/pom.xml                            |   6 +
 .../apache/camel/language/simple/SimpleTest.java   | 267 ---------------------
 .../simple/functions/DateFunctionFactoryTest.java  | 158 ++++++++++++
 .../functions/MessageFunctionFactoryTest.java      |  58 +++++
 .../functions/OutputFunctionFactoryTest.java       |  88 +++++++
 .../functions/PropertiesFunctionFactoryTest.java   |  95 ++++++++
 .../functions/SystemFunctionFactoryTest.java       | 105 ++++++++
 .../simple/functions/TypeFunctionFactoryTest.java  |  73 ++++++
 16 files changed, 1041 insertions(+), 533 deletions(-)

diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
index 2080ac72c648..3f5c2256a6a4 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleFunctionDispatcher.java
@@ -24,13 +24,19 @@ import org.apache.camel.Expression;
 import org.apache.camel.language.simple.functions.BodyFunctionFactory;
 import org.apache.camel.language.simple.functions.CollateFunctionFactory;
 import org.apache.camel.language.simple.functions.CollectionFunctionFactory;
+import org.apache.camel.language.simple.functions.DateFunctionFactory;
 import org.apache.camel.language.simple.functions.HeaderFunctionFactory;
 import org.apache.camel.language.simple.functions.JoinFunctionFactory;
 import org.apache.camel.language.simple.functions.MathFunctionFactory;
+import org.apache.camel.language.simple.functions.MessageFunctionFactory;
 import org.apache.camel.language.simple.functions.MiscFunctionFactory;
+import org.apache.camel.language.simple.functions.OutputFunctionFactory;
+import org.apache.camel.language.simple.functions.PropertiesFunctionFactory;
 import org.apache.camel.language.simple.functions.RandomFunctionFactory;
 import org.apache.camel.language.simple.functions.SkipFunctionFactory;
 import org.apache.camel.language.simple.functions.StringFunctionFactory;
+import org.apache.camel.language.simple.functions.SystemFunctionFactory;
+import org.apache.camel.language.simple.functions.TypeFunctionFactory;
 import org.apache.camel.language.simple.functions.VariableFunctionFactory;
 import org.apache.camel.spi.SimpleLanguageFunctionFactory;
 import org.apache.camel.support.ResolverHelper;
@@ -65,7 +71,13 @@ public final class SimpleFunctionDispatcher {
             new MathFunctionFactory(),
             new StringFunctionFactory(),
             new CollectionFunctionFactory(),
-            new MiscFunctionFactory());
+            new MiscFunctionFactory(),
+            new SystemFunctionFactory(),
+            new PropertiesFunctionFactory(),
+            new TypeFunctionFactory(),
+            new DateFunctionFactory(),
+            new MessageFunctionFactory(),
+            new OutputFunctionFactory());
 
     private static final List<Entry> EXPRESSION_ENTRIES = List.of(
             new Entry("camel-attachments", 
SimpleFunctionDispatcher::isAttachmentFunction),
@@ -83,19 +95,6 @@ public final class SimpleFunctionDispatcher {
     private SimpleFunctionDispatcher() {
     }
 
-    /**
-     * Migrated as-is from main; not currently called. Candidate for removal 
once all Simple functions are extracted
-     * into dedicated {@link SimpleLanguageFunctionFactory} implementations 
(CAMEL-22894).
-     */
-    @Deprecated(forRemoval = true)
-    public static Expression tryCreate(CamelContext camelContext, String 
function, int index) {
-        Expression answer = tryCreateBuiltIn(camelContext, function, index);
-        if (answer != null) {
-            return answer;
-        }
-        return tryCreateExternal(camelContext, function, index);
-    }
-
     public static Expression tryCreateBuiltIn(CamelContext camelContext, 
String function, int index) {
         for (SimpleLanguageFunctionFactory factory : BUILT_INS) {
             Expression answer = factory.createFunction(camelContext, function, 
index);
@@ -120,19 +119,6 @@ public final class SimpleFunctionDispatcher {
         return null;
     }
 
-    /**
-     * Migrated as-is from main; not currently called. Candidate for removal 
once all Simple functions are extracted
-     * into dedicated {@link SimpleLanguageFunctionFactory} implementations 
(CAMEL-22894).
-     */
-    @Deprecated(forRemoval = true)
-    public static String tryCreateCode(CamelContext camelContext, String 
function, int index) {
-        String code = tryCreateCodeBuiltIn(camelContext, function, index);
-        if (code != null) {
-            return code;
-        }
-        return tryCreateCodeExternal(camelContext, function, index);
-    }
-
     public static String tryCreateCodeBuiltIn(CamelContext camelContext, 
String function, int index) {
         for (SimpleLanguageFunctionFactory factory : BUILT_INS) {
             @SuppressWarnings("deprecation")
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index 5708f1850500..408897ceff38 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -112,12 +112,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return answer;
         }
 
-        // message first
-        answer = createSimpleExpressionMessage(camelContext, function, strict);
-        if (answer != null) {
-            return answer;
-        }
-
         // custom functions
         answer = createSimpleCustomFunction(camelContext, function, strict);
         if (answer != null) {
@@ -177,25 +171,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             }
         }
 
-        // system property
-        remainder = ifStartsWithReturnRemainder("sys.", function);
-        if (remainder != null) {
-            return ExpressionBuilder.systemPropertyExpression(remainder);
-        }
-        remainder = ifStartsWithReturnRemainder("sysenv.", function);
-        if (remainder == null) {
-            remainder = ifStartsWithReturnRemainder("sysenv:", function);
-        }
-        if (remainder == null) {
-            remainder = ifStartsWithReturnRemainder("env.", function);
-        }
-        if (remainder == null) {
-            remainder = ifStartsWithReturnRemainder("env:", function);
-        }
-        if (remainder != null) {
-            return ExpressionBuilder.systemEnvironmentExpression(remainder);
-        }
-
         // exchange OGNL
         remainder = ifStartsWithReturnRemainder("exchange", function);
         if (remainder != null) {
@@ -206,41 +181,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return SimpleExpressionBuilder.exchangeOgnlExpression(remainder);
         }
 
-        // pretty
-        remainder = ifStartsWithReturnRemainder("pretty(", function);
-        if (remainder != null) {
-            String exp = StringHelper.beforeLast(remainder, ")");
-            if (exp == null) {
-                throw new SimpleParserException("Valid syntax: ${pretty(exp)} 
was: " + function, token.getIndex());
-            }
-            exp = StringHelper.removeLeadingAndEndingQuotes(exp);
-            Expression inlined = 
camelContext.resolveLanguage("simple").createExpression(exp);
-            return ExpressionBuilder.prettyExpression(inlined);
-        }
-
-        // toJson
-        remainder = ifStartsWithReturnRemainder("toJson(", function);
-        if (remainder != null) {
-            String exp = StringHelper.beforeLast(remainder, ")");
-            if (exp == null) {
-                throw new SimpleParserException("Valid syntax: ${toJson(exp)} 
was: " + function, token.getIndex());
-            }
-            exp = StringHelper.removeLeadingAndEndingQuotes(exp);
-            Expression inlined = 
camelContext.resolveLanguage("simple").createExpression(exp);
-            return ExpressionBuilder.toJsonExpression(inlined, false);
-        }
-        // toPrettyJson
-        remainder = ifStartsWithReturnRemainder("toPrettyJson(", function);
-        if (remainder != null) {
-            String exp = StringHelper.beforeLast(remainder, ")");
-            if (exp == null) {
-                throw new SimpleParserException("Valid syntax: 
${toPrettyJson(exp)} was: " + function, token.getIndex());
-            }
-            exp = StringHelper.removeLeadingAndEndingQuotes(exp);
-            Expression inlined = 
camelContext.resolveLanguage("simple").createExpression(exp);
-            return ExpressionBuilder.toJsonExpression(inlined, true);
-        }
-
         // file: prefix
         remainder = ifStartsWithReturnRemainder("file:", function);
         if (remainder != null) {
@@ -256,28 +196,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             }
         }
 
-        // date: prefix
-        remainder = ifStartsWithReturnRemainder("date:", function);
-        if (remainder != null) {
-            String[] parts = remainder.split(":", 2);
-            if (parts.length == 1) {
-                return SimpleExpressionBuilder.dateExpression(parts[0]);
-            } else if (parts.length == 2) {
-                return SimpleExpressionBuilder.dateExpression(parts[0], 
parts[1]);
-            }
-        }
-
-        // date-with-timezone: prefix
-        remainder = ifStartsWithReturnRemainder("date-with-timezone:", 
function);
-        if (remainder != null) {
-            String[] parts = remainder.split(":", 3);
-            if (parts.length < 3) {
-                throw new SimpleParserException(
-                        "Valid syntax: 
${date-with-timezone:command:timezone:pattern} was: " + function, 
token.getIndex());
-            }
-            return SimpleExpressionBuilder.dateExpression(parts[0], parts[1], 
parts[2]);
-        }
-
         // bean: prefix
         remainder = ifStartsWithReturnRemainder("bean:", function);
         if (remainder != null) {
@@ -333,51 +251,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return bean.createExpression(null, properties);
         }
 
-        // properties-exist: prefix
-        remainder = ifStartsWithReturnRemainder("propertiesExist:", function);
-        if (remainder != null) {
-            String[] parts = remainder.split(":", 2);
-            if (parts.length > 2) {
-                throw new SimpleParserException("Valid syntax: 
${propertiesExist:key} was: " + function, token.getIndex());
-            }
-            String key = parts[0];
-            boolean negate = key != null && key.startsWith("!");
-            if (negate) {
-                key = key.substring(1);
-            }
-            return ExpressionBuilder.propertiesComponentExist(key, negate);
-        }
-
-        // properties: prefix
-        remainder = ifStartsWithReturnRemainder("properties:", function);
-        if (remainder != null) {
-            String[] parts = remainder.split(":", 2);
-            if (parts.length > 2) {
-                throw new SimpleParserException("Valid syntax: 
${properties:key[:default]} was: " + function, token.getIndex());
-            }
-            String defaultValue = null;
-            if (parts.length >= 2) {
-                defaultValue = parts[1];
-            }
-            String key = parts[0];
-            return ExpressionBuilder.propertiesComponentExpression(key, 
defaultValue);
-        }
-
-        // ref: prefix
-        remainder = ifStartsWithReturnRemainder("ref:", function);
-        if (remainder != null) {
-            return ExpressionBuilder.refExpression(remainder);
-        }
-
-        // type: prefix
-        remainder = ifStartsWithReturnRemainder("type:", function);
-        if (remainder != null) {
-            Expression exp = SimpleExpressionBuilder.typeExpression(remainder);
-            exp.init(camelContext);
-            // we want to cache this expression, so we won't re-evaluate it as 
the type/constant won't change
-            return SimpleExpressionBuilder.cacheExpression(exp);
-        }
-
         // miscellaneous and other built-in functions
         Expression builtIn = 
SimpleFunctionDispatcher.tryCreateBuiltIn(camelContext, function, 
token.getIndex());
         if (builtIn != null) {
@@ -412,31 +285,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
         }
     }
 
-    private Expression createSimpleExpressionMessage(CamelContext 
camelContext, String function, boolean strict) {
-        // messageAs
-        String remainder = ifStartsWithReturnRemainder("messageAs(", function);
-        if (remainder != null) {
-            String type = StringHelper.before(remainder, ")");
-            if (type == null) {
-                throw new SimpleParserException("Valid syntax: 
${messageAs(type)} was: " + function, token.getIndex());
-            }
-            type = StringHelper.removeQuotes(type);
-            remainder = StringHelper.after(remainder, ")");
-
-            if (ObjectHelper.isNotEmpty(remainder)) {
-                boolean invalid = 
OgnlHelper.isInvalidValidOgnlExpression(remainder);
-                if (invalid) {
-                    throw new SimpleParserException("Valid syntax: 
${messageAs(type).OGNL} was: " + function, token.getIndex());
-                }
-                return SimpleExpressionBuilder.messageOgnlExpression(type, 
remainder);
-            } else {
-                return ExpressionBuilder.messageExpression(type);
-            }
-        }
-
-        return null;
-    }
-
     private Expression createSimpleCustomFunction(CamelContext camelContext, 
String function, boolean strict) {
         String remainder = ifStartsWithReturnRemainder("function(", function);
         if (remainder != null) {
@@ -657,25 +505,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return "exception(exchange)" + ognlCodeMethods(remainder, null);
         }
 
-        // system property
-        remainder = ifStartsWithReturnRemainder("sys.", function);
-        if (remainder != null) {
-            return "sys(\"" + remainder + "\")";
-        }
-        remainder = ifStartsWithReturnRemainder("sysenv.", function);
-        if (remainder == null) {
-            remainder = ifStartsWithReturnRemainder("sysenv:", function);
-        }
-        if (remainder == null) {
-            remainder = ifStartsWithReturnRemainder("env.", function);
-        }
-        if (remainder == null) {
-            remainder = ifStartsWithReturnRemainder("env:", function);
-        }
-        if (remainder != null) {
-            return "sysenv(\"" + remainder + "\")";
-        }
-
         // exchange OGNL
         remainder = ifStartsWithReturnRemainder("exchange", function);
         if (remainder != null) {
@@ -692,31 +521,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             return createCodeFileExpression(remainder);
         }
 
-        if ("date:millis".equals(function)) {
-            return "System.currentTimeMillis()";
-        }
-        // date: prefix
-        remainder = ifStartsWithReturnRemainder("date:", function);
-        if (remainder != null) {
-            String[] parts = remainder.split(":", 2);
-            if (parts.length == 1) {
-                return "date(exchange, \"" + parts[0] + "\")";
-            } else if (parts.length == 2) {
-                return "date(exchange, \"" + parts[0] + "\", null, \"" + 
parts[1] + "\")";
-            }
-        }
-
-        // date-with-timezone: prefix
-        remainder = ifStartsWithReturnRemainder("date-with-timezone:", 
function);
-        if (remainder != null) {
-            String[] parts = remainder.split(":", 3);
-            if (parts.length < 3) {
-                throw new SimpleParserException(
-                        "Valid syntax: 
${date-with-timezone:command:timezone:pattern} was: " + function, 
token.getIndex());
-            }
-            return "date(exchange, \"" + parts[0] + "\", \"" + parts[1] + "\", 
\"" + parts[2] + "\")";
-        }
-
         // bean: prefix
         remainder = ifStartsWithReturnRemainder("bean:", function);
         if (remainder != null) {
@@ -761,49 +565,6 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
             }
         }
 
-        // properties: prefix
-        remainder = ifStartsWithReturnRemainder("properties:", function);
-        if (remainder != null) {
-            String[] parts = remainder.split(":", 2);
-            if (parts.length > 2) {
-                throw new SimpleParserException("Valid syntax: 
${properties:key[:default]} was: " + function, token.getIndex());
-            }
-            String defaultValue = null;
-            if (parts.length >= 2) {
-                defaultValue = parts[1];
-            }
-            String key = parts[0];
-            key = key.trim();
-            if (defaultValue != null) {
-                return "properties(exchange, \"" + key + "\", \"" + 
defaultValue.trim() + "\")";
-            } else {
-                return "properties(exchange, \"" + key + "\")";
-            }
-        }
-
-        // ref: prefix
-        remainder = ifStartsWithReturnRemainder("ref:", function);
-        if (remainder != null) {
-            return "ref(exchange, \"" + remainder + "\")";
-        }
-
-        // type: prefix
-        remainder = ifStartsWithReturnRemainder("type:", function);
-        if (remainder != null) {
-            int pos = remainder.lastIndexOf('.');
-            String type = pos != -1 ? remainder.substring(0, pos) : remainder;
-            String field = pos != -1 ? remainder.substring(pos + 1) : null;
-            if (!type.endsWith(".class")) {
-                type += ".class";
-            }
-            type = type.replace('$', '.');
-            if (field != null) {
-                return "type(exchange, " + type + ", \"" + field + "\")";
-            } else {
-                return "type(exchange, " + type + ")";
-            }
-        }
-
         // miscellaneous and other built-in functions
         String builtIn = 
SimpleFunctionDispatcher.tryCreateCodeBuiltIn(camelContext, function, 
token.getIndex());
         if (builtIn != null) {
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/DateFunctionFactory.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/DateFunctionFactory.java
new file mode 100644
index 000000000000..25a41f131a67
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/DateFunctionFactory.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple.functions;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.language.simple.SimpleExpressionBuilder;
+import org.apache.camel.language.simple.types.SimpleParserException;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple functions for date/time: {@code ${date:command}}, {@code 
${date:command:pattern}},
+ * {@code ${date-with-timezone:command:timezone:pattern}}.
+ */
+public final class DateFunctionFactory implements 
SimpleLanguageFunctionFactory {
+
+    @Override
+    public Expression createFunction(CamelContext camelContext, String 
function, int index) {
+        String remainder = ifStartsWithReturnRemainder("date-with-timezone:", 
function);
+        if (remainder != null) {
+            String[] parts = remainder.split(":", 3);
+            if (parts.length < 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: 
${date-with-timezone:command:timezone:pattern} was: " + function, index);
+            }
+            return SimpleExpressionBuilder.dateExpression(parts[0], parts[1], 
parts[2]);
+        }
+
+        remainder = ifStartsWithReturnRemainder("date:", function);
+        if (remainder != null) {
+            String[] parts = remainder.split(":", 2);
+            if (parts.length == 1) {
+                return SimpleExpressionBuilder.dateExpression(parts[0]);
+            } else {
+                return SimpleExpressionBuilder.dateExpression(parts[0], 
parts[1]);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public String createCode(CamelContext camelContext, String function, int 
index) {
+        if ("date:millis".equals(function)) {
+            return "System.currentTimeMillis()";
+        }
+
+        String remainder = ifStartsWithReturnRemainder("date-with-timezone:", 
function);
+        if (remainder != null) {
+            String[] parts = remainder.split(":", 3);
+            if (parts.length < 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: 
${date-with-timezone:command:timezone:pattern} was: " + function, index);
+            }
+            return "date(exchange, \"" + parts[0] + "\", \"" + parts[1] + "\", 
\"" + parts[2] + "\")";
+        }
+
+        remainder = ifStartsWithReturnRemainder("date:", function);
+        if (remainder != null) {
+            String[] parts = remainder.split(":", 2);
+            if (parts.length == 1) {
+                return "date(exchange, \"" + parts[0] + "\")";
+            } else {
+                return "date(exchange, \"" + parts[0] + "\", null, \"" + 
parts[1] + "\")";
+            }
+        }
+
+        return null;
+    }
+}
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MessageFunctionFactory.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MessageFunctionFactory.java
new file mode 100644
index 000000000000..9d6c0ff6e7cd
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/MessageFunctionFactory.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.language.simple.functions;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.language.simple.SimpleExpressionBuilder;
+import org.apache.camel.language.simple.types.SimpleParserException;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.apache.camel.support.builder.ExpressionBuilder;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.OgnlHelper;
+import org.apache.camel.util.StringHelper;
+
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple function for typed message access: {@code 
${messageAs(type)}}, {@code ${messageAs(type).OGNL}}.
+ */
+public final class MessageFunctionFactory implements 
SimpleLanguageFunctionFactory {
+
+    @Override
+    public Expression createFunction(CamelContext camelContext, String 
function, int index) {
+        String remainder = ifStartsWithReturnRemainder("messageAs(", function);
+        if (remainder != null) {
+            String type = StringHelper.before(remainder, ")");
+            if (type == null) {
+                throw new SimpleParserException("Valid syntax: 
${messageAs(type)} was: " + function, index);
+            }
+            type = StringHelper.removeQuotes(type);
+            remainder = StringHelper.after(remainder, ")");
+            if (ObjectHelper.isNotEmpty(remainder)) {
+                boolean invalid = 
OgnlHelper.isInvalidValidOgnlExpression(remainder);
+                if (invalid) {
+                    throw new SimpleParserException("Valid syntax: 
${messageAs(type).OGNL} was: " + function, index);
+                }
+                return SimpleExpressionBuilder.messageOgnlExpression(type, 
remainder);
+            } else {
+                return ExpressionBuilder.messageExpression(type);
+            }
+        }
+        return null;
+    }
+}
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/OutputFunctionFactory.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/OutputFunctionFactory.java
new file mode 100644
index 000000000000..6f3d59b6b1e7
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/OutputFunctionFactory.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple.functions;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.language.simple.types.SimpleParserException;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.apache.camel.support.builder.ExpressionBuilder;
+import org.apache.camel.util.StringHelper;
+
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple functions for formatted output: {@code ${pretty(exp)}}, 
{@code ${toJson(exp)}},
+ * {@code ${toPrettyJson(exp)}}.
+ */
+public final class OutputFunctionFactory implements 
SimpleLanguageFunctionFactory {
+
+    @Override
+    public Expression createFunction(CamelContext camelContext, String 
function, int index) {
+        String remainder = ifStartsWithReturnRemainder("pretty(", function);
+        if (remainder != null) {
+            String exp = StringHelper.beforeLast(remainder, ")");
+            if (exp == null) {
+                throw new SimpleParserException("Valid syntax: ${pretty(exp)} 
was: " + function, index);
+            }
+            exp = StringHelper.removeLeadingAndEndingQuotes(exp);
+            Expression inlined = 
camelContext.resolveLanguage("simple").createExpression(exp);
+            return ExpressionBuilder.prettyExpression(inlined);
+        }
+
+        remainder = ifStartsWithReturnRemainder("toPrettyJson(", function);
+        if (remainder != null) {
+            String exp = StringHelper.beforeLast(remainder, ")");
+            if (exp == null) {
+                throw new SimpleParserException("Valid syntax: 
${toPrettyJson(exp)} was: " + function, index);
+            }
+            exp = StringHelper.removeLeadingAndEndingQuotes(exp);
+            Expression inlined = 
camelContext.resolveLanguage("simple").createExpression(exp);
+            return ExpressionBuilder.toJsonExpression(inlined, true);
+        }
+
+        remainder = ifStartsWithReturnRemainder("toJson(", function);
+        if (remainder != null) {
+            String exp = StringHelper.beforeLast(remainder, ")");
+            if (exp == null) {
+                throw new SimpleParserException("Valid syntax: ${toJson(exp)} 
was: " + function, index);
+            }
+            exp = StringHelper.removeLeadingAndEndingQuotes(exp);
+            Expression inlined = 
camelContext.resolveLanguage("simple").createExpression(exp);
+            return ExpressionBuilder.toJsonExpression(inlined, false);
+        }
+
+        return null;
+    }
+}
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/PropertiesFunctionFactory.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/PropertiesFunctionFactory.java
new file mode 100644
index 000000000000..ccbff2b776ce
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/PropertiesFunctionFactory.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple.functions;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.language.simple.types.SimpleParserException;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.apache.camel.support.builder.ExpressionBuilder;
+
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple functions for properties component and registry references: 
{@code ${propertiesExist:key}},
+ * {@code ${propertiesExist:!key}}, {@code ${properties:key}}, {@code 
${properties:key:default}}, {@code ${ref:name}}.
+ */
+public final class PropertiesFunctionFactory implements 
SimpleLanguageFunctionFactory {
+
+    @Override
+    public Expression createFunction(CamelContext camelContext, String 
function, int index) {
+        String remainder = ifStartsWithReturnRemainder("propertiesExist:", 
function);
+        if (remainder != null) {
+            String[] parts = remainder.split(":", 2);
+            String key = parts[0];
+            boolean negate = key != null && key.startsWith("!");
+            if (negate) {
+                key = key.substring(1);
+            }
+            return ExpressionBuilder.propertiesComponentExist(key, negate);
+        }
+
+        remainder = ifStartsWithReturnRemainder("properties:", function);
+        if (remainder != null) {
+            String[] parts = remainder.split(":", 2);
+            String defaultValue = parts.length >= 2 ? parts[1] : null;
+            return ExpressionBuilder.propertiesComponentExpression(parts[0], 
defaultValue);
+        }
+
+        remainder = ifStartsWithReturnRemainder("ref:", function);
+        if (remainder != null) {
+            return ExpressionBuilder.refExpression(remainder);
+        }
+
+        return null;
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public String createCode(CamelContext camelContext, String function, int 
index) {
+        String remainder = ifStartsWithReturnRemainder("properties:", 
function);
+        if (remainder != null) {
+            String[] parts = remainder.split(":", 2);
+            if (parts.length > 2) {
+                throw new SimpleParserException("Valid syntax: 
${properties:key[:default]} was: " + function, index);
+            }
+            String key = parts[0].trim();
+            if (parts.length >= 2) {
+                return "properties(exchange, \"" + key + "\", \"" + 
parts[1].trim() + "\")";
+            } else {
+                return "properties(exchange, \"" + key + "\")";
+            }
+        }
+
+        remainder = ifStartsWithReturnRemainder("ref:", function);
+        if (remainder != null) {
+            return "ref(exchange, \"" + remainder + "\")";
+        }
+
+        return null;
+    }
+}
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/SystemFunctionFactory.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/SystemFunctionFactory.java
new file mode 100644
index 000000000000..afd634d58347
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/SystemFunctionFactory.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.language.simple.functions;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.apache.camel.support.builder.ExpressionBuilder;
+
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple functions for system properties and environment variables: 
{@code ${sys.name}},
+ * {@code ${sysenv.name}}, {@code ${sysenv:name}}, {@code ${env.name}}, {@code 
${env:name}}.
+ */
+public final class SystemFunctionFactory implements 
SimpleLanguageFunctionFactory {
+
+    @Override
+    public Expression createFunction(CamelContext camelContext, String 
function, int index) {
+        String remainder = ifStartsWithReturnRemainder("sys.", function);
+        if (remainder != null) {
+            return ExpressionBuilder.systemPropertyExpression(remainder);
+        }
+
+        remainder = ifStartsWithReturnRemainder("sysenv.", function);
+        if (remainder == null) {
+            remainder = ifStartsWithReturnRemainder("sysenv:", function);
+        }
+        if (remainder == null) {
+            remainder = ifStartsWithReturnRemainder("env.", function);
+        }
+        if (remainder == null) {
+            remainder = ifStartsWithReturnRemainder("env:", function);
+        }
+        if (remainder != null) {
+            return ExpressionBuilder.systemEnvironmentExpression(remainder);
+        }
+
+        return null;
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public String createCode(CamelContext camelContext, String function, int 
index) {
+        String remainder = ifStartsWithReturnRemainder("sys.", function);
+        if (remainder != null) {
+            return "sys(\"" + remainder + "\")";
+        }
+
+        remainder = ifStartsWithReturnRemainder("sysenv.", function);
+        if (remainder == null) {
+            remainder = ifStartsWithReturnRemainder("sysenv:", function);
+        }
+        if (remainder == null) {
+            remainder = ifStartsWithReturnRemainder("env.", function);
+        }
+        if (remainder == null) {
+            remainder = ifStartsWithReturnRemainder("env:", function);
+        }
+        if (remainder != null) {
+            return "sysenv(\"" + remainder + "\")";
+        }
+
+        return null;
+    }
+}
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/TypeFunctionFactory.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/TypeFunctionFactory.java
new file mode 100644
index 000000000000..09151c9f63a1
--- /dev/null
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/functions/TypeFunctionFactory.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.language.simple.functions;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Expression;
+import org.apache.camel.language.simple.SimpleExpressionBuilder;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.appendClass;
+import static 
org.apache.camel.language.simple.SimpleFunctionHelper.ifStartsWithReturnRemainder;
+
+/**
+ * Built-in Simple function for type literal access: {@code ${type:fqn}}, 
{@code ${type:fqn.FIELD}}.
+ *
+ * <p>
+ * The expression is eagerly initialized and cached because type references 
are constant.
+ */
+public final class TypeFunctionFactory implements 
SimpleLanguageFunctionFactory {
+
+    @Override
+    public Expression createFunction(CamelContext camelContext, String 
function, int index) {
+        String remainder = ifStartsWithReturnRemainder("type:", function);
+        if (remainder != null) {
+            Expression exp = SimpleExpressionBuilder.typeExpression(remainder);
+            exp.init(camelContext);
+            return SimpleExpressionBuilder.cacheExpression(exp);
+        }
+        return null;
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public String createCode(CamelContext camelContext, String function, int 
index) {
+        String remainder = ifStartsWithReturnRemainder("type:", function);
+        if (remainder != null) {
+            int pos = remainder.lastIndexOf('.');
+            String type = pos != -1 ? remainder.substring(0, pos) : remainder;
+            String field = pos != -1 ? remainder.substring(pos + 1) : null;
+            type = appendClass(type);
+            type = type.replace('$', '.');
+            if (field != null) {
+                return "type(exchange, " + type + ", \"" + field + "\")";
+            } else {
+                return "type(exchange, " + type + ")";
+            }
+        }
+        return null;
+    }
+}
diff --git a/core/camel-core/pom.xml b/core/camel-core/pom.xml
index 2b0148d43e0d..7f5e87177061 100644
--- a/core/camel-core/pom.xml
+++ b/core/camel-core/pom.xml
@@ -250,6 +250,12 @@
             <artifactId>junit-jupiter-engine</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.junit-pioneer</groupId>
+            <artifactId>junit-pioneer</artifactId>
+            <version>${junit-pioneer-version}</version>
+            <scope>test</scope>
+        </dependency>
 
     </dependencies>
 
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
index 7255773cf3f2..5f55e5515849 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
@@ -22,7 +22,6 @@ import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -30,12 +29,10 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.TimeZone;
 
 import org.apache.camel.CamelAuthorizationException;
 import org.apache.camel.CamelExecutionException;
 import org.apache.camel.Exchange;
-import org.apache.camel.ExchangePattern;
 import org.apache.camel.Expression;
 import org.apache.camel.ExpressionIllegalSyntaxException;
 import org.apache.camel.InvalidPayloadException;
@@ -45,11 +42,9 @@ import org.apache.camel.StreamCache;
 import org.apache.camel.component.bean.MethodNotFoundException;
 import org.apache.camel.converter.stream.FileInputStreamCache;
 import org.apache.camel.language.bean.RuntimeBeanExpressionException;
-import org.apache.camel.language.simple.myconverter.MyCustomDate;
 import org.apache.camel.language.simple.types.SimpleIllegalSyntaxException;
 import org.apache.camel.spi.ExchangeFormatter;
 import org.apache.camel.spi.Language;
-import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.Registry;
 import org.apache.camel.spi.UuidGenerator;
 import org.apache.camel.spi.VariableRepository;
@@ -61,10 +56,7 @@ import org.apache.camel.util.InetAddressUtil;
 import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.json.JsonArray;
 import org.apache.camel.util.json.JsonObject;
-import org.apache.camel.util.json.Jsoner;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.parallel.ResourceLock;
-import org.junit.jupiter.api.parallel.Resources;
 
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -148,16 +140,6 @@ public class SimpleTest extends LanguageTestSupport {
         
assertNull(context.resolveLanguage("simple").createExpression("${header.unknown}").evaluate(exchange,
 String.class));
     }
 
-    @Test
-    public void testRefExpression() {
-        assertExpressionResultInstanceOf("${ref:myAnimal}", Animal.class);
-
-        assertExpression("${ref:myAnimal}", "Donkey");
-        assertExpression("${ref:unknown}", null);
-        assertExpression("Hello ${ref:myAnimal}", "Hello Donkey");
-        assertExpression("Hello ${ref:unknown}", "Hello ");
-    }
-
     @Test
     public void testConstantExpression() {
         assertExpression("Hello World", "Hello World");
@@ -333,46 +315,6 @@ public class SimpleTest extends LanguageTestSupport {
         assertExpression("${exchangeProperty:medal}", "gold");
     }
 
-    @Test
-    @ResourceLock(Resources.SYSTEM_PROPERTIES)
-    public void testSimpleSystemPropertyExpressions() {
-        System.setProperty("who", "I was here");
-        assertExpression("${sys.who}", "I was here");
-    }
-
-    @Test
-    public void testSimpleSystemEnvironmentExpressions() {
-        String path = System.getenv("PATH");
-        if (path != null) {
-            assertExpression("${sysenv.PATH}", path);
-            assertExpression("${sysenv:PATH}", path);
-            assertExpression("${env.PATH}", path);
-            assertExpression("${env:PATH}", path);
-        }
-    }
-
-    @Test
-    public void testSimpleSystemEnvironmentExpressionsIfDash() {
-        String foo = System.getenv("FOO_SERVICE_HOST");
-        if (foo != null) {
-            assertExpression("${sysenv.FOO-SERVICE-HOST}", foo);
-            assertExpression("${sysenv:FOO-SERVICE-HOST}", foo);
-            assertExpression("${env.FOO-SERVICE-HOST}", foo);
-            assertExpression("${env:FOO-SERVICE-HOST}", foo);
-        }
-    }
-
-    @Test
-    public void testSimpleSystemEnvironmentExpressionsIfLowercase() {
-        String path = System.getenv("PATH");
-        if (path != null) {
-            assertExpression("${sysenv.path}", path);
-            assertExpression("${sysenv:path}", path);
-            assertExpression("${env.path}", path);
-            assertExpression("${env:path}", path);
-        }
-    }
-
     @Test
     public void testSimpleCamelId() {
         assertExpression("${camelId}", context.getName());
@@ -622,108 +564,6 @@ public class SimpleTest extends LanguageTestSupport {
         assertPredicate("${header.beer.trim()} == \"\"", true);
     }
 
-    @Test
-    public void testDateExpressions() {
-        Calendar inHeaderCalendar = Calendar.getInstance();
-        inHeaderCalendar.set(1974, Calendar.APRIL, 20);
-        exchange.getIn().setHeader("birthday", inHeaderCalendar.getTime());
-
-        Calendar propertyCalendar = Calendar.getInstance();
-        propertyCalendar.set(1976, Calendar.JUNE, 22);
-        exchange.setProperty("birthday", propertyCalendar.getTime());
-
-        assertExpression("${date:header.birthday}", 
inHeaderCalendar.getTime());
-        assertExpression("${date:header.birthday:yyyyMMdd}", "19740420");
-        assertExpression("${date:header.birthday+24h:yyyyMMdd}", "19740421");
-
-        // long
-        assertExpression("${date:exchangeProperty.birthday}", 
propertyCalendar.getTime().getTime());
-        // date
-        assertExpression("${date:exchangeProperty.birthday}", 
propertyCalendar.getTime());
-        assertExpression("${date:exchangeProperty.birthday:yyyyMMdd}", 
"19760622");
-        assertExpression("${date:exchangeProperty.birthday+24h:yyyyMMdd}", 
"19760623");
-
-        IllegalArgumentException e = 
assertThrows(IllegalArgumentException.class,
-                () -> assertExpression("${date:yyyyMMdd}", "19740420"),
-                "Should thrown an exception");
-
-        assertEquals("Command not supported for dateExpression: yyyyMMdd", 
e.getMessage());
-    }
-
-    @Test
-    public void testDateAndTimeExpressions() {
-        Calendar cal = Calendar.getInstance();
-        cal.set(1974, Calendar.APRIL, 20, 8, 55, 47);
-        cal.set(Calendar.MILLISECOND, 123);
-        exchange.getIn().setHeader("birthday", cal.getTime());
-
-        assertExpression("${date:header.birthday - 
10s:yyyy-MM-dd'T'HH:mm:ss:SSS}", "1974-04-20T08:55:37:123");
-        assertExpression("${date:header.birthday:yyyy-MM-dd'T'HH:mm:ss:SSS}", 
"1974-04-20T08:55:47:123");
-    }
-
-    @Test
-    public void testDateWithConverterExpressions() {
-        exchange.getIn().setHeader("birthday", new MyCustomDate(1974, 
Calendar.APRIL, 20));
-        exchange.setProperty("birthday", new MyCustomDate(1974, 
Calendar.APRIL, 20));
-        exchange.getIn().setHeader("other", new ArrayList<>());
-
-        assertExpression("${date:header.birthday:yyyyMMdd}", "19740420");
-        assertExpression("${date:exchangeProperty.birthday:yyyyMMdd}", 
"19740420");
-
-        IllegalArgumentException e = 
assertThrows(IllegalArgumentException.class,
-                () -> assertExpression("${date:header.other:yyyyMMdd}", 
"19740420"),
-                "Should thrown an exception");
-
-        assertEquals("Cannot find Date/long object at command: header.other", 
e.getMessage());
-    }
-
-    @Test
-    public void testDateWithTimezone() {
-        Calendar cal = Calendar.getInstance();
-        cal.setTimeZone(TimeZone.getTimeZone("GMT+8"));
-        cal.set(1974, Calendar.APRIL, 20, 8, 55, 47);
-        cal.set(Calendar.MILLISECOND, 123);
-        exchange.getIn().setHeader("birthday", cal.getTime());
-
-        
assertExpression("${date-with-timezone:header.birthday:GMT+8:yyyy-MM-dd'T'HH:mm:ss:SSS}",
 "1974-04-20T08:55:47:123");
-        
assertExpression("${date-with-timezone:header.birthday:GMT:yyyy-MM-dd'T'HH:mm:ss:SSS}",
 "1974-04-20T00:55:47:123");
-    }
-
-    @Test
-    public void testDateNow() {
-        Object out = evaluateExpression("${date:now}", null);
-        assertNotNull(out);
-        assertIsInstanceOf(Date.class, out);
-
-        out = evaluateExpression("${date:now:hh:mm:ss a}", null);
-        assertNotNull(out);
-        out = evaluateExpression("${date:now:hh:mm:ss}", null);
-        assertNotNull(out);
-        out = evaluateExpression("${date:now-2h:hh:mm:ss}", null);
-        assertNotNull(out);
-    }
-
-    @Test
-    public void testDateMillis() {
-        Object out = evaluateExpression("${date:millis}", null);
-        assertNotNull(out);
-        assertIsInstanceOf(Long.class, out);
-    }
-
-    @Test
-    public void testDateExchangeCreated() {
-        Object out
-                = evaluateExpression("${date:exchangeCreated:hh:mm:ss a}", ("" 
+ exchange.getClock().getCreated()).getClass());
-        assertNotNull(out);
-    }
-
-    @Test
-    public void testDatePredicates() {
-        assertPredicate("${date:now} < ${date:now+60s}");
-        assertPredicate("${date:now-5s} < ${date:now}");
-        assertPredicate("${date:now+5s} > ${date:now}");
-    }
-
     @Test
     public void testLanguagesInContext() {
         // evaluate so we know there is 1 language in the context
@@ -813,21 +653,6 @@ public class SimpleTest extends LanguageTestSupport {
         assertEquals("Just testing", out.getMessage());
     }
 
-    @Test
-    public void testMessageAs() {
-        // should be false as message is default
-        
assertPredicate("${messageAs(org.apache.camel.language.simple.MyAttachmentMessage).hasAttachments}",
 false);
-        
assertPredicate("${messageAs(org.apache.camel.language.simple.MyAttachmentMessage)?.hasAttachments}",
 false);
-
-        MyAttachmentMessage msg = new MyAttachmentMessage(exchange);
-        msg.setBody("<hello id='m123'>world!</hello>");
-        exchange.setMessage(msg);
-
-        
assertPredicate("${messageAs(org.apache.camel.language.simple.MyAttachmentMessage).hasAttachments}",
 true);
-        
assertPredicate("${messageAs(org.apache.camel.language.simple.MyAttachmentMessage)?.hasAttachments}",
 true);
-        
assertExpression("${messageAs(org.apache.camel.language.simple.MyAttachmentMessage).size}",
 "42");
-    }
-
     @Test
     public void testBodyAs() {
         assertExpression("${bodyAs(String)}", "<hello 
id='m123'>world!</hello>");
@@ -1864,31 +1689,6 @@ public class SimpleTest extends LanguageTestSupport {
         assertExpression("${camelContext.version}", context.getVersion());
     }
 
-    @Test
-    public void testTypeConstant() {
-        assertExpression("${type:org.apache.camel.Exchange.FILE_NAME}", 
Exchange.FILE_NAME);
-        assertExpression("${type:org.apache.camel.ExchangePattern.InOut}", 
ExchangePattern.InOut);
-
-        // non existing fields
-        Exception e1 = assertThrows(Exception.class,
-                () -> 
assertExpression("${type:org.apache.camel.ExchangePattern.}", null),
-                "Should throw exception");
-
-        assertIsInstanceOf(ClassNotFoundException.class, e1.getCause());
-
-        Exception e2 = assertThrows(Exception.class,
-                () -> 
assertExpression("${type:org.apache.camel.ExchangePattern.UNKNOWN}", null),
-                "Should throw exception");
-
-        assertIsInstanceOf(ClassNotFoundException.class, e2.getCause());
-    }
-
-    @Test
-    public void testTypeConstantInnerClass() {
-        
assertExpression("${type:org.apache.camel.language.simple.Constants$MyInnerStuff.FOO}",
 123);
-        
assertExpression("${type:org.apache.camel.language.simple.Constants.BAR}", 456);
-    }
-
     @Test
     public void testStringArrayLength() {
         exchange.getIn().setBody(new String[] { "foo", "bar" });
@@ -2345,22 +2145,6 @@ public class SimpleTest extends LanguageTestSupport {
         assertExpression("${body.replace(\"((\", \"--\").replace(\"((((\", 
\"----\")}", "Hello -- World ---- Again");
     }
 
-    @Test
-    public void testPropertiesExist() {
-        PropertiesComponent pc = context.getPropertiesComponent();
-
-        assertExpression("${propertiesExist:myKey}", "false");
-        assertExpression("${propertiesExist:!myKey}", "true");
-        assertPredicate("${propertiesExist:myKey}", false);
-        assertPredicate("${propertiesExist:!myKey}", true);
-
-        pc.addInitialProperty("myKey", "abc");
-        assertExpression("${propertiesExist:myKey}", "true");
-        assertExpression("${propertiesExist:!myKey}", "false");
-        assertPredicate("${propertiesExist:myKey}", true);
-        assertPredicate("${propertiesExist:!myKey}", false);
-    }
-
     @Test
     public void testUuid() {
         Expression expression = 
context.resolveLanguage("simple").createExpression("${uuid}");
@@ -3171,57 +2955,6 @@ public class SimpleTest extends LanguageTestSupport {
         assertThrows(IllegalArgumentException.class, () -> 
evaluateExpression("${newEmpty(unknownType)}", null));
     }
 
-    @Test
-    public void testPretty() {
-        assertExpression(exchange, "${pretty('Hello')}", "Hello");
-        assertExpression(exchange, "${pretty(${body})}", "<hello 
id=\"m123\">\n</hello>");
-
-        exchange.getMessage().setBody("{\"name\": \"Jack\", \"id\": 123}");
-        assertExpression(exchange, "${pretty(${body})}", "{\n\t\"name\": 
\"Jack\",\n\t\"id\": 123\n}\n");
-    }
-
-    @Test
-    public void testToJson() {
-        // string body is returned as-is
-        exchange.getMessage().setBody("Hello");
-        assertExpression(exchange, "${toJson(${body})}", "Hello");
-        assertExpression(exchange, "${toJsonBody}", "Hello");
-
-        // map body is serialized to JSON
-        Map<String, Object> map = new LinkedHashMap<>();
-        map.put("name", "Jack");
-        map.put("id", 123);
-        exchange.getMessage().setBody(map);
-        assertExpression(exchange, "${toJson(${body})}", 
"{\"name\":\"Jack\",\"id\":123}");
-        assertExpression(exchange, "${toJsonBody}", 
"{\"name\":\"Jack\",\"id\":123}");
-        // pretty mode
-        String pretty = Jsoner.prettyPrint("{\"name\":\"Jack\",\"id\":123}");
-        assertExpression(exchange, "${toPrettyJson(${body})}", pretty);
-        assertExpression(exchange, "${toPrettyJsonBody}", pretty);
-
-        // list body is serialized to JSON array
-        exchange.getMessage().setBody(List.of("a", "b", "c"));
-        assertExpression(exchange, "${toJson(${body})}", 
"[\"a\",\"b\",\"c\"]");
-        // pretty mode
-        pretty = Jsoner.prettyPrint("[\"a\",\"b\",\"c\"]");
-        assertExpression(exchange, "${toPrettyJson(${body})}", pretty);
-        assertExpression(exchange, "${toPrettyJsonBody}", pretty);
-
-        // null body
-        exchange.getMessage().setBody(null);
-        assertExpression(exchange, "${toJsonBody}", null);
-        assertExpression(exchange, "${toJson(${body})}", null);
-        // pretty mode
-        assertExpression(exchange, "${toPrettyJsonBody}", null);
-        assertExpression(exchange, "${toPrettyJson(${body})}", null);
-
-        // toJson with a header expression
-        exchange.getMessage().setHeader("myNum", 42);
-        assertExpression(exchange, "${toJson(${header.myNum})}", "42");
-        // pretty mode
-        assertExpression(exchange, "${toPrettyJson(${header.myNum})}", "42");
-    }
-
     @Test
     public void testTrimResult() {
         exchange.getMessage().setBody("Camel  ");
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/DateFunctionFactoryTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/DateFunctionFactoryTest.java
new file mode 100644
index 000000000000..9e79ab846e86
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/DateFunctionFactoryTest.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple.functions;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import org.apache.camel.language.simple.myconverter.MyCustomDate;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class DateFunctionFactoryTest extends 
AbstractSimpleFunctionFactoryTestSupport {
+
+    @Override
+    protected SimpleLanguageFunctionFactory createFactory() {
+        return new DateFunctionFactory();
+    }
+
+    // --- date: ---
+
+    @Test
+    public void testDateExpressions() {
+        Calendar inHeaderCalendar = Calendar.getInstance();
+        inHeaderCalendar.set(1974, Calendar.APRIL, 20);
+        exchange.getIn().setHeader("birthday", inHeaderCalendar.getTime());
+
+        Calendar propertyCalendar = Calendar.getInstance();
+        propertyCalendar.set(1976, Calendar.JUNE, 22);
+        exchange.setProperty("birthday", propertyCalendar.getTime());
+
+        assertEquals(inHeaderCalendar.getTime(), 
evaluate("date:header.birthday", Date.class));
+        assertEquals("19740420", evaluate("date:header.birthday:yyyyMMdd", 
String.class));
+        assertEquals("19740421", evaluate("date:header.birthday+24h:yyyyMMdd", 
String.class));
+
+        // as long
+        assertEquals(propertyCalendar.getTime().getTime(), 
evaluate("date:exchangeProperty.birthday", Long.class));
+        // as date
+        assertEquals(propertyCalendar.getTime(), 
evaluate("date:exchangeProperty.birthday", Date.class));
+        assertEquals("19760622", 
evaluate("date:exchangeProperty.birthday:yyyyMMdd", String.class));
+        assertEquals("19760623", 
evaluate("date:exchangeProperty.birthday+24h:yyyyMMdd", String.class));
+
+        IllegalArgumentException e = 
assertThrows(IllegalArgumentException.class,
+                () -> evaluate("date:yyyyMMdd", String.class));
+        assertEquals("Command not supported for dateExpression: yyyyMMdd", 
e.getMessage());
+    }
+
+    @Test
+    public void testDateAndTimeExpressions() {
+        Calendar cal = Calendar.getInstance();
+        cal.set(1974, Calendar.APRIL, 20, 8, 55, 47);
+        cal.set(Calendar.MILLISECOND, 123);
+        exchange.getIn().setHeader("birthday", cal.getTime());
+
+        assertEquals("1974-04-20T08:55:37:123", evaluate("date:header.birthday 
- 10s:yyyy-MM-dd'T'HH:mm:ss:SSS", String.class));
+        assertEquals("1974-04-20T08:55:47:123", 
evaluate("date:header.birthday:yyyy-MM-dd'T'HH:mm:ss:SSS", String.class));
+    }
+
+    @Test
+    public void testDateWithConverterExpressions() {
+        exchange.getIn().setHeader("birthday", new MyCustomDate(1974, 
Calendar.APRIL, 20));
+        exchange.setProperty("birthday", new MyCustomDate(1974, 
Calendar.APRIL, 20));
+        exchange.getIn().setHeader("other", new ArrayList<>());
+
+        assertEquals("19740420", evaluate("date:header.birthday:yyyyMMdd", 
String.class));
+        assertEquals("19740420", 
evaluate("date:exchangeProperty.birthday:yyyyMMdd", String.class));
+
+        IllegalArgumentException e = 
assertThrows(IllegalArgumentException.class,
+                () -> evaluate("date:header.other:yyyyMMdd", String.class));
+        assertEquals("Cannot find Date/long object at command: header.other", 
e.getMessage());
+    }
+
+    @Test
+    public void testDateWithTimezone() {
+        Calendar cal = Calendar.getInstance();
+        cal.setTimeZone(TimeZone.getTimeZone("GMT+8"));
+        cal.set(1974, Calendar.APRIL, 20, 8, 55, 47);
+        cal.set(Calendar.MILLISECOND, 123);
+        exchange.getIn().setHeader("birthday", cal.getTime());
+
+        assertEquals("1974-04-20T08:55:47:123",
+                
evaluate("date-with-timezone:header.birthday:GMT+8:yyyy-MM-dd'T'HH:mm:ss:SSS", 
String.class));
+        assertEquals("1974-04-20T00:55:47:123",
+                
evaluate("date-with-timezone:header.birthday:GMT:yyyy-MM-dd'T'HH:mm:ss:SSS", 
String.class));
+    }
+
+    @Test
+    public void testDateNow() {
+        Object out = evaluate("date:now", Object.class);
+        assertNotNull(out);
+        assertIsInstanceOf(Date.class, out);
+
+        assertNotNull(evaluate("date:now:hh:mm:ss a", Object.class));
+        assertNotNull(evaluate("date:now:hh:mm:ss", Object.class));
+        assertNotNull(evaluate("date:now-2h:hh:mm:ss", Object.class));
+    }
+
+    @Test
+    public void testDateMillis() {
+        Object out = evaluate("date:millis", Object.class);
+        assertNotNull(out);
+        assertIsInstanceOf(Long.class, out);
+    }
+
+    @Test
+    public void testDateExchangeCreated() {
+        Object out = evaluate("date:exchangeCreated:hh:mm:ss a", String.class);
+        assertNotNull(out);
+    }
+
+    // --- date-with-timezone: code generation ---
+
+    @Test
+    public void testCreateCodeDateMillis() {
+        assertEquals("System.currentTimeMillis()", createCode("date:millis"));
+    }
+
+    @Test
+    public void testCreateCodeDateNoPattern() {
+        assertEquals("date(exchange, \"now\")", createCode("date:now"));
+    }
+
+    @Test
+    public void testCreateCodeDateWithPattern() {
+        assertEquals("date(exchange, \"now\", null, \"yyyy-MM-dd\")", 
createCode("date:now:yyyy-MM-dd"));
+    }
+
+    @Test
+    public void testCreateCodeDateWithTimezone() {
+        assertEquals("date(exchange, \"now\", \"UTC\", \"yyyy-MM-dd\")",
+                createCode("date-with-timezone:now:UTC:yyyy-MM-dd"));
+    }
+
+    @Test
+    public void testCreateCodeUnknown() {
+        assertNull(createFactory().createCode(context, "unknown", 0));
+    }
+}
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MessageFunctionFactoryTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MessageFunctionFactoryTest.java
new file mode 100644
index 000000000000..0014923d6f4e
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/MessageFunctionFactoryTest.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.language.simple.functions;
+
+import org.apache.camel.language.simple.MyAttachmentMessage;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class MessageFunctionFactoryTest extends 
AbstractSimpleFunctionFactoryTestSupport {
+
+    @Override
+    protected SimpleLanguageFunctionFactory createFactory() {
+        return new MessageFunctionFactory();
+    }
+
+    // --- messageAs( ---
+
+    @Test
+    public void testMessageAs() {
+        // exchange.getMessage(MyAttachmentMessage.class) returns null when 
the current message is
+        // a DefaultMessage (no type-converter exists). messageOgnlExpression 
short-circuits on null
+        // and returns null without invoking OGNL. The original SimpleTest 
used assertPredicate(...,
+        // false) which passed because the Simple predicate engine coerces 
null to false; the raw
+        // expression value itself is null, not Boolean.FALSE.
+        
assertNull(evaluate("messageAs(org.apache.camel.language.simple.MyAttachmentMessage).hasAttachments",
+                Boolean.class));
+        
assertNull(evaluate("messageAs(org.apache.camel.language.simple.MyAttachmentMessage)?.hasAttachments",
+                Boolean.class));
+
+        MyAttachmentMessage msg = new MyAttachmentMessage(exchange);
+        msg.setBody("<hello id='m123'>world!</hello>");
+        exchange.setMessage(msg);
+
+        assertEquals(true,
+                
evaluate("messageAs(org.apache.camel.language.simple.MyAttachmentMessage).hasAttachments",
 Boolean.class));
+        assertEquals(true,
+                
evaluate("messageAs(org.apache.camel.language.simple.MyAttachmentMessage)?.hasAttachments",
 Boolean.class));
+        assertEquals("42",
+                
evaluate("messageAs(org.apache.camel.language.simple.MyAttachmentMessage).size",
 String.class));
+    }
+}
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/OutputFunctionFactoryTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/OutputFunctionFactoryTest.java
new file mode 100644
index 000000000000..01f6e2b979f8
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/OutputFunctionFactoryTest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple.functions;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.apache.camel.util.json.Jsoner;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class OutputFunctionFactoryTest extends 
AbstractSimpleFunctionFactoryTestSupport {
+
+    @Override
+    protected SimpleLanguageFunctionFactory createFactory() {
+        return new OutputFunctionFactory();
+    }
+
+    // --- pretty( ---
+
+    @Test
+    public void testPretty() {
+        assertEquals("Hello", evaluate("pretty('Hello')", String.class));
+
+        // XmlPrettyPrinter only emits text content when indent > 1 (i.e., 
inside a nested element).
+        // Text directly inside the root element is silently dropped, so 
"world!" does not appear.
+        assertEquals("<hello id=\"m123\">\n</hello>", 
evaluate("pretty(${body})", String.class));
+
+        exchange.getMessage().setBody("{\"name\": \"Jack\", \"id\": 123}");
+        assertEquals("{\n\t\"name\": \"Jack\",\n\t\"id\": 123\n}\n", 
evaluate("pretty(${body})", String.class));
+    }
+
+    // --- toJson( / toPrettyJson( ---
+
+    @Test
+    public void testToJson() {
+        // string body is returned as-is
+        exchange.getMessage().setBody("Hello");
+        assertEquals("Hello", evaluate("toJson(${body})", String.class));
+
+        // map body is serialized to JSON
+        Map<String, Object> map = new LinkedHashMap<>();
+        map.put("name", "Jack");
+        map.put("id", 123);
+        exchange.getMessage().setBody(map);
+        assertEquals("{\"name\":\"Jack\",\"id\":123}", 
evaluate("toJson(${body})", String.class));
+        // pretty mode
+        String pretty = Jsoner.prettyPrint("{\"name\":\"Jack\",\"id\":123}");
+        assertEquals(pretty, evaluate("toPrettyJson(${body})", String.class));
+
+        // list body is serialized to JSON array
+        exchange.getMessage().setBody(List.of("a", "b", "c"));
+        assertEquals("[\"a\",\"b\",\"c\"]", evaluate("toJson(${body})", 
String.class));
+        // pretty mode
+        pretty = Jsoner.prettyPrint("[\"a\",\"b\",\"c\"]");
+        assertEquals(pretty, evaluate("toPrettyJson(${body})", String.class));
+
+        // null body
+        exchange.getMessage().setBody(null);
+        assertNull(evaluate("toJson(${body})", Object.class));
+        // pretty mode
+        assertNull(evaluate("toPrettyJson(${body})", Object.class));
+
+        // toJson with a header expression
+        exchange.getMessage().setHeader("myNum", 42);
+        assertEquals("42", evaluate("toJson(${header.myNum})", String.class));
+        // pretty mode
+        assertEquals("42", evaluate("toPrettyJson(${header.myNum})", 
String.class));
+    }
+}
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/PropertiesFunctionFactoryTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/PropertiesFunctionFactoryTest.java
new file mode 100644
index 000000000000..7d1eb2dc9a34
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/PropertiesFunctionFactoryTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple.functions;
+
+import org.apache.camel.spi.PropertiesComponent;
+import org.apache.camel.spi.Registry;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class PropertiesFunctionFactoryTest extends 
AbstractSimpleFunctionFactoryTestSupport {
+
+    @Override
+    protected SimpleLanguageFunctionFactory createFactory() {
+        return new PropertiesFunctionFactory();
+    }
+
+    @Override
+    protected Registry createCamelRegistry() throws Exception {
+        Registry registry = super.createCamelRegistry();
+        registry.bind("myAnimal", "Donkey");
+        return registry;
+    }
+
+    // --- ref: ---
+
+    @Test
+    public void testRefExpression() {
+        assertIsInstanceOf(String.class, evaluate("ref:myAnimal", 
Object.class));
+        assertEquals("Donkey", evaluate("ref:myAnimal", String.class));
+        assertNull(evaluate("ref:unknown", Object.class));
+    }
+
+    @Test
+    public void testCreateCodeRef() {
+        assertEquals("ref(exchange, \"myBean\")", createCode("ref:myBean"));
+    }
+
+    // --- propertiesExist: ---
+
+    @Test
+    public void testPropertiesExist() {
+        PropertiesComponent pc = context.getPropertiesComponent();
+
+        assertEquals("false", evaluate("propertiesExist:myKey", String.class));
+        assertEquals("true", evaluate("propertiesExist:!myKey", String.class));
+        assertEquals(false, evaluate("propertiesExist:myKey", Boolean.class));
+        assertEquals(true, evaluate("propertiesExist:!myKey", Boolean.class));
+
+        pc.addInitialProperty("myKey", "abc");
+        assertEquals("true", evaluate("propertiesExist:myKey", String.class));
+        assertEquals("false", evaluate("propertiesExist:!myKey", 
String.class));
+        assertEquals(true, evaluate("propertiesExist:myKey", Boolean.class));
+        assertEquals(false, evaluate("propertiesExist:!myKey", Boolean.class));
+    }
+
+    @Test
+    public void testPropertiesExistHasNoCodeGeneration() {
+        // propertiesExist: is handled at runtime only; CSimple has no 
code-gen path for it
+        assertNull(createFactory().createCode(context, 
"propertiesExist:myKey", 0));
+    }
+
+    // --- properties: ---
+
+    @Test
+    public void testCreateCodePropertiesNoDefault() {
+        assertEquals("properties(exchange, \"myKey\")", 
createCode("properties:myKey"));
+    }
+
+    @Test
+    public void testCreateCodePropertiesWithDefault() {
+        assertEquals("properties(exchange, \"myKey\", \"myDefault\")", 
createCode("properties:myKey:myDefault"));
+    }
+
+    @Test
+    public void testCreateCodeUnknown() {
+        assertNull(createFactory().createCode(context, "unknown", 0));
+    }
+}
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/SystemFunctionFactoryTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/SystemFunctionFactoryTest.java
new file mode 100644
index 000000000000..31d668095278
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/SystemFunctionFactoryTest.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple.functions;
+
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.SetSystemProperty;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class SystemFunctionFactoryTest extends 
AbstractSimpleFunctionFactoryTestSupport {
+
+    @Override
+    protected SimpleLanguageFunctionFactory createFactory() {
+        return new SystemFunctionFactory();
+    }
+
+    // --- sys. ---
+
+    @Test
+    @SetSystemProperty(key = "who", value = "I was here")
+    public void testSimpleSystemPropertyExpressions() {
+        assertEquals("I was here", evaluate("sys.who", String.class));
+    }
+
+    @Test
+    public void testCreateCodeSys() {
+        assertEquals("sys(\"java.version\")", createCode("sys.java.version"));
+    }
+
+    // --- sysenv. / sysenv: / env. / env: ---
+
+    @Test
+    public void testSimpleSystemEnvironmentExpressions() {
+        String path = System.getenv("PATH");
+        if (path != null) {
+            assertEquals(path, evaluate("sysenv.PATH", String.class));
+            assertEquals(path, evaluate("sysenv:PATH", String.class));
+            assertEquals(path, evaluate("env.PATH", String.class));
+            assertEquals(path, evaluate("env:PATH", String.class));
+        }
+    }
+
+    @Test
+    public void testSimpleSystemEnvironmentExpressionsIfDash() {
+        String foo = System.getenv("FOO_SERVICE_HOST");
+        if (foo != null) {
+            assertEquals(foo, evaluate("sysenv.FOO-SERVICE-HOST", 
String.class));
+            assertEquals(foo, evaluate("sysenv:FOO-SERVICE-HOST", 
String.class));
+            assertEquals(foo, evaluate("env.FOO-SERVICE-HOST", String.class));
+            assertEquals(foo, evaluate("env:FOO-SERVICE-HOST", String.class));
+        }
+    }
+
+    @Test
+    public void testSimpleSystemEnvironmentExpressionsIfLowercase() {
+        String path = System.getenv("PATH");
+        if (path != null) {
+            assertEquals(path, evaluate("sysenv.path", String.class));
+            assertEquals(path, evaluate("sysenv:path", String.class));
+            assertEquals(path, evaluate("env.path", String.class));
+            assertEquals(path, evaluate("env:path", String.class));
+        }
+    }
+
+    @Test
+    public void testCreateCodeSysenvDot() {
+        assertEquals("sysenv(\"MY_VAR\")", createCode("sysenv.MY_VAR"));
+    }
+
+    @Test
+    public void testCreateCodeSysenvColon() {
+        assertEquals("sysenv(\"MY_VAR\")", createCode("sysenv:MY_VAR"));
+    }
+
+    @Test
+    public void testCreateCodeEnvDot() {
+        assertEquals("sysenv(\"MY_VAR\")", createCode("env.MY_VAR"));
+    }
+
+    @Test
+    public void testCreateCodeEnvColon() {
+        assertEquals("sysenv(\"MY_VAR\")", createCode("env:MY_VAR"));
+    }
+
+    @Test
+    public void testCreateCodeUnknown() {
+        assertNull(createFactory().createCode(context, "unknown", 0));
+    }
+}
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/TypeFunctionFactoryTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/TypeFunctionFactoryTest.java
new file mode 100644
index 000000000000..ed1b11c913f7
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/functions/TypeFunctionFactoryTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language.simple.functions;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.spi.SimpleLanguageFunctionFactory;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class TypeFunctionFactoryTest extends 
AbstractSimpleFunctionFactoryTestSupport {
+
+    @Override
+    protected SimpleLanguageFunctionFactory createFactory() {
+        return new TypeFunctionFactory();
+    }
+
+    // --- type: ---
+
+    @Test
+    public void testTypeConstant() {
+        assertEquals(Exchange.FILE_NAME, 
evaluate("type:org.apache.camel.Exchange.FILE_NAME", String.class));
+        assertEquals(ExchangePattern.InOut, 
evaluate("type:org.apache.camel.ExchangePattern.InOut", ExchangePattern.class));
+
+        Exception e1 = assertThrows(Exception.class,
+                () -> evaluate("type:org.apache.camel.ExchangePattern.", 
Object.class));
+        assertIsInstanceOf(ClassNotFoundException.class, e1.getCause());
+
+        Exception e2 = assertThrows(Exception.class,
+                () -> 
evaluate("type:org.apache.camel.ExchangePattern.UNKNOWN", Object.class));
+        assertIsInstanceOf(ClassNotFoundException.class, e2.getCause());
+    }
+
+    @Test
+    public void testTypeConstantInnerClass() {
+        assertEquals(123, 
evaluate("type:org.apache.camel.language.simple.Constants$MyInnerStuff.FOO", 
Integer.class));
+        assertEquals(456, 
evaluate("type:org.apache.camel.language.simple.Constants.BAR", Integer.class));
+    }
+
+    @Test
+    public void testCreateCodeTypeWithField() {
+        assertEquals("type(exchange, java.lang.Integer.class, \"MAX_VALUE\")",
+                createCode("type:java.lang.Integer.MAX_VALUE"));
+    }
+
+    @Test
+    public void testCreateCodeTypeNoField() {
+        // no dots in the remainder -> field is null, only class emitted
+        assertEquals("type(exchange, String.class)", 
createCode("type:String"));
+    }
+
+    @Test
+    public void testCreateCodeUnknown() {
+        assertNull(createFactory().createCode(context, "unknown", 0));
+    }
+}

Reply via email to