This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-4.22.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.22.x by this push:
new a3e872ec7b4e [backport camel-4.22.x] CAMEL-24482: camel-yaml-dsl -
Canonical schema wrongly requires every data format on unmarshal
a3e872ec7b4e is described below
commit a3e872ec7b4ebfc7204da7cdb660dd085f0853a0
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Aug 28 09:16:12 2026 +0200
[backport camel-4.22.x] CAMEL-24482: camel-yaml-dsl - Canonical schema
wrongly requires every data format on unmarshal
Cherry-pick of #25840 onto camel-4.22.x. Generated schema/deserializer
files were regenerated from source to match this branch's actual
component set (fewer data formats than main).
Co-authored-by: Claude Sonnet 5 <[email protected]>
---
.../camel/catalog/schemas/camelYamlDsl-model.json | 152 +++++++--------------
.../org/apache/camel/model/MarshalDefinition.java | 3 +-
.../dsl/yaml/deserializers/ModelDeserializers.java | 96 ++++++-------
.../maven/dsl/yaml/GenerateYamlSchemaMojo.java | 7 +-
.../camel-yaml-dsl-validator/pom.xml | 4 +
.../camel/dsl/yaml/validator/YamlValidator.java | 123 ++++++++++++++++-
.../yaml/validator/YamlCanonicalValidatorTest.java | 66 +++++++++
.../canonical-invalid-missing-dataformat.yaml | 22 +++
.../test/resources/canonical-valid-dataformat.yaml | 27 ++++
.../resources/schema/camelYamlDsl-canonical.json | 8 +-
.../resources/schema/camelYamlDsl-model.json | 152 +++++++--------------
.../generated/resources/schema/camelYamlDsl.json | 100 --------------
.../org/apache/camel/dsl/yaml/MarshalTest.groovy | 12 +-
13 files changed, 411 insertions(+), 361 deletions(-)
diff --git
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
index 2c7cb827c3cf..7614f49e514d 100644
---
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
+++
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camelYamlDsl-model.json
@@ -5128,11 +5128,11 @@
"ref" : "expression",
"description" : "The property value as an expression.",
"title" : "Expression",
- "required" : true,
"displayName" : "Expression",
"kind" : "expression",
"index" : 1,
- "group" : "common"
+ "group" : "common",
+ "required" : true
} ]
},
"recipientList" : {
@@ -5981,11 +5981,11 @@
"ref" : "expression",
"description" : "Expression to use for re-ordering the messages, such
as a header with a sequence number.",
"title" : "Expression",
- "required" : true,
"displayName" : "Expression",
"kind" : "expression",
"index" : 4,
- "group" : "common"
+ "group" : "common",
+ "required" : true
}, {
"name" : "batchConfig",
"type" : "object",
@@ -9110,243 +9110,195 @@
}, {
"name" : "asn1",
"type" : "object",
- "ref" : "aSN1",
- "required" : true
+ "ref" : "aSN1"
}, {
"name" : "avro",
"type" : "object",
- "ref" : "avro",
- "required" : true
+ "ref" : "avro"
}, {
"name" : "barcode",
"type" : "object",
- "ref" : "barcode",
- "required" : true
+ "ref" : "barcode"
}, {
"name" : "base64",
"type" : "object",
- "ref" : "base64",
- "required" : true
+ "ref" : "base64"
}, {
"name" : "beanio",
"type" : "object",
- "ref" : "beanio",
- "required" : true
+ "ref" : "beanio"
}, {
"name" : "bindy",
"type" : "object",
- "ref" : "bindy",
- "required" : true
+ "ref" : "bindy"
}, {
"name" : "cbor",
"type" : "object",
- "ref" : "cBOR",
- "required" : true
+ "ref" : "cBOR"
}, {
"name" : "crypto",
"type" : "object",
- "ref" : "crypto",
- "required" : true
+ "ref" : "crypto"
}, {
"name" : "csv",
"type" : "object",
- "ref" : "csv",
- "required" : true
+ "ref" : "csv"
}, {
"name" : "custom",
"type" : "object",
- "ref" : "custom",
- "required" : true
+ "ref" : "custom"
}, {
"name" : "dfdl",
"type" : "object",
- "ref" : "dfdl",
- "required" : true
+ "ref" : "dfdl"
}, {
"name" : "fhirJson",
"type" : "object",
- "ref" : "fhirJson",
- "required" : true
+ "ref" : "fhirJson"
}, {
"name" : "fhirXml",
"type" : "object",
- "ref" : "fhirXml",
- "required" : true
+ "ref" : "fhirXml"
}, {
"name" : "flatpack",
"type" : "object",
- "ref" : "flatpack",
- "required" : true
+ "ref" : "flatpack"
}, {
"name" : "fory",
"type" : "object",
- "ref" : "fory",
- "required" : true
+ "ref" : "fory"
}, {
"name" : "grok",
"type" : "object",
- "ref" : "grok",
- "required" : true
+ "ref" : "grok"
}, {
"name" : "groovyJson",
"type" : "object",
- "ref" : "groovyJSon",
- "required" : true
+ "ref" : "groovyJSon"
}, {
"name" : "groovyXml",
"type" : "object",
- "ref" : "groovyXml",
- "required" : true
+ "ref" : "groovyXml"
}, {
"name" : "gzipDeflater",
"type" : "object",
- "ref" : "gzipDeflater",
- "required" : true
+ "ref" : "gzipDeflater"
}, {
"name" : "hl7",
"type" : "object",
- "ref" : "hL7",
- "required" : true
+ "ref" : "hL7"
}, {
"name" : "ical",
"type" : "object",
- "ref" : "ical",
- "required" : true
+ "ref" : "ical"
}, {
"name" : "iso8583",
"type" : "object",
- "ref" : "iso8583",
- "required" : true
+ "ref" : "iso8583"
}, {
"name" : "jacksonXml",
"type" : "object",
- "ref" : "jacksonXML",
- "required" : true
+ "ref" : "jacksonXML"
}, {
"name" : "jaxb",
"type" : "object",
- "ref" : "jaxb",
- "required" : true
+ "ref" : "jaxb"
}, {
"name" : "json",
"type" : "object",
- "ref" : "json",
- "required" : true
+ "ref" : "json"
}, {
"name" : "jsonApi",
"type" : "object",
- "ref" : "jsonApi",
- "required" : true
+ "ref" : "jsonApi"
}, {
"name" : "lzf",
"type" : "object",
- "ref" : "lZF",
- "required" : true
+ "ref" : "lZF"
}, {
"name" : "mimeMultipart",
"type" : "object",
- "ref" : "mimeMultipart",
- "required" : true
+ "ref" : "mimeMultipart"
}, {
"name" : "ocsf",
"type" : "object",
- "ref" : "ocsf",
- "required" : true
+ "ref" : "ocsf"
}, {
"name" : "parquetAvro",
"type" : "object",
- "ref" : "parquetAvro",
- "required" : true
+ "ref" : "parquetAvro"
}, {
"name" : "pgp",
"type" : "object",
- "ref" : "pGP",
- "required" : true
+ "ref" : "pGP"
}, {
"name" : "pqc",
"type" : "object",
- "ref" : "pQC",
- "required" : true
+ "ref" : "pQC"
}, {
"name" : "protobuf",
"type" : "object",
- "ref" : "protobuf",
- "required" : true
+ "ref" : "protobuf"
}, {
"name" : "rss",
"type" : "object",
- "ref" : "rss",
- "required" : true
+ "ref" : "rss"
}, {
"name" : "smooks",
"type" : "object",
- "ref" : "smooks",
- "required" : true
+ "ref" : "smooks"
}, {
"name" : "soap",
"type" : "object",
- "ref" : "soap",
- "required" : true
+ "ref" : "soap"
}, {
"name" : "swiftMt",
"type" : "object",
- "ref" : "swiftMt",
- "required" : true
+ "ref" : "swiftMt"
}, {
"name" : "swiftMx",
"type" : "object",
- "ref" : "swiftMx",
- "required" : true
+ "ref" : "swiftMx"
}, {
"name" : "syslog",
"type" : "object",
- "ref" : "syslog",
- "required" : true
+ "ref" : "syslog"
}, {
"name" : "tarFile",
"type" : "object",
- "ref" : "tarFile",
- "required" : true
+ "ref" : "tarFile"
}, {
"name" : "thrift",
"type" : "object",
- "ref" : "thrift",
- "required" : true
+ "ref" : "thrift"
}, {
"name" : "univocityCsv",
"type" : "object",
- "ref" : "uniVocityCsv",
- "required" : true
+ "ref" : "uniVocityCsv"
}, {
"name" : "univocityFixed",
"type" : "object",
- "ref" : "uniVocityFixed",
- "required" : true
+ "ref" : "uniVocityFixed"
}, {
"name" : "univocityTsv",
"type" : "object",
- "ref" : "uniVocityTsv",
- "required" : true
+ "ref" : "uniVocityTsv"
}, {
"name" : "xmlSecurity",
"type" : "object",
- "ref" : "xMLSecurity",
- "required" : true
+ "ref" : "xMLSecurity"
}, {
"name" : "yaml",
"type" : "object",
- "ref" : "yAML",
- "required" : true
+ "ref" : "yAML"
}, {
"name" : "zipDeflater",
"type" : "object",
- "ref" : "zipDeflater",
- "required" : true
+ "ref" : "zipDeflater"
}, {
"name" : "zipFile",
"type" : "object",
- "ref" : "zipFile",
- "required" : true
+ "ref" : "zipFile"
} ]
},
"validate" : {
diff --git
a/core/camel-core-model/src/main/java/org/apache/camel/model/MarshalDefinition.java
b/core/camel-core-model/src/main/java/org/apache/camel/model/MarshalDefinition.java
index 564cdef59f92..1a300b2e0928 100644
---
a/core/camel-core-model/src/main/java/org/apache/camel/model/MarshalDefinition.java
+++
b/core/camel-core-model/src/main/java/org/apache/camel/model/MarshalDefinition.java
@@ -132,7 +132,8 @@ public class MarshalDefinition extends
NoOutputDefinition<MarshalDefinition> imp
@XmlElement(name = "yaml", type = YAMLDataFormat.class),
@XmlElement(name = "zipDeflater", type =
ZipDeflaterDataFormat.class),
@XmlElement(name = "zipFile", type = ZipFileDataFormat.class) })
- @Metadata(description = "The data format to use for marshalling the
message body into a specific format such as JSON, XML, CSV, Avro, Protobuf,
etc.")
+ @Metadata(required = true,
+ description = "The data format to use for marshalling the
message body into a specific format such as JSON, XML, CSV, Avro, Protobuf,
etc.")
private DataFormatDefinition dataFormatType;
@XmlAttribute
@Metadata(description = "To use a variable as the source for the message
body to send. This makes it handy to use variables for user data and to easily
control what data to use for sending and receiving.")
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index 6a183fc53af1..46f6c98a8159 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -9423,60 +9423,60 @@ public final class ModelDeserializers extends
YamlDeserializerSupport {
description = "Serializes the message body into a specific data
format such as JSON, XML, CSV, or Protobuf for transmission or storage",
deprecated = false,
properties = {
- @YamlProperty(name = "asn1", type =
"object:org.apache.camel.model.dataformat.ASN1DataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "avro", type =
"object:org.apache.camel.model.dataformat.AvroDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "barcode", type =
"object:org.apache.camel.model.dataformat.BarcodeDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "base64", type =
"object:org.apache.camel.model.dataformat.Base64DataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "beanio", type =
"object:org.apache.camel.model.dataformat.BeanioDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "bindy", type =
"object:org.apache.camel.model.dataformat.BindyDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "cbor", type =
"object:org.apache.camel.model.dataformat.CBORDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "crypto", type =
"object:org.apache.camel.model.dataformat.CryptoDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "csv", type =
"object:org.apache.camel.model.dataformat.CsvDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "custom", type =
"object:org.apache.camel.model.dataformat.CustomDataFormat", oneOf =
"dataFormatType"),
+ @YamlProperty(name = "asn1", type =
"object:org.apache.camel.model.dataformat.ASN1DataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "avro", type =
"object:org.apache.camel.model.dataformat.AvroDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "barcode", type =
"object:org.apache.camel.model.dataformat.BarcodeDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "base64", type =
"object:org.apache.camel.model.dataformat.Base64DataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "beanio", type =
"object:org.apache.camel.model.dataformat.BeanioDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "bindy", type =
"object:org.apache.camel.model.dataformat.BindyDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "cbor", type =
"object:org.apache.camel.model.dataformat.CBORDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "crypto", type =
"object:org.apache.camel.model.dataformat.CryptoDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "csv", type =
"object:org.apache.camel.model.dataformat.CsvDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "custom", type =
"object:org.apache.camel.model.dataformat.CustomDataFormat", required = true,
oneOf = "dataFormatType"),
@YamlProperty(name = "description", type = "string",
description = "The description for this node", displayName = "Description"),
- @YamlProperty(name = "dfdl", type =
"object:org.apache.camel.model.dataformat.DfdlDataFormat", oneOf =
"dataFormatType"),
+ @YamlProperty(name = "dfdl", type =
"object:org.apache.camel.model.dataformat.DfdlDataFormat", required = true,
oneOf = "dataFormatType"),
@YamlProperty(name = "disabled", type = "boolean",
defaultValue = "false", description = "Whether to disable this EIP from the
route during build time. Once an EIP has been disabled then it cannot be
enabled later at runtime.", displayName = "Disabled"),
- @YamlProperty(name = "fhirJson", type =
"object:org.apache.camel.model.dataformat.FhirJsonDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "fhirXml", type =
"object:org.apache.camel.model.dataformat.FhirXmlDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "flatpack", type =
"object:org.apache.camel.model.dataformat.FlatpackDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "fory", type =
"object:org.apache.camel.model.dataformat.ForyDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "grok", type =
"object:org.apache.camel.model.dataformat.GrokDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "groovyJson", type =
"object:org.apache.camel.model.dataformat.GroovyJSonDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "groovyXml", type =
"object:org.apache.camel.model.dataformat.GroovyXmlDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "gzipDeflater", type =
"object:org.apache.camel.model.dataformat.GzipDeflaterDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "hl7", type =
"object:org.apache.camel.model.dataformat.HL7DataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "ical", type =
"object:org.apache.camel.model.dataformat.IcalDataFormat", oneOf =
"dataFormatType"),
+ @YamlProperty(name = "fhirJson", type =
"object:org.apache.camel.model.dataformat.FhirJsonDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "fhirXml", type =
"object:org.apache.camel.model.dataformat.FhirXmlDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "flatpack", type =
"object:org.apache.camel.model.dataformat.FlatpackDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "fory", type =
"object:org.apache.camel.model.dataformat.ForyDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "grok", type =
"object:org.apache.camel.model.dataformat.GrokDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "groovyJson", type =
"object:org.apache.camel.model.dataformat.GroovyJSonDataFormat", required =
true, oneOf = "dataFormatType"),
+ @YamlProperty(name = "groovyXml", type =
"object:org.apache.camel.model.dataformat.GroovyXmlDataFormat", required =
true, oneOf = "dataFormatType"),
+ @YamlProperty(name = "gzipDeflater", type =
"object:org.apache.camel.model.dataformat.GzipDeflaterDataFormat", required =
true, oneOf = "dataFormatType"),
+ @YamlProperty(name = "hl7", type =
"object:org.apache.camel.model.dataformat.HL7DataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "ical", type =
"object:org.apache.camel.model.dataformat.IcalDataFormat", required = true,
oneOf = "dataFormatType"),
@YamlProperty(name = "id", type = "string", description =
"The id of this node", displayName = "Id"),
- @YamlProperty(name = "iso8583", type =
"object:org.apache.camel.model.dataformat.Iso8583DataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "jacksonXml", type =
"object:org.apache.camel.model.dataformat.JacksonXMLDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "jaxb", type =
"object:org.apache.camel.model.dataformat.JaxbDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "json", type =
"object:org.apache.camel.model.dataformat.JsonDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "jsonApi", type =
"object:org.apache.camel.model.dataformat.JsonApiDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "lzf", type =
"object:org.apache.camel.model.dataformat.LZFDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "mimeMultipart", type =
"object:org.apache.camel.model.dataformat.MimeMultipartDataFormat", oneOf =
"dataFormatType"),
+ @YamlProperty(name = "iso8583", type =
"object:org.apache.camel.model.dataformat.Iso8583DataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "jacksonXml", type =
"object:org.apache.camel.model.dataformat.JacksonXMLDataFormat", required =
true, oneOf = "dataFormatType"),
+ @YamlProperty(name = "jaxb", type =
"object:org.apache.camel.model.dataformat.JaxbDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "json", type =
"object:org.apache.camel.model.dataformat.JsonDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "jsonApi", type =
"object:org.apache.camel.model.dataformat.JsonApiDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "lzf", type =
"object:org.apache.camel.model.dataformat.LZFDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "mimeMultipart", type =
"object:org.apache.camel.model.dataformat.MimeMultipartDataFormat", required =
true, oneOf = "dataFormatType"),
@YamlProperty(name = "note", type = "string", description
= "The note for this node", displayName = "Note"),
- @YamlProperty(name = "ocsf", type =
"object:org.apache.camel.model.dataformat.OcsfDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "parquetAvro", type =
"object:org.apache.camel.model.dataformat.ParquetAvroDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "pgp", type =
"object:org.apache.camel.model.dataformat.PGPDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "pqc", type =
"object:org.apache.camel.model.dataformat.PQCDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "protobuf", type =
"object:org.apache.camel.model.dataformat.ProtobufDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "rss", type =
"object:org.apache.camel.model.dataformat.RssDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "smooks", type =
"object:org.apache.camel.model.dataformat.SmooksDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "soap", type =
"object:org.apache.camel.model.dataformat.SoapDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "swiftMt", type =
"object:org.apache.camel.model.dataformat.SwiftMtDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "swiftMx", type =
"object:org.apache.camel.model.dataformat.SwiftMxDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "syslog", type =
"object:org.apache.camel.model.dataformat.SyslogDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "tarFile", type =
"object:org.apache.camel.model.dataformat.TarFileDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "thrift", type =
"object:org.apache.camel.model.dataformat.ThriftDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "univocityCsv", type =
"object:org.apache.camel.model.dataformat.UniVocityCsvDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "univocityFixed", type =
"object:org.apache.camel.model.dataformat.UniVocityFixedDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "univocityTsv", type =
"object:org.apache.camel.model.dataformat.UniVocityTsvDataFormat", oneOf =
"dataFormatType"),
+ @YamlProperty(name = "ocsf", type =
"object:org.apache.camel.model.dataformat.OcsfDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "parquetAvro", type =
"object:org.apache.camel.model.dataformat.ParquetAvroDataFormat", required =
true, oneOf = "dataFormatType"),
+ @YamlProperty(name = "pgp", type =
"object:org.apache.camel.model.dataformat.PGPDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "pqc", type =
"object:org.apache.camel.model.dataformat.PQCDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "protobuf", type =
"object:org.apache.camel.model.dataformat.ProtobufDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "rss", type =
"object:org.apache.camel.model.dataformat.RssDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "smooks", type =
"object:org.apache.camel.model.dataformat.SmooksDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "soap", type =
"object:org.apache.camel.model.dataformat.SoapDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "swiftMt", type =
"object:org.apache.camel.model.dataformat.SwiftMtDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "swiftMx", type =
"object:org.apache.camel.model.dataformat.SwiftMxDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "syslog", type =
"object:org.apache.camel.model.dataformat.SyslogDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "tarFile", type =
"object:org.apache.camel.model.dataformat.TarFileDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "thrift", type =
"object:org.apache.camel.model.dataformat.ThriftDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "univocityCsv", type =
"object:org.apache.camel.model.dataformat.UniVocityCsvDataFormat", required =
true, oneOf = "dataFormatType"),
+ @YamlProperty(name = "univocityFixed", type =
"object:org.apache.camel.model.dataformat.UniVocityFixedDataFormat", required =
true, oneOf = "dataFormatType"),
+ @YamlProperty(name = "univocityTsv", type =
"object:org.apache.camel.model.dataformat.UniVocityTsvDataFormat", required =
true, oneOf = "dataFormatType"),
@YamlProperty(name = "variableReceive", type = "string",
description = "To use a variable to store the received message body (only body,
not headers). This makes it handy to use variables for user data and to easily
control what data to use for sending and receiving.", displayName = "Variable
Receive"),
@YamlProperty(name = "variableSend", type = "string",
description = "To use a variable as the source for the message body to send.
This makes it handy to use variables for user data and to easily control what
data to use for sending and receiving.", displayName = "Variable Send"),
- @YamlProperty(name = "xmlSecurity", type =
"object:org.apache.camel.model.dataformat.XMLSecurityDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "yaml", type =
"object:org.apache.camel.model.dataformat.YAMLDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "zipDeflater", type =
"object:org.apache.camel.model.dataformat.ZipDeflaterDataFormat", oneOf =
"dataFormatType"),
- @YamlProperty(name = "zipFile", type =
"object:org.apache.camel.model.dataformat.ZipFileDataFormat", oneOf =
"dataFormatType")
+ @YamlProperty(name = "xmlSecurity", type =
"object:org.apache.camel.model.dataformat.XMLSecurityDataFormat", required =
true, oneOf = "dataFormatType"),
+ @YamlProperty(name = "yaml", type =
"object:org.apache.camel.model.dataformat.YAMLDataFormat", required = true,
oneOf = "dataFormatType"),
+ @YamlProperty(name = "zipDeflater", type =
"object:org.apache.camel.model.dataformat.ZipDeflaterDataFormat", required =
true, oneOf = "dataFormatType"),
+ @YamlProperty(name = "zipFile", type =
"object:org.apache.camel.model.dataformat.ZipFileDataFormat", required = true,
oneOf = "dataFormatType")
}
)
public static class MarshalDefinitionDeserializer extends
YamlDeserializerBase<MarshalDefinition> {
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlSchemaMojo.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlSchemaMojo.java
index e00456472f88..d02214acc159 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlSchemaMojo.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-maven-plugin/src/main/java/org/apache/camel/maven/dsl/yaml/GenerateYamlSchemaMojo.java
@@ -345,7 +345,12 @@ public class GenerateYamlSchemaMojo extends
GenerateYamlSupportMojo {
propertyWrapItem,
additionalProperties);
- if (propertyRequired) {
+ // A property that belongs to a oneOf group (e.g. the data formats
of marshal/unmarshal, or the
+ // languages of an expression) is only required as part of
choosing one of the alternatives, not
+ // unconditionally. In canonical mode the oneOf grouping itself is
dropped (isInOneOf is always
+ // false), so without this guard every alternative would end up in
the flat "required" list,
+ // demanding all of them at once instead of exactly one.
+ if (propertyRequired && StringUtils.isEmpty(propertyOneOf)) {
definition.withArray("required").add(propertyName);
}
}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/pom.xml
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/pom.xml
index 76af060a96b1..2d4892b9d868 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/pom.xml
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/pom.xml
@@ -54,6 +54,10 @@
<groupId>org.apache.camel</groupId>
<artifactId>camel-stub</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-catalog</artifactId>
+ </dependency>
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
index efc833acb421..5b10bcc80123 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java
@@ -20,6 +20,8 @@ import java.io.File;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -40,6 +42,11 @@ import com.networknt.schema.SpecificationVersion;
import com.networknt.schema.dialect.Dialect;
import com.networknt.schema.dialect.Dialects;
import com.networknt.schema.keyword.NonValidationKeyword;
+import com.networknt.schema.path.NodePath;
+import com.networknt.schema.path.PathType;
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.catalog.DefaultCamelCatalog;
+import org.apache.camel.tooling.model.EipModel;
/**
* YAML DSL validator that tooling can use to validate Camel source files if
they can be parsed and are valid according
@@ -50,9 +57,27 @@ public class YamlValidator {
private static final String LOCATION = "/schema/camelYamlDsl.json";
private static final String LOCATION_CANONICAL =
"/schema/camelYamlDsl-canonical.json";
+ /**
+ * A handful of "pick exactly one" EIP option groups (see {@link
EipModel.EipOptionModel#getOneOfs()}) flatten their
+ * alternatives directly onto a specific host node instead of appearing
under a wrapper key named after the option
+ * itself (that's how "expression" works). The canonical schema cannot
express this "exactly one of" cardinality (it
+ * has no oneOf/anyOf constructs), so {@link #checkOneOfCardinality}
re-checks it here, driven by the same catalog
+ * metadata the classic schema is generated from.
+ */
+ private static final Map<String, Set<String>> FLATTENED_HOSTS = Map.of(
+ "dataFormatType", Set.of("marshal", "unmarshal"),
+ "errorHandlerType", Set.of("errorHandler"),
+ "tokenizerImplementation", Set.of("tokenizer"),
+ "resequencerConfig", Set.of("resequence"),
+ "loadBalancerType", Set.of("loadBalance"));
+
private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
private final boolean canonical;
private Schema schema;
+ private Map<String, OneOfGroup> oneOfGroups;
+
+ private record OneOfGroup(Set<String> alternatives, boolean required) {
+ }
public YamlValidator() {
this(false);
@@ -72,7 +97,7 @@ public class YamlValidator {
}
try {
var target = mapper.readTree(file);
- return filterOneOfNoise(new ArrayList<>(schema.validate(target)));
+ return validate(target);
} catch (Exception e) {
return List.of(parseError(e));
}
@@ -84,12 +109,20 @@ public class YamlValidator {
}
try {
var target = mapper.readTree(content);
- return filterOneOfNoise(new ArrayList<>(schema.validate(target)));
+ return validate(target);
} catch (Exception e) {
return List.of(parseError(e));
}
}
+ private List<Error> validate(JsonNode target) {
+ var errors = filterOneOfNoise(new
ArrayList<>(schema.validate(target)));
+ if (canonical) {
+ checkOneOfCardinality(target, new NodePath(PathType.JSON_POINTER),
errors);
+ }
+ return errors;
+ }
+
/**
* Filters noise from {@code oneOf} validation. When a {@code oneOf} has N
branches and none match, the validator
* reports errors from ALL branches — producing dozens of "required
property 'X' not found" messages for branches
@@ -221,6 +254,88 @@ public class YamlValidator {
|| "maxItems".equals(keyword));
}
+ /**
+ * Recursively walks the parsed YAML tree looking for the host
nodes/wrapper keys of a "pick exactly one" option
+ * group, and reports a synthetic error when zero (for a required group)
or more than one alternative is present.
+ */
+ private void checkOneOfCardinality(JsonNode node, NodePath path,
List<Error> errors) {
+ if (node.isObject()) {
+ Iterator<Map.Entry<String, JsonNode>> it = node.fields();
+ while (it.hasNext()) {
+ Map.Entry<String, JsonNode> entry = it.next();
+ String key = entry.getKey();
+ JsonNode value = entry.getValue();
+ NodePath childPath = path.append(key);
+ if (value.isObject()) {
+ for (Map.Entry<String, Set<String>> hostEntry :
FLATTENED_HOSTS.entrySet()) {
+ if (hostEntry.getValue().contains(key)) {
+ reportIfInvalidCardinality(value,
oneOfGroups.get(hostEntry.getKey()), childPath, errors);
+ }
+ }
+ if (!FLATTENED_HOSTS.containsKey(key)) {
+ reportIfInvalidCardinality(value,
oneOfGroups.get(key), childPath, errors);
+ }
+ }
+ checkOneOfCardinality(value, childPath, errors);
+ }
+ } else if (node.isArray()) {
+ for (int i = 0; i < node.size(); i++) {
+ checkOneOfCardinality(node.get(i), path.append(i), errors);
+ }
+ }
+ }
+
+ private static void reportIfInvalidCardinality(JsonNode container,
OneOfGroup group, NodePath path, List<Error> errors) {
+ if (group == null) {
+ return;
+ }
+ List<String> found = new ArrayList<>();
+ Iterator<String> names = container.fieldNames();
+ while (names.hasNext()) {
+ String name = names.next();
+ if (group.alternatives().contains(name)) {
+ found.add(name);
+ }
+ }
+ if (found.isEmpty() && group.required()) {
+ errors.add(Error.builder()
+ .keyword("oneOf")
+ .instanceLocation(path)
+ .message("must have exactly one of " +
group.alternatives() + " but found none")
+ .build());
+ } else if (found.size() > 1) {
+ errors.add(Error.builder()
+ .keyword("oneOf")
+ .instanceLocation(path)
+ .message("must have exactly one of " +
group.alternatives() + " but found: " + found)
+ .build());
+ }
+ }
+
+ /**
+ * Builds the "pick exactly one" option groups from the Camel catalog's
EIP model metadata - the same metadata the
+ * classic (non-canonical) schema's oneOf groups are generated from. Only
object-typed options are considered;
+ * array-typed options (e.g. "outputs") use "oneOf" to mean "each element
is one of these types", not "exactly one
+ * of these sibling keys must be present".
+ */
+ private static Map<String, OneOfGroup> loadOneOfGroups() {
+ Map<String, OneOfGroup> groups = new HashMap<>();
+ CamelCatalog catalog = new DefaultCamelCatalog();
+ for (String name : catalog.findModelNames()) {
+ EipModel model = catalog.eipModel(name);
+ if (model == null) {
+ continue;
+ }
+ for (EipModel.EipOptionModel option : model.getOptions()) {
+ List<String> oneOfs = option.getOneOfs();
+ if (oneOfs != null && !oneOfs.isEmpty() &&
"object".equals(option.getType())) {
+ groups.putIfAbsent(option.getName(), new OneOfGroup(new
LinkedHashSet<>(oneOfs), option.isRequired()));
+ }
+ }
+ }
+ return groups;
+ }
+
private static Error parseError(Exception e) {
String msg = e.getClass().getName() + ": " + e.getMessage();
return Error.builder()
@@ -248,6 +363,10 @@ public class YamlValidator {
// Use a proper URI for the schema location to ensure $ref resolution
works
var schemaLocation = SchemaLocation.of(location);
schema = schemaRegistry.getSchema(schemaLocation, model);
+
+ if (canonical) {
+ oneOfGroups = loadOneOfGroups();
+ }
}
private static Dialect getBaseDialect(SpecificationVersion version) {
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlCanonicalValidatorTest.java
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlCanonicalValidatorTest.java
index 0c5578139dc4..45c5c17de9e3 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlCanonicalValidatorTest.java
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/java/org/apache/camel/dsl/yaml/validator/YamlCanonicalValidatorTest.java
@@ -22,6 +22,8 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class YamlCanonicalValidatorTest {
private static YamlValidator canonicalValidator;
@@ -96,4 +98,68 @@ public class YamlCanonicalValidatorTest {
Assertions.assertFalse(canonicalReport.isEmpty(),
"foo.yaml uses implicit forms and should fail canonical
validation");
}
+
+ @Test
+ public void
testUnmarshalMarshalWithSingleDataFormatPassesCanonicalValidation() throws
Exception {
+ // CAMEL-24482: a single data format (e.g. json) on unmarshal/marshal
must not require
+ // every other data format to also be present.
+ var report = canonicalValidator.validate(new
File("src/test/resources/canonical-valid-dataformat.yaml"));
+ assertThat(report).as("Single data format should pass canonical
validation but got: %s", report).isEmpty();
+ }
+
+ @Test
+ public void
testUnmarshalMarshalWithSingleDataFormatPassesClassicValidation() throws
Exception {
+ var report = classicValidator.validate(new
File("src/test/resources/canonical-valid-dataformat.yaml"));
+ assertThat(report).as("Single data format should pass classic
validation but got: %s", report).isEmpty();
+ }
+
+ @Test
+ public void testUnmarshalWithoutDataFormatFailsCanonicalValidation()
throws Exception {
+ // The canonical schema itself has no oneOf/anyOf constructs to
express "exactly one of these N
+ // properties is required", so YamlValidator re-checks this
cardinality itself, driven by the same
+ // catalog "oneOf" metadata the classic schema is generated from.
+ var report = canonicalValidator.validate(new
File("src/test/resources/canonical-invalid-missing-dataformat.yaml"));
+ assertThat(report).as("unmarshal without a data format should fail
canonical validation").isNotEmpty();
+ }
+
+ @Test
+ public void testUnmarshalWithoutDataFormatFailsClassicValidation() throws
Exception {
+ // Unlike canonical mode, the classic schema keeps its oneOf group and
still requires exactly
+ // one data format to be chosen.
+ var report = classicValidator.validate(new
File("src/test/resources/canonical-invalid-missing-dataformat.yaml"));
+ assertThat(report).as("unmarshal without a data format should fail
classic validation").isNotEmpty();
+ }
+
+ @Test
+ public void
testResequenceWithoutBatchOrStreamConfigFailsCanonicalValidation() throws
Exception {
+ // The "exactly one of" cardinality check is generic, not
special-cased to marshal/unmarshal:
+ // resequence must pick exactly one of batchConfig/streamConfig too.
+ var route = """
+ - route:
+ from:
+ uri: "direct:start"
+ steps:
+ - resequence:
+ expression:
+ simple:
+ expression: "${header.seqnum}"
+ """;
+ var report = canonicalValidator.validate(route);
+ assertThat(report).as("resequence without batchConfig/streamConfig
should fail canonical validation").isNotEmpty();
+ }
+
+ @Test
+ public void testLoadBalanceWithTwoLoadBalancersFailsCanonicalValidation()
throws Exception {
+ var route = """
+ - route:
+ from:
+ uri: "direct:start"
+ steps:
+ - loadBalance:
+ roundRobinLoadBalancer: {}
+ randomLoadBalancer: {}
+ """;
+ var report = canonicalValidator.validate(route);
+ assertThat(report).as("loadBalance with two load balancers should fail
canonical validation").isNotEmpty();
+ }
}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/canonical-invalid-missing-dataformat.yaml
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/canonical-invalid-missing-dataformat.yaml
new file mode 100644
index 000000000000..0fb0c7cd2f19
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/canonical-invalid-missing-dataformat.yaml
@@ -0,0 +1,22 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+- route:
+ from:
+ uri: direct:start
+ steps:
+ - unmarshal: {}
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/canonical-valid-dataformat.yaml
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/canonical-valid-dataformat.yaml
new file mode 100644
index 000000000000..ccad9e74c408
--- /dev/null
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/test/resources/canonical-valid-dataformat.yaml
@@ -0,0 +1,27 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+- route:
+ from:
+ uri: direct:start
+ steps:
+ - unmarshal:
+ json:
+ id: json-unmarshal
+ - marshal:
+ json:
+ id: json-marshal
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json
index 13dbe0c2b152..48fa4364b386 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-canonical.json
@@ -3103,7 +3103,7 @@
"description" : "The property key."
}
},
- "required" : [ "expression", "key" ]
+ "required" : [ "key" ]
},
"org.apache.camel.model.RecipientListDefinition" : {
"title" : "Recipient List",
@@ -3615,8 +3615,7 @@
"streamConfig" : {
"$ref" :
"#/items/definitions/org.apache.camel.model.config.StreamResequencerConfig"
}
- },
- "required" : [ "expression" ]
+ }
},
"org.apache.camel.model.Resilience4jConfigurationDefinition" : {
"title" : "Resilience4j Configuration",
@@ -5749,8 +5748,7 @@
"zipFile" : {
"$ref" :
"#/items/definitions/org.apache.camel.model.dataformat.ZipFileDataFormat"
}
- },
- "required" : [ "asn1", "avro", "barcode", "base64", "beanio", "bindy",
"cbor", "crypto", "csv", "custom", "dfdl", "fhirJson", "fhirXml", "flatpack",
"fory", "grok", "groovyJson", "groovyXml", "gzipDeflater", "hl7", "ical",
"iso8583", "jacksonXml", "jaxb", "json", "jsonApi", "lzf", "mimeMultipart",
"ocsf", "parquetAvro", "pgp", "pqc", "protobuf", "rss", "smooks", "soap",
"swiftMt", "swiftMx", "syslog", "tarFile", "thrift", "univocityCsv",
"univocityFixed", "univocityTsv", "xmlSecu [...]
+ }
},
"org.apache.camel.model.ValidateDefinition" : {
"title" : "Validate",
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
index 2c7cb827c3cf..7614f49e514d 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl-model.json
@@ -5128,11 +5128,11 @@
"ref" : "expression",
"description" : "The property value as an expression.",
"title" : "Expression",
- "required" : true,
"displayName" : "Expression",
"kind" : "expression",
"index" : 1,
- "group" : "common"
+ "group" : "common",
+ "required" : true
} ]
},
"recipientList" : {
@@ -5981,11 +5981,11 @@
"ref" : "expression",
"description" : "Expression to use for re-ordering the messages, such
as a header with a sequence number.",
"title" : "Expression",
- "required" : true,
"displayName" : "Expression",
"kind" : "expression",
"index" : 4,
- "group" : "common"
+ "group" : "common",
+ "required" : true
}, {
"name" : "batchConfig",
"type" : "object",
@@ -9110,243 +9110,195 @@
}, {
"name" : "asn1",
"type" : "object",
- "ref" : "aSN1",
- "required" : true
+ "ref" : "aSN1"
}, {
"name" : "avro",
"type" : "object",
- "ref" : "avro",
- "required" : true
+ "ref" : "avro"
}, {
"name" : "barcode",
"type" : "object",
- "ref" : "barcode",
- "required" : true
+ "ref" : "barcode"
}, {
"name" : "base64",
"type" : "object",
- "ref" : "base64",
- "required" : true
+ "ref" : "base64"
}, {
"name" : "beanio",
"type" : "object",
- "ref" : "beanio",
- "required" : true
+ "ref" : "beanio"
}, {
"name" : "bindy",
"type" : "object",
- "ref" : "bindy",
- "required" : true
+ "ref" : "bindy"
}, {
"name" : "cbor",
"type" : "object",
- "ref" : "cBOR",
- "required" : true
+ "ref" : "cBOR"
}, {
"name" : "crypto",
"type" : "object",
- "ref" : "crypto",
- "required" : true
+ "ref" : "crypto"
}, {
"name" : "csv",
"type" : "object",
- "ref" : "csv",
- "required" : true
+ "ref" : "csv"
}, {
"name" : "custom",
"type" : "object",
- "ref" : "custom",
- "required" : true
+ "ref" : "custom"
}, {
"name" : "dfdl",
"type" : "object",
- "ref" : "dfdl",
- "required" : true
+ "ref" : "dfdl"
}, {
"name" : "fhirJson",
"type" : "object",
- "ref" : "fhirJson",
- "required" : true
+ "ref" : "fhirJson"
}, {
"name" : "fhirXml",
"type" : "object",
- "ref" : "fhirXml",
- "required" : true
+ "ref" : "fhirXml"
}, {
"name" : "flatpack",
"type" : "object",
- "ref" : "flatpack",
- "required" : true
+ "ref" : "flatpack"
}, {
"name" : "fory",
"type" : "object",
- "ref" : "fory",
- "required" : true
+ "ref" : "fory"
}, {
"name" : "grok",
"type" : "object",
- "ref" : "grok",
- "required" : true
+ "ref" : "grok"
}, {
"name" : "groovyJson",
"type" : "object",
- "ref" : "groovyJSon",
- "required" : true
+ "ref" : "groovyJSon"
}, {
"name" : "groovyXml",
"type" : "object",
- "ref" : "groovyXml",
- "required" : true
+ "ref" : "groovyXml"
}, {
"name" : "gzipDeflater",
"type" : "object",
- "ref" : "gzipDeflater",
- "required" : true
+ "ref" : "gzipDeflater"
}, {
"name" : "hl7",
"type" : "object",
- "ref" : "hL7",
- "required" : true
+ "ref" : "hL7"
}, {
"name" : "ical",
"type" : "object",
- "ref" : "ical",
- "required" : true
+ "ref" : "ical"
}, {
"name" : "iso8583",
"type" : "object",
- "ref" : "iso8583",
- "required" : true
+ "ref" : "iso8583"
}, {
"name" : "jacksonXml",
"type" : "object",
- "ref" : "jacksonXML",
- "required" : true
+ "ref" : "jacksonXML"
}, {
"name" : "jaxb",
"type" : "object",
- "ref" : "jaxb",
- "required" : true
+ "ref" : "jaxb"
}, {
"name" : "json",
"type" : "object",
- "ref" : "json",
- "required" : true
+ "ref" : "json"
}, {
"name" : "jsonApi",
"type" : "object",
- "ref" : "jsonApi",
- "required" : true
+ "ref" : "jsonApi"
}, {
"name" : "lzf",
"type" : "object",
- "ref" : "lZF",
- "required" : true
+ "ref" : "lZF"
}, {
"name" : "mimeMultipart",
"type" : "object",
- "ref" : "mimeMultipart",
- "required" : true
+ "ref" : "mimeMultipart"
}, {
"name" : "ocsf",
"type" : "object",
- "ref" : "ocsf",
- "required" : true
+ "ref" : "ocsf"
}, {
"name" : "parquetAvro",
"type" : "object",
- "ref" : "parquetAvro",
- "required" : true
+ "ref" : "parquetAvro"
}, {
"name" : "pgp",
"type" : "object",
- "ref" : "pGP",
- "required" : true
+ "ref" : "pGP"
}, {
"name" : "pqc",
"type" : "object",
- "ref" : "pQC",
- "required" : true
+ "ref" : "pQC"
}, {
"name" : "protobuf",
"type" : "object",
- "ref" : "protobuf",
- "required" : true
+ "ref" : "protobuf"
}, {
"name" : "rss",
"type" : "object",
- "ref" : "rss",
- "required" : true
+ "ref" : "rss"
}, {
"name" : "smooks",
"type" : "object",
- "ref" : "smooks",
- "required" : true
+ "ref" : "smooks"
}, {
"name" : "soap",
"type" : "object",
- "ref" : "soap",
- "required" : true
+ "ref" : "soap"
}, {
"name" : "swiftMt",
"type" : "object",
- "ref" : "swiftMt",
- "required" : true
+ "ref" : "swiftMt"
}, {
"name" : "swiftMx",
"type" : "object",
- "ref" : "swiftMx",
- "required" : true
+ "ref" : "swiftMx"
}, {
"name" : "syslog",
"type" : "object",
- "ref" : "syslog",
- "required" : true
+ "ref" : "syslog"
}, {
"name" : "tarFile",
"type" : "object",
- "ref" : "tarFile",
- "required" : true
+ "ref" : "tarFile"
}, {
"name" : "thrift",
"type" : "object",
- "ref" : "thrift",
- "required" : true
+ "ref" : "thrift"
}, {
"name" : "univocityCsv",
"type" : "object",
- "ref" : "uniVocityCsv",
- "required" : true
+ "ref" : "uniVocityCsv"
}, {
"name" : "univocityFixed",
"type" : "object",
- "ref" : "uniVocityFixed",
- "required" : true
+ "ref" : "uniVocityFixed"
}, {
"name" : "univocityTsv",
"type" : "object",
- "ref" : "uniVocityTsv",
- "required" : true
+ "ref" : "uniVocityTsv"
}, {
"name" : "xmlSecurity",
"type" : "object",
- "ref" : "xMLSecurity",
- "required" : true
+ "ref" : "xMLSecurity"
}, {
"name" : "yaml",
"type" : "object",
- "ref" : "yAML",
- "required" : true
+ "ref" : "yAML"
}, {
"name" : "zipDeflater",
"type" : "object",
- "ref" : "zipDeflater",
- "required" : true
+ "ref" : "zipDeflater"
}, {
"name" : "zipFile",
"type" : "object",
- "ref" : "zipFile",
- "required" : true
+ "ref" : "zipFile"
} ]
},
"validate" : {
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
index 5a42e8e49b50..2957e6d2a41e 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
@@ -3111,106 +3111,6 @@
"$ref" :
"#/items/definitions/org.apache.camel.model.dataformat.ASN1DataFormat"
}
}
- }, {
- "not" : {
- "anyOf" : [ {
- "required" : [ "asn1" ]
- }, {
- "required" : [ "avro" ]
- }, {
- "required" : [ "barcode" ]
- }, {
- "required" : [ "base64" ]
- }, {
- "required" : [ "beanio" ]
- }, {
- "required" : [ "bindy" ]
- }, {
- "required" : [ "cbor" ]
- }, {
- "required" : [ "crypto" ]
- }, {
- "required" : [ "csv" ]
- }, {
- "required" : [ "custom" ]
- }, {
- "required" : [ "dfdl" ]
- }, {
- "required" : [ "fhirJson" ]
- }, {
- "required" : [ "fhirXml" ]
- }, {
- "required" : [ "flatpack" ]
- }, {
- "required" : [ "fory" ]
- }, {
- "required" : [ "grok" ]
- }, {
- "required" : [ "groovyJson" ]
- }, {
- "required" : [ "groovyXml" ]
- }, {
- "required" : [ "gzipDeflater" ]
- }, {
- "required" : [ "hl7" ]
- }, {
- "required" : [ "ical" ]
- }, {
- "required" : [ "iso8583" ]
- }, {
- "required" : [ "jacksonXml" ]
- }, {
- "required" : [ "jaxb" ]
- }, {
- "required" : [ "json" ]
- }, {
- "required" : [ "jsonApi" ]
- }, {
- "required" : [ "lzf" ]
- }, {
- "required" : [ "mimeMultipart" ]
- }, {
- "required" : [ "ocsf" ]
- }, {
- "required" : [ "parquetAvro" ]
- }, {
- "required" : [ "pgp" ]
- }, {
- "required" : [ "pqc" ]
- }, {
- "required" : [ "protobuf" ]
- }, {
- "required" : [ "rss" ]
- }, {
- "required" : [ "smooks" ]
- }, {
- "required" : [ "soap" ]
- }, {
- "required" : [ "swiftMt" ]
- }, {
- "required" : [ "swiftMx" ]
- }, {
- "required" : [ "syslog" ]
- }, {
- "required" : [ "tarFile" ]
- }, {
- "required" : [ "thrift" ]
- }, {
- "required" : [ "univocityCsv" ]
- }, {
- "required" : [ "univocityFixed" ]
- }, {
- "required" : [ "univocityTsv" ]
- }, {
- "required" : [ "xmlSecurity" ]
- }, {
- "required" : [ "yaml" ]
- }, {
- "required" : [ "zipDeflater" ]
- }, {
- "required" : [ "zipFile" ]
- } ]
- }
}, {
"type" : "object",
"required" : [ "avro" ],
diff --git
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/MarshalTest.groovy
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/MarshalTest.groovy
index 7ce4877cb22b..18b80c7b0bdb 100644
---
a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/MarshalTest.groovy
+++
b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/MarshalTest.groovy
@@ -108,17 +108,21 @@ class MarshalTest extends YamlTestSupport {
}
}
- def "no dataformat"() {
+ def "Error: no dataformat"() {
when:
var route = '''
- from:
uri: "direct:start"
- steps:
+ steps:
- marshal: {}
- to: "mock:result"
'''
- loadRoutes(route)
then:
- context.routeDefinitions.size() == 1
+ try {
+ loadRoutes(route)
+ Assertions.fail("Should have thrown exception")
+ } catch (IllegalArgumentException e) {
+ Assertions.assertTrue(e.getMessage().contains("0 are valid"),
e.getMessage())
+ }
}
}