From 630863fb753b341f35b0a416676dbb1078d31e6c Mon Sep 17 00:00:00 2001 From: Carlos Tasada Date: Tue, 6 Jun 2023 18:22:02 +0200 Subject: [PATCH] feat: Added support for Message description While working at https://github.com/springwolf/springwolf-core/pull/189 we found out that the provided Message description was, in fact, the one associated to the Operation. As a result we decided to fully remove the description until we could fix it. This PR adds support for Message description. Any `Message` object, annotated with `@Schema` will use the annotation `description` value, as the Message description. The https://www.springwolf.dev/docs/configuration/documenting-schemas documentation is already stating this scenario, so I don't think we need further documentation updates. --- .../AbstractOperationDataScanner.java | 6 +++++- .../asyncapi/DefaultAsyncApiServiceTest.java | 2 -- .../ConsumerOperationDataScannerTest.java | 15 +++++++++------ .../ProducerOperationDataScannerTest.java | 16 +++++++++------- .../AsyncListenerAnnotationScannerTest.java | 14 ++++++-------- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/AbstractOperationDataScanner.java b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/AbstractOperationDataScanner.java index fbd8eaa6a..9e61059d6 100644 --- a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/AbstractOperationDataScanner.java +++ b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/AbstractOperationDataScanner.java @@ -11,6 +11,7 @@ import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference; import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.HeaderReference; import io.github.stavshamir.springwolf.schemas.SchemasService; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.extern.slf4j.Slf4j; import org.springframework.core.annotation.Order; @@ -94,10 +95,13 @@ private Message buildMessage(OperationData operationData) { String modelName = this.getSchemaService().register(payloadType); String headerModelName = this.getSchemaService().register(operationData.getHeaders()); + Schema schema = payloadType.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); + String description = schema != null ? schema.description() : null; + return Message.builder() .name(payloadType.getName()) .title(modelName) - // FIXME: Add support for Message Description + .description(description) .payload(PayloadReference.fromModelName(modelName)) .headers(HeaderReference.fromModelName(headerModelName)) .bindings(operationData.getMessageBinding()) diff --git a/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/DefaultAsyncApiServiceTest.java b/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/DefaultAsyncApiServiceTest.java index 1e5aeffba..e1ceefe16 100644 --- a/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/DefaultAsyncApiServiceTest.java +++ b/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/DefaultAsyncApiServiceTest.java @@ -109,7 +109,6 @@ void getAsyncAPI_producers_should_be_correct() { final ChannelItem channel = actualChannels.get("producer-topic"); assertThat(channel.getSubscribe()).isNotNull(); final Message message = (Message) channel.getSubscribe().getMessage(); - // Message description is not supported yet assertThat(message.getDescription()).isNull(); assertThat(message.getBindings()).isEqualTo(ImmutableMap.of("kafka", new KafkaMessageBinding())); } @@ -125,7 +124,6 @@ void getAsyncAPI_consumers_should_be_correct() { final ChannelItem channel = actualChannels.get("consumer-topic"); assertThat(channel.getPublish()).isNotNull(); final Message message = (Message) channel.getPublish().getMessage(); - // Message description is not supported yet assertThat(message.getDescription()).isNull(); assertThat(message.getBindings()).isEqualTo(ImmutableMap.of("kafka", new KafkaMessageBinding())); } diff --git a/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ConsumerOperationDataScannerTest.java b/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ConsumerOperationDataScannerTest.java index ce5046ff8..14f42eb21 100644 --- a/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ConsumerOperationDataScannerTest.java +++ b/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ConsumerOperationDataScannerTest.java @@ -17,6 +17,7 @@ import io.github.stavshamir.springwolf.configuration.AsyncApiDocket; import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService; import io.github.stavshamir.springwolf.schemas.DefaultSchemasService; +import io.swagger.v3.oas.annotations.media.Schema; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -65,14 +66,14 @@ void allFieldsConsumerData() { assertThat(consumerChannels) .containsKey(channelName); + String messageDescription = "Example Payload DTO Description"; Operation operation = Operation.builder() .description(description) .operationId("example-consumer-topic-foo1_publish") .bindings(ImmutableMap.of("kafka", new KafkaOperationBinding())) .message(Message.builder() .name(ExamplePayloadDto.class.getName()) - // Message description is not supported yet -// .description(description) + .description(messageDescription) .title(ExamplePayloadDto.class.getSimpleName()) .payload(PayloadReference.fromModelName(ExamplePayloadDto.class.getSimpleName())) .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) @@ -142,11 +143,12 @@ void multipleConsumersForSameTopic() { .hasSize(1) .containsKey(channelName); + String messageDescription1 = "Example Payload DTO Description"; + String messageDescription2 = "Another Example Payload DTO Description"; Set messages = ImmutableSet.of( Message.builder() .name(ExamplePayloadDto.class.getName()) - // Message description is not supported yet -// .description(description1) + .description(messageDescription1) .title(ExamplePayloadDto.class.getSimpleName()) .payload(PayloadReference.fromModelName(ExamplePayloadDto.class.getSimpleName())) .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) @@ -154,8 +156,7 @@ void multipleConsumersForSameTopic() { .build(), Message.builder() .name(AnotherExamplePayloadDto.class.getName()) - // Message description is not supported yet -// .description(description2) + .description(messageDescription2) .title(AnotherExamplePayloadDto.class.getSimpleName()) .payload(PayloadReference.fromModelName(AnotherExamplePayloadDto.class.getSimpleName())) .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_USED.getSchemaName())) @@ -190,10 +191,12 @@ private void mockConsumers(Collection consumers) { when(asyncApiDocketService.getAsyncApiDocket()).thenReturn(asyncApiDocket); } + @Schema(description = "Example Payload DTO Description") static class ExamplePayloadDto { private String foo; } + @Schema(description = "Another Example Payload DTO Description") static class AnotherExamplePayloadDto { private String bar; } diff --git a/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ProducerOperationDataScannerTest.java b/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ProducerOperationDataScannerTest.java index 6bf2c3b19..711432e37 100644 --- a/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ProducerOperationDataScannerTest.java +++ b/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/ProducerOperationDataScannerTest.java @@ -17,6 +17,7 @@ import io.github.stavshamir.springwolf.configuration.AsyncApiDocket; import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService; import io.github.stavshamir.springwolf.schemas.DefaultSchemasService; +import io.swagger.v3.oas.annotations.media.Schema; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; @@ -65,14 +66,14 @@ void allFieldsProducerData() { assertThat(producerChannels) .containsKey(channelName); + String messageDescription1 = "Example Payload DTO Description"; Operation operation = Operation.builder() .description(description) .operationId("example-producer-topic-foo1_subscribe") .bindings(ImmutableMap.of("kafka", new KafkaOperationBinding())) .message(Message.builder() .name(ExamplePayloadDto.class.getName()) - // Message description is not supported yet -// .description(description) + .description(messageDescription1) .title(ExamplePayloadDto.class.getSimpleName()) .payload(PayloadReference.fromModelName(ExamplePayloadDto.class.getSimpleName())) .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) @@ -142,11 +143,12 @@ void multipleProducersForSameTopic() { .hasSize(1) .containsKey(channelName); + String messageDescription1 = "Example Payload DTO Description"; + String messageDescription2 = "Another Example Payload DTO Description"; Set messages = ImmutableSet.of( Message.builder() .name(ExamplePayloadDto.class.getName()) - // Message description is not supported yet -// .description(description1) + .description(messageDescription1) .title(ExamplePayloadDto.class.getSimpleName()) .payload(PayloadReference.fromModelName(ExamplePayloadDto.class.getSimpleName())) .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) @@ -154,8 +156,7 @@ void multipleProducersForSameTopic() { .build(), Message.builder() .name(AnotherExamplePayloadDto.class.getName()) - // Message description is not supported yet -// .description(description2) + .description(messageDescription2) .title(AnotherExamplePayloadDto.class.getSimpleName()) .payload(PayloadReference.fromModelName(AnotherExamplePayloadDto.class.getSimpleName())) .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_USED.getSchemaName())) @@ -189,12 +190,13 @@ private void mockProducers(Collection producers) { when(asyncApiDocketService.getAsyncApiDocket()).thenReturn(asyncApiDocket); } + @Schema(description = "Example Payload DTO Description") static class ExamplePayloadDto { private String foo; } + @Schema(description = "Another Example Payload DTO Description") static class AnotherExamplePayloadDto { private String bar; } - } diff --git a/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/annotation/AsyncListenerAnnotationScannerTest.java b/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/annotation/AsyncListenerAnnotationScannerTest.java index 068869fd1..8958717ba 100644 --- a/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/annotation/AsyncListenerAnnotationScannerTest.java +++ b/springwolf-core/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/operationdata/annotation/AsyncListenerAnnotationScannerTest.java @@ -10,6 +10,7 @@ import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders; import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.HeaderReference; import io.github.stavshamir.springwolf.schemas.DefaultSchemasService; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.NoArgsConstructor; import org.junit.jupiter.api.Test; @@ -66,8 +67,7 @@ void scan_componentHasListenerMethod() { Message message = Message.builder() .name(SimpleFoo.class.getName()) .title(SimpleFoo.class.getSimpleName()) - // Message description is not supported yet -// .description("test channel operation description") + .description("SimpleFoo Message Description") .payload(PayloadReference.fromModelName(SimpleFoo.class.getSimpleName())) .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) .bindings(EMPTY_MAP) @@ -101,8 +101,7 @@ void scan_componentHasListenerMethodWithAllAttributes() { Message message = Message.builder() .name(SimpleFoo.class.getName()) .title(SimpleFoo.class.getSimpleName()) - // Message description is not supported yet -// .description("description") + .description("SimpleFoo Message Description") .payload(PayloadReference.fromModelName(SimpleFoo.class.getSimpleName())) .headers(HeaderReference.fromModelName("TestSchema")) .bindings(EMPTY_MAP) @@ -144,8 +143,7 @@ void scan_componentHasMultipleListenerAnnotations() { .description("test-channel-1-description") .operationId("test-channel-1_publish") .bindings(EMPTY_MAP) - // Message description is not supported yet - .message(builder/*.description("test-channel-1-description")*/.build()) + .message(builder.description("SimpleFoo Message Description").build()) .build(); ChannelItem expectedChannel1 = ChannelItem.builder() @@ -157,8 +155,7 @@ void scan_componentHasMultipleListenerAnnotations() { .description("test-channel-2-description") .operationId("test-channel-2_publish") .bindings(EMPTY_MAP) - // Message description is not supported yet - .message(builder/*.description("test-channel-2-description")*/.build()) + .message(builder.description("SimpleFoo Message Description").build()) .build(); ChannelItem expectedChannel2 = ChannelItem.builder() @@ -228,6 +225,7 @@ private void methodWithMultipleAnnotation(SimpleFoo payload) { @Data @NoArgsConstructor + @Schema(description = "SimpleFoo Message Description") private static class SimpleFoo { private String s; private boolean b;