Repository navigation
CAMEL-24704: camel-yaml-dsl - beans keyed by the bean name fail with the list form to write - #26921
Conversation
|
🌟 Thank you for your contribution to the Apache Camel project! 🌟 🐫 Apache Camel Committers, please review the following items:
|
gnodet-bot
left a comment
There was a problem hiding this comment.
Solid feature PR — well-structured code, comprehensive error handling, and thorough test coverage across all three beans: entry points. The map-to-list conversion in asBeanDefinitions() is clean, the schema generation correctly produces oneOf with a keyed definition, and the scanBeansBlocks() refactoring properly isolates blocks to prevent cross-block name/type leakage. One doc nit below.
Milestone: this targets main and the feature is @since 4.23 — should carry milestone 4.23.0.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
|
🧪 CI tested the following changed modules:
🔬 Scalpel shadow comparison — Scalpel: 7 of 706 tested, 9 compile-only — current: 7 all testedMaveniverse Scalpel detected 7 affected modules (current approach: 7). Skip-tests mode would test 7 modules (3 direct + 6 downstream), skip tests for 9 (generated code, meta-modules) Modules Scalpel would test (7)
Modules with tests skipped (9)
All tested modules (18 modules, 3m 27s total)Total reactor time: 3m 27s
Top 20 slowest modules:
|
davsclaus
left a comment
There was a problem hiding this comment.
Thanks @ammachado, this is a careful implementation of the JIRA proposal. The list stays canonical: the canonical schema, the writer and --canonical still use it, and the map form is only in the lenient schema. The map-to-list conversion reuses every existing check and the pre-parse dedup. The "forgotten - " case gets its own error, so the two forms don't blur, and the upgrade-guide note for schema consumers is appreciated.
One small consistency point, inline: the new hint suggests the flow form myBean: {type: ...}, but the jbang bean-reference scanner only recognizes the block form. A model that follows the hint then gets "bean not declared", and camel_write_file refuses the file. Either write the hint in block form, or teach MAP_KEY_PATTERN the flow form.
This review was generated by an AI agent on behalf of davsclaus and may contain inaccuracies. Please verify all suggestions before applying.
davsclaus
left a comment
There was a problem hiding this comment.
Follow-up on the hints (this replaces my earlier "write the hint in block form" suggestion; my approval of the change itself stands).
The hints are what steer AI models writing Camel YAML, so they should only teach the canonical form. The list stays canonical in this PR (canonical schema, writer, docs), so a hint should not advertise the map form as an alternative, in flow style or block style. Two spots, inline:
- The missing-
-hint offersmyBean: {type: ...}as an alternative. I'd drop that tail so it only shows the list form. This also avoids theBeanRefChecksblind spot for the flow form, where a model that follows the hint has its file refused as "bean not declared". - The widened id/ref/class hint reads oddly for a map-form bean: for
myBean: {class: ...}it says "(name instead of class, type instead of class)", but the name is already the key. The new test only checks the "type instead of class" part, so it doesn't catch this.
Separately, MAP_KEY_PATTERN still doesn't see a flow-style map bean (myBean: {type: "#class:..."}). The runtime accepts it and a model may write it unprompted, so a small fix plus a test would be good to have.
This review was generated by an AI agent on behalf of davsclaus and may contain inaccuracies. Please verify all suggestions before applying.
davsclaus
left a comment
There was a problem hiding this comment.
Stepping back from the hint details: I think the PR does exactly what CAMEL-24704 proposed, but on reflection that proposal (accept the map form, keep the list canonical) leaves us with two styles for the same thing. All docs, examples, the YAML writer, the canonical schema and Kaoto use the list, while the runtime and the lenient schema quietly accept a map. Users and AI models will copy whichever they see first, and every tool that reads the schema has to handle both. I don't want us in that half-and-half state.
So I think we should pick one:
- Switch fully to the name-keyed map. Change all docs and examples, the YAML writer, the canonical schema, the hints and Kaoto to the map form, and deprecate the list form (still accepted, but no longer shown anywhere). If we go this way it should be a deliberate decision, discussed on the dev list since it affects Kaoto and other schema consumers. It should cover beans first, with the same plan for the other name-keyed lists in the JIRA (parameters, headers, variables, param).
- Stay with the list only. Don't accept the map form, and fix the "AI writes a map" problem through the hints alone: a clear "beans is a list: - name: myBean ..." message on the map shape, which the validator already largely gives.
We need to think more about this before going further, so I'm changing my review to request changes to hold the merge until it's decided. Sorry for the back-and-forth, @ammachado. The implementation itself is careful, and if we choose option 1 most of it (deserializer, schema oneOf, the mapKey annotation) is the foundation we'd need anyway.
This review was generated by an AI agent on behalf of davsclaus and may contain inaccuracies. Please verify all suggestions before applying.
…the list form to write
beans: is a list of items with a name: property. People and AI models
tend to write it keyed by the bean name instead, as a map
(beans: {myBean: {type: ...}}) or as list items (- myBean: {type: ...}).
camel run then failed with "Node type map is invalid, expected array" or
"Unsupported field: myBean", which does not say what to write.
BeansDeserializer.checkBeansIsAList now fails on both shapes with the list
form to write, using the name that was written:
- a map: "beans is a list: each bean starts with \"- \": - name: myBean
followed by type: ...". When the first key is name: (the "- " of the
list item was forgotten) the hint uses its value.
- an item with a single key holding a map, other than the bean's own map
properties (properties, constructors): "a bean item is written as
- name: myBean ... (the name is a property, not the key)".
The top-level beans, routeTemplate and templatedRoute all call it. These
are the hints the validator already gives, so camel run and camel
validate say the same thing. The list stays the only form of beans:.
_Claude Code on behalf of Adriano Machado (@ammachado)_
_This was generated by an AI agent and may contain inaccuracies.
Please verify before relying on it._
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…r routeTemplate and templatedRoute
The hints for a bean item keyed by the bean name (- myBean: {type: ...})
and for id/ref/class instead of name/type matched the location
/\d+/beans/\d+ in full, so only the top-level beans got them. The beans
of a routeTemplate (/0/routeTemplate/beans/0) and a templatedRoute are
the same list, and now match .*/beans/\d+, like the "beans is a list"
hint for a map already did with .*/beans.
_Claude Code on behalf of Adriano Machado (@ammachado)_
_This was generated by an AI agent and may contain inaccuracies.
Please verify before relying on it._
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2b2e44f to
fa433b6
Compare
|
Thanks @davsclaus, agreed that the half-and-half state is the worst of both. I went with option 2: the list stays the only form of What changed (rebased on main, force-pushed):
On the inline threads: the hints now teach only the list form (no I kept the map-form implementation on a local branch. If the project later decides on option 1 through the dev list, it is a starting point for that, and for the other name-keyed lists. Claude Code on behalf of Adriano Machado (@ammachado) This was generated by an AI agent and may contain inaccuracies. Please verify before relying on it. |
davsclaus
left a comment
There was a problem hiding this comment.
Thanks @ammachado, and thanks for taking option 2 so cleanly. The list stays the only form of beans:, and the PR is now only about messages, so my request for changes is resolved.
I read the new diff:
checkBeansIsAListruns for the top-levelbeans(both the pre-parse inYamlRoutesBuilderLoaderand the normal path go throughBeansDeserializer.construct) and forrouteTemplate/templatedRoute. The map case reuses the name from a forgotten- name:, which is a nice touch.- The keyed-item check skips
propertiesandconstructors. Those are the only map-valued bean properties in the generatedBeanFactoryDefinitiondeserializer, so a valid bean item cannot be refused. - The validator regexes now match
.*/beans/\d+, so the "name instead of ..." wording only reaches list items, which settles my earlier point about it. - The tests cover each shape, including the lone
properties:guard. No sleeps.
I resolved my four inline threads: the map form, the flow-form hint and the BeanRefChecks gap are all gone.
One small, non-blocking nit: the PR says camel run and camel validate now say the same thing, but the wording differs a little. The runtime says beans is a list: each bean starts with "- ": - name: <the real name> ..., while the validator's .*/beans hint says beans is a list: - name: myBean .... Aligning the validator text with the runtime one would make them identical. Fine as a follow-up.
The CI failure is not caused by this PR. CatalogSamplesTest.callingAServiceIsTheHttpComponentNotEnrich expects uri: http in the first http sample, and CAMEL-25745 (#28041) just added a first sample on main whose URI is quoted (uri: "http://localhost:8080/stock/..."). So main fails that test too. Once main is fixed, a re-run should be green. Approving.
Claude Code on behalf of Claus Ibsen. This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.
|
Closing and reopening to re-run CI against main: the Claude Code on behalf of Claus Ibsen |
Description
CAMEL-24704:
beanswritten keyed by the bean name now fails with the list form to write, at runtime as well as in the validator. The list stays the only form ofbeans:.This PR first accepted the map form next to the list, as the JIRA proposed. Following the review, it now takes the other option: keep one form (the list) and steer people and AI models to it through the error messages, so docs, the writer, the schemas and Kaoto stay on a single style. The map-form implementation is kept on a local branch in case the project later decides to switch fully to the map form (that would be a dev list decision).
The two shapes people and models write first:
camel validatealready explained how to rewrite both, butcamel runfailed withNode type map is invalid, expected arrayorUnsupported field: myProcessor.Runtime (
camel-yaml-dsl-deserializers)BeansDeserializer.checkBeansIsAList(Node)is called for the top-levelbeans, and for thebeansofrouteTemplateandtemplatedRoute.beans is a list: each bean starts with "- ": - name: myProcessor followed by type: "#class:com.example.MyBean" (indented under the -). When the first key isname:(the-of the list item was forgotten), the hint uses its value.properties,constructors):a bean item is written as - name: myProcessor followed by type: ... (the name is a property, not the key).camel runandcamel validatenow say the same thing.Validator (
camel-yaml-dsl-validator)id/ref/classinstead ofname/type) matched/\d+/beans/\d+in full, so only the top-level beans got them. They now match.*/beans/\d+, like the existing map hint (.*/beans), which also coversrouteTemplateandtemplatedRoute.No schema, doc or upgrade-guide change: what is accepted is unchanged, only the messages are.
Tests:
BeansTestcovers the map, the forgotten-, an item keyed by name, arouteTemplatemap and atemplatedRoutekeyed item, plus a guard that a loneproperties:item still reports the missing name.YamlValidatorPropertyHintTestcovers the template hints. Againstmain's code, 5 of the 6 newBeansTesttests and the new validator test fail (the guard passes by design). With this change: camel-yaml-dsl-validator 262/262, andBeansTest,RouteTemplateTest,TemplatedRouteTest41/41.Target
mainbranch)Tracking
Apache Camel coding standards and style
mvn clean install -DskipTestslocally from root folder and I have committed all auto-generated changes.The root build passed (run with
mvnd). The change adds no generated content, and the build left no uncommitted changes from this PR. It did regeneratemodel.propertieswith awasmentry, which came from untrackedsrc/generatedfiles left in my worktree from before CAMEL-25677 removed the wasm language. I deleted those local files and did not commit anything for it.AI-assisted contributions
Co-authored-bytrailers) and the PR description identifies the AI tool used.🤖 Generated with Claude Code on behalf of Adriano Machado (@ammachado)
This was generated by an AI agent and may contain inaccuracies. Please verify before relying on it.