davsclaus opened a new pull request, #26351: URL: https://github.com/apache/camel/pull/26351
Fixes [CAMEL-24694](https://issues.apache.org/jira/browse/CAMEL-24694). ## Problem The generated YAML DSL JSON schema types scalar attributes from the model's catalog metadata, but the model fields are `String` and the YAML deserializer passes the raw text to the setter — Camel converts it (resolving property placeholders) when the route starts. The schema is therefore stricter than the runtime, and every consumer of it — `camel validate yaml`, the TUI save-time validation and its `tui_write_file` / `tui_validate_source` MCP tools, camel-jbang-mcp `camel_validate_yaml_dsl`, IDE plugins and Kaoto — refuses input that `camel run` accepts. ```yaml - route: from: uri: timer:tick?period=1000 steps: - split: parallelProcessing: "true" # string found, boolean expected tokenize: "," steps: - log: "${body}" ``` Three shapes are affected: a quoted scalar at a typed attribute, a **property placeholder** at a typed attribute (the largest class — 572 EIP options are schema `boolean`/`integer`/`number` backed by `String` fields), and a bare integer at a `duration` attribute, which the schema emits as `string` (27 options). ## Approach The schema keeps its real types — Kaoto forms, TUI completion and catalog docs rely on them, so no type unions are emitted. The leniency lives in `YamlValidator`, and applies in **both** classic and canonical mode (they share one `init()`): 1. **`typeLoose(true)`** on `SchemaRegistryConfig` — a quoted scalar that parses as the expected type validates. This is a validator-runtime flag only; `camelYamlDsl.json` is unchanged. Values that do not parse (`parallelProcessing: "yes please"`) are still rejected. 2. **`isRuntimeAcceptedScalar`** post-filter — drops a `type` error when the instance is a property placeholder at a typed attribute, or a number/boolean at a string-typed attribute. It keys off `getSchemaNode()` / `getInstanceNode()` rather than parsing message text, and follows the existing `filterOneOfNoise` pattern in the same class. Everything else stays strict: unknown properties, structure, enums, and strings that do not parse as the expected type. ## Keeping the runtime honest The filter is only correct if the runtime really does defer conversion for every scalar attribute the schema exposes. Out of ~1660 generated deserializer cases, five converted eagerly, so a property placeholder was never resolved for them — `Boolean.valueOf("{{flag}}")` silently yields `false`. Two of the five are reachable from the schema and are ported here to `String` fields with `@Metadata(javaType = ...)`, like the rest of the model: * `ParamDefinition.required` (rest DSL `param`) * `RouteTemplateParameterDefinition.required` (`templateParameter`) Because the metadata still declares `javaType = java.lang.Boolean`, the catalog and the schema continue to emit `boolean` — only the deserializer changes, from `Boolean.valueOf(val)` to passing the text through. The XML parser gains the same placeholder support for free. The other three are **not reachable from the generated schema**, so the leniency cannot affect them, and they are left alone and tracked in [CAMEL-24696](https://issues.apache.org/jira/browse/CAMEL-24696): | attribute | why it is unreachable | | --- | --- | | `CircuitBreakerDefinition.inheritErrorHandler` | `GenerateYamlSchemaMojo` skips `inheritErrorHandler` deliberately | | `FailoverLoadBalancerDefinition.inheritErrorHandler` | same | | `BeanConstructorDefinition.index` | orphan definition — `BeanFactoryDefinition.constructors` is emitted as a free-form `object`, so nothing `$ref`s it | `index` is additionally unportable: it ends up as a `Map<Integer, Object>` key ordering the constructor arguments, so a placeholder can never work there. ## API change `getRequired()` / `setRequired(...)` on the two definitions above now use `String` instead of `Boolean`. The fluent `ParamDefinition.required(Boolean)` is unchanged and a `required(String)` overload was added for placeholders. `RouteTemplateParameterDefinition.isRequired()` still returns `boolean` but does not resolve placeholders — callers with a `CamelContext` should use `CamelContextHelper.parseBoolean(...)`, which `DefaultModel` now does. Documented in the 4.23 upgrade guide. Routes written in XML, YAML or the Java DSL need no change. ## Testing New `YamlValidatorScalarLeniencyTest` runs every case against **both** the classic and canonical validator: | case | before | after | | --- | --- | --- | | `parallelProcessing: "true"` | string found, boolean expected | accepted | | `parallelProcessing: "{{myParallel}}"` | string found, boolean expected | accepted | | `group: "100"` / `errorThreshold: "0.5"` | string found, number expected | accepted | | `group: "{{myGroup}}"` | string found, number expected | accepted | | `timeout: 5000` (duration) | integer found, string expected | accepted | | `parallelProcessing: "yes please"` | rejected | **still rejected** | | `group: "a lot"` | rejected | **still rejected** | | `cheese: true` (unknown property) | rejected | **still rejected** | Plus two runtime regression tests in `RouteTemplateTest` for the placeholder at `templateParameter.required` — the case that previously turned a required parameter into an optional one without any error. Green: full clean build (611 modules), camel-yaml-dsl (412), camel-openapi-java (97), camel-core template/rest (163), camel-yaml-dsl-validator, camel-xml-io, camel-yaml-io, camel-java-io, camel-core-engine. --- _Claude Code on behalf of davsclaus_ -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
