You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Claus Ibsen (Jira)" <ji...@apache.org> on 2026/10/05 08:24:00 UTC

[jira] [Created] (CAMEL-25334) Content-type aware payloads for low-code: the body stays text with its content type, Groovy and simple read JSON fields from it, structured results go back to text

Claus Ibsen created CAMEL-25334:
-----------------------------------

             Summary: Content-type aware payloads for low-code: the body stays text with its content type, Groovy and simple read JSON fields from it, structured results go back to text
                 Key: CAMEL-25334
                 URL: https://issues.apache.org/jira/browse/CAMEL-25334
             Project: Camel
          Issue Type: New Feature
          Components: camel-groovy, camel-core
            Reporter: Claus Ibsen


Low-code users, and AI models writing routes, think of the payload as JSON (or XML, CSV, text) and write data mappings in Groovy and simple accordingly. Camel carries the native Java type of each component instead - a GenericFile, a byte[], an InputStream, a Map - and the gap shows up as runtime errors:

* Groovy {{body.find { it.sku == headers.sku } }} on JSON that was not unmarshalled: {{No such property: sku for class: java.lang.Byte}}
* simple {{$\{body[amount]\}}} on the file consumer's body: {{Key: amount not found in bean: GenericFile[...]}}
* a mapping that returns a Map, sent to an http producer: no type converter from LinkedHashMap to InputStream
* a jsonpath result stored in a header as a LinkedList, which disappears when the message crosses a JMS broker

Raymond Meester described the same from the Fluxygen low-code platform on Camel, where users write Groovy and simple without knowing Java: [Text-orientated vs. Object-orientated in integration|https://camel.zulipchat.com/#narrow/channel/257298-camel/topic/.E2.9C.94.20Text-orientated.20vs.2E.20Object-orientated.20in.20integration/with/568024059]. In the local-model benchmark, 19 of 156 attempts in one series died on such a body type collision.

h3. Proposal: a content-type aware mode

Not "everything is text", and not a second Camel: the payload keeps its content type, the body stays the raw text or bytes between steps, and each language reads it the way it expects:

||who||what it sees when the content type is JSON||
|jsonpath, jq|the raw JSON text, as today|
|Groovy|parsed data (Map / List), so {{body.sku}}, {{body.find \{ it.sku == ... \}}}, {{body.items.each \{ ... \}}} work; the text stays available (for example as {{bodyText}})|
|simple {{$\{body[sku]\}}}, {{$\{body.sku\}}}|the field, read from the parsed JSON|
|producers|the text, unchanged|
|marshal json|the text, passed through (CAMEL-25329)|

The return side matters as much as the read side: a structured result (Map, List, JsonNode) that a language stores with setBody or setHeader becomes JSON text again, so the next producer, broker or mapping gets text and headers survive a JMS hop.

Where the content type comes from: the Content-Type header, which HTTP consumers and Jackson's marshal already set; for the file consumer, the file name through MimeTypeHelper (probeContentType); otherwise the first character of the text. Binary content stays binary, and a size threshold (as stream caching has) keeps large payloads as streams.

Groovy needs no new dependency: camel-groovy already depends on groovy-json and groovy-xml (JsonSlurper gives Map/List, XmlSlurper GPath for XML). Simple already compares text numbers numerically (ObjectHelper.typeCoerceCompare), so {{$\{header.qty\} > 5}} keeps working with text headers.

h3. Prototype and measurement

# Groovy, behind an option: a JSON body is bound as Map/List, the text as bodyText, a Map/List result goes back to JSON text.
# simple: {{$\{body[x]\}}} and {{$\{body.x\}}} read fields from JSON text.
# Headers: a structured result from any language becomes JSON text when the mode is on.
# Run the local-model benchmark ladder with the mode off and on and compare the body type collisions and pass rate before deciding on the switch (one camel.main property, or per language) and on defaults.

Classic routes keep the native body types; the mode is opt-in.

Related: CAMEL-24844 (body type flow), CAMEL-25330 (the Groovy hint this would replace with behaviour), CAMEL-25329 (marshal passes JSON text through).

_Claude Code on behalf of davsclaus_



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