From 7a2b5cf6309df24728c6996c930ab5fd22d91700 Mon Sep 17 00:00:00 2001 From: Timon Back Date: Fri, 24 May 2024 19:04:27 +0200 Subject: [PATCH] chore: create discriminator example (#771) --- .../e2e/tests/publishing.spec.ts | 1 + .../consumers/DiscriminatorConsumer.java | 19 ++ .../kafka/dtos/discriminator/VehicleBase.java | 33 +++ .../VehicleElectricPayloadDto.java | 25 ++ .../VehicleGasolinePayloadDto.java | 24 ++ .../kafka/SpringContextIntegrationTest.java | 2 +- .../src/test/resources/asyncapi.json | 230 ++++++++++++++++++ 7 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/consumers/DiscriminatorConsumer.java create mode 100644 springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleBase.java create mode 100644 springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleElectricPayloadDto.java create mode 100644 springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleGasolinePayloadDto.java diff --git a/springwolf-examples/e2e/tests/publishing.spec.ts b/springwolf-examples/e2e/tests/publishing.spec.ts index bc6230aa4..34e7f20a7 100644 --- a/springwolf-examples/e2e/tests/publishing.spec.ts +++ b/springwolf-examples/e2e/tests/publishing.spec.ts @@ -73,6 +73,7 @@ function testPublishingEveryChannelItem() { payload === "YamlPayloadDto" || // Unable to create correct yaml payload payload === "MonetaryAmount" || // Issue with either MonetaryAmount of ModelConverters payload === "Message" || // Unable to instantiate ExamplePayloadProtobufDto$Message class + payload === "VehicleBase" || // Unable to publish abstract class for discriminator demo channelName === "example-topic-routing-key" // Publishing through amqp exchange is not supported, see GH-366 ) { return; // skip diff --git a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/consumers/DiscriminatorConsumer.java b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/consumers/DiscriminatorConsumer.java new file mode 100644 index 000000000..97381cb9d --- /dev/null +++ b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/consumers/DiscriminatorConsumer.java @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.examples.kafka.consumers; + +import io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Slf4j +public class DiscriminatorConsumer { + + @KafkaListener(topics = "vehicle-topic") + public void receiveExamplePayload(VehicleBase payload) { + log.info("Received new message in vehicle-topic: {}", payload.toString()); + } +} diff --git a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleBase.java b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleBase.java new file mode 100644 index 000000000..bc95bc108 --- /dev/null +++ b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleBase.java @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.examples.kafka.dtos.discriminator; + +import com.fasterxml.jackson.annotation.JsonSubTypes; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.swagger.v3.oas.annotations.media.DiscriminatorMapping; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "vehicleType") +@JsonSubTypes({ + @JsonSubTypes.Type(value = VehicleElectricPayloadDto.class, name = "VehicleElectricPayloadDto"), + @JsonSubTypes.Type(value = VehicleGasolinePayloadDto.class, name = "VehicleGasolinePayloadDto"), +}) +@Schema( + subTypes = {VehicleElectricPayloadDto.class}, + discriminatorProperty = "vehicleType", + discriminatorMapping = { + @DiscriminatorMapping(value = "VehicleElectricPayloadDto", schema = VehicleElectricPayloadDto.class), + @DiscriminatorMapping(value = "VehicleGasolinePayloadDto", schema = VehicleGasolinePayloadDto.class), + }, + description = "Demonstrates the use of discriminator for polymorphic deserialization (not publishable)") +@Data +@AllArgsConstructor +@NoArgsConstructor +public abstract class VehicleBase { + private String vehicleType; // added for discriminator + + private String powerSource; + private int topSpeed; +} diff --git a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleElectricPayloadDto.java b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleElectricPayloadDto.java new file mode 100644 index 000000000..100d83e7a --- /dev/null +++ b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleElectricPayloadDto.java @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.examples.kafka.dtos.discriminator; + +import com.fasterxml.jackson.annotation.JsonTypeName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@JsonTypeName("VehicleElectricPayloadDto") +@Schema( + description = "Electric vehicle implementation of VehicleBase" + + // Alternative, when you do not want to add the discriminator property vehicleType to VehicleBase + // allOf = {VehicleBase.class} + ) +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +public class VehicleElectricPayloadDto extends VehicleBase { + private int batteryCapacity; + private int chargeTime; +} diff --git a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleGasolinePayloadDto.java b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleGasolinePayloadDto.java new file mode 100644 index 000000000..26de17b3f --- /dev/null +++ b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/dtos/discriminator/VehicleGasolinePayloadDto.java @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.examples.kafka.dtos.discriminator; + +import com.fasterxml.jackson.annotation.JsonTypeName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@JsonTypeName("VehicleGasolinePayloadDto") +@Schema( + description = "Gasoline vehicle implementation of VehicleBase" + + // Alternative, when you do not want to add the discriminator property vehicleType to VehicleBase + // allOf = {VehicleBase.class} + ) +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +public class VehicleGasolinePayloadDto extends VehicleBase { + private int fuelCapacity; +} diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/SpringContextIntegrationTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/SpringContextIntegrationTest.java index 9eaa2e370..7ad5f1287 100644 --- a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/SpringContextIntegrationTest.java +++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/SpringContextIntegrationTest.java @@ -48,7 +48,7 @@ void testContextWithApplicationProperties() { @Test void testAllChannelsAreFound() { - assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(11); + assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(12); } } diff --git a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json index 3377298c5..0ac38622d 100644 --- a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json @@ -124,6 +124,18 @@ } ] }, + "vehicle-topic": { + "messages": { + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": { + "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + } + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, "xml-topic": { "messages": { "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto": { @@ -605,6 +617,39 @@ "type": "object" } }, + "SpringKafkaDefaultHeaders-VehicleBase": { + "type": "object", + "properties": { + "__TypeId__": { + "type": "string", + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + ], + "examples": [ + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + ] + } + }, + "examples": [ + { + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "properties": { + "__TypeId__": { + "description": "Spring Type Id Header", + "enum": [ + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + ], + "type": "string" + } + }, + "type": "object" + } + }, "SpringKafkaDefaultHeaders-XmlPayloadDto": { "type": "object", "properties": { @@ -1136,6 +1181,157 @@ "type": "string" } }, + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": { + "discriminator": "vehicleType", + "type": "object", + "properties": { + "powerSource": { + "type": "string" + }, + "topSpeed": { + "type": "integer", + "format": "int32" + }, + "vehicleType": { + "type": "string" + } + }, + "description": "Demonstrates the use of discriminator for polymorphic deserialization (not publishable)", + "examples": [ + { + "powerSource": "string", + "topSpeed": 0, + "vehicleType": "string" + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "description": "Demonstrates the use of discriminator for polymorphic deserialization (not publishable)", + "properties": { + "powerSource": { + "type": "string" + }, + "topSpeed": { + "format": "int32", + "type": "integer" + }, + "vehicleType": { } + }, + "type": "object" + } + }, + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleElectricPayloadDto": { + "type": "object", + "description": "Electric vehicle implementation of VehicleBase", + "examples": [ + { + "batteryCapacity": 0, + "chargeTime": 0, + "powerSource": "string", + "topSpeed": 0, + "vehicleType": "string" + } + ], + "allOf": [ + { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + }, + { + "type": "object", + "properties": { + "batteryCapacity": { + "type": "integer", + "format": "int32" + }, + "chargeTime": { + "type": "integer", + "format": "int32" + } + } + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "allOf": [ + { + "description": "Demonstrates the use of discriminator for polymorphic deserialization (not publishable)", + "properties": { + "powerSource": { + "type": "string" + }, + "topSpeed": { + "format": "int32", + "type": "integer" + }, + "vehicleType": { } + }, + "type": "object" + }, + { + "properties": { + "batteryCapacity": { }, + "chargeTime": { } + }, + "type": "object" + } + ], + "description": "Electric vehicle implementation of VehicleBase", + "type": "object" + } + }, + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleGasolinePayloadDto": { + "type": "object", + "description": "Gasoline vehicle implementation of VehicleBase", + "examples": [ + { + "fuelCapacity": 0, + "powerSource": "string", + "topSpeed": 0, + "vehicleType": "string" + } + ], + "allOf": [ + { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + }, + { + "type": "object", + "properties": { + "fuelCapacity": { + "type": "integer", + "format": "int32" + } + } + } + ], + "x-json-schema": { + "$schema": "https://json-schema.org/draft-04/schema#", + "allOf": [ + { + "description": "Demonstrates the use of discriminator for polymorphic deserialization (not publishable)", + "properties": { + "powerSource": { + "type": "string" + }, + "topSpeed": { + "format": "int32", + "type": "integer" + }, + "vehicleType": { } + }, + "type": "object" + }, + { + "properties": { + "fuelCapacity": { } + }, + "type": "object" + } + ], + "description": "Gasoline vehicle implementation of VehicleBase", + "type": "object" + } + }, "java.lang.Number": { "type": "number", "examples": [ @@ -1370,6 +1566,24 @@ } } }, + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": { + "headers": { + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-VehicleBase" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + } + }, + "name": "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase", + "title": "VehicleBase", + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + } + }, "java.lang.Number": { "headers": { "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-Integer" @@ -1635,6 +1849,22 @@ } ] }, + "vehicle-topic_receive_receiveExamplePayload": { + "action": "receive", + "channel": { + "$ref": "#/channels/vehicle-topic" + }, + "bindings": { + "kafka": { + "bindingVersion": "0.5.0" + } + }, + "messages": [ + { + "$ref": "#/channels/vehicle-topic/messages/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + } + ] + }, "xml-topic_receive_receiveExamplePayload": { "action": "receive", "channel": {