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)