Skip to content

CAMEL-24961: camel-yaml-dsl-validator - the body walks read the body types of the catalog instead of their own tables - #28246

Merged
davsclaus merged 17 commits into
mainfrom
feature/CAMEL-24961-catalog-body-types-3
Oct 24, 2026
Merged

davsclaus merged 17 commits into
mainfrom
feature/CAMEL-24961-catalog-body-types-3

Conversation

@davsclaus

Copy link
Copy Markdown
Contributor

Stacked on #28242. This is the third part of the catalog body types (CAMEL-24961): the YAML validator's body walks read the body types of the catalog instead of tables in their own source, so every component, data format and language that declares its body types is covered without a change to the validator.

What moved

Table in the validator Catalog side Also covered now
the file consumer gives the file as read consumerOut ftp, ftps and sftp (a stream with streamDownload); aws2-sqs gives text; paho-mqtt5 gives bytes; sql gives a row as a Map
KEEPS_THE_BODY: log, mock producerOut unchanged a file write, kafka, paho-mqtt5, seda with waitForTaskToComplete=Never
(none) producerOut the response of the http producer as bytes or a stream; xslt gives text (with output=DOM, a Document, which is neither text nor data); mongodb findAll gives a List
WRITES_A_FILE: file, ftp, ftps, sftp producerIn paho-mqtt5
PARSES and NOT_A_MAP: json, jacksonXml, yaml, csv; unmarshalType, lazyLoad unmarshalOut csv with lazyLoad gives the iterator carrier of #28241, which is not a Map or a List; the options the side depends on also include collectionType and allowUnmarshallType; gson, fastjson and jsonb have no body types yet, so they are not known
the platform-http reply consumerReply
NO_BODY_CONSUMER: timer, quartz, scheduler, cron consumerOut null ftp with download=false

No guesses. A side holds for a step only when the step sets every option the side depends on, or the option keeps its default:

  • An option that the component can also be configured with counts only when the endpoint sets it. For example, camel.component.kafka.valueDeserializer in application.properties changes the body of every kafka consumer, and the route file does not show it. So kafka stays silent, as before, and so does the operation of aws2-sqs.
  • A placeholder value is not known.

A catalog of another Camel version. camel validate --camel-version (CAMEL-24711) validates with the catalog of that version. An older catalog has no body types, so the validator's own catalog stands in for a model without them, and the walk keeps its rules, as it did with the tables.

One report for a step that fails. A file write now keeps the body. Without a change, a second write after the first would be reported as well. As the first write fails at runtime, the walk stops after the step it reports.

What stays in the validator:

  • whether the http producer sends the body at all: the http method, the query string, the CamelHttpMethod header;
  • the REST binding mode;
  • the consumers that bring no HTTP headers;
  • the EIP tables (KEEPING_STEPS, SAME_BODY_BLOCKS), until the EIPs have body types (CAMEL-25928);
  • which expressions fail on no body in BodyTypeFlow: the catalog says jsonpath reads any body, which is true, but it fails on no body.

Message. "to: file writes the body to a file" is now "to: file needs the body as text, bytes, a stream or a file", from the carriers of the catalog. paho-mqtt5, and any producer annotated later, get the same sentence.

Measured. I ran the validator over two sets of route files, before and after:

  • 1204 human-written route files (the Camel repository, camel-examples, camel-jbang-examples, camel-kamelets, camel-kamelets-examples, camel-k, camel-kit, camel-spring-boot-examples and camel-quarkus-examples): the same reports, and none from the body walks;
  • 1209 model-written ones (the r17 benchmark series): the same 9 reports.

The extra coverage found nothing new in these files, as none has those components in a failing shape. The value is that the rules are now data, and each component annotated next is checked.

Tests:

  • TextBodyFlowTest: the consumers and producers the catalog adds, the options a side depends on, what the component may configure (kafka, aws2-sqs, a placeholder), one report for a failing step, and a catalog without body types.
  • BodyTypeFlowTest: cron, and ftp with download=false, give no body.
  • These pass:
    • the 279 tests of camel-yaml-dsl-validator, including the doc examples that EipDocExamplesTest validates (more than 1100, none with a report);
    • the 459 validator tests of camel-jbang-core.

Docs: the validation page of the Camel CLI says the body walk reads the catalog, and what it stays silent on. The catalog page says the validator uses the body types.

Claude Code on behalf of davsclaus

🤖 Generated with Claude Code

davsclaus and others added 7 commits October 21, 2026 13:58
…s, and the body it leaves after a step

A @BodyTypes annotation on the endpoint, data format or language class says the
body per side (consumerOut, consumerReply, producerIn, producerOut, marshal,
unmarshal and expression in and out): its carriers (null, text, bytes, stream,
file, value, map, list, pojo, unchanged, any, unknown), the Java type when it is
always the same, the format, the options it depends on, the body for other
option values, and a description. The package plugin writes it as a bodyTypes
section of the catalog JSON and checks that each side fits the kind and that
the options it names exist. A subclass declares its own.

The first slice: file, direct, seda, timer, cron, kamelet, http, https,
rest-openapi, xslt, sql and the json data format (jackson), read from the code
that sets the body and checked against the body types the message history
records when routes run. camel_catalog_doc returns them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
…tp, jms, kafka, aws2-sqs, the csv, jacksonXml and yaml data formats, and the languages

The second slice of the catalog body types:
- components: platform-http, rest (and the rest-openapi consumer), ftp, ftps,
  sftp, jms, activemq, activemq6, amqp, kafka, aws2-sqs, log, mock, scheduler,
  quartz;
- data formats: csv, jacksonXml, snakeYaml;
- languages: simple, constant, jsonpath, xpath, groovy, jq.

Each value is read from the code that sets the body, and checked against the
body types the message history recorded when the tests of the modules and
reference routes ran (the ftp integration tests included).

camel_catalog_doc gives the body types a line per side, and its answer is cut
at 18000 characters instead of 16000, so the four sides of the jms components
leave the options a limit asks for room.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
paho-mqtt5: the consumer gives the payload as a byte array, the producer sends
what converts to one and leaves the body unchanged.

mongodb: the consumer gives a Document (or null for a change without its full
document with changeStreams); the producer takes a document or a query, and
leaves a body by operation: a Document or null for a find of one, a List for
findAll, findDistinct and aggregate, a Long for count, the result of the driver
for the other writes.

Read from the code that sets the body, and checked against a mosquitto and a
mongodb container started with camel infra.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
…ts an option value without carriers

From the review of PR 28241:

- An iterator is read once and has no size and no index, so tooling that
  reads list as a List accepts ${body.size()} or ${body[0]} on it, which fail
  at runtime. The new iterator carrier names it: sql with outputType=StreamList
  gives an iterator, not a list.
- A @BodyType.When with no carriers (carrier = {}) wrote "carriers": [] into
  the catalog. The build now rejects it, as it does a side without carriers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
…MEL-24961-catalog-body-types-2

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
… camel_catalog_doc says unknown for no carriers

From the review of PR 28242:

- The csv data format with lazyLoad=true gives an iterator, with the iterator
  carrier of PR 28241, not a list.
- camel_catalog_doc says unknown for a body without carriers, instead of
  failing. The build rejects it now, but a catalog read from elsewhere may
  have one.
- Sqs2Endpoint imports org.apache.camel.spi.* already: only the import of the
  nested BodyType.Carrier stays.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
…types of the catalog instead of their own tables

The YAML validator's body walks read what a component or a data format does
with the body from the catalog, instead of from tables in their source:

- the consumer a route starts with (consumerOut): the file as read, text,
  bytes or data, instead of the file consumer only;
- the body after a to: (producerOut): unchanged for log and mock and now for a
  file write, the response of the http producer as bytes or a stream;
- the producers that need text (producerIn), instead of file, ftp, ftps and
  sftp only;
- the body after an unmarshal (unmarshalOut), instead of the json, jacksonXml,
  yaml and csv table and the options that make something else;
- the consumers that reply with text (consumerReply), instead of platform-http;
- the consumers that give no body, instead of timer, quartz, scheduler and cron.

A side holds for a step only when the step decides every option it depends
on: an option the component can also be configured with (the valueDeserializer
of kafka) counts only when the endpoint sets it, and a placeholder value is not
known. The catalog of an older Camel version has no body types, so the
validator's own catalog stands in for it. After a step that fails at runtime
the walk stops, so a file write that keeps the body is reported once.

The rules about HTTP methods, REST bindings and EIPs stay in the validator; the
EIPs get body types with CAMEL-25928.

The same reports as before on 1204 human-written route files (the Camel
repository, the examples, kamelets, camel-k and camel-kit) and on 1209
model-written ones (the r17 benchmark series), and the doc examples of the
validator tests still validate.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
@davsclaus davsclaus added this to the 4.24.0 milestone Oct 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Clean refactoring that replaces the hardcoded body-type sets (NO_BODY_CONSUMER, KEEPS_THE_BODY, WRITES_A_FILE, PARSES, NOT_A_MAP) with catalog-driven lookups via the new CatalogBodyTypes class. The option-dependent logic in answer() is carefully designed, the fallback for older catalog versions is sound, and test coverage is thorough — including the new testACatalogWithoutBodyTypes test that validates the fallback path explicitly.

The body = null; continue addition after reporting a failing step (preventing cascading false positives on the same body) is a nice correctness fix as a side effect of this refactoring.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

davsclaus and others added 9 commits October 21, 2026 20:46
The attribute holds an array, and the catalog JSON and BodyTypeModel call
the same field carriers. The Javadoc of BodyTypeModel.isUnknown() says that
a side with no carriers is unknown too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
…e data format and language schemas

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
…n read as a list, as the carriers do

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
@davsclaus
davsclaus changed the base branch from feature/CAMEL-24961-catalog-body-types-2 to main October 23, 2026 08:45
…atalog-body-types-3

Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • docs
  • dsl/camel-yaml-dsl/camel-yaml-dsl-validator

🔁 1 test passed only after a retry on JDK 21 (1 retried attempt)

Recovered flaky tests on JDK 21 (1)
Module Test Failed attempts First failure
dsl/camel-jbang/camel-jbang-plugin-tui LaunchManagerOutcomeTest.startedWhenTheStatusFileSaysSo 1 expected: null but was: LaunchOutcome[ok=false, log=null]

ℹ️ These tests did not fail the build. Surefire retried them and they passed.
Retries are enabled project-wide by surefire.rerunFailingTestsCount in parent/pom.xml.


🔬 Scalpel shadow comparison — Scalpel: 7 of 707 tested, 9 compile-only — current: 7 all tested

Maveniverse Scalpel detected 7 affected modules (current approach: 7).

Skip-tests mode would test 7 modules (2 direct + 6 downstream), skip tests for 9 (generated code, meta-modules)

Modules Scalpel would test (7)
  • camel-jbang-mcp ← downstream of org.apache.camel:camel-yaml-dsl-validator
  • camel-jbang-plugin-mcp ← downstream of org.apache.camel:camel-jbang-core
  • camel-jbang-plugin-tui ← downstream of org.apache.camel:camel-yaml-dsl-validator
  • camel-jbang-plugin-validate ← downstream of org.apache.camel:camel-yaml-dsl-validator
  • camel-launcher-container ← downstream of org.apache.camel:camel-launcher
  • camel-yaml-dsl-validator ← dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/BodyTypeFlow.java, dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/CatalogBodyTypes.java, dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/RouteGraph.java, dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/TextBodyFlow.java, dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java, dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/BodyTypeFlowTest.java, dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/TextBodyFlowTest.java
  • camel-yaml-dsl-validator-maven-plugin ← downstream of org.apache.camel:camel-yaml-dsl-validator
Modules with tests skipped (9)
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-launcher
  • coverage

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

All tested modules (17 modules, 3m 52s total)

Total reactor time: 3m 52s

Module Duration Status
Camel :: Launcher 52.9s SUCCESS
Camel :: JBang :: MCP 45.3s SUCCESS
Camel :: YAML DSL :: Validator 36.8s SUCCESS
Camel :: JBang :: Plugin :: Validate 31.8s SUCCESS
Camel :: Docs 20.5s SUCCESS
Camel :: JBang :: Plugin :: Testing 16.3s SUCCESS
Camel :: JBang :: Plugin :: Kubernetes 15.0s SUCCESS
Camel :: YAML DSL :: Validator Maven Plugin 3.5s SUCCESS
Camel :: Coverage 2.3s SUCCESS
Camel :: JBang :: Plugin :: Generate 1.8s SUCCESS
Camel :: JBang :: Plugin :: Edit 1.7s SUCCESS
Camel :: JBang :: Plugin :: MCP 1.6s SUCCESS
Camel :: JBang :: Integration tests 1.4s SUCCESS
Camel :: JBang :: Main 0.9s SUCCESS
Camel :: Launcher :: Container 0.7s SUCCESS
Camel :: JBang :: Core n/a
Camel :: JBang :: Plugin :: TUI n/a

Top 20 slowest modules:

  • Camel :: Launcher (52.9s)
  • Camel :: JBang :: MCP (45.3s)
  • Camel :: YAML DSL :: Validator (36.8s)
  • Camel :: JBang :: Plugin :: Validate (31.8s)
  • Camel :: Docs (20.5s)
  • Camel :: JBang :: Plugin :: Testing (16.3s)
  • Camel :: JBang :: Plugin :: Kubernetes (15.0s)
  • Camel :: YAML DSL :: Validator Maven Plugin (3.5s)
  • Camel :: Coverage (2.3s)
  • Camel :: JBang :: Plugin :: Generate (1.8s)
  • Camel :: JBang :: Plugin :: Edit (1.7s)
  • Camel :: JBang :: Plugin :: MCP (1.6s)
  • Camel :: JBang :: Integration tests (1.4s)
  • Camel :: JBang :: Main (0.9s)
  • Camel :: Launcher :: Container (0.7s)

⚙️ View full build and test results

@davsclaus davsclaus added the enhancement New feature or request label Oct 24, 2026
@davsclaus
davsclaus merged commit dd8c3d2 into main Oct 24, 2026
7 checks passed
@davsclaus
davsclaus deleted the feature/CAMEL-24961-catalog-body-types-3 branch October 24, 2026 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs dsl enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants