Raymond created CAMEL-25922:
-------------------------------

             Summary: Route template parameter value containing }} (e.g. JSON) 
fails with “Missing {{ from the text”
                 Key: CAMEL-25922
                 URL: https://issues.apache.org/jira/browse/CAMEL-25922
             Project: Camel
          Issue Type: Bug
    Affects Versions: 4.23.0
            Reporter: Raymond


h3. Problem

When a route template parameter value contains the text {{}}}} (for example a 
JSON body or a Simple expression that ends with a nested object), creating the 
route fails with:

{noformat}
org.apache.camel.FailedToCreateRouteException: Failed to create route: 
templated at: >>> SetBody[simple{{{expression}}}] <<< ...
Caused by: java.lang.IllegalArgumentException: Missing {{ from the text: 
{"title":${header.title}}
        at 
org.apache.camel.component.properties.DefaultPropertiesParser$ParsingContext.readProperty(DefaultPropertiesParser.java:268)
        at 
org.apache.camel.component.properties.DefaultPropertiesParser$ParsingContext.doParseNested(DefaultPropertiesParser.java:192)
        at 
org.apache.camel.component.properties.DefaultPropertiesParser$ParsingContext.doParseNested(DefaultPropertiesParser.java:217)
        ...
{noformat}

The exact same expression works when used directly in a route. It only fails 
when passed as a template parameter (or any property value referenced via 
{{...}}).

The cause: {{{{expression}}}} is resolved, and then the resolved value is 
parsed again for nested placeholders. In {{{"title":${header.title}}}} the 
closing brace of {{${...}}} plus the closing brace of the JSON object form 
{{}}}}, which is taken as a placeholder suffix without a matching prefix.

Top-level text without {{{{}} is skipped by the parser, so it is not affected. 
A resolved value is always parsed, so there the same text fails.

h3. Reproducer

{code:java}
import java.util.Map;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;

public class JsonTemplateParameterIssue {

    public static void main(String[] args) throws Exception {
        try (DefaultCamelContext context = new DefaultCamelContext()) {
            context.addRoutes(new RouteBuilder() {
                @Override
                public void configure() {
                    // works: expression used directly
                    from("direct:plain")
                        .setBody().simple("{\"title\":${header.title}}");

                    // fails: same expression passed as a route template 
parameter
                    routeTemplate("setBodyTemplate")
                        .templateParameter("expression")
                        .from("direct:{{routeId}}")
                        .setBody().simple("{{expression}}");
                }
            });
            context.start();

            System.out.println(context.createProducerTemplate()
                .requestBodyAndHeader("direct:plain", null, "title", 
"\"Hello\""));
            // prints {"title":"Hello"}

            context.addRouteFromTemplate("templated", "setBodyTemplate",
                Map.of("routeId", "templated", "expression", 
"{\"title\":${header.title}}"));
            // throws FailedToCreateRouteException
            //   Caused by: IllegalArgumentException: Missing {{ from the text: 
{"title":${header.title}}
        }
    }
}
{code}

h3. Observed results (Camel 4.23.0, template parameter "expression")

||Value||Result||
|{{{"title":${header.title}}}}|FAIL - Missing {{|
|{{{"a":{"b":1}}}} (plain nested JSON, constant)|FAIL - Missing {{|
|{{{"title":"${header.title}"}}}|OK|
|{{{"title":${header.title} }}} (space added)|OK|
|{{{"title":${header.title\}}}} (escaped)|OK|
|any of the above with {{setNestedPlaceholder(false)}}|OK|

A related silent case: a value such as {{{{"a":1}}}} does not fail. It is 
resolved as placeholder key {{"a"}} with default value {{1}}, so the route gets 
{{1}} instead of the JSON.

h3. Context

We hit this in Assimbly (https://github.com/assimbly/runtime), which builds 
routes from Kamelet-style route templates. User-supplied setBody expressions 
(often JSON) are passed as template parameters. Users can't be expected to 
escape {{}}}} in JSON payloads, and turning off nested placeholders for the 
whole CamelContext is too broad.

h3. Suggested improvements (any of these)

# When parsing a resolved (nested) value, treat an unmatched {{}}}} (no {{{{}} 
in the text) as literal text instead of throwing. This is consistent with 
top-level text, which is left untouched when it contains no {{{{}}.
# Allow route template parameters to be marked as raw/literal (e.g. per 
{{templateParameter}}, or a template-level option), so their values are not 
parsed for nested placeholders.
# Document the {{\}}}} / {{\{{}} escape for template parameter values in the 
route template docs.



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

Reply via email to