diff --git a/dependencies.gradle b/dependencies.gradle index ac939a5db..635f519e6 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -50,6 +50,7 @@ ext { moneyApiVersion = '1.1' junitJupiterVersion = '5.10.1' + jsonUnitAssertJVersion = '3.2.2' lombokVersion = '1.18.30' diff --git a/springwolf-asyncapi/build.gradle b/springwolf-asyncapi/build.gradle index 37f2ff587..85bfce7e0 100644 --- a/springwolf-asyncapi/build.gradle +++ b/springwolf-asyncapi/build.gradle @@ -26,7 +26,7 @@ dependencies { testImplementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" testImplementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${jacksonVersion}" testImplementation "io.swagger.core.v3:swagger-core-jakarta:${swaggerVersion}" - testImplementation "net.javacrumbs.json-unit:json-unit-assertj:3.2.2" + testImplementation "net.javacrumbs.json-unit:json-unit-assertj:${jsonUnitAssertJVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/MessageBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/MessageBinding.java index 13d064141..1c3bee48a 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/MessageBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/MessageBinding.java @@ -5,4 +5,4 @@ import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) -public class MessageBinding extends ExtendableObject {} +public abstract class MessageBinding extends ExtendableObject {} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPChannelExchangeType.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPChannelExchangeType.java index 60f2dcc0f..d5f66f294 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPChannelExchangeType.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPChannelExchangeType.java @@ -1,21 +1,25 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.amqp; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum AMQPChannelExchangeType { - @JsonProperty("topic") - TOPIC, + TOPIC("topic"), + DIRECT("direct"), + FANOUT("fanout"), + DEFAULT("default"), + HEADERS("headers"); - @JsonProperty("direct") - DIRECT, + public final String type; - @JsonProperty("fanout") - FANOUT, + AMQPChannelExchangeType(String type) { + this.type = type; + } - @JsonProperty("default") - DEFAULT, + public static AMQPChannelExchangeType fromString(String type) { + return valueOf(type.toUpperCase()); + } - @JsonProperty("headers") - HEADERS + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPChannelType.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPChannelType.java index c0eb811e4..edce99490 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPChannelType.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPChannelType.java @@ -1,12 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.amqp; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum AMQPChannelType { - @JsonProperty("queue") - QUEUE, + QUEUE("queue"), + ROUTING_KEY("routingKey"); + + public final String type; + + AMQPChannelType(String type) { + this.type = type; + } + + public static AMQPChannelType fromString(String type) { + return valueOf(type.toUpperCase()); + } - @JsonProperty("routingKey") - ROUTING_KEY + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPOperationBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPOperationBinding.java index a47e8dc75..941071daa 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPOperationBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPOperationBinding.java @@ -31,9 +31,10 @@ public class AMQPOperationBinding extends OperationBinding { *

* Applies to: receive, send */ + @Builder.Default @PositiveOrZero @JsonProperty("expiration") - private Integer expiration; + private Integer expiration = 0; /** * Identifies the user who has sent the message. diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/googlepubsub/GooglePubSubOperationBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/googlepubsub/GooglePubSubOperationBinding.java index 96f3851f0..fbd396610 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/googlepubsub/GooglePubSubOperationBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/googlepubsub/GooglePubSubOperationBinding.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.googlepubsub; -import io.github.stavshamir.springwolf.asyncapi.v3.bindings.ChannelBinding; +import io.github.stavshamir.springwolf.asyncapi.v3.bindings.OperationBinding; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; @@ -16,4 +16,4 @@ @Builder @NoArgsConstructor @EqualsAndHashCode(callSuper = true) -public class GooglePubSubOperationBinding extends ChannelBinding {} +public class GooglePubSubOperationBinding extends OperationBinding {} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/jms/JMSChannelBindingDestinationType.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/jms/JMSChannelBindingDestinationType.java index c50156010..8174576a1 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/jms/JMSChannelBindingDestinationType.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/jms/JMSChannelBindingDestinationType.java @@ -1,12 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.jms; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum JMSChannelBindingDestinationType { - @JsonProperty("queue") - QUEUE, + QUEUE("queue"), + FIFO_QUEUE("fifo-queue"); + + public final String type; + + JMSChannelBindingDestinationType(String type) { + this.type = type; + } + + public static JMSChannelBindingDestinationType fromString(String type) { + return valueOf(type.toUpperCase()); + } - @JsonProperty("fifo-queue") - FIFO_QUEUE + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/kafka/KafkaChannelTopicCleanupPolicy.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/kafka/KafkaChannelTopicCleanupPolicy.java index 3459c0ecc..53cb8832a 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/kafka/KafkaChannelTopicCleanupPolicy.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/kafka/KafkaChannelTopicCleanupPolicy.java @@ -1,12 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.kafka; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum KafkaChannelTopicCleanupPolicy { - @JsonProperty("compact") - COMPACT, + COMPACT("compact"), + DELETE("delete"); + + public final String type; + + KafkaChannelTopicCleanupPolicy(String type) { + this.type = type; + } + + public static KafkaChannelTopicCleanupPolicy fromString(String type) { + return valueOf(type.toUpperCase()); + } - @JsonProperty("delete") - DELETE + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTMessageBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTMessageBinding.java index ef1b65636..5f15f4aa8 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTMessageBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTMessageBinding.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.github.stavshamir.springwolf.asyncapi.v3.bindings.ChannelBinding; -import io.github.stavshamir.springwolf.asyncapi.v3.model.Reference; import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; @@ -38,7 +37,7 @@ public class MQTTMessageBinding extends ChannelBinding { * for when it is received. */ @JsonProperty("correlationData") - private Object correlationData; + private Schema correlationData; /** * String describing the content type of the message payload. This should not conflict with the contentType field @@ -67,29 +66,13 @@ public static MQTTMessageBindingBuilder builder() { } public static class CustomMQTTMessageBinding extends MQTTMessageBindingBuilder { - private Object correlationData; private Object responseTopic; - public MQTTMessageBindingBuilder correlationData(Schema schema) { - this.correlationData = schema; - return this; - } - - public MQTTMessageBindingBuilder correlationData(Reference reference) { - this.correlationData = reference; - return this; - } - public MQTTMessageBindingBuilder responseTopic(Schema schema) { this.responseTopic = schema; return this; } - public MQTTMessageBindingBuilder responseTopic(Reference reference) { - this.responseTopic = reference; - return this; - } - public MQTTMessageBindingBuilder responseTopic(String uriString) { this.responseTopic = uriString; return this; diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTOperationBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTOperationBinding.java index 51666c974..9eb954b21 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTOperationBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTOperationBinding.java @@ -2,8 +2,7 @@ package io.github.stavshamir.springwolf.asyncapi.v3.bindings.mqtt; import com.fasterxml.jackson.annotation.JsonProperty; -import io.github.stavshamir.springwolf.asyncapi.v3.bindings.ChannelBinding; -import io.github.stavshamir.springwolf.asyncapi.v3.model.Reference; +import io.github.stavshamir.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; @@ -23,7 +22,7 @@ @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(callSuper = true) -public class MQTTOperationBinding extends ChannelBinding { +public class MQTTOperationBinding extends OperationBinding { /** * Defines the Quality of Service (QoS) levels for the message flow between client and server. * Its value MUST be either 0 (At most once delivery), 1 (At least once delivery), or 2 (Exactly once delivery). @@ -76,10 +75,5 @@ public MQTTOperationBindingBuilder messageExpiryInterval(Schema schema) { this.messageExpiryInterval = schema; return this; } - - public MQTTOperationBindingBuilder messageExpiryInterval(Reference reference) { - this.messageExpiryInterval = reference; - return this; - } } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTServerBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTServerBinding.java index d78b995c3..886f331b0 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTServerBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTServerBinding.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.github.stavshamir.springwolf.asyncapi.v3.bindings.ServerBinding; -import io.github.stavshamir.springwolf.asyncapi.v3.model.Reference; import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; import lombok.AllArgsConstructor; import lombok.Builder; @@ -87,11 +86,6 @@ public MQTTServerBindingBuilder sessionExpiryInterval(Schema schema) { return this; } - public MQTTServerBindingBuilder sessionExpiryInterval(Reference reference) { - this.sessionExpiryInterval = reference; - return this; - } - public MQTTServerBindingBuilder maximumPacketSize(Integer integer) { this.maximumPacketSize = integer; return this; @@ -101,10 +95,5 @@ public MQTTServerBindingBuilder maximumPacketSize(Schema schema) { this.maximumPacketSize = schema; return this; } - - public MQTTServerBindingBuilder maximumPacketSize(Reference reference) { - this.maximumPacketSize = reference; - return this; - } } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/nats/NATSOperationBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/nats/NATSOperationBinding.java index 4543fa1a3..bec478f3a 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/nats/NATSOperationBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/nats/NATSOperationBinding.java @@ -2,7 +2,7 @@ package io.github.stavshamir.springwolf.asyncapi.v3.bindings.nats; import com.fasterxml.jackson.annotation.JsonProperty; -import io.github.stavshamir.springwolf.asyncapi.v3.bindings.ChannelBinding; +import io.github.stavshamir.springwolf.asyncapi.v3.bindings.OperationBinding; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -17,7 +17,7 @@ @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(callSuper = true) -public class NATSOperationBinding extends ChannelBinding { +public class NATSOperationBinding extends OperationBinding { /** * Defines the name of the queue to use. It MUST NOT exceed 255 characters. */ diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarChannelBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarChannelBinding.java index 41f016866..36b8cff43 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarChannelBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarChannelBinding.java @@ -78,10 +78,22 @@ public class PulsarChannelBinding extends ChannelBinding { private String bindingVersion = "0.1.0"; public enum PulsarPesistenceType { - @JsonProperty("persistent") - PERSISTENCE, + PERSISTENCE("persistent"), + NON_PERSISTENCE("non-persistent"); - @JsonProperty("non-persistent") - NON_PERSISTENCE + public final String type; + + PulsarPesistenceType(String type) { + this.type = type; + } + + public static PulsarPesistenceType fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarOperationBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarOperationBinding.java index fcb50c89f..b133a1a8b 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarOperationBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarOperationBinding.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.pulsar; -import io.github.stavshamir.springwolf.asyncapi.v3.bindings.ChannelBinding; +import io.github.stavshamir.springwolf.asyncapi.v3.bindings.OperationBinding; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -16,4 +16,4 @@ @Builder @AllArgsConstructor @EqualsAndHashCode(callSuper = true) -public class PulsarOperationBinding extends ChannelBinding {} +public class PulsarOperationBinding extends OperationBinding {} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSChannelBindingEffect.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSChannelBindingEffect.java index 677e87a65..84d1c0155 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSChannelBindingEffect.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSChannelBindingEffect.java @@ -1,11 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sns; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum SNSChannelBindingEffect { - @JsonProperty("Allow") - ALLOW, - @JsonProperty("Deny") - DENY + ALLOW("Allow"), + DENY("Deny"); + + public final String type; + + SNSChannelBindingEffect(String type) { + this.type = type; + } + + public static SNSChannelBindingEffect fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSChannelBindingOrderingType.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSChannelBindingOrderingType.java index 1b82db0f7..6c9acb98c 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSChannelBindingOrderingType.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSChannelBindingOrderingType.java @@ -1,11 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sns; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum SNSChannelBindingOrderingType { - @JsonProperty("standard") - STANDARD, - @JsonProperty("FIFO") - FIFO + STANDARD("standard"), + FIFO("FIFO"); + + public final String type; + + SNSChannelBindingOrderingType(String type) { + this.type = type; + } + + public static SNSChannelBindingOrderingType fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBinding.java new file mode 100644 index 000000000..77c590338 --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBinding.java @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sns; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.stavshamir.springwolf.asyncapi.v3.bindings.OperationBinding; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * This object contains information operation binding in SNS. + *

+ * We represent SNS producers via a subscribe Operation Object. In simple cases this may not require configuration, and + * can be shown as an empty SNS Binding Object i.e. {} if you need to explicitly indicate how a producer publishes to + * the channel. + *

+ * We represent SNS consumers via a publish Operation Object. These consumers need an SNS Subscription that defines how + * they consume from SNS i.e. the protocol that they use, and any filters applied. + *

+ * The SNS binding does not describe the receiver.If you wish to define the receiver, add a publish Operation Binding + * Object for that receiver. For example, if you send message to an SQS queue from an SNS Topic, you would add a + * protocol of 'sqs' and an Identifier object for the queue. That identifier could be an ARN of a queue defined outside + * of the scope of AsyncAPI, but if you wanted to define the receiver you would use the name of a queue defined in an + * SQS Binding on the publish Operation Binding Object. + *

+ * We support an array of consumers via the consumers field. This allows you to represent multiple protocols consuming + * an SNS Topic in one file. You may also use it for multiple consumers with the same protocol, instead of representing + * each consumer in a separate file. + * + * @see SNS Operation binding + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SNSOperationBinding extends OperationBinding { + + /** + * Optional. Often we can assume that the SNS Topic is the channel name-we provide this field in case the you need + * to supply the ARN, or the Topic name is not the channel name in the AsyncAPI document. + *

+ * Applies to: Publish, Subscribe + */ + @JsonProperty("topic") + private SNSOperationBindingIdentifier topic; + + /** + * Required. The protocols that listen to this topic and their endpoints. + *

+ * Applies to: Publish + */ + @NotNull + @JsonProperty("consumers") + private List consumers; + + /** + * Optional. Policy for retries to HTTP. The field is the default for HTTP receivers of the SNS Topic which may be + * overridden by a specific consumer. + *

+ * Applies to: Subscribe + */ + @JsonProperty("deliveryPolicy") + private Object deliveryPolicy; + + /** + * Optional, defaults to latest. The version of this binding. + */ + @Builder.Default + @JsonProperty("bindingVersion") + private String bindingVersion = "0.1.0"; +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingConsumer.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingConsumer.java new file mode 100644 index 000000000..f9e4a0acd --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingConsumer.java @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sns; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * Operation Consumer + * + * @see SNS Operation Consumer + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode +public class SNSOperationBindingConsumer { + /** + * Required. The protocol that this endpoint receives messages by. + * Can be http, https, email, email-json, sms, sqs, application, lambda or firehose + */ + @JsonProperty("protocol") + private Protocol protocol; + + /** + * Required. The endpoint messages are delivered to. + */ + @NotNull + @JsonProperty("endpoint") + private SNSOperationBindingIdentifier endpoint; + + /** + * Optional. Only receive a subset of messages from the channel, determined by this policy. + */ + @JsonProperty("filterPolicy") + private Object filterPolicy; + + /** + * Optional. Determines whether the FilterPolicy applies to MessageAttributes (default) or MessageBody. + */ + @Builder.Default + @JsonProperty("filterPolicyScope") + private FilterPolicyScope filterPolicyScope = FilterPolicyScope.MESSAGE_ATTRIBUTES; + + /** + * Required. If true AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied + * to SQS message attributes. If false the SNS attributes are included in the body. + */ + @NotNull + @JsonProperty("rawMessageDelivery") + private Boolean rawMessageDelivery; + + /** + * Optional. Prevent poison pill messages by moving un-processable messages to an SQS dead letter queue. + */ + @JsonProperty("redrivePolicy") + private SNSOperationBindingRedrivePolicy redrivePolicy; + + /** + * Optional. Policy for retries to HTTP. The parameter is for that SNS Subscription and overrides any policy on + * the SNS Topic. + */ + @JsonProperty("deliveryPolicy") + private SNSOperationBindingDeliveryPolicy deliveryPolicy; + + /** + * Optional. The display name to use with an SMS subscription + */ + @JsonProperty("displayName") + private String displayName; + + public enum Protocol { + HTTP("http"), + HTTPS("https"), + EMAIL("email"), + EMAIL_JSON("email-json"), + SMS("sms"), + SQS("sqs"), + APPLICATION("application"), + LAMBDA("lambda"), + FIREHOSE("firehose"); + + public final String type; + + Protocol(String type) { + this.type = type; + } + + public static Protocol fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } + } + + public enum FilterPolicyScope { + MESSAGE_ATTRIBUTES("MessageAttributes"), + MESSAGE_BODY("MessageBody"); + + public final String type; + + FilterPolicyScope(String type) { + this.type = type; + } + + public static FilterPolicyScope fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } + } +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingDeliveryPolicy.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingDeliveryPolicy.java new file mode 100644 index 000000000..fe6ee2b01 --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingDeliveryPolicy.java @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sns; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * + * @see Delivery Policy + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode +public class SNSOperationBindingDeliveryPolicy { + /** + * Optional. The minimum delay for a retry in seconds + */ + @JsonProperty("minDelayTarget") + private Integer minDelayTarget; + + /** + * Optional. The maximum delay for a retry in seconds + */ + @JsonProperty("maxDelayTarget") + private Integer maxDelayTarget; + + /** + * Optional. The total number of retries, including immediate, pre-backoff, backoff, and post-backoff retries + */ + @JsonProperty("numRetries") + private Integer numRetries; + + /** + * Optional. The number of immediate retries (with no delay) + */ + @JsonProperty("numNoDelayRetries") + private Integer numNoDelayRetries; + + /** + * Optional. The number of immediate retries (with delay) + */ + @JsonProperty("numMinDelayRetries") + private Integer numMinDelayRetries; + + /** + * Optional. The number of post-backoff phase retries, with the maximum delay between retries + */ + @JsonProperty("numMaxDelayRetries") + private Integer numMaxDelayRetries; + + /** + * Optional. The algorithm for backoff between retries + */ + @JsonProperty("backoffFunction") + private BackoffFunction backoffFunction; + + /** + * Optional. The maximum number of deliveries per second, per subscription + */ + @JsonProperty("maxReceivesPerSecond") + private Integer maxReceivesPerSecond; + + public enum BackoffFunction { + ARITHMETIC("arithmetic"), + EXPONENTIAL("exponential"), + GEOMETRIC("geometric"), + LINEAR("linear"); + + public final String type; + + BackoffFunction(String type) { + this.type = type; + } + + public static BackoffFunction fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } + } +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingIdentifier.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingIdentifier.java new file mode 100644 index 000000000..3e29d4ea4 --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingIdentifier.java @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sns; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * We provide an Identifer Object to support providing the identifier of an externally defined endpoint for this SNS + * publication to target, or an endpoint on another binding against this Operation Object (via the name field). + * + * @see SNS Operation Identifier + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode +public class SNSOperationBindingIdentifier { + /** + * Optional. The endpoint is a URL + */ + @JsonProperty("url") + private String url; + /** + * Optional. The endpoint is an email address + */ + @JsonProperty("email") + private String email; + /** + * Optional. The endpoint is a phone number + */ + @JsonProperty("phone") + private String phone; + /** + * Optional. The target is an ARN. For example, for SQS, the identifier may be an ARN, which will be of the form: + * "arn:aws:sqs:{region}:{account-id}:{queueName}" + */ + @JsonProperty("arn") + private String arn; + /** + * Optional. The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a + * binding for that protocol on this publish Operation Object. For example, if the protocol is 'sqs' then the name + * refers to the name field sqs binding. We don't use $ref because we are referring, not including. + */ + @JsonProperty("name") + private String name; +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingRedrivePolicy.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingRedrivePolicy.java new file mode 100644 index 000000000..51ae41784 --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSOperationBindingRedrivePolicy.java @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sns; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * + * @see Redrive Policy + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode +public class SNSOperationBindingRedrivePolicy { + + /** + * Required. The SQS queue to use as a dead letter queue (DLQ). Note that you may have a Redrive Policy to put + * messages that cannot be delivered to an SQS queue, even if you use another protocol to consume messages from the + * queue, so it is defined at the level of the SNS Operation Binding Object in a Consumer Object (and is applied + * as part of an SNS Subscription). The SQS Binding describes how to define an SQS Binding that supports defining + * the target SQS of the Redrive Policy. + */ + @NotNull + @JsonProperty("deadLetterQueue") + private SNSOperationBindingIdentifier deadLetterQueue; + + /** + * Optional. The number of times a message is delivered to the source queue before being moved to the dead-letter + * queue. Defaults to 10. + */ + @Builder.Default + @JsonProperty("maxReceiveCount") + private Integer maxReceiveCount = 10; +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingDeduplicationScope.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingDeduplicationScope.java index 640b8dd1e..e5cf75814 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingDeduplicationScope.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingDeduplicationScope.java @@ -1,11 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sqs; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum SQSChannelBindingDeduplicationScope { - @JsonProperty("messageGroup") - MESSAGE_GROUP, - @JsonProperty("queue") - QUEUE + MESSAGE_GROUP("messageGroup"), + QUEUE("queue"); + + public final String type; + + SQSChannelBindingDeduplicationScope(String type) { + this.type = type; + } + + public static SQSChannelBindingDeduplicationScope fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingFifoThroughput.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingFifoThroughput.java index 2070007b3..8c1fdf360 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingFifoThroughput.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingFifoThroughput.java @@ -1,11 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sqs; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum SQSChannelBindingFifoThroughput { - @JsonProperty("perQueue") - PER_QUEUE, - @JsonProperty("perMessageGroupId") - PER_MESSAGE_GROUP_ID + PER_QUEUE("perQueue"), + PER_MESSAGE_GROUP_ID("perMessageGroupId"); + + public final String type; + + SQSChannelBindingFifoThroughput(String type) { + this.type = type; + } + + public static SQSChannelBindingFifoThroughput fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingStatementEffect.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingStatementEffect.java index 9373d9126..2b44bab6c 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingStatementEffect.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSChannelBindingStatementEffect.java @@ -1,11 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sqs; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum SQSChannelBindingStatementEffect { - @JsonProperty("Allow") - ALLOW, - @JsonProperty("Deny") - DENY + ALLOW("Allow"), + DENY("Deny"); + + public final String type; + + SQSChannelBindingStatementEffect(String type) { + this.type = type; + } + + public static SQSChannelBindingStatementEffect fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSOperationBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSOperationBinding.java index 330db28ff..d7e278a50 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSOperationBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSOperationBinding.java @@ -2,7 +2,7 @@ package io.github.stavshamir.springwolf.asyncapi.v3.bindings.sqs; import com.fasterxml.jackson.annotation.JsonProperty; -import io.github.stavshamir.springwolf.asyncapi.v3.bindings.ChannelBinding; +import io.github.stavshamir.springwolf.asyncapi.v3.bindings.OperationBinding; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; @@ -25,7 +25,7 @@ @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(callSuper = true) -public class SQSOperationBinding extends ChannelBinding { +public class SQSOperationBinding extends OperationBinding { /** * Required. Queue objects that are either the endpoint for an SNS Operation Binding Object, or the deadLetterQueue * of the SQS Operation Binding Object diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/websockets/WebSocketChannelBinding.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/websockets/WebSocketChannelBinding.java index 8b903ff98..66e7ab61c 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/websockets/WebSocketChannelBinding.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/websockets/WebSocketChannelBinding.java @@ -55,6 +55,6 @@ public enum WebSocketsChannelMethod { GET, @JsonProperty("POST") - POST + POST; } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/AsyncAPI.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/AsyncAPI.java index de5ea9708..fd595832c 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/AsyncAPI.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/AsyncAPI.java @@ -2,7 +2,7 @@ package io.github.stavshamir.springwolf.asyncapi.v3.model; import com.fasterxml.jackson.annotation.JsonProperty; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.components.Components; import io.github.stavshamir.springwolf.asyncapi.v3.model.info.Info; import io.github.stavshamir.springwolf.asyncapi.v3.model.operation.Operation; @@ -29,6 +29,8 @@ @EqualsAndHashCode(callSuper = true) public class AsyncAPI extends ExtendableObject { + public static final String ASYNCAPI_DEFAULT_VERSION = "3.0.0"; + /** * REQUIRED. Specifies the AsyncAPI Specification version being used. It can be used by tooling Specifications and * clients to interpret the version. The structure shall be major.minor.patch, where patch versions must be @@ -39,7 +41,7 @@ public class AsyncAPI extends ExtendableObject { @NotNull @Builder.Default @JsonProperty(value = "asyncapi") - private String asyncapi = "3.0.0"; + private String asyncapi = ASYNCAPI_DEFAULT_VERSION; /** * Identifier of the @@ -89,7 +91,7 @@ public class AsyncAPI extends ExtendableObject { * naming conventions. */ @JsonProperty(value = "channels") - private Map channels; + private Map channels; /** * Holds a dictionary with all the operations this application MUST implement. diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/Channel.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/Channel.java index 961ab7345..3da07afd0 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/Channel.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/Channel.java @@ -1,105 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.model.channel; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.github.stavshamir.springwolf.asyncapi.v3.bindings.ChannelBinding; -import io.github.stavshamir.springwolf.asyncapi.v3.model.ExtendableObject; -import io.github.stavshamir.springwolf.asyncapi.v3.model.ExternalDocumentation; -import io.github.stavshamir.springwolf.asyncapi.v3.model.Tag; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - /** - * Describes a shared communication channel. - * - * @see Channel Object + * Represents a Channel. A Channel can be a ChannelObject or a ChannelReference. */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class Channel extends ExtendableObject { - - /** - * An optional string representation of this channel's address. The address is typically the "topic name", - * "routing key", "event type", or "path". When null or absent, it MUST be interpreted as unknown. This is useful - * when the address is generated dynamically at runtime or can't be known upfront. It MAY contain Channel Address - * Expressions. Query parameters and fragments SHALL NOT be used, instead use bindings to define them. - */ - @JsonProperty(value = "address") - private String address; - - /** - * A map of the messages that will be sent to this channel by any application at any time. Every message sent to - * this channel MUST be valid against one, and only one, of the message objects defined in this map. - */ - @JsonProperty(value = "messages") - private Map messages; - - /** - * A human-friendly title for the channel. - */ - @JsonProperty(value = "title") - private String title; - - /** - * A short summary of the channel. - */ - @JsonProperty(value = "summary") - private String summary; - - /** - * An optional description of this channel. CommonMark syntax can be - * used for rich text representation. - */ - @JsonProperty(value = "description") - private String description; - - /** - * An array of $ref pointers to the definition of the servers in which this channel is available. If the channel - * is located in the root Channels Object, it MUST point to a subset of server definitions located in the root - * Servers Object, and MUST NOT point to a subset of server definitions located in the Components Object or - * anywhere else. If the channel is located in the Components Object, it MAY point to a Server Objects in any - * location. If servers is absent or empty, this channel MUST be available on all the servers defined in the - * Servers Object. Please note the servers property value MUST be an array of Reference Objects and, therefore, - * MUST NOT contain an array of Server Objects. However, it is RECOMMENDED that parsers (or other software) - * dereference this property for a better development experience. - */ - @JsonProperty(value = "servers") - private List servers; - - /** - * A map of the parameters included in the channel address. It MUST be present only when the address contains - * Channel Address Expressions. - */ - @JsonProperty(value = "parameters") - private Map parameters; - - /** - * A map of the parameters included in the channel address. It MUST be present only when the address contains - * Channel Address Expressions. - */ - @JsonProperty(value = "tags") - private List tags; - - /** - * Additional external documentation of the exposed API. - */ - @JsonProperty(value = "externalDocs") - private ExternalDocumentation externalDocs; - - /** - * A map where the keys describe the name of the protocol and the values describe protocol-specific definitions - * for the channel. - */ - @JsonProperty(value = "bindings") - private Map bindings; -} +public interface Channel {} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelObject.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelObject.java new file mode 100644 index 000000000..18688d0cf --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelObject.java @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.model.channel; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.stavshamir.springwolf.asyncapi.v3.bindings.ChannelBinding; +import io.github.stavshamir.springwolf.asyncapi.v3.model.ExtendableObject; +import io.github.stavshamir.springwolf.asyncapi.v3.model.ExternalDocumentation; +import io.github.stavshamir.springwolf.asyncapi.v3.model.Tag; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * Describes a shared communication channel. + * + * @see Channel Object + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class ChannelObject extends ExtendableObject implements Channel { + + /** + * An identifier for the described channel. The channelId value is case-sensitive. Tools and libraries MAY use the + * channelId to uniquely identify a channel, therefore, it is RECOMMENDED to follow common programming naming + * conventions. + */ + @JsonIgnore + private String channelId; + + /** + * An optional string representation of this channel's address. The address is typically the "topic name", + * "routing key", "event type", or "path". When null or absent, it MUST be interpreted as unknown. This is useful + * when the address is generated dynamically at runtime or can't be known upfront. It MAY contain Channel Address + * Expressions. Query parameters and fragments SHALL NOT be used, instead use bindings to define them. + */ + @JsonProperty(value = "address") + private String address; + + /** + * A map of the messages that will be sent to this channel by any application at any time. Every message sent to + * this channel MUST be valid against one, and only one, of the message objects defined in this map. + */ + @JsonProperty(value = "messages") + private Map messages; + + /** + * A human-friendly title for the channel. + */ + @JsonProperty(value = "title") + private String title; + + /** + * A short summary of the channel. + */ + @JsonProperty(value = "summary") + private String summary; + + /** + * An optional description of this channel. CommonMark syntax can be + * used for rich text representation. + */ + @JsonProperty(value = "description") + private String description; + + /** + * An array of $ref pointers to the definition of the servers in which this channel is available. If the channel + * is located in the root Channels Object, it MUST point to a subset of server definitions located in the root + * Servers Object, and MUST NOT point to a subset of server definitions located in the Components Object or + * anywhere else. If the channel is located in the Components Object, it MAY point to a Server Objects in any + * location. If servers is absent or empty, this channel MUST be available on all the servers defined in the + * Servers Object. Please note the servers property value MUST be an array of Reference Objects and, therefore, + * MUST NOT contain an array of Server Objects. However, it is RECOMMENDED that parsers (or other software) + * dereference this property for a better development experience. + */ + @JsonProperty(value = "servers") + private List servers; + + /** + * A map of the parameters included in the channel address. It MUST be present only when the address contains + * Channel Address Expressions. + */ + @JsonProperty(value = "parameters") + private Map parameters; + + /** + * A map of the parameters included in the channel address. It MUST be present only when the address contains + * Channel Address Expressions. + */ + @JsonProperty(value = "tags") + private List tags; + + /** + * Additional external documentation of the exposed API. + */ + @JsonProperty(value = "externalDocs") + private ExternalDocumentation externalDocs; + + /** + * A map where the keys describe the name of the protocol and the values describe protocol-specific definitions + * for the channel. + */ + @JsonProperty(value = "bindings") + private Map bindings; +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelReference.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelReference.java index 8e46a9256..b3051777b 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelReference.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelReference.java @@ -12,7 +12,7 @@ @Builder @NoArgsConstructor @AllArgsConstructor -public class ChannelReference implements Reference { +public class ChannelReference implements Channel, Reference { @JsonIgnore private String ref; @@ -20,4 +20,21 @@ public class ChannelReference implements Reference { public String getRef() { return ref; } + + public static ChannelReference fromChannel(String channelName) { + return new ChannelReference("#/channels/" + channelName); + } + + /** + * Convenient Builder to create a Channel reference to an existing Channel + * @param channel Channel to create the reference to. This Channel MUST have a 'channelId' field + * @return a Channel with the 'ref' field pointing to "#/channels/{channelId" + */ + public static ChannelReference fromChannel(ChannelObject channel) { + var channelId = channel.getChannelId(); + if (channelId == null) { + throw new IllegalArgumentException("The channel must have a 'channelId' defined"); + } + return new ChannelReference("#/channels/" + channelId); + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/Message.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/Message.java index 8f0bac5a8..7283d3ee8 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/Message.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/Message.java @@ -1,122 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.github.stavshamir.springwolf.asyncapi.v3.bindings.MessageBinding; -import io.github.stavshamir.springwolf.asyncapi.v3.model.ExtendableObject; -import io.github.stavshamir.springwolf.asyncapi.v3.model.ExternalDocumentation; -import io.github.stavshamir.springwolf.asyncapi.v3.model.Reference; -import io.github.stavshamir.springwolf.asyncapi.v3.model.Tag; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.CorrelationID; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - /** - * Describes a message received on a given channel and operation. + * Represents a Message. A Message can be a MessageObject or a MessageReference. */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class Message extends ExtendableObject implements Reference { - - /** - * Schema definition of the application headers. Schema MUST be a map of key-value pairs. It MUST NOT define the - * protocol headers. If this is a Schema Object, then the schemaFormat will be assumed to be - * "application/vnd.aai.asyncapi+json;version=asyncapi" where the version is equal to the AsyncAPI Version String. - */ - @JsonProperty(value = "headers") - private MessageHeaders headers; - - /** - * Definition of the message payload. If this is a Schema Object, then the schemaFormat will be assumed to be - * "application/vnd.aai.asyncapi+json;version=asyncapi" where the version is equal to the AsyncAPI Version String. - */ - @JsonProperty(value = "payload") - private MessagePayload payload; - - /** - * Definition of the correlation ID used for message tracing or matching. - */ - @JsonProperty(value = "correlationId") - private CorrelationID correlationId; - - /** - * The content type to use when encoding/decoding a message's payload. The value MUST be a specific media type - * (e.g. application/json). When omitted, the value MUST be the one specified on the defaultContentType field. - */ - @JsonProperty(value = "contentType") - private String contentType; - - /** - * A machine-friendly name for the message. - */ - @JsonProperty(value = "name") - private String name; - - /** - * A human-friendly title for the message. - */ - @JsonProperty(value = "title") - private String title; - - /** - * A short summary of what the message is about. - */ - @JsonProperty(value = "summary") - private String summary; - - /** - * A verbose explanation of the message. CommonMark syntax can be used - * for rich text representation. - */ - @JsonProperty(value = "description") - private String description; - - /** - * A list of tags for logical grouping and categorization of messages. - */ - @JsonProperty(value = "tags") - private List tags; - - /** - * Additional external documentation for this message. - */ - @JsonProperty(value = "externalDocs") - private ExternalDocumentation externalDocs; - - /** - * A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the message. - */ - @JsonProperty(value = "bindings") - private Map bindings; - - /** - * List of examples. - */ - @JsonProperty(value = "examples") - private List examples; - - /** - * A list of traits to apply to the message object. Traits MUST be merged using traits merge mechanism. - * The resulting object MUST be a valid Message Object. - */ - @JsonProperty(value = "traits") - private List traits; - - @JsonIgnore - private String ref; - - @Override - public String getRef() { - return ref; - } -} +public interface Message {} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageHeaders.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageHeaders.java index 836e58975..bb5c864bf 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageHeaders.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageHeaders.java @@ -4,21 +4,21 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.model.channel.message.MessageHeadersSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaObject; import lombok.Getter; @Getter @JsonSerialize(using = MessageHeadersSerializer.class) public class MessageHeaders { private MultiFormatSchema multiFormatSchema; - private Schema schema; + private SchemaObject schema; private MessageReference reference; private MessageHeaders(MultiFormatSchema multiFormatSchema) { this.multiFormatSchema = multiFormatSchema; } - private MessageHeaders(Schema schema) { + private MessageHeaders(SchemaObject schema) { this.schema = schema; } @@ -30,7 +30,7 @@ public static MessageHeaders of(MultiFormatSchema multiFormatSchema) { return new MessageHeaders(multiFormatSchema); } - public static MessageHeaders of(Schema schema) { + public static MessageHeaders of(SchemaObject schema) { return new MessageHeaders(schema); } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageObject.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageObject.java new file mode 100644 index 000000000..b50246464 --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageObject.java @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.stavshamir.springwolf.asyncapi.v3.bindings.MessageBinding; +import io.github.stavshamir.springwolf.asyncapi.v3.model.ExtendableObject; +import io.github.stavshamir.springwolf.asyncapi.v3.model.ExternalDocumentation; +import io.github.stavshamir.springwolf.asyncapi.v3.model.Tag; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.CorrelationID; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * Describes a message received on a given channel and operation. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class MessageObject extends ExtendableObject implements Message { + + /** + * The key represents the message identifier. The messageId value is case-sensitive. Tools and libraries MAY use + * the messageId value to uniquely identify a message, therefore, it is RECOMMENDED to follow common programming + * naming conventions. + */ + @JsonIgnore + private String messageId; + + /** + * Schema definition of the application headers. Schema MUST be a map of key-value pairs. It MUST NOT define the + * protocol headers. If this is a Schema Object, then the schemaFormat will be assumed to be + * "application/vnd.aai.asyncapi+json;version=asyncapi" where the version is equal to the AsyncAPI Version String. + */ + @JsonProperty(value = "headers") + private MessageHeaders headers; + + /** + * Definition of the message payload. If this is a Schema Object, then the schemaFormat will be assumed to be + * "application/vnd.aai.asyncapi+json;version=asyncapi" where the version is equal to the AsyncAPI Version String. + */ + @JsonProperty(value = "payload") + private MessagePayload payload; + + /** + * Definition of the correlation ID used for message tracing or matching. + */ + @JsonProperty(value = "correlationId") + private CorrelationID correlationId; + + /** + * The content type to use when encoding/decoding a message's payload. The value MUST be a specific media type + * (e.g. application/json). When omitted, the value MUST be the one specified on the defaultContentType field. + */ + @JsonProperty(value = "contentType") + private String contentType; + + /** + * A machine-friendly name for the message. + */ + @JsonProperty(value = "name") + private String name; + + /** + * A human-friendly title for the message. + */ + @JsonProperty(value = "title") + private String title; + + /** + * A short summary of what the message is about. + */ + @JsonProperty(value = "summary") + private String summary; + + /** + * A verbose explanation of the message. CommonMark syntax can be used + * for rich text representation. + */ + @JsonProperty(value = "description") + private String description; + + /** + * A list of tags for logical grouping and categorization of messages. + */ + @JsonProperty(value = "tags") + private List tags; + + /** + * Additional external documentation for this message. + */ + @JsonProperty(value = "externalDocs") + private ExternalDocumentation externalDocs; + + /** + * A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the message. + */ + @JsonProperty(value = "bindings") + private Map bindings; + + /** + * List of examples. + */ + @JsonProperty(value = "examples") + private List examples; + + /** + * A list of traits to apply to the message object. Traits MUST be merged using traits merge mechanism. + * The resulting object MUST be a valid Message Object. + */ + @JsonProperty(value = "traits") + private List traits; +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessagePayload.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessagePayload.java index 697be3a65..f43f9c696 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessagePayload.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessagePayload.java @@ -4,21 +4,21 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.model.channel.message.MessagePayloadSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaObject; import lombok.Getter; @Getter @JsonSerialize(using = MessagePayloadSerializer.class) public class MessagePayload { private MultiFormatSchema multiFormatSchema; - private Schema schema; + private SchemaObject schema; private MessageReference reference; private MessagePayload(MultiFormatSchema multiFormatSchema) { this.multiFormatSchema = multiFormatSchema; } - private MessagePayload(Schema schema) { + private MessagePayload(SchemaObject schema) { this.schema = schema; } @@ -30,7 +30,7 @@ public static MessagePayload of(MultiFormatSchema multiFormatSchema) { return new MessagePayload(multiFormatSchema); } - public static MessagePayload of(Schema schema) { + public static MessagePayload of(SchemaObject schema) { return new MessagePayload(schema); } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageReference.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageReference.java index fa996dcf3..e4e299b7b 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageReference.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/message/MessageReference.java @@ -4,15 +4,17 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import io.github.stavshamir.springwolf.asyncapi.v3.model.Reference; import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.ToString; -@Data -@Builder +@EqualsAndHashCode @NoArgsConstructor @AllArgsConstructor -public class MessageReference implements Reference { +public class MessageReference implements Message, Reference { + + @EqualsAndHashCode.Include + @ToString.Include @JsonIgnore private String ref; @@ -20,4 +22,25 @@ public class MessageReference implements Reference { public String getRef() { return ref; } + + /** + * Convenient Builder to create a Message reference to an existing Message + * @param message Message to create the reference to. This Message MUST have a 'messageId' field + * @return a Message with the 'ref' field pointing to "#/components/messages/{messageId" + */ + public static MessageReference fromMessage(MessageObject message) { + var messageId = message.getMessageId(); + if (messageId == null) { + throw new IllegalArgumentException("The message must have a 'messageId' defined"); + } + return new MessageReference("#/components/messages/" + messageId); + } + + public static MessageReference fromMessage(String messageName) { + return new MessageReference("#/components/messages/" + messageName); + } + + public static MessageReference fromSchema(String schemaName) { + return new MessageReference("#/components/schemas/" + schemaName); + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/components/ComponentSchema.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/components/ComponentSchema.java index 350b86c1e..411478127 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/components/ComponentSchema.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/components/ComponentSchema.java @@ -5,21 +5,21 @@ import io.github.stavshamir.springwolf.asyncapi.v3.jackson.model.channel.message.ComponentSchemaSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaObject; import lombok.Getter; @Getter @JsonSerialize(using = ComponentSchemaSerializer.class) public class ComponentSchema { private MultiFormatSchema multiFormatSchema; - private Schema schema; + private SchemaObject schema; private MessageReference reference; private ComponentSchema(MultiFormatSchema multiFormatSchema) { this.multiFormatSchema = multiFormatSchema; } - private ComponentSchema(Schema schema) { + private ComponentSchema(SchemaObject schema) { this.schema = schema; } @@ -31,7 +31,7 @@ public static ComponentSchema of(MultiFormatSchema multiFormatSchema) { return new ComponentSchema(multiFormatSchema); } - public static ComponentSchema of(Schema schema) { + public static ComponentSchema of(SchemaObject schema) { return new ComponentSchema(schema); } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/components/Components.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/components/Components.java index 8cbfd12df..de4fa300f 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/components/Components.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/components/Components.java @@ -9,7 +9,7 @@ import io.github.stavshamir.springwolf.asyncapi.v3.model.ExtendableObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.ExternalDocumentation; import io.github.stavshamir.springwolf.asyncapi.v3.model.Tag; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelParameter; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.CorrelationID; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; @@ -57,7 +57,7 @@ public class Components extends ExtendableObject { * An object to hold reusable Channel Objects. */ @JsonProperty(value = "channels") - private Map channels; + private Map channels; /** * An object to hold reusable Operation Objects. diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/Operation.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/Operation.java index 6ce8048af..7b1a9b2f5 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/Operation.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/Operation.java @@ -5,9 +5,9 @@ import io.github.stavshamir.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.stavshamir.springwolf.asyncapi.v3.model.ExtendableObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.ExternalDocumentation; -import io.github.stavshamir.springwolf.asyncapi.v3.model.Reference; import io.github.stavshamir.springwolf.asyncapi.v3.model.Tag; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelReference; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.stavshamir.springwolf.asyncapi.v3.model.security_scheme.SecurityScheme; import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; @@ -114,7 +114,7 @@ public class Operation extends ExtendableObject { * dereference this property for a better development experience. */ @JsonProperty(value = "messages") - private List messages; + private List messages; /** * The definition of the reply in a request-reply operation. diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/OperationAction.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/OperationAction.java index 36c61abc6..f9c95f7e4 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/OperationAction.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/OperationAction.java @@ -1,11 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.model.operation; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum OperationAction { - @JsonProperty("send") - SEND, - @JsonProperty("receive") - RECEIVE + SEND("send"), + RECEIVE("receive"); + + public final String type; + + OperationAction(String type) { + this.type = type; + } + + public static OperationAction fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/MultiFormatSchema.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/MultiFormatSchema.java index 0a9c927cf..292e1a694 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/MultiFormatSchema.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/MultiFormatSchema.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.github.stavshamir.springwolf.asyncapi.v3.model.ExtendableObject; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -35,8 +36,10 @@ public class MultiFormatSchema extends ExtendableObject { * When using Reference Objects within the schema, the schemaFormat of the referenced resource MUST match the * schemaFormat of the schema containing the reference. */ + @Builder.Default + @NotNull @JsonProperty(value = "schemaFormat") - private String schemaFormat; + private String schemaFormat = SchemaFormat.DEFAULT.toString(); /** * Required. Definition of the message payload. It can be of any type but defaults to Schema Object. It MUST match diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/Schema.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/Schema.java index 32d5b813d..3cd4da28b 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/Schema.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/Schema.java @@ -1,94 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.model.schema; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.github.stavshamir.springwolf.asyncapi.v3.model.ExtendableObject; -import io.github.stavshamir.springwolf.asyncapi.v3.model.ExternalDocumentation; -import io.github.stavshamir.springwolf.asyncapi.v3.model.Reference; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.List; -import java.util.Map; - /** - * The Schema Object allows the definition of input and output data types. These types can be objects, but also - * primitives and arrays. This object is a superset of the JSON Schema Specification Draft 07. The empty schema - * (which allows any instance to validate) MAY be represented by the boolean value true and a schema which allows no - * instance to validate MAY be represented by the boolean value false. - *

- * Further information about the properties can be found in JSON Schema Core and JSON Schema Validation. Unless stated - * otherwise, the property definitions follow the JSON Schema specification as referenced here. - * - * @see Schema Object + * Represents a Schema. A Schema can be a SchemaObject or a SchemaReference. */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class Schema extends ExtendableObject implements Reference { - /** - * Adds support for polymorphism. The discriminator is the schema property name that is used to differentiate - * between other schema that inherit this schema. The property name used MUST be defined at this schema and it - * MUST be in the required property list. When used, the value MUST be the name of this schema or any schema that - * inherits it. See Composition and Inheritance for more details. - */ - @JsonProperty(value = "discriminator") - private String discriminator; - - /** - * Additional external documentation for this schema. - */ - @JsonProperty(value = "externalDocs") - private ExternalDocumentation externalDocs; - - /** - * Specifies that a schema is deprecated and SHOULD be transitioned out of usage. Default value is false. - */ - @JsonProperty(value = "deprecated") - private Boolean deprecated; - - @JsonProperty(value = "title") - private String title; - - @JsonProperty(value = "type") - private String type; - - @JsonProperty(value = "properties") - private Map properties; - - /** - * CommonMark syntax can be used for rich text representation. - */ - @JsonProperty(value = "description") - private String description; - - /** - * See Data Type Formats for further details. While relying on JSON Schema's defined formats, the AsyncAPI - * Specification offers a few additional predefined formats. - */ - @JsonProperty(value = "format") - private String format; - - @JsonProperty(value = "maximum") - private Integer maximum; - - @JsonProperty(value = "minimum") - private Integer minimum; - - @JsonProperty("enum") - private List enumValues; - - @JsonIgnore - private String ref; - - @Override - public String getRef() { - return ref; - } -} +public interface Schema {} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaFormat.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaFormat.java new file mode 100644 index 000000000..a209ec4ae --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaFormat.java @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.model.schema; + +import static io.github.stavshamir.springwolf.asyncapi.v3.model.AsyncAPI.ASYNCAPI_DEFAULT_VERSION; + +public enum SchemaFormat { + /** + * This is the default when a schemaFormat is not provided. + */ + DEFAULT("application/vnd.aai.asyncapi+json;version=" + ASYNCAPI_DEFAULT_VERSION), + ASYNCAPI_V3("application/vnd.aai.asyncapi;version=" + ASYNCAPI_DEFAULT_VERSION), + ASYNCAPI_V3_JSON("application/vnd.aai.asyncapi+json;version=" + ASYNCAPI_DEFAULT_VERSION), + ASYNCAPI_V3_YAML("application/vnd.aai.asyncapi+yaml;version=" + ASYNCAPI_DEFAULT_VERSION), + JSON_SCHEMA_JSON("application/schema+json;version=draft-07"), + JSON_SCHEMA_YAML("application/schema+yaml;version=draft-07"), + AVRO_V1_9_0("application/vnd.apache.avro;version=1.9.0"), + RAML_V1("application/raml+yaml;version=1.0"), + PROTOBUF_V2("application/vnd.google.protobuf;version=2"), + PROTOBUF_V3("application/vnd.google.protobuf;version=3"); + + public final String value; + + SchemaFormat(String schemaFormat) { + this.value = schemaFormat; + } + + @Override + public String toString() { + return this.value; + } +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaObject.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaObject.java new file mode 100644 index 000000000..abc863cc7 --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaObject.java @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.model.schema; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.github.stavshamir.springwolf.asyncapi.v3.model.ExtendableObject; +import io.github.stavshamir.springwolf.asyncapi.v3.model.ExternalDocumentation; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * The Schema Object allows the definition of input and output data types. These types can be objects, but also + * primitives and arrays. This object is a superset of the JSON Schema Specification Draft 07. The empty schema + * (which allows any instance to validate) MAY be represented by the boolean value true and a schema which allows no + * instance to validate MAY be represented by the boolean value false. + *

+ * Further information about the properties can be found in JSON Schema Core and JSON Schema Validation. Unless stated + * otherwise, the property definitions follow the JSON Schema specification as referenced here. + * + * @see Schema Object + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SchemaObject extends ExtendableObject implements Schema { + /** + * Adds support for polymorphism. The discriminator is the schema property name that is used to differentiate + * between other schema that inherit this schema. The property name used MUST be defined at this schema and it + * MUST be in the required property list. When used, the value MUST be the name of this schema or any schema that + * inherits it. See Composition and Inheritance for more details. + */ + @JsonProperty(value = "discriminator") + private String discriminator; + + /** + * Additional external documentation for this schema. + */ + @JsonProperty(value = "externalDocs") + private ExternalDocumentation externalDocs; + + /** + * Specifies that a schema is deprecated and SHOULD be transitioned out of usage. Default value is false. + */ + @JsonProperty(value = "deprecated") + private Boolean deprecated; + + @JsonProperty(value = "title") + private String title; + + @JsonProperty(value = "type") + private String type; + + @JsonProperty(value = "properties") + private Map properties; + + /** + * CommonMark syntax can be used for rich text representation. + */ + @JsonProperty(value = "description") + private String description; + + /** + * See Data Type Formats for further details. While relying on JSON Schema's defined formats, the AsyncAPI + * Specification offers a few additional predefined formats. + */ + @JsonProperty(value = "format") + private String format; + + @JsonProperty(value = "maximum") + private Integer maximum; + + @JsonProperty(value = "minimum") + private Integer minimum; + + @JsonProperty("enum") + private List enumValues; + + @JsonProperty(value = "examples") + public List examples; + + @JsonProperty(value = "additionalProperties") + public Schema additionalProperties; + + @JsonProperty(value = "required") + public List required; + + @JsonProperty(value = "allOf") + public List allOf; + + @JsonProperty(value = "oneOf") + public List oneOf; + + @JsonProperty(value = "anyOf") + public List anyOf; + + @JsonProperty(value = "const") + public Object constValue; +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaReference.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaReference.java new file mode 100644 index 000000000..3523ea76f --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaReference.java @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.model.schema; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import io.github.stavshamir.springwolf.asyncapi.v3.model.Reference; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +public class SchemaReference implements Schema, Reference { + + @EqualsAndHashCode.Include + @ToString.Include + @JsonIgnore + private String ref; + + @Override + public String getRef() { + return ref; + } + + public static SchemaReference fromSchema(String schemaName) { + return new SchemaReference("#/components/schemas/" + schemaName); + } +} diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/ApiKeySecurityScheme.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/ApiKeySecurityScheme.java index e6838c73e..d943f0a9d 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/ApiKeySecurityScheme.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/ApiKeySecurityScheme.java @@ -29,9 +29,22 @@ public ApiKeySecurityScheme(String description, @NotNull ApiKeyLocation in, Stri } public enum ApiKeyLocation { - @JsonProperty("user") - USER, - @JsonProperty("password") - PASSWORD + USER("user"), + PASSWORD("password"); + + public final String type; + + ApiKeyLocation(String type) { + this.type = type; + } + + public static ApiKeyLocation fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/HttpApiKeySecurityScheme.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/HttpApiKeySecurityScheme.java index 60674e881..137d8e9c8 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/HttpApiKeySecurityScheme.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/HttpApiKeySecurityScheme.java @@ -36,11 +36,23 @@ public HttpApiKeySecurityScheme(String name, @NotNull HttpApiKeyLocation in, Str } public enum HttpApiKeyLocation { - @JsonProperty("query") - QUERY, - @JsonProperty("header") - HEADER, - @JsonProperty("cookie") - COOKIE + QUERY("query"), + HEADER("header"), + COOKIE("cookie"); + + public final String type; + + HttpApiKeyLocation(String type) { + this.type = type; + } + + public static HttpApiKeyLocation fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } } diff --git a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/SecurityType.java b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/SecurityType.java index c92f93e0d..e59d677f4 100644 --- a/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/SecurityType.java +++ b/springwolf-asyncapi/src/main/java/io/github/stavshamir/springwolf/asyncapi/v3/model/security_scheme/SecurityType.java @@ -1,33 +1,33 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.stavshamir.springwolf.asyncapi.v3.model.security_scheme; -import com.fasterxml.jackson.annotation.JsonProperty; - public enum SecurityType { - @JsonProperty("userPassword") - USER_PASSWORD, - @JsonProperty("apiKey") - API_KEY, - @JsonProperty("X509") - X509, - @JsonProperty("symmetricEncryption") - SYMMETRIC_ENCRYPTION, - @JsonProperty("asymmetricEncryption") - ASYMMETRIC_ENCRYPTION, - @JsonProperty("httpApiKey") - HTTP_API_KEY, - @JsonProperty("http") - HTTP, - @JsonProperty("oauth2") - OAUTH2, - @JsonProperty("openIdConnect") - OPEN_ID_CONNECT, - @JsonProperty("plain") - PLAIN, - @JsonProperty("scramSha256") - SCRAM_SHA256, - @JsonProperty("scramSha512") - SCRAM_SHA512, - @JsonProperty("gssapi") - GSSAPI + USER_PASSWORD("userPassword"), + API_KEY("apiKey"), + X509("X509"), + SYMMETRIC_ENCRYPTION("symmetricEncryption"), + ASYMMETRIC_ENCRYPTION("asymmetricEncryption"), + HTTP_API_KEY("httpApiKey"), + HTTP("http"), + OAUTH2("oauth2"), + OPEN_ID_CONNECT("openIdConnect"), + PLAIN("plain"), + SCRAM_SHA256("scramSha256"), + SCRAM_SHA512("scramSha512"), + GSSAPI("gssapi"); + + public final String type; + + SecurityType(String type) { + this.type = type; + } + + public static SecurityType fromString(String type) { + return valueOf(type.toUpperCase()); + } + + @Override + public String toString() { + return this.type; + } } diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPBindingTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPBindingTest.java index 0d4d4fc3b..d46707381 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPBindingTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/amqp/AMQPBindingTest.java @@ -4,9 +4,9 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.AsyncAPI; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.operation.Operation; import org.junit.jupiter.api.Test; @@ -25,7 +25,7 @@ void shouldSerializeAMQPChannelBinding() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "userSignup", - Channel.builder() + ChannelObject.builder() .address("user/signup") .bindings(Map.of( "amqp", @@ -92,11 +92,11 @@ void shouldSerializeAMQPMessageBinding() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "userSignup", - Channel.builder() + ChannelObject.builder() .address("user/signup") .messages(Map.of( "userSignupMessage", - Message.builder() + MessageObject.builder() .bindings(Map.of( "amqp", AMQPMessageBinding.builder() diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/googlepubsub/GooglePubSubBindingTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/googlepubsub/GooglePubSubBindingTest.java index 9830fa523..58de73762 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/googlepubsub/GooglePubSubBindingTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/googlepubsub/GooglePubSubBindingTest.java @@ -4,8 +4,8 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.AsyncAPI; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessagePayload; import io.github.stavshamir.springwolf.asyncapi.v3.model.components.Components; import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; @@ -26,7 +26,7 @@ void shouldSerializeGooglePubSubMessage() throws IOException { .components(Components.builder() .messages(Map.of( "messageAvro", - Message.builder() + MessageObject.builder() .bindings(Map.of( "googlepubsub", GooglePubSubMessageBinding.builder() @@ -48,7 +48,7 @@ void shouldSerializeGooglePubSubMessage() throws IOException { .build())) .build(), "messageProto", - Message.builder() + MessageObject.builder() .bindings(Map.of( "googlepubsub", GooglePubSubMessageBinding.builder() @@ -88,7 +88,7 @@ void shouldSerializeGooglePubSubChannel() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "topic-avro-schema", - Channel.builder() + ChannelObject.builder() .address("projects/your-project/topics/topic-avro-schema") .bindings(Map.of( "googlepubsub", @@ -100,7 +100,7 @@ void shouldSerializeGooglePubSubChannel() throws IOException { .build())) .build(), "topic-proto-schema", - Channel.builder() + ChannelObject.builder() .address("projects/your-project/topics/topic-proto-schema") .bindings(Map.of( "googlepubsub", diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/jms/JMSBindingTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/jms/JMSBindingTest.java index 62840c0cf..1f1802c05 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/jms/JMSBindingTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/jms/JMSBindingTest.java @@ -4,10 +4,10 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.AsyncAPI; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; -import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.server.Server; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -26,7 +26,7 @@ void shouldSerializeJMSChannel() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "user.signup", - Channel.builder() + ChannelObject.builder() .description( "This application receives command messages from this channel about users to sign up.") .bindings(Map.of( @@ -79,13 +79,13 @@ void shouldSerializeJMSServerBinding() throws IOException { void shouldSerializeJMSMessageBinding() throws IOException { var message = Map.of( "message", - Message.builder() + MessageObject.builder() .bindings(Map.of( "jms", JMSMessageBinding.builder() - .headers(Schema.builder().build()) + .headers(SchemaObject.builder().build()) .build())) - .headers(MessageHeaders.of(Schema.builder().build())) + .headers(MessageHeaders.of(SchemaObject.builder().build())) .build()); // https://github.com/asyncapi/bindings/blob/master/jms/README.md#examples diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/kafka/KafkaBindingTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/kafka/KafkaBindingTest.java index 8f93c3eaa..c7bc44719 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/kafka/KafkaBindingTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/kafka/KafkaBindingTest.java @@ -4,11 +4,11 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.AsyncAPI; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.operation.Operation; import io.github.stavshamir.springwolf.asyncapi.v3.model.operation.OperationAction; -import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.server.Server; import org.junit.jupiter.api.Test; @@ -51,11 +51,11 @@ void shouldSerializeKafkaOperationBinding() throws IOException { .bindings(Map.of( "kafka", KafkaOperationBinding.builder() - .groupId(Schema.builder() + .groupId(SchemaObject.builder() .type("string") .enumValues(List.of("myGroupId")) .build()) - .clientId(Schema.builder() + .clientId(SchemaObject.builder() .type("string") .enumValues(List.of("myClientId")) .build()) @@ -75,7 +75,7 @@ void shouldSerializeKafkaChannel() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "user-signedup", - Channel.builder() + ChannelObject.builder() .bindings(Map.of( "kafka", KafkaChannelBinding.builder() @@ -126,16 +126,16 @@ void shouldSerializeKafkaMessage() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "test", - Channel.builder() + ChannelObject.builder() .address("test-topic") .messages(Map.of( "testMessage", - Message.builder() + MessageObject.builder() .bindings(Map.of( "kafka", KafkaMessageBinding.builder() .key( - Schema.builder() + SchemaObject.builder() .type("string") .enumValues(List.of("myKey")) .build()) diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTBindingTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTBindingTest.java index 25caf52d6..38ea5501f 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTBindingTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/mqtt/MQTTBindingTest.java @@ -4,7 +4,7 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.AsyncAPI; -import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.server.Server; import org.junit.jupiter.api.Test; @@ -56,12 +56,12 @@ void shouldSerializeMQTTServerExample2() throws IOException { .bindings(Map.of( "mqtt", MQTTServerBinding.builder() - .sessionExpiryInterval(Schema.builder() + .sessionExpiryInterval(SchemaObject.builder() .type("integer") .minimum(30) .maximum(1200) .build()) - .maximumPacketSize(Schema.builder() + .maximumPacketSize(SchemaObject.builder() .type("integer") .minimum(256) .build()) diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarBindingTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarBindingTest.java index 6c900a312..7a1d1e324 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarBindingTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/pulsar/PulsarBindingTest.java @@ -4,7 +4,7 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.AsyncAPI; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.server.Server; import org.junit.jupiter.api.Test; @@ -43,7 +43,7 @@ void shouldSerializePulsarChannel() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "user-signedup", - Channel.builder() + ChannelObject.builder() .bindings(Map.of( "pulsar", PulsarChannelBinding.builder() diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSBindingTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSBindingTest.java index d37319d9b..76ff5bdeb 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSBindingTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sns/SNSBindingTest.java @@ -4,7 +4,7 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.AsyncAPI; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -22,7 +22,7 @@ void shouldSerializeSNSChannel() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "user-signedup", - Channel.builder() + ChannelObject.builder() .description("A user has signed up to our service") .bindings(Map.of( "sns", @@ -38,7 +38,7 @@ void shouldSerializeSNSChannel() throws IOException { .build())) .build(); - // https://github.com/asyncapi/bindings/blob/master/kafka/README.md#example-1 + // https://github.com/asyncapi/bindings/tree/master/sns var example = ClasspathUtil.parseYamlFile("/v3/bindings/sns/sns-channel.yaml"); assertThatJson(serializer.toJsonString(asyncapi)) .whenIgnoringPaths("asyncapi", "channels.user-signedup.bindings.sns.bindingVersion") @@ -51,7 +51,7 @@ void shouldSerializeSNSSendMessageOperation() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "user-signedup", - Channel.builder() + ChannelObject.builder() .description("A user has signed up to our service") .bindings(Map.of( "sns", SNSChannelBinding.builder().build())) @@ -59,7 +59,7 @@ void shouldSerializeSNSSendMessageOperation() throws IOException { .build())) .build(); - // https://github.com/asyncapi/bindings/blob/master/kafka/README.md#example-1 + // https://github.com/asyncapi/bindings/tree/master/sns var example = ClasspathUtil.parseYamlFile("/v3/bindings/sns/sns-sendMessage.yaml"); assertThatJson(serializer.toJsonString(asyncapi)) .whenIgnoringPaths("asyncapi", "channels.user-signedup.bindings.sns.bindingVersion") diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSBindingTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSBindingTest.java index 2c7be9692..fc601b77a 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSBindingTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/bindings/sqs/SQSBindingTest.java @@ -4,7 +4,7 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.AsyncAPI; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -22,7 +22,7 @@ void shouldSerializeSQSConsumer() throws IOException { var asyncapi = AsyncAPI.builder() .channels(Map.of( "user-signedup", - Channel.builder() + ChannelObject.builder() .description("A user has signed up for our service") .build())) .build(); diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/AsyncAPITest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/AsyncAPITest.java index b1c7e5a5c..0f230b6b5 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/AsyncAPITest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/AsyncAPITest.java @@ -4,11 +4,11 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.bindings.kafka.KafkaOperationBinding; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.Channel; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelParameter; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessagePayload; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageTrait; @@ -19,7 +19,8 @@ import io.github.stavshamir.springwolf.asyncapi.v3.model.operation.Operation; import io.github.stavshamir.springwolf.asyncapi.v3.model.operation.OperationAction; import io.github.stavshamir.springwolf.asyncapi.v3.model.operation.OperationTraits; -import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.stavshamir.springwolf.asyncapi.v3.model.security_scheme.SecurityScheme; import io.github.stavshamir.springwolf.asyncapi.v3.model.security_scheme.SecurityType; import io.github.stavshamir.springwolf.asyncapi.v3.model.server.Server; @@ -36,53 +37,48 @@ class AsyncAPITest { @Test void shouldCreateSimpleAsyncAPI() throws IOException { + var userSignUpMessage = MessageObject.builder() + .messageId("UserSignedUp") + .payload(MessagePayload.of(SchemaObject.builder() + .type("object") + .properties(Map.of( + "displayName", + SchemaObject.builder() + .type("string") + .description("Name of the user") + .build(), + "email", + SchemaObject.builder() + .type("string") + .format("email") + .description("Email of the user") + .build())) + .build())) + .build(); + + var channelUserSignedup = ChannelObject.builder() + .channelId("userSignedup") + .address("user/signedup") + .messages(Map.of(userSignUpMessage.getMessageId(), MessageReference.fromMessage(userSignUpMessage))) + .build(); + AsyncAPI asyncAPI = AsyncAPI.builder() .info(Info.builder() .title("Account Service") .version("1.0.0") .description("This service is in charge of processing user signups") .build()) - .channels(Map.of( - "userSignedup", - Channel.builder() - .address("user/signedup") - .messages(Map.of( - "UserSignedUp", - Message.builder() - .ref("#/components/messages/UserSignedUp") - .build())) - .build())) + .channels(Map.of(channelUserSignedup.getChannelId(), channelUserSignedup)) .operations(Map.of( "sendUserSignedup", Operation.builder() .action(OperationAction.SEND) - .channel(ChannelReference.builder() - .ref("#/channels/userSignedup") - .build()) - .messages(List.of(MessageReference.builder() - .ref("#/channels/userSignedup/messages/UserSignedUp") - .build())) + .channel(ChannelReference.fromChannel(channelUserSignedup)) + .messages( + List.of(new MessageReference("#/channels/userSignedup/messages/UserSignedUp"))) .build())) .components(Components.builder() - .messages(Map.of( - "UserSignedUp", - Message.builder() - .payload(MessagePayload.of(Schema.builder() - .type("object") - .properties(Map.of( - "displayName", - Schema.builder() - .type("string") - .description("Name of the user") - .build(), - "email", - Schema.builder() - .type("string") - .format("email") - .description("Email of the user") - .build())) - .build())) - .build())) + .messages(Map.of(userSignUpMessage.getMessageId(), userSignUpMessage)) .build()) .build(); @@ -93,6 +89,40 @@ void shouldCreateSimpleAsyncAPI() throws IOException { @Test void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { + var lightMeasuredMessage = MessageObject.builder() + .messageId("lightMeasured") + .name("lightMeasured") + .title("Light measured") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .contentType("application/json") + .traits(List.of(MessageTrait.builder() + .ref("#/components/messageTraits/commonHeaders") + .build())) + .payload(MessagePayload.of(MessageReference.fromSchema("lightMeasuredPayload"))) + .build(); + + var turnOnOffMessage = MessageObject.builder() + .messageId("turnOnOff") + .name("turnOnOff") + .title("Turn on/off") + .summary("Command a particular streetlight to turn the lights on or off.") + .traits(List.of(MessageTrait.builder() + .ref("#/components/messageTraits/commonHeaders") + .build())) + .payload(MessagePayload.of(MessageReference.fromSchema("turnOnOffPayload"))) + .build(); + + var dimLightMessage = MessageObject.builder() + .messageId("dimLight") + .name("dimLight") + .title("Dim light") + .summary("Command a particular streetlight to dim the lights.") + .traits(List.of(MessageTrait.builder() + .ref("#/components/messageTraits/commonHeaders") + .build())) + .payload(MessagePayload.of(MessageReference.fromSchema("dimLightPayload"))) + .build(); + AsyncAPI asyncAPI = AsyncAPI.builder() .info(Info.builder() .title("Streetlights Kafka API") @@ -158,13 +188,9 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .build())) .channels(Map.of( "lightingMeasured", - Channel.builder() + ChannelObject.builder() .address("smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured") - .messages(Map.of( - "lightMeasured", - Message.builder() - .ref("#/components/messages/lightMeasured") - .build())) + .messages(Map.of("lightMeasured", MessageReference.fromMessage(lightMeasuredMessage))) .description("The topic on which measured values may be produced and consumed.") .parameters(Map.of( "streetlightId", @@ -173,13 +199,9 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .build())) .build(), "lightTurnOn", - Channel.builder() + ChannelObject.builder() .address("smartylighting.streetlights.1.0.action.{streetlightId}.turn.on") - .messages(Map.of( - "turnOn", - Message.builder() - .ref("#/components/messages/turnOnOff") - .build())) + .messages(Map.of("turnOn", MessageReference.fromMessage(turnOnOffMessage))) .parameters(Map.of( "streetlightId", ChannelParameter.builder() @@ -187,13 +209,9 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .build())) .build(), "lightTurnOff", - Channel.builder() + ChannelObject.builder() .address("smartylighting.streetlights.1.0.action.{streetlightId}.turn.off") - .messages(Map.of( - "turnOff", - Message.builder() - .ref("#/components/messages/turnOnOff") - .build())) + .messages(Map.of("turnOff", MessageReference.fromMessage(turnOnOffMessage))) .parameters(Map.of( "streetlightId", ChannelParameter.builder() @@ -201,13 +219,9 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .build())) .build(), "lightsDim", - Channel.builder() + ChannelObject.builder() .address("smartylighting.streetlights.1.0.action.{streetlightId}.dim") - .messages(Map.of( - "dimLight", - Message.builder() - .ref("#/components/messages/dimLight") - .build())) + .messages(Map.of("dimLight", MessageReference.fromMessage(dimLightMessage))) .parameters(Map.of( "streetlightId", ChannelParameter.builder() @@ -225,9 +239,8 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .traits(List.of(OperationTraits.builder() .ref("#/components/operationTraits/kafka") .build())) - .messages(List.of(MessageReference.builder() - .ref("#/channels/lightingMeasured/messages/lightMeasured") - .build())) + .messages(List.of( + new MessageReference("#/channels/lightingMeasured/messages/lightMeasured"))) .build(), "turnOn", Operation.builder() @@ -238,9 +251,7 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .traits(List.of(OperationTraits.builder() .ref("#/components/operationTraits/kafka") .build())) - .messages(List.of(MessageReference.builder() - .ref("#/channels/lightTurnOn/messages/turnOn") - .build())) + .messages(List.of(new MessageReference("#/channels/lightTurnOn/messages/turnOn"))) .build(), "turnOff", Operation.builder() @@ -251,9 +262,7 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .traits(List.of(OperationTraits.builder() .ref("#/components/operationTraits/kafka") .build())) - .messages(List.of(MessageReference.builder() - .ref("#/channels/lightTurnOff/messages/turnOff") - .build())) + .messages(List.of(new MessageReference("#/channels/lightTurnOff/messages/turnOff"))) .build(), "dimLight", Operation.builder() @@ -264,87 +273,46 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .traits(List.of(OperationTraits.builder() .ref("#/components/operationTraits/kafka") .build())) - .messages(List.of(MessageReference.builder() - .ref("#/channels/lightsDim/messages/dimLight") - .build())) + .messages(List.of(new MessageReference("#/channels/lightsDim/messages/dimLight"))) .build())) .components(Components.builder() .messages(Map.of( - "lightMeasured", - Message.builder() - .name("lightMeasured") - .title("Light measured") - .summary( - "Inform about environmental lighting conditions of a particular streetlight.") - .contentType("application/json") - .traits(List.of(MessageTrait.builder() - .ref("#/components/messageTraits/commonHeaders") - .build())) - .payload(MessagePayload.of(MessageReference.builder() - .ref("#/components/schemas/lightMeasuredPayload") - .build())) - .build(), - "turnOnOff", - Message.builder() - .name("turnOnOff") - .title("Turn on/off") - .summary("Command a particular streetlight to turn the lights on or off.") - .traits(List.of(MessageTrait.builder() - .ref("#/components/messageTraits/commonHeaders") - .build())) - .payload(MessagePayload.of(MessageReference.builder() - .ref("#/components/schemas/turnOnOffPayload") - .build())) - .build(), - "dimLight", - Message.builder() - .name("dimLight") - .title("Dim light") - .summary("Command a particular streetlight to dim the lights.") - .traits(List.of(MessageTrait.builder() - .ref("#/components/messageTraits/commonHeaders") - .build())) - .payload(MessagePayload.of(MessageReference.builder() - .ref("#/components/schemas/dimLightPayload") - .build())) - .build())) + lightMeasuredMessage.getMessageId(), lightMeasuredMessage, + turnOnOffMessage.getMessageId(), turnOnOffMessage, + dimLightMessage.getMessageId(), dimLightMessage)) .schemas(Map.of( "lightMeasuredPayload", - ComponentSchema.of(Schema.builder() + ComponentSchema.of(SchemaObject.builder() .type("object") .properties(Map.of( "lumens", - Schema.builder() + SchemaObject.builder() .type("integer") .minimum(0) .description("Light intensity measured in lumens.") .build(), "sentAt", - Schema.builder() - .ref("#/components/schemas/sentAt") - .build())) + SchemaReference.fromSchema("sentAt"))) .build()), "turnOnOffPayload", - ComponentSchema.of(Schema.builder() + ComponentSchema.of(SchemaObject.builder() .type("object") .properties(Map.of( "command", - Schema.builder() + SchemaObject.builder() .type("string") .enumValues(List.of("on", "off")) .description("Whether to turn on or off the light.") .build(), "sentAt", - Schema.builder() - .ref("#/components/schemas/sentAt") - .build())) + SchemaReference.fromSchema("sentAt"))) .build()), "dimLightPayload", - ComponentSchema.of(Schema.builder() + ComponentSchema.of(SchemaObject.builder() .type("object") .properties(Map.of( "percentage", - Schema.builder() + SchemaObject.builder() .type("integer") .description( "Percentage to which the light should be dimmed to.") @@ -352,12 +320,10 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .maximum(100) .build(), "sentAt", - Schema.builder() - .ref("#/components/schemas/sentAt") - .build())) + SchemaReference.fromSchema("sentAt"))) .build()), "sentAt", - ComponentSchema.of(Schema.builder() + ComponentSchema.of(SchemaObject.builder() .type("string") .format("date-time") .description("Date and time when the message was sent.") @@ -381,11 +347,11 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .messageTraits(Map.of( "commonHeaders", MessageTrait.builder() - .headers(MessageHeaders.of(Schema.builder() + .headers(MessageHeaders.of(SchemaObject.builder() .type("object") .properties(Map.of( "my-app-header", - Schema.builder() + SchemaObject.builder() .type("integer") .minimum(0) .maximum(100) @@ -398,7 +364,7 @@ void shouldCreateStreetlightsKafkaAsyncAPI() throws IOException { .bindings(Map.of( "kafka", KafkaOperationBinding.builder() - .clientId(Schema.builder() + .clientId(SchemaObject.builder() .type("string") .enumValues(List.of("my-app-id")) .build()) diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelObjectTest.java similarity index 86% rename from springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelTest.java rename to springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelObjectTest.java index ef1f18ba7..361a5b2a0 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelObjectTest.java @@ -8,7 +8,7 @@ import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.ExternalDocumentation; import io.github.stavshamir.springwolf.asyncapi.v3.model.Tag; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageReference; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -17,24 +17,20 @@ import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; -class ChannelTest { +class ChannelObjectTest { private static final DefaultAsyncApiSerializer serializer = new DefaultAsyncApiSerializer(); @Test void shouldSerializeChannelObject() throws IOException { - Channel channel = Channel.builder() + ChannelObject channelObject = ChannelObject.builder() .address("users.{userId}") .title("Users channel") .description("This channel is used to exchange messages about user events.") .messages(Map.of( "userSignedUp", - Message.builder() - .ref("#/components/messages/userSignedUp") - .build(), + MessageReference.fromMessage("userSignedUp"), "userCompletedOrder", - Message.builder() - .ref("#/components/messages/userCompletedOrder") - .build())) + MessageReference.fromMessage("userCompletedOrder"))) .parameters(Map.of( "userId", ChannelParameter.builder() @@ -66,7 +62,7 @@ void shouldSerializeChannelObject() throws IOException { .build(); String example = ClasspathUtil.readAsString("/v3/model/channel/channel.json"); - assertThatJson(serializer.toJsonString(channel)) + assertThatJson(serializer.toJsonString(channelObject)) // These values are autogenerated, so we can ignore them from the test .whenIgnoringPaths("bindings.amqp.bindingVersion", "bindings.amqp.queue.vhost") .isEqualTo(example); diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelParameterTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelParameterTest.java index f082200e3..73eb9e166 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelParameterTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/ChannelParameterTest.java @@ -15,7 +15,7 @@ class ChannelParameterTest { @Test void shouldSerializeChannelParameter() throws IOException { - var channel = Channel.builder() + var channel = ChannelObject.builder() .address("user/{userId}/signedup") .parameters(Map.of( "userId", diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/MessageTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/MessageTest.java index 34b8c4816..cca3cb035 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/MessageTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/channel/MessageTest.java @@ -4,12 +4,13 @@ import io.github.stavshamir.springwolf.asyncapi.v3.ClasspathUtil; import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; import io.github.stavshamir.springwolf.asyncapi.v3.model.Tag; -import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.Message; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageExample; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; +import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessagePayload; import io.github.stavshamir.springwolf.asyncapi.v3.model.channel.message.MessageTrait; -import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.Schema; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.stavshamir.springwolf.asyncapi.v3.model.schema.SchemaReference; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -23,7 +24,7 @@ class MessageTest { @Test void shouldSerializeMessage() throws IOException { - Message message = Message.builder() + MessageObject message = MessageObject.builder() .name("UserSignup") .title("User signup") .summary("Action to sign a user up.") @@ -33,32 +34,26 @@ void shouldSerializeMessage() throws IOException { Tag.builder().name("user").build(), Tag.builder().name("signup").build(), Tag.builder().name("register").build())) - .headers(MessageHeaders.of(Schema.builder() + .headers(MessageHeaders.of(SchemaObject.builder() .type("object") .properties(Map.of( "correlationId", - Schema.builder() + SchemaObject.builder() .description("Correlation ID set by application") .type("string") .build(), "applicationInstanceId", - Schema.builder() + SchemaObject.builder() .description( "Unique identifier for a given instance of the publishing application") .type("string") .build())) .build())) - .payload(MessagePayload.of(Schema.builder() + .payload(MessagePayload.of(SchemaObject.builder() .type("object") .properties(Map.of( - "user", - Schema.builder() - .ref("#/components/schemas/userCreate") - .build(), - "signup", - Schema.builder() - .ref("#/components/schemas/signup") - .build())) + "user", SchemaReference.fromSchema("userCreate"), + "signup", SchemaReference.fromSchema("signup"))) .build())) .correlationId(CorrelationID.builder() .description("Default Correlation ID") diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/OperationTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/OperationTest.java index 75bb28f3b..c7965e172 100644 --- a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/OperationTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/operation/OperationTest.java @@ -37,9 +37,7 @@ void shouldSerializeOperation() throws IOException { .traits(List.of(OperationTraits.builder() .ref("#/components/operationTraits/kafka") .build())) - .messages(List.of(MessageReference.builder() - .ref("/components/messages/userSignedUp") - .build())) + .messages(List.of(MessageReference.fromMessage("userSignedUp"))) .reply(OperationReply.builder() .address(OperationReplyAddress.builder() .location("$message.header#/replyTo") @@ -47,16 +45,14 @@ void shouldSerializeOperation() throws IOException { .channel(ChannelReference.builder() .ref("#/channels/userSignupReply") .build()) - .messages(List.of(MessageReference.builder() - .ref("/components/messages/userSignedUpReply") - .build())) + .messages(List.of(MessageReference.fromMessage("userSignedUpReply"))) .build()) .build(); String example = ClasspathUtil.readAsString("/v3/model/operation/operation.json"); assertThatJson(serializer.toJsonString(operation)) // FIXME: https://github.com/asyncapi/spec/issues/1007 - .whenIgnoringPaths("bindings.amqp.bindingVersion", "security") + .whenIgnoringPaths("bindings.amqp.bindingVersion", "bindings.amqp.expiration", "security") .isEqualTo(example); } } diff --git a/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaTest.java b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaTest.java new file mode 100644 index 000000000..e1161cd50 --- /dev/null +++ b/springwolf-asyncapi/src/test/java/io/github/stavshamir/springwolf/asyncapi/v3/model/schema/SchemaTest.java @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.stavshamir.springwolf.asyncapi.v3.model.schema; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.github.stavshamir.springwolf.asyncapi.v3.jackson.DefaultAsyncApiSerializer; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson; + +class SchemaTest { + private static final DefaultAsyncApiSerializer serializer = new DefaultAsyncApiSerializer(); + + @Test + void shouldSerializePrimitiveSample() throws JsonProcessingException { + var schema = SchemaObject.builder().type("string").format("email").build(); + + String example = + """ + { + "type": "string", + "format": "email" + } + """; + assertThatJson(serializer.toJsonString(schema)).isEqualTo(example); + } + + @Test + void shouldSerializeSimpleModel() throws JsonProcessingException { + var schema = SchemaObject.builder() + .type("object") + .required(List.of("name")) + .properties(Map.of( + "name", SchemaObject.builder().type("string").build(), + "address", SchemaReference.fromSchema("Address"), + "age", + SchemaObject.builder() + .type("integer") + .format("int32") + .minimum(0) + .build())) + .build(); + + String example = + """ + { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "address": { + "$ref": "#/components/schemas/Address" + }, + "age": { + "type": "integer", + "format": "int32", + "minimum": 0 + } + } + } + """; + assertThatJson(serializer.toJsonString(schema)).isEqualTo(example); + } + + @Test + void shouldSerializeStringToStringMapping() throws JsonProcessingException { + var schema = SchemaObject.builder() + .type("object") + .additionalProperties(SchemaObject.builder().type("string").build()) + .build(); + + var example = + """ + { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + """; + assertThatJson(serializer.toJsonString(schema)).isEqualTo(example); + } + + @Test + void shouldSerializeModelMapping() throws JsonProcessingException { + var schema = SchemaObject.builder() + .type("object") + .additionalProperties(SchemaReference.fromSchema("ComplexModel")) + .build(); + + var example = + """ + { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ComplexModel" + } + } + """; + assertThatJson(serializer.toJsonString(schema)).isEqualTo(example); + } + + @Test + void shouldSerializeModelWithExample() throws JsonProcessingException { + var schema = SchemaObject.builder() + .type("object") + .properties(Map.of( + "id", + SchemaObject.builder() + .type("integer") + .format("int64") + .build(), + "name", SchemaObject.builder().type("string").build())) + .required(List.of("name")) + .examples(List.of(Map.of("name", "Puma", "id", 1))) + .build(); + + var example = + """ + { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name" + ], + "examples": [ + { + "name": "Puma", + "id": 1 + } + ] + } + """; + assertThatJson(serializer.toJsonString(schema)).isEqualTo(example); + } + + @Test + @Disabled("MODEL WITH BOOLEAN SCHEMAS is not supported yet") + // FIXME: See https://www.asyncapi.com/docs/reference/specification/v3.0.0#schemaObject + void shouldSerializeModelWithBooleans() throws JsonProcessingException { + var schema = SchemaObject.builder() + .type("object") + // .properties(Map.of( + // "anySchema", true, + // "cannotBeDefined", false)) + .required(List.of("anySchema")) + .build(); + + var example = + """ + { + "type": "object", + "required": [ + "anySchema" + ], + "properties": { + "anySchema": true, + "cannotBeDefined": false + } + } + """; + assertThatJson(serializer.toJsonString(schema)).isEqualTo(example); + } + + @Test + void shouldSerializeModelsWithComposition() throws JsonProcessingException { + var schemas = Map.of( + "schemas", + Map.of( + "ErrorModel", + SchemaObject.builder() + .type("object") + .required(List.of("message", "code")) + .properties(Map.of( + "message", + SchemaObject.builder() + .type("string") + .build(), + "code", + SchemaObject.builder() + .type("integer") + .minimum(100) + .maximum(600) + .build())) + .build(), + "ExtendedErrorModel", + SchemaObject.builder() + .allOf(List.of( + SchemaReference.fromSchema("ErrorModel"), + SchemaObject.builder() + .type("object") + .required(List.of("rootCause")) + .properties(Map.of( + "rootCause", + SchemaObject.builder() + .type("string") + .build())) + .build())) + .build())); + + var example = + """ + { + "schemas": { + "ErrorModel": { + "type": "object", + "required": [ + "message", + "code" + ], + "properties": { + "message": { + "type": "string" + }, + "code": { + "type": "integer", + "minimum": 100, + "maximum": 600 + } + } + }, + "ExtendedErrorModel": { + "allOf": [ + { + "$ref": "#/components/schemas/ErrorModel" + }, + { + "type": "object", + "required": [ + "rootCause" + ], + "properties": { + "rootCause": { + "type": "string" + } + } + } + ] + } + } + } + """; + assertThatJson(serializer.toJsonString(schemas)).isEqualTo(example); + } + + @Test + void shouldSerializeModelsWithPolimorphismSupport() throws JsonProcessingException { + var schemas = Map.of( + "schemas", + Map.of( + "Pet", + SchemaObject.builder() + .type("object") + .discriminator("petType") + .properties(Map.of( + "name", + SchemaObject.builder().type("string").build(), + "petType", + SchemaObject.builder().type("string").build())) + .required(List.of("name", "petType")) + .build(), + "Cat", + SchemaObject.builder() + .description( + "A representation of a cat. Note that `Cat` will be used as the discriminator value.") + .allOf(List.of( + SchemaReference.fromSchema("Pet"), + SchemaObject.builder() + .type("object") + .properties(Map.of( + "huntingSkill", + SchemaObject.builder() + .type("string") + .description("The measured skill for hunting") + .enumValues( + List.of( + "clueless", + "lazy", + "adventurous", + "aggressive")) + .build())) + .required(List.of("huntingSkill")) + .build())) + .build(), + "Dog", + SchemaObject.builder() + .description( + "A representation of a dog. Note that `Dog` will be used as the discriminator value.") + .allOf(List.of( + SchemaReference.fromSchema("Pet"), + SchemaObject.builder() + .type("object") + .properties(Map.of( + "packSize", + SchemaObject.builder() + .type("integer") + .format("int32") + .description("the size of the pack the dog is from") + .minimum(0) + .build())) + .required(List.of("packSize")) + .build())) + .build(), + "StickInsect", + SchemaObject.builder() + .description( + "A representation of an Australian walking stick. Note that `StickBug` will be used as the discriminator value.") + .allOf(List.of( + SchemaReference.fromSchema("Pet"), + SchemaObject.builder() + .type("object") + .properties(Map.of( + "petType", + SchemaObject.builder() + .constValue("StickBug") + .build(), + "color", + SchemaObject.builder() + .type("string") + .build())) + .required(List.of("color")) + .build())) + .build())); + var example = + """ + { + "schemas": { + "Pet": { + "type": "object", + "discriminator": "petType", + "properties": { + "name": { + "type": "string" + }, + "petType": { + "type": "string" + } + }, + "required": [ + "name", + "petType" + ] + }, + "Cat": { + "description": "A representation of a cat. Note that `Cat` will be used as the discriminator value.", + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "type": "object", + "properties": { + "huntingSkill": { + "type": "string", + "description": "The measured skill for hunting", + "enum": [ + "clueless", + "lazy", + "adventurous", + "aggressive" + ] + } + }, + "required": [ + "huntingSkill" + ] + } + ] + }, + "Dog": { + "description": "A representation of a dog. Note that `Dog` will be used as the discriminator value.", + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "type": "object", + "properties": { + "packSize": { + "type": "integer", + "format": "int32", + "description": "the size of the pack the dog is from", + "minimum": 0 + } + }, + "required": [ + "packSize" + ] + } + ] + }, + "StickInsect": { + "description": "A representation of an Australian walking stick. Note that `StickBug` will be used as the discriminator value.", + "allOf": [ + { + "$ref": "#/components/schemas/Pet" + }, + { + "type": "object", + "properties": { + "petType": { + "const": "StickBug" + }, + "color": { + "type": "string" + } + }, + "required": [ + "color" + ] + } + ] + } + } + } + """; + assertThatJson(serializer.toJsonString(schemas)).isEqualTo(example); + } +} diff --git a/springwolf-asyncapi/src/test/resources/v3/model/operation/operation.json b/springwolf-asyncapi/src/test/resources/v3/model/operation/operation.json index 456e0c59e..3c578d71b 100644 --- a/springwolf-asyncapi/src/test/resources/v3/model/operation/operation.json +++ b/springwolf-asyncapi/src/test/resources/v3/model/operation/operation.json @@ -37,7 +37,7 @@ ], "messages": [ { - "$ref": "/components/messages/userSignedUp" + "$ref": "#/components/messages/userSignedUp" } ], "reply": { @@ -49,7 +49,7 @@ }, "messages": [ { - "$ref": "/components/messages/userSignedUpReply" + "$ref": "#/components/messages/userSignedUpReply" } ] }