Claus Ibsen created CAMEL-24486:
-----------------------------------

             Summary: camel-core - Simple language init block custom functions 
($foo ~:= ...) fail with "No custom simple function" when CamelContext profile 
is dev
                 Key: CAMEL-24486
                 URL: https://issues.apache.org/jira/browse/CAMEL-24486
             Project: Camel
          Issue Type: Bug
          Components: camel-core
            Reporter: Claus Ibsen


The Simple language's init-block custom-function syntax ($init{ $foo ~:= 
<expr>; }init$ followed by a call like ${foo(...)}) fails at route-creation 
time with:

org.apache.camel.language.simple.types.SimpleIllegalSyntaxException: No custom 
simple function with name: foo

whenever the CamelContext's profile is "dev" (e.g. every `camel run` via 
camel-jbang defaults to `--profile=dev`). It works fine with the 
default/non-dev profile.

h3. Root cause

DefaultSimpleFunctionRegistry.getFunction(String) in 
core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultSimpleFunctionRegistry.java
 (around lines 102-116):

{code:java}
public Expression getFunction(String name) {
    // in dev mode then always lookup function as it may be updated due to a 
live reload
    boolean dev = 
"dev".equals(camelContext.getCamelContextExtension().getProfile());
    Expression exp = dev ? null : functions.get(name);
    if (exp == null) {
        SimpleFunction sf = lookupFunction(name);
        if (sf != null) {
            removeFunction(name);
            addFunction(sf);
            exp = functions.get(name);
        }
    }
    return exp;
}
{code}

In dev profile, the method intentionally ignores its own functions cache (to 
support hot-reloading of SimpleFunction beans registered in the Camel registry) 
and only re-resolves via lookupFunction(), which searches 
camelContext.getRegistry().findByType(SimpleFunction.class). Custom functions 
defined via the Simple language's $foo ~:= <expr>; init-block chain-assignment 
syntax are stored directly as plain Expression objects in the functions map 
(via addFunction(String, Expression), see InitBlockExpression.java) - they are 
never registered as SimpleFunction beans. So in dev mode, the lookup for such 
functions always misses and throws, even though the function was just 
registered moments earlier in the same parse.

h3. Reproduction

A minimal YAML route (also reproducible with 'camel run foo.yaml' against a 
plain file):

{code:yaml}
- route:
    from:
      uri: timer:yaml
      parameters:
        period: "10000"
      steps:
        - setBody:
            simple: |-
              $init{
                $foo ~:= ${uppercase()};
              }init$
              ${foo('hello')}
{code}

Run with 'camel run foo.yaml' (dev profile is the default) -> fails. Running 
the exact same route with a non-dev profile works fine. Also reproduced 
directly in a JUnit/Spock test by setting 
context.getCamelContextExtension().setProfile("dev") before loading the route 
(no camel-jbang / CLI needed).

h3. Suggested fix

In DefaultSimpleFunctionRegistry.getFunction(), when in dev mode and 
lookupFunction() (bean-based) finds nothing, fall back to the existing 
functions.get(name) cache entry instead of returning null:

{code:java}
if (sf != null) {
    removeFunction(name);
    addFunction(sf);
    exp = functions.get(name);
} else if (dev) {
    exp = functions.get(name);
}
{code}

This preserves dev-mode hot-reload semantics for SimpleFunction-bean-based 
custom functions while not breaking init-block-defined (~:=) custom functions 
that aren't backed by a registry bean.

Reported by a community member (Adam Tetz) via Zulip using Camel 4.22.0, JBang 
0.141.0, Java 25 on macOS. Confirmed still present on main (4.23.0-SNAPSHOT).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to