diff --git a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/AbstractClassLevelListenerScanner.java b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/AbstractClassLevelListenerScanner.java index 67408b10d..15ba53f28 100644 --- a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/AbstractClassLevelListenerScanner.java +++ b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/AbstractClassLevelListenerScanner.java @@ -21,13 +21,11 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.TreeSet; -import java.util.function.Supplier; import java.util.stream.Collectors; import static io.github.stavshamir.springwolf.asyncapi.MessageHelper.toMessageObjectOrComposition; @@ -44,11 +42,6 @@ public abstract class AbstractClassLevelListenerScanner< private final SchemasService schemasService; - private static final Comparator> byPublishOperationName = - Comparator.comparing(it -> it.getValue().getPublish().getOperationId()); - private static final Supplier>> channelItemSupplier = - () -> new TreeSet<>(byPublishOperationName); - /** * This annotation is used on class level * @@ -100,17 +93,17 @@ protected AsyncHeaders buildHeaders(Method method) { @Override public Map scan() { Set> components = componentClassScanner.scan(); - Set> channels = mapToChannels(components); + List> channels = mapToChannels(components); return ChannelMerger.merge(new ArrayList<>(channels)); } - private Set> mapToChannels(Set> components) { + private List> mapToChannels(Set> components) { return components.stream() .filter(this::isClassAnnotated) .map(this::mapClassToChannel) .filter(Optional::isPresent) .map(Optional::get) - .collect(Collectors.toCollection(channelItemSupplier)); + .collect(Collectors.toList()); } private boolean isClassAnnotated(Class component) { diff --git a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/AbstractMethodLevelListenerScanner.java b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/AbstractMethodLevelListenerScanner.java index 18ab12b87..2fe477e4e 100644 --- a/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/AbstractMethodLevelListenerScanner.java +++ b/springwolf-core/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/AbstractMethodLevelListenerScanner.java @@ -6,6 +6,7 @@ import com.asyncapi.v2.binding.channel.ChannelBinding; import com.asyncapi.v2.binding.message.MessageBinding; import com.asyncapi.v2.binding.operation.OperationBinding; +import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelMerger; import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelsScanner; import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner; import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message; @@ -21,11 +22,12 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; -import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toSet; @Slf4j @@ -38,11 +40,17 @@ public abstract class AbstractMethodLevelListenerScanner i @Override public Map scan() { - return componentClassScanner.scan().stream() + Set> components = componentClassScanner.scan(); + List> channels = mapToChannels(components); + return ChannelMerger.merge(channels); + } + + private List> mapToChannels(Set> components) { + return components.stream() .map(this::getAnnotatedMethods) .flatMap(Collection::stream) .map(this::mapMethodToChannel) - .collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (el1, el2) -> el1)); + .collect(Collectors.toList()); } /** diff --git a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/configuration/RabbitConfiguration.java b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/configuration/RabbitConfiguration.java index 72ff0c404..4418a7031 100644 --- a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/configuration/RabbitConfiguration.java +++ b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/configuration/RabbitConfiguration.java @@ -43,7 +43,7 @@ public Exchange exampleTopicExchange() { @Bean public Queue exampleTopicQueue() { - return new Queue("example-topic-queue"); + return new Queue("multi-payload-queue"); } @Bean diff --git a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/consumers/ExampleConsumer.java b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/consumers/ExampleConsumer.java index a5c446f86..47317804a 100644 --- a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/consumers/ExampleConsumer.java +++ b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/consumers/ExampleConsumer.java @@ -52,8 +52,13 @@ public void bindingsExample(AnotherPayloadDto payload) { log.info("Received new message in example-bindings-queue: {}", payload.toString()); } - @RabbitListener(queues = "example-topic-queue") + @RabbitListener(queues = "multi-payload-queue") public void bindingsBeanExample(AnotherPayloadDto payload) { - log.info("Received new message in example-topic-queue: {}", payload.toString()); + log.info("Received new message in multi-payload-queue (AnotherPayloadDto): {}", payload.toString()); + } + + @RabbitListener(queues = "multi-payload-queue") + public void bindingsBeanExample(ExamplePayloadDto payload) { + log.info("Received new message in multi-payload-queue (ExamplePayloadDto): {}", payload.toString()); } } diff --git a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json index a5d8d8a8e..1f1cdaf20 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json @@ -241,9 +241,9 @@ } } }, - "example-topic-queue": { + "example-topic-routing-key": { "publish": { - "operationId": "example-topic-queue_publish_bindingsBeanExample", + "operationId": "example-topic-routing-key_publish_bindingsExample", "description": "Auto-generated description", "bindings": { "amqp": { @@ -274,26 +274,26 @@ "amqp": { "is": "routingKey", "exchange": { - "name": "example-topic-exchange", + "name": "example-bindings-exchange-name", "type": "topic", "durable": true, "autoDelete": false, "vhost": "/" }, "queue": { - "name": "example-topic-queue", - "durable": true, - "exclusive": false, - "autoDelete": false, + "name": "example-bindings-queue", + "durable": false, + "exclusive": true, + "autoDelete": true, "vhost": "/" }, "bindingVersion": "0.2.0" } } }, - "example-topic-routing-key": { + "multi-payload-queue": { "publish": { - "operationId": "example-topic-routing-key_publish_bindingsExample", + "operationId": "multi-payload-queue_publish_bindingsBeanExample", "description": "Auto-generated description", "bindings": { "amqp": { @@ -304,37 +304,57 @@ } }, "message": { - "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", - "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto", - "title": "AnotherPayloadDto", - "payload": { - "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto" - }, - "headers": { - "$ref": "#/components/schemas/HeadersNotDocumented" - }, - "bindings": { - "amqp": { - "bindingVersion": "0.2.0" + "oneOf": [ + { + "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", + "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto", + "title": "AnotherPayloadDto", + "payload": { + "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto" + }, + "headers": { + "$ref": "#/components/schemas/HeadersNotDocumented" + }, + "bindings": { + "amqp": { + "bindingVersion": "0.2.0" + } + } + }, + { + "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", + "name": "io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto", + "title": "ExamplePayloadDto", + "payload": { + "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto" + }, + "headers": { + "$ref": "#/components/schemas/HeadersNotDocumented" + }, + "bindings": { + "amqp": { + "bindingVersion": "0.2.0" + } + } } - } + ] } }, "bindings": { "amqp": { "is": "routingKey", "exchange": { - "name": "example-bindings-exchange-name", + "name": "example-topic-exchange", "type": "topic", "durable": true, "autoDelete": false, "vhost": "/" }, "queue": { - "name": "example-bindings-queue", - "durable": false, - "exclusive": true, - "autoDelete": true, + "name": "multi-payload-queue", + "durable": true, + "exclusive": false, + "autoDelete": false, "vhost": "/" }, "bindingVersion": "0.2.0" diff --git a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi_withdocketfromenvironment.json b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi_withdocketfromenvironment.json index 980378240..6c6d4ad90 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi_withdocketfromenvironment.json +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi_withdocketfromenvironment.json @@ -159,9 +159,9 @@ } } }, - "example-topic-queue": { + "example-topic-routing-key": { "publish": { - "operationId": "example-topic-queue_publish_bindingsBeanExample", + "operationId": "example-topic-routing-key_publish_bindingsExample", "description": "Auto-generated description", "bindings": { "amqp": { @@ -192,26 +192,26 @@ "amqp": { "is": "routingKey", "exchange": { - "name": "example-topic-exchange", + "name": "example-bindings-exchange-name", "type": "topic", "durable": true, "autoDelete": false, "vhost": "/" }, "queue": { - "name": "example-topic-queue", - "durable": true, - "exclusive": false, - "autoDelete": false, + "name": "example-bindings-queue", + "durable": false, + "exclusive": true, + "autoDelete": true, "vhost": "/" }, "bindingVersion": "0.2.0" } } }, - "example-topic-routing-key": { + "multi-payload-queue": { "publish": { - "operationId": "example-topic-routing-key_publish_bindingsExample", + "operationId": "multi-payload-queue_publish_bindingsBeanExample", "description": "Auto-generated description", "bindings": { "amqp": { @@ -222,37 +222,57 @@ } }, "message": { - "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", - "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto", - "title": "AnotherPayloadDto", - "payload": { - "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto" - }, - "headers": { - "$ref": "#/components/schemas/HeadersNotDocumented" - }, - "bindings": { - "amqp": { - "bindingVersion": "0.2.0" + "oneOf": [ + { + "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", + "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto", + "title": "AnotherPayloadDto", + "payload": { + "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto" + }, + "headers": { + "$ref": "#/components/schemas/HeadersNotDocumented" + }, + "bindings": { + "amqp": { + "bindingVersion": "0.2.0" + } + } + }, + { + "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0", + "name": "io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto", + "title": "ExamplePayloadDto", + "payload": { + "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto" + }, + "headers": { + "$ref": "#/components/schemas/HeadersNotDocumented" + }, + "bindings": { + "amqp": { + "bindingVersion": "0.2.0" + } + } } - } + ] } }, "bindings": { "amqp": { "is": "routingKey", "exchange": { - "name": "example-bindings-exchange-name", + "name": "example-topic-exchange", "type": "topic", "durable": true, "autoDelete": false, "vhost": "/" }, "queue": { - "name": "example-bindings-queue", - "durable": false, - "exclusive": true, - "autoDelete": true, + "name": "multi-payload-queue", + "durable": true, + "exclusive": false, + "autoDelete": false, "vhost": "/" }, "bindingVersion": "0.2.0" diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScannerIntegrationTest.java b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScannerIntegrationTest.java index 6163b5c91..9ba91059d 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScannerIntegrationTest.java +++ b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScannerIntegrationTest.java @@ -8,6 +8,7 @@ import com.asyncapi.v2.binding.message.MessageBinding; import com.asyncapi.v2.binding.message.amqp.AMQPMessageBinding; import com.asyncapi.v2.binding.operation.amqp.AMQPOperationBinding; +import io.github.stavshamir.springwolf.asyncapi.MessageHelper; import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner; import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message; import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference; @@ -348,6 +349,52 @@ void scan_componentHasRabbitListenerMethods_multipleParamsWithPayloadAnnotation( assertThat(actualChannelItems).containsExactly(Map.entry(QUEUE, expectedChannelItem)); } + @Test + void scan_componentHasRabbitListenerMethods_multiplePayloads() { + // Given a class with two method annotated with RabbitListener: + // - Both methods have the same queue + setClassToScan(ClassWithRabbitListenerAnnotationMultiplePayloads.class); + + // When scan is called + Map actualChannelItems = rabbitListenerScanner.scan(); + + // Then the returned collection contains the channel, and the message contains both payload options using anyOf + AMQPChannelBinding.ExchangeProperties properties = new AMQPChannelBinding.ExchangeProperties(); + properties.setName(""); + properties.setType(ExchangeTypes.DIRECT); + properties.setAutoDelete(false); + properties.setDurable(true); + + Message messageSimpleFoo = Message.builder() + .name(SimpleFoo.class.getName()) + .title(SimpleFoo.class.getSimpleName()) + .payload(PayloadReference.fromModelName(SimpleFoo.class.getSimpleName())) + .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) + .bindings(defaultMessageBinding) + .build(); + Message messageString = Message.builder() + .name(String.class.getName()) + .title(String.class.getSimpleName()) + .payload(PayloadReference.fromModelName(String.class.getSimpleName())) + .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) + .bindings(defaultMessageBinding) + .build(); + + Operation operation = Operation.builder() + .description("Auto-generated description") + .operationId(QUEUE + "_publish_methodWithAnnotation") + .bindings(defaultOperationBinding) + .message(MessageHelper.toMessageObjectOrComposition(Set.of(messageSimpleFoo, messageString))) + .build(); + + ChannelItem expectedChannelItem = ChannelItem.builder() + .bindings(defaultChannelBinding) + .publish(operation) + .build(); + + assertThat(actualChannelItems).containsExactly(Map.entry(QUEUE, expectedChannelItem)); + } + private static class ClassWithoutRabbitListenerAnnotations { private void methodWithoutAnnotation() {} @@ -415,6 +462,15 @@ private static class ClassWithRabbitListenerAnnotationMultipleParamsWithPayloadA private void methodWithAnnotation(String anotherParam, @Payload SimpleFoo payload) {} } + private static class ClassWithRabbitListenerAnnotationMultiplePayloads { + + @RabbitListener(queues = QUEUE) + private void methodWithAnnotation(SimpleFoo payload) {} + + @RabbitListener(queues = QUEUE) + private void methodWithAnnotation(String payload) {} + } + @Data @NoArgsConstructor private static class SimpleFoo { diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelKafkaListenerScannerIntegrationTest.java b/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelKafkaListenerScannerIntegrationTest.java index 8353a4976..b8add57ed 100644 --- a/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelKafkaListenerScannerIntegrationTest.java +++ b/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelKafkaListenerScannerIntegrationTest.java @@ -7,6 +7,7 @@ import com.asyncapi.v2.binding.message.MessageBinding; import com.asyncapi.v2.binding.message.kafka.KafkaMessageBinding; import com.asyncapi.v2.binding.operation.kafka.KafkaOperationBinding; +import io.github.stavshamir.springwolf.asyncapi.MessageHelper; import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner; import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message; import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference; @@ -230,6 +231,46 @@ void scan_componentHasKafkaListenerMethods_multipleParamsWithPayloadAnnotation() assertThat(actualChannels).containsExactly(Map.entry(TOPIC, expectedChannel)); } + @Test + void scan_componentHasKafkaListenerMethods_multiplePayloads() { + // Given a class with two method annotated with KafkaListener: + // - Both methods have the same queue + setClassToScan(ClassWithKafkaListenerAnnotationMultiplePayloads.class); + + // When scan is called + Map actualChannels = methodLevelKafkaListenerScanner.scan(); + + // Then the returned collection contains the channel, and the message contains both payload options using anyOf + Message messageSimpleFoo = Message.builder() + .name(SimpleFoo.class.getName()) + .title(SimpleFoo.class.getSimpleName()) + .payload(PayloadReference.fromModelName(SimpleFoo.class.getSimpleName())) + .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) + .bindings(defaultMessageBinding) + .build(); + Message messageString = Message.builder() + .name(String.class.getName()) + .title(String.class.getSimpleName()) + .payload(PayloadReference.fromModelName(String.class.getSimpleName())) + .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) + .bindings(defaultMessageBinding) + .build(); + + Operation operation = Operation.builder() + .description("Auto-generated description") + .operationId("test-topic_publish_methodWithAnnotation") + .bindings(defaultOperationBinding) + .message(MessageHelper.toMessageObjectOrComposition(Set.of(messageSimpleFoo, messageString))) + .build(); + + ChannelItem expectedChannel = ChannelItem.builder() + .bindings(defaultChannelBinding) + .publish(operation) + .build(); + + assertThat(actualChannels).containsExactly(Map.entry(TOPIC, expectedChannel)); + } + @Test void scan_componentHasKafkaListenerMethods_batchPayload() { // Given a class with a method annotated with KafkaListener with a payload of type List @@ -314,6 +355,15 @@ private static class ClassWithKafkaListenerAnnotationMultipleParamsWithPayloadAn private void methodWithAnnotation(String anotherParam, @Payload SimpleFoo payload) {} } + private static class ClassWithKafkaListenerAnnotationMultiplePayloads { + + @KafkaListener(topics = TOPIC) + private void methodWithAnnotation(SimpleFoo payload) {} + + @KafkaListener(topics = TOPIC) + private void methodWithAnnotation(String payload) {} + } + private static class ClassWithKafkaListenerWithBatchPayload { @KafkaListener(topics = TOPIC) diff --git a/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelSqsListenerScannerIntegrationTest.java b/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelSqsListenerScannerIntegrationTest.java index e8e161ca3..ecc017256 100644 --- a/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelSqsListenerScannerIntegrationTest.java +++ b/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelSqsListenerScannerIntegrationTest.java @@ -8,6 +8,7 @@ import com.asyncapi.v2.binding.message.sqs.SQSMessageBinding; import com.asyncapi.v2.binding.operation.sqs.SQSOperationBinding; import io.awspring.cloud.sqs.annotation.SqsListener; +import io.github.stavshamir.springwolf.asyncapi.MessageHelper; import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner; import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message; import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference; @@ -216,6 +217,46 @@ void scan_componentHasSqsListenerMethods_multipleParamsWithPayloadAnnotation() { assertThat(actualChannelItems).containsExactly(Map.entry(QUEUE, expectedChannelItem)); } + @Test + void scan_componentHasSqsListenerMethods_multiplePayloads() { + // Given a class with two method annotated with SqsListener: + // - Both methods have the same queue + setClassToScan(ClassWithSqsListenerAnnotationMultiplePayloads.class); + + // When scan is called + Map actualChannelItems = scanner.scan(); + + // Then the returned collection contains the channel, and the message contains both payload options using anyOf + Message messageSimpleFoo = Message.builder() + .name(SimpleFoo.class.getName()) + .title(SimpleFoo.class.getSimpleName()) + .payload(PayloadReference.fromModelName(SimpleFoo.class.getSimpleName())) + .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) + .bindings(defaultMessageBinding) + .build(); + Message messageString = Message.builder() + .name(String.class.getName()) + .title(String.class.getSimpleName()) + .payload(PayloadReference.fromModelName(String.class.getSimpleName())) + .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName())) + .bindings(defaultMessageBinding) + .build(); + + Operation operation = Operation.builder() + .description("Auto-generated description") + .operationId("test-queue_publish_methodWithAnnotation") + .bindings(defaultOperationBinding) + .message(MessageHelper.toMessageObjectOrComposition(Set.of(messageSimpleFoo, messageString))) + .build(); + + ChannelItem expectedChannelItem = ChannelItem.builder() + .bindings(defaultChannelBinding) + .publish(operation) + .build(); + + assertThat(actualChannelItems).containsExactly(Map.entry(QUEUE, expectedChannelItem)); + } + private static class ClassWithoutSqsListenerAnnotations { private void methodWithoutAnnotation() {} @@ -253,6 +294,15 @@ private static class ClassWithSqsListenerAnnotationMultipleQueues { private void methodWithMultipleQueueNames(String anotherParam, @Payload SimpleFoo payload) {} } + private static class ClassWithSqsListenerAnnotationMultiplePayloads { + + @SqsListener(value = QUEUE) + private void methodWithAnnotation(SimpleFoo payload) {} + + @SqsListener(value = QUEUE) + private void methodWithAnnotation(String payload) {} + } + @Data @NoArgsConstructor private static class SimpleFoo {