From 6e18922bddf4da046ef0b34164e21932ac0f58f8 Mon Sep 17 00:00:00 2001 From: Timon Back Date: Fri, 13 Sep 2024 15:56:35 +0200 Subject: [PATCH 01/34] Chore/improve amqp test coverage (#948) * tests: refactoring + add yaml endpoint testing * tests: additional RabbitListener tests * chore(amqp): fix queue configuration * chore(amqp): simplify local testing * chore: update asyncapi.yaml gradle script * feat(amqp): scan all queues In addition to the routingKeys * test(amqp): update asyncapi artifacts Part of GH-366 * test(ui): use valid mock data * chore(ui): fix formatting * test(amqp): update asyncapi artifacts * feat(ui): show channel bindings * test: add WaitStrategy for ApiSystemTest * chore(amqp): use non-exclusive queue in example * chore(amqp): use non-exclusive queue in example * test(amqp): persist patched asyncapi.yaml * chore(amqp): add spring-messaging dependency in example * test(amqp): wait for ready amqp server * test(amqp): update e2e * test(amqp): cleanup --------- Co-authored-by: Pascal Dal Farra --- build.gradle | 3 + .../SpringwolfInitApplicationListener.java | 4 +- .../e2e/tests/publishing.spec.ts | 2 + .../springwolf-amqp-example/build.gradle | 1 + .../docker-compose.yml | 2 + .../examples/amqp/AmqpConstants.java | 41 ++ .../configuration/RabbitConfiguration.java | 18 +- .../amqp/consumers/ExampleConsumer.java | 97 ++++- .../examples/amqp/dtos/GenericPayloadDto.java | 19 + .../amqp/producers/AnotherProducer.java | 8 +- .../src/main/resources/application.properties | 2 +- .../examples/amqp/ApiIntegrationTest.java | 37 +- .../examples/amqp/ApiSystemTest.java | 2 + .../examples/amqp/ProducerSystemTest.java | 4 +- .../amqp/SpringContextIntegrationTest.java | 2 +- .../src/test/resources/asyncapi.json | 231 ++++++++++ .../src/test/resources/asyncapi.yaml | 406 ++++++++++++++++++ .../examples/cloudstream/ApiSystemTest.java | 2 + .../examples/jms/ApiSystemTest.java | 2 + .../examples/kafka/ApiSystemTest.java | 2 + .../examples/sns/ApiSystemTest.java | 2 + .../examples/sqs/ApiSystemTest.java | 2 + .../examples/stomp/stomp/ApiSystemTest.java | 2 + .../scanners/bindings/RabbitListenerUtil.java | 27 +- .../channels/RabbitQueueBeanScanner.java | 30 ++ .../SpringwolfAmqpScannerConfiguration.java | 11 + .../channels/RabbitQueueBeanScannerTest.java | 47 ++ .../channel-main.component.spec.ts | 4 +- .../channel-operation.component.spec.ts | 4 +- .../new/channels/channels.component.html | 16 + .../new/channels/channels.component.ts | 12 +- .../asyncapi/asyncapi-mapper.service.ts | 2 +- .../service/asyncapi/models/channels.model.ts | 2 +- .../app/service/mock/mock-asyncapi.service.ts | 2 +- 34 files changed, 1007 insertions(+), 41 deletions(-) create mode 100644 springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/AmqpConstants.java create mode 100644 springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/dtos/GenericPayloadDto.java create mode 100644 springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml create mode 100644 springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/channels/RabbitQueueBeanScanner.java create mode 100644 springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/channels/RabbitQueueBeanScannerTest.java diff --git a/build.gradle b/build.gradle index 06044eaf4..c95af39a1 100644 --- a/build.gradle +++ b/build.gradle @@ -162,6 +162,9 @@ allprojects { project .file('springwolf-examples/' + it + '-example/src/test/resources/asyncapi.actual.json') .renameTo('springwolf-examples/' + it + '-example/src/test/resources/asyncapi.json') + project + .file('springwolf-examples/' + it + '-example/src/test/resources/asyncapi.actual.yaml') + .renameTo('springwolf-examples/' + it + '-example/src/test/resources/asyncapi.yaml') } } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/SpringwolfInitApplicationListener.java b/springwolf-core/src/main/java/io/github/springwolf/core/SpringwolfInitApplicationListener.java index 952bf8f71..db68ab950 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/SpringwolfInitApplicationListener.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/SpringwolfInitApplicationListener.java @@ -24,10 +24,10 @@ public class SpringwolfInitApplicationListener implements ApplicationListener + * Note:
+ * The 'Default exchange' is a 'Direct exchange' with an empty name ( name= "") + */ + public static final String EXCHANGE_DEFAULT_EXCHANGE = ""; + + // Routing keys + /** + * When a queue is bound with "#" (hash) binding key, + * it will receive all the messages, regardless of the routing key - like in fanout exchange. + */ + public static final String ROUTING_KEY_ALL_MESSAGES = "#"; + + public static final String ROUTING_KEY_EXAMPLE_TOPIC_ROUTING_KEY = "example-topic-routing-key"; + + // Queues + public static final String QUEUE_EXAMPLE_QUEUE = "example-queue"; + public static final String QUEUE_ANOTHER_QUEUE = "another-queue"; + public static final String QUEUE_MULTI_PAYLOAD_QUEUE = "multi-payload-queue"; + public static final String QUEUE_EXAMPLE_BINDINGS_QUEUE = "example-bindings-queue"; + + public static final String QUEUE_CREATE = "queue-create"; + public static final String QUEUE_READ = "queue-read"; + public static final String QUEUE_DELETE = "queue-delete"; + public static final String QUEUE_UPDATE = "queue-update"; +} diff --git a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/configuration/RabbitConfiguration.java b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/configuration/RabbitConfiguration.java index 2e92ce5e8..adfe68e26 100644 --- a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/configuration/RabbitConfiguration.java +++ b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/configuration/RabbitConfiguration.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.examples.amqp.configuration; +import io.github.springwolf.examples.amqp.AmqpConstants; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.Exchange; @@ -23,34 +24,39 @@ public Jackson2JsonMessageConverter converter() { @Bean public Queue exampleQueue() { - return new Queue("example-queue", false); + return new Queue(AmqpConstants.QUEUE_EXAMPLE_QUEUE, false); } @Bean public Queue anotherQueue() { - return new Queue("another-queue", false); + return new Queue(AmqpConstants.QUEUE_ANOTHER_QUEUE, false); } @Bean public Queue exampleBindingsQueue() { - return new Queue("example-bindings-queue", false, true, true); + return new Queue(AmqpConstants.QUEUE_EXAMPLE_BINDINGS_QUEUE, false, false, true); + } + + @Bean + public Queue queueRead() { + return new Queue(AmqpConstants.QUEUE_READ, false); } @Bean public Exchange exampleTopicExchange() { - return new TopicExchange("example-topic-exchange"); + return new TopicExchange(AmqpConstants.EXCHANGE_EXAMPLE_TOPIC_EXCHANGE); } @Bean public Queue multiPayloadQueue() { - return new Queue("multi-payload-queue"); + return new Queue(AmqpConstants.QUEUE_MULTI_PAYLOAD_QUEUE); } @Bean public Binding exampleTopicBinding(Queue exampleBindingsQueue, Exchange exampleTopicExchange) { return BindingBuilder.bind(exampleBindingsQueue) .to(exampleTopicExchange) - .with("example-topic-routing-key") + .with(AmqpConstants.ROUTING_KEY_EXAMPLE_TOPIC_ROUTING_KEY) .noargs(); } } diff --git a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/consumers/ExampleConsumer.java b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/consumers/ExampleConsumer.java index fddf77bc0..79416adbc 100644 --- a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/consumers/ExampleConsumer.java +++ b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/consumers/ExampleConsumer.java @@ -1,16 +1,20 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.examples.amqp.consumers; +import io.github.springwolf.examples.amqp.AmqpConstants; import io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto; import io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto; +import io.github.springwolf.examples.amqp.dtos.GenericPayloadDto; import io.github.springwolf.examples.amqp.producers.AnotherProducer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.ExchangeTypes; +import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.Exchange; import org.springframework.amqp.rabbit.annotation.Queue; import org.springframework.amqp.rabbit.annotation.QueueBinding; import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.messaging.handler.annotation.Payload; import org.springframework.stereotype.Component; @Component @@ -20,9 +24,9 @@ public class ExampleConsumer { private final AnotherProducer anotherProducer; - @RabbitListener(queues = "example-queue") + @RabbitListener(queues = AmqpConstants.QUEUE_EXAMPLE_QUEUE) public void receiveExamplePayload(ExamplePayloadDto payload) { - log.info("Received new message in example-queue: {}", payload.toString()); + log.info("Received new message in {}: {}", AmqpConstants.QUEUE_EXAMPLE_QUEUE, payload.toString()); AnotherPayloadDto example = new AnotherPayloadDto(); example.setExample(payload); @@ -31,37 +35,102 @@ public void receiveExamplePayload(ExamplePayloadDto payload) { anotherProducer.sendMessage(example); } - @RabbitListener(queues = "another-queue") + @RabbitListener(queues = AmqpConstants.QUEUE_ANOTHER_QUEUE) public void receiveAnotherPayload(AnotherPayloadDto payload) { - log.info("Received new message in another-queue: {}", payload.toString()); + log.info("Received new message in {}: {}", AmqpConstants.QUEUE_ANOTHER_QUEUE, payload.toString()); } @RabbitListener( bindings = { @QueueBinding( - exchange = @Exchange(name = "example-topic-exchange", type = ExchangeTypes.TOPIC), + exchange = + @Exchange( + name = AmqpConstants.EXCHANGE_EXAMPLE_TOPIC_EXCHANGE, + type = ExchangeTypes.TOPIC), value = @Queue( - name = "example-bindings-queue", + name = AmqpConstants.QUEUE_EXAMPLE_BINDINGS_QUEUE, durable = "false", - exclusive = "true", + exclusive = "false", autoDelete = "true"), - key = "example-topic-routing-key") + key = AmqpConstants.ROUTING_KEY_EXAMPLE_TOPIC_ROUTING_KEY) }) public void bindingsExample(AnotherPayloadDto payload) { log.info( - "Received new message in example-bindings-queue" - + " through exchange example-topic-exchange using routing key example-topic-routing-key: {}", + "Received new message in {}" + " through exchange {}" + " using routing key {}: {}", + AmqpConstants.QUEUE_EXAMPLE_BINDINGS_QUEUE, + AmqpConstants.EXCHANGE_EXAMPLE_TOPIC_EXCHANGE, + AmqpConstants.ROUTING_KEY_EXAMPLE_TOPIC_ROUTING_KEY, payload.toString()); } - @RabbitListener(queues = "multi-payload-queue") + @RabbitListener(queues = AmqpConstants.QUEUE_MULTI_PAYLOAD_QUEUE) public void bindingsBeanExample(AnotherPayloadDto payload) { - log.info("Received new message in multi-payload-queue (AnotherPayloadDto): {}", payload.toString()); + log.info( + "Received new message in {} (AnotherPayloadDto): {}", + AmqpConstants.QUEUE_MULTI_PAYLOAD_QUEUE, + payload.toString()); } - @RabbitListener(queues = "multi-payload-queue") + @RabbitListener(queues = AmqpConstants.QUEUE_MULTI_PAYLOAD_QUEUE) public void bindingsBeanExample(ExamplePayloadDto payload) { - log.info("Received new message in multi-payload-queue (ExamplePayloadDto): {}", payload.toString()); + log.info( + "Received new message in {} (ExamplePayloadDto): {}", + AmqpConstants.QUEUE_MULTI_PAYLOAD_QUEUE, + payload.toString()); + } + + @RabbitListener(queuesToDeclare = @Queue(name = AmqpConstants.QUEUE_CREATE, autoDelete = "false", durable = "true")) + public void queuesToDeclareCreate(Message message, @Payload GenericPayloadDto payload) { + log.info( + "Received new message {} in {} (GenericPayloadDto): {}", + message, + AmqpConstants.QUEUE_CREATE, + payload.toString()); + } + + @RabbitListener(queuesToDeclare = @Queue(name = AmqpConstants.QUEUE_DELETE, autoDelete = "false", durable = "true")) + public void queuesToDeclareDelete(Message message, @Payload GenericPayloadDto payload) { + log.info( + "Received new message {} in {} (GenericPayloadDto): {}", + message, + AmqpConstants.QUEUE_DELETE, + payload.toString()); + } + + @RabbitListener( + autoStartup = "false", + bindings = + @QueueBinding( + exchange = + @Exchange( + name = AmqpConstants.EXCHANGE_CRUD_TOPIC_EXCHANGE_1, + type = ExchangeTypes.TOPIC), + key = AmqpConstants.ROUTING_KEY_ALL_MESSAGES, + value = @Queue(name = AmqpConstants.QUEUE_UPDATE, durable = "true", autoDelete = "false"))) + public void bindingsUpdate(Message message, @Payload GenericPayloadDto payload) { + log.info( + "Received new message {} in {} (GenericPayloadDto): {}", + message, + AmqpConstants.QUEUE_UPDATE, + payload.toString()); + } + + @RabbitListener( + autoStartup = "false", + bindings = + @QueueBinding( + exchange = + @Exchange( + name = AmqpConstants.EXCHANGE_CRUD_TOPIC_EXCHANGE_2, + type = ExchangeTypes.TOPIC), + key = AmqpConstants.ROUTING_KEY_ALL_MESSAGES, + value = @Queue(name = AmqpConstants.QUEUE_READ, durable = "false", autoDelete = "false"))) + public void bindingsRead(Message message, @Payload ExamplePayloadDto payload) { + log.info( + "Received new message {} in {} (ExamplePayloadDto): {}", + message, + AmqpConstants.QUEUE_UPDATE, + payload.toString()); } } diff --git a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/dtos/GenericPayloadDto.java b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/dtos/GenericPayloadDto.java new file mode 100644 index 000000000..c376517a9 --- /dev/null +++ b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/dtos/GenericPayloadDto.java @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.examples.amqp.dtos; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Schema(description = "Generic payload model") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GenericPayloadDto { + + @Schema(description = "Generic Payload field", requiredMode = REQUIRED) + private T genericValue; +} diff --git a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/producers/AnotherProducer.java b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/producers/AnotherProducer.java index c2b200ae3..e8cc5cbf0 100644 --- a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/producers/AnotherProducer.java +++ b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/springwolf/examples/amqp/producers/AnotherProducer.java @@ -4,6 +4,7 @@ import io.github.springwolf.bindings.amqp.annotations.AmqpAsyncOperationBinding; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.annotations.AsyncPublisher; +import io.github.springwolf.examples.amqp.AmqpConstants; import io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto; import lombok.RequiredArgsConstructor; import org.springframework.amqp.rabbit.core.RabbitTemplate; @@ -17,11 +18,14 @@ public class AnotherProducer { @AsyncPublisher( operation = @AsyncOperation( - channelName = "example-topic-exchange", + channelName = AmqpConstants.EXCHANGE_EXAMPLE_TOPIC_EXCHANGE, description = "Custom, optional description defined in the AsyncPublisher annotation")) @AmqpAsyncOperationBinding() public void sendMessage(AnotherPayloadDto msg) { // send - rabbitTemplate.convertAndSend("example-topic-exchange", "example-topic-routing-key", msg); + rabbitTemplate.convertAndSend( + AmqpConstants.EXCHANGE_EXAMPLE_TOPIC_EXCHANGE, + AmqpConstants.ROUTING_KEY_EXAMPLE_TOPIC_ROUTING_KEY, + msg); } } diff --git a/springwolf-examples/springwolf-amqp-example/src/main/resources/application.properties b/springwolf-examples/springwolf-amqp-example/src/main/resources/application.properties index fe58d88d9..b8d3f8122 100644 --- a/springwolf-examples/springwolf-amqp-example/src/main/resources/application.properties +++ b/springwolf-examples/springwolf-amqp-example/src/main/resources/application.properties @@ -5,7 +5,7 @@ spring.application.name=Springwolf example project - AMQP ######### # Spring amqp configuration -spring.rabbitmq.host=amqp +spring.rabbitmq.host=${AMQP_HOST:localhost} spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ApiIntegrationTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ApiIntegrationTest.java index 26025d272..75c11c29c 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ApiIntegrationTest.java +++ b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ApiIntegrationTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.test.context.ActiveProfiles; @@ -24,15 +25,41 @@ class ApiIntegrationTest { @Autowired private TestRestTemplate restTemplate; + @Value("${spring.rabbitmq.host}") + public String amqpHost; + + @Value("${spring.rabbitmq.port}") + public String amqpPort; + @Test - void asyncApiResourceArtifactTest() throws IOException { + void asyncApiResourceJsonArtifactTest() throws IOException { String url = "/springwolf/docs"; String actual = restTemplate.getForObject(url, String.class); - Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actual); + String actualPatched = actual.replace(amqpHost + ":" + amqpPort, "amqp:5672"); + Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actualPatched); + + String expected; + try (InputStream s = this.getClass().getResourceAsStream("/asyncapi.json")) { + assert s != null; + expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim(); + } + + assertEquals(expected, actualPatched); + } + + @Test + void asyncApiResourceYamlArtifactTest() throws IOException { + String url = "/springwolf/docs.yaml"; + String actual = restTemplate.getForObject(url, String.class); + String actualPatched = actual.replace(amqpHost + ":" + amqpPort, "amqp:5672"); + Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.yaml"), actualPatched); - InputStream s = this.getClass().getResourceAsStream("/asyncapi.json"); - String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim(); + String expected; + try (InputStream s = this.getClass().getResourceAsStream("/asyncapi.yaml")) { + assert s != null; + expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim() + "\n"; + } - assertEquals(expected, actual); + assertEquals(expected, actualPatched); } } diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ApiSystemTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ApiSystemTest.java index acf71965a..0a9756007 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ApiSystemTest.java +++ b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ApiSystemTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -47,6 +48,7 @@ public class ApiSystemTest { @Container public static DockerComposeContainer environment = new DockerComposeContainer<>(new File("docker-compose.yml")) .withExposedService(APP_NAME, APP_PORT) + .waitingFor(APP_NAME, Wait.forLogMessage(".*AsyncAPI document was built.*", 1)) .withEnv(ENV) .withLogConsumer(APP_NAME, l -> log.debug("APP: {}", l.getUtf8StringWithoutLineEnding())); diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ProducerSystemTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ProducerSystemTest.java index dce74e9f5..d47631301 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ProducerSystemTest.java +++ b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/ProducerSystemTest.java @@ -19,6 +19,7 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -57,6 +58,7 @@ public class ProducerSystemTest { @Container public static DockerComposeContainer environment = new DockerComposeContainer<>(new File("docker-compose.yml")) .withServices(AMQP_NAME) + .waitingFor(AMQP_NAME, Wait.forLogMessage(".*Server startup complete.*", 1)) .withLogConsumer(AMQP_NAME, l -> log.debug("amqp: {}", l.getUtf8StringWithoutLineEnding())); @Test @@ -79,7 +81,7 @@ void producerCanUseSpringwolfConfigurationToSendMessage() { payload.setSomeEnum(FOO1); // when - springwolfAmqpProducer.send("example-queue", payload); + springwolfAmqpProducer.send(AmqpConstants.QUEUE_EXAMPLE_QUEUE, payload); // then verify(exampleConsumer, timeout(10000)).receiveExamplePayload(payload); diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/SpringContextIntegrationTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/SpringContextIntegrationTest.java index 1554babb9..f38bccbf6 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/SpringContextIntegrationTest.java +++ b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/SpringContextIntegrationTest.java @@ -44,7 +44,7 @@ void testContextWithApplicationProperties() { @Test void testAllChannelsAreFound() { - assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(5); + assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(11); } } 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 72a57381d..8deb3416f 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json @@ -25,6 +25,30 @@ } }, "channels": { + "#": { + "address": "#", + "messages": { + "io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + }, + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + } + }, + "bindings": { + "amqp": { + "is": "routingKey", + "exchange": { + "name": "CRUD-topic-exchange-1", + "type": "topic", + "durable": true, + "autoDelete": false, + "vhost": "/" + }, + "bindingVersion": "0.3.0" + } + } + }, "another-queue": { "address": "another-queue", "messages": { @@ -46,6 +70,22 @@ } } }, + "example-bindings-queue": { + "address": "example-bindings-queue", + "bindings": { + "amqp": { + "is": "queue", + "queue": { + "name": "example-bindings-queue", + "durable": false, + "exclusive": false, + "autoDelete": true, + "vhost": "/" + }, + "bindingVersion": "0.3.0" + } + } + }, "example-queue": { "address": "example-queue", "messages": { @@ -119,6 +159,80 @@ "bindingVersion": "0.3.0" } } + }, + "queue-create": { + "address": "queue-create", + "messages": { + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + } + }, + "bindings": { + "amqp": { + "is": "queue", + "queue": { + "name": "queue-create", + "durable": true, + "exclusive": false, + "autoDelete": false, + "vhost": "/" + }, + "bindingVersion": "0.3.0" + } + } + }, + "queue-delete": { + "address": "queue-delete", + "messages": { + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + } + }, + "bindings": { + "amqp": { + "is": "queue", + "queue": { + "name": "queue-delete", + "durable": true, + "exclusive": false, + "autoDelete": false, + "vhost": "/" + }, + "bindingVersion": "0.3.0" + } + } + }, + "queue-read": { + "address": "queue-read", + "bindings": { + "amqp": { + "is": "queue", + "queue": { + "name": "queue-read", + "durable": false, + "exclusive": false, + "autoDelete": false, + "vhost": "/" + }, + "bindingVersion": "0.3.0" + } + } + }, + "queue-update": { + "address": "queue-update", + "bindings": { + "amqp": { + "is": "queue", + "queue": { + "name": "queue-update", + "durable": true, + "exclusive": false, + "autoDelete": false, + "vhost": "/" + }, + "bindingVersion": "0.3.0" + } + } } }, "components": { @@ -216,6 +330,25 @@ "someEnum", "someString" ] + }, + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { + "title": "GenericPayloadDto", + "type": "object", + "properties": { + "genericValue": { + "type": "object", + "description": "Generic Payload field" + } + }, + "description": "Generic payload model", + "examples": [ + { + "genericValue": { } + } + ], + "required": [ + "genericValue" + ] } }, "messages": { @@ -255,10 +388,68 @@ "bindingVersion": "0.3.0" } } + }, + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { + "headers": { + "$ref": "#/components/schemas/SpringRabbitListenerDefaultHeaders" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + } + }, + "name": "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto", + "title": "GenericPayloadDto", + "bindings": { + "amqp": { + "bindingVersion": "0.3.0" + } + } } } }, "operations": { + "#_receive_bindingsRead": { + "action": "receive", + "channel": { + "$ref": "#/channels/#" + }, + "bindings": { + "amqp": { + "expiration": 0, + "cc": [ + "#" + ], + "bindingVersion": "0.3.0" + } + }, + "messages": [ + { + "$ref": "#/channels/#/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + } + ] + }, + "#_receive_bindingsUpdate": { + "action": "receive", + "channel": { + "$ref": "#/channels/#" + }, + "bindings": { + "amqp": { + "expiration": 0, + "cc": [ + "#" + ], + "bindingVersion": "0.3.0" + } + }, + "messages": [ + { + "$ref": "#/channels/#/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + } + ] + }, "another-queue_receive_receiveAnotherPayload": { "action": "receive", "channel": { @@ -366,6 +557,46 @@ "$ref": "#/channels/multi-payload-queue/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" } ] + }, + "queue-create_receive_queuesToDeclareCreate": { + "action": "receive", + "channel": { + "$ref": "#/channels/queue-create" + }, + "bindings": { + "amqp": { + "expiration": 0, + "cc": [ + "queue-create" + ], + "bindingVersion": "0.3.0" + } + }, + "messages": [ + { + "$ref": "#/channels/queue-create/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + } + ] + }, + "queue-delete_receive_queuesToDeclareDelete": { + "action": "receive", + "channel": { + "$ref": "#/channels/queue-delete" + }, + "bindings": { + "amqp": { + "expiration": 0, + "cc": [ + "queue-delete" + ], + "bindingVersion": "0.3.0" + } + }, + "messages": [ + { + "$ref": "#/channels/queue-delete/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + } + ] } } } \ No newline at end of file diff --git a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml new file mode 100644 index 000000000..ca18082d5 --- /dev/null +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml @@ -0,0 +1,406 @@ +asyncapi: 3.0.0 +info: + title: Springwolf example project - AMQP + version: 1.0.0 + description: Springwolf example project to demonstrate springwolfs abilities + contact: + name: springwolf + url: https://github.com/springwolf/springwolf-core + email: example@example.com + x-phone: +49 123 456789 + license: + name: Apache License 2.0 + x-desc: some description + x-api-audience: company-internal + x-generator: springwolf +defaultContentType: application/json +servers: + amqp-server: + host: amqp:5672 + protocol: amqp +channels: + '#': + address: "#" + messages: + io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + bindings: + amqp: + is: routingKey + exchange: + name: CRUD-topic-exchange-1 + type: topic + durable: true + autoDelete: false + vhost: / + bindingVersion: 0.3.0 + another-queue: + address: another-queue + messages: + io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" + bindings: + amqp: + is: queue + queue: + name: another-queue + durable: false + exclusive: false + autoDelete: false + vhost: / + bindingVersion: 0.3.0 + example-bindings-queue: + address: example-bindings-queue + bindings: + amqp: + is: queue + queue: + name: example-bindings-queue + durable: false + exclusive: false + autoDelete: true + vhost: / + bindingVersion: 0.3.0 + example-queue: + address: example-queue + messages: + io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + bindings: + amqp: + is: queue + queue: + name: example-queue + durable: false + exclusive: false + autoDelete: false + vhost: / + bindingVersion: 0.3.0 + example-topic-exchange: + address: example-topic-exchange + messages: + io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" + example-topic-routing-key: + address: example-topic-routing-key + messages: + io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" + bindings: + amqp: + is: routingKey + exchange: + name: example-topic-exchange + type: topic + durable: true + autoDelete: false + vhost: / + bindingVersion: 0.3.0 + multi-payload-queue: + address: multi-payload-queue + messages: + io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" + io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + bindings: + amqp: + is: queue + queue: + name: multi-payload-queue + durable: true + exclusive: false + autoDelete: false + vhost: / + bindingVersion: 0.3.0 + queue-create: + address: queue-create + messages: + io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + bindings: + amqp: + is: queue + queue: + name: queue-create + durable: true + exclusive: false + autoDelete: false + vhost: / + bindingVersion: 0.3.0 + queue-delete: + address: queue-delete + messages: + io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + bindings: + amqp: + is: queue + queue: + name: queue-delete + durable: true + exclusive: false + autoDelete: false + vhost: / + bindingVersion: 0.3.0 + queue-read: + address: queue-read + bindings: + amqp: + is: queue + queue: + name: queue-read + durable: false + exclusive: false + autoDelete: false + vhost: / + bindingVersion: 0.3.0 + queue-update: + address: queue-update + bindings: + amqp: + is: queue + queue: + name: queue-update + durable: true + exclusive: false + autoDelete: false + vhost: / + bindingVersion: 0.3.0 +components: + schemas: + HeadersNotDocumented: + title: HeadersNotDocumented + type: object + properties: {} + description: "There can be headers, but they are not explicitly documented." + examples: + - {} + SpringRabbitListenerDefaultHeaders: + title: SpringRabbitListenerDefaultHeaders + type: object + properties: {} + examples: + - {} + io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto: + title: AnotherPayloadDto + type: object + properties: + example: + $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + foo: + type: string + description: Foo field + maxLength: 100 + examples: + - bar + description: Another payload model + examples: + - example: + someEnum: FOO2 + someLong: 5 + someString: some string value + foo: bar + required: + - example + io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto: + title: ExamplePayloadDto + type: object + properties: + someEnum: + type: string + description: Some enum field + enum: + - FOO1 + - FOO2 + - FOO3 + examples: + - FOO2 + someLong: + type: integer + description: Some long field + format: int64 + minimum: 0 + examples: + - 5 + someString: + type: string + description: Some string field + examples: + - some string value + description: Example payload model + examples: + - someEnum: FOO2 + someLong: 5 + someString: some string value + required: + - someEnum + - someString + io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: + title: GenericPayloadDto + type: object + properties: + genericValue: + type: object + description: Generic Payload field + description: Generic payload model + examples: + - genericValue: {} + required: + - genericValue + messages: + io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto: + headers: + $ref: "#/components/schemas/HeadersNotDocumented" + payload: + schemaFormat: application/vnd.aai.asyncapi+json;version=3.0.0 + schema: + $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" + name: io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto + title: AnotherPayloadDto + description: Another payload model + bindings: + amqp: + bindingVersion: 0.3.0 + io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto: + headers: + $ref: "#/components/schemas/SpringRabbitListenerDefaultHeaders" + payload: + schemaFormat: application/vnd.aai.asyncapi+json;version=3.0.0 + schema: + $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + name: io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto + title: ExamplePayloadDto + bindings: + amqp: + bindingVersion: 0.3.0 + io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: + headers: + $ref: "#/components/schemas/SpringRabbitListenerDefaultHeaders" + payload: + schemaFormat: application/vnd.aai.asyncapi+json;version=3.0.0 + schema: + $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + name: io.github.springwolf.examples.amqp.dtos.GenericPayloadDto + title: GenericPayloadDto + bindings: + amqp: + bindingVersion: 0.3.0 +operations: + '#_receive_bindingsRead': + action: receive + channel: + $ref: "#/channels/#" + bindings: + amqp: + expiration: 0 + cc: + - "#" + bindingVersion: 0.3.0 + messages: + - $ref: "#/channels/#/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + '#_receive_bindingsUpdate': + action: receive + channel: + $ref: "#/channels/#" + bindings: + amqp: + expiration: 0 + cc: + - "#" + bindingVersion: 0.3.0 + messages: + - $ref: "#/channels/#/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + another-queue_receive_receiveAnotherPayload: + action: receive + channel: + $ref: "#/channels/another-queue" + bindings: + amqp: + expiration: 0 + cc: + - another-queue + bindingVersion: 0.3.0 + messages: + - $ref: "#/channels/another-queue/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" + example-queue_receive_receiveExamplePayload: + action: receive + channel: + $ref: "#/channels/example-queue" + bindings: + amqp: + expiration: 0 + cc: + - example-queue + bindingVersion: 0.3.0 + messages: + - $ref: "#/channels/example-queue/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + example-topic-exchange_send_sendMessage: + action: send + channel: + $ref: "#/channels/example-topic-exchange" + title: example-topic-exchange_send + description: "Custom, optional description defined in the AsyncPublisher annotation" + bindings: + amqp: + expiration: 0 + cc: [] + priority: 0 + deliveryMode: 1 + mandatory: false + timestamp: false + ack: false + bindingVersion: 0.3.0 + messages: + - $ref: "#/channels/example-topic-exchange/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" + example-topic-routing-key_receive_bindingsExample: + action: receive + channel: + $ref: "#/channels/example-topic-routing-key" + bindings: + amqp: + expiration: 0 + cc: + - example-topic-routing-key + bindingVersion: 0.3.0 + messages: + - $ref: "#/channels/example-topic-routing-key/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" + multi-payload-queue_receive_bindingsBeanExample: + action: receive + channel: + $ref: "#/channels/multi-payload-queue" + bindings: + amqp: + expiration: 0 + cc: + - multi-payload-queue + bindingVersion: 0.3.0 + messages: + - $ref: "#/channels/multi-payload-queue/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" + - $ref: "#/channels/multi-payload-queue/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + queue-create_receive_queuesToDeclareCreate: + action: receive + channel: + $ref: "#/channels/queue-create" + bindings: + amqp: + expiration: 0 + cc: + - queue-create + bindingVersion: 0.3.0 + messages: + - $ref: "#/channels/queue-create/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + queue-delete_receive_queuesToDeclareDelete: + action: receive + channel: + $ref: "#/channels/queue-delete" + bindings: + amqp: + expiration: 0 + cc: + - queue-delete + bindingVersion: 0.3.0 + messages: + - $ref: "#/channels/queue-delete/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/springwolf/examples/cloudstream/ApiSystemTest.java b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/springwolf/examples/cloudstream/ApiSystemTest.java index 6845d6753..f8e4b823f 100644 --- a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/springwolf/examples/cloudstream/ApiSystemTest.java +++ b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/springwolf/examples/cloudstream/ApiSystemTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -47,6 +48,7 @@ public class ApiSystemTest { @Container public static DockerComposeContainer environment = new DockerComposeContainer<>(new File("docker-compose.yml")) .withExposedService(APP_NAME, APP_PORT) + .waitingFor(APP_NAME, Wait.forLogMessage(".*AsyncAPI document was built.*", 1)) .withEnv(ENV) .withLogConsumer(APP_NAME, l -> log.debug("APP: {}", l.getUtf8StringWithoutLineEnding())); diff --git a/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/ApiSystemTest.java b/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/ApiSystemTest.java index 8c458f201..f6a6a3d4a 100644 --- a/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/ApiSystemTest.java +++ b/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/ApiSystemTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -47,6 +48,7 @@ public class ApiSystemTest { @Container public static DockerComposeContainer environment = new DockerComposeContainer<>(new File("docker-compose.yml")) .withExposedService(APP_NAME, APP_PORT) + .waitingFor(APP_NAME, Wait.forLogMessage(".*AsyncAPI document was built.*", 1)) .withEnv(ENV) .withLogConsumer(APP_NAME, l -> log.debug("APP: {}", l.getUtf8StringWithoutLineEnding())); diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiSystemTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiSystemTest.java index 48319c403..053cf52aa 100644 --- a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiSystemTest.java +++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiSystemTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -47,6 +48,7 @@ public class ApiSystemTest { @Container public static DockerComposeContainer environment = new DockerComposeContainer<>(new File("docker-compose.yml")) .withExposedService(APP_NAME, APP_PORT) + .waitingFor(APP_NAME, Wait.forLogMessage(".*AsyncAPI document was built.*", 1)) .withEnv(ENV) .withLogConsumer(APP_NAME, l -> log.debug("APP: {}", l.getUtf8StringWithoutLineEnding())); diff --git a/springwolf-examples/springwolf-sns-example/src/test/java/io/github/springwolf/examples/sns/ApiSystemTest.java b/springwolf-examples/springwolf-sns-example/src/test/java/io/github/springwolf/examples/sns/ApiSystemTest.java index 415ce0ea0..ba9c856e6 100644 --- a/springwolf-examples/springwolf-sns-example/src/test/java/io/github/springwolf/examples/sns/ApiSystemTest.java +++ b/springwolf-examples/springwolf-sns-example/src/test/java/io/github/springwolf/examples/sns/ApiSystemTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -47,6 +48,7 @@ public class ApiSystemTest { @Container public static DockerComposeContainer environment = new DockerComposeContainer<>(new File("docker-compose.yml")) .withExposedService(APP_NAME, APP_PORT) + .waitingFor(APP_NAME, Wait.forLogMessage(".*AsyncAPI document was built.*", 1)) .withEnv(ENV) .withLogConsumer(APP_NAME, l -> log.debug("APP: {}", l.getUtf8StringWithoutLineEnding())); diff --git a/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/springwolf/examples/sqs/ApiSystemTest.java b/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/springwolf/examples/sqs/ApiSystemTest.java index e6f6130de..bdae15593 100644 --- a/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/springwolf/examples/sqs/ApiSystemTest.java +++ b/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/springwolf/examples/sqs/ApiSystemTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -47,6 +48,7 @@ public class ApiSystemTest { @Container public static DockerComposeContainer environment = new DockerComposeContainer<>(new File("docker-compose.yml")) .withExposedService(APP_NAME, APP_PORT) + .waitingFor(APP_NAME, Wait.forLogMessage(".*AsyncAPI document was built.*", 1)) .withEnv(ENV) .withLogConsumer(APP_NAME, l -> log.debug("APP: {}", l.getUtf8StringWithoutLineEnding())); diff --git a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiSystemTest.java b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiSystemTest.java index 4b01a5fce..d8a8d5723 100644 --- a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiSystemTest.java +++ b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiSystemTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test; import org.springframework.web.client.RestTemplate; import org.testcontainers.containers.DockerComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -45,6 +46,7 @@ public class ApiSystemTest { @Container public static DockerComposeContainer environment = new DockerComposeContainer<>(new File("docker-compose.yml")) .withExposedService(APP_NAME, APP_PORT) + .waitingFor(APP_NAME, Wait.forLogMessage(".*AsyncAPI document was built.*", 1)) .withEnv(ENV) .withLogConsumer(APP_NAME, l -> log.debug("APP: {}", l.getUtf8StringWithoutLineEnding())); diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtil.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtil.java index 09a6200a3..e5d925482 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtil.java +++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtil.java @@ -11,6 +11,8 @@ import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelType; import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPMessageBinding; import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.Exchange; @@ -33,6 +35,7 @@ @Slf4j public class RabbitListenerUtil { + public static final String BINDING_NAME = "amqp"; private static final Boolean DEFAULT_AUTO_DELETE = false; private static final Boolean DEFAULT_DURABLE = true; private static final Boolean DEFAULT_EXCLUSIVE = false; @@ -98,7 +101,7 @@ public static Map buildChannelBinding( channelBinding.exchange(buildExchangeProperties(annotation, exchangeName, context)); } - return Map.of("amqp", channelBinding.build()); + return Map.of(BINDING_NAME, channelBinding.build()); } private static AMQPChannelExchangeProperties buildExchangeProperties( @@ -163,6 +166,24 @@ private static AMQPChannelQueueProperties buildQueueProperties( .build(); } + public static ChannelObject buildChannelObject(org.springframework.amqp.core.Queue queue) { + return ChannelObject.builder() + .channelId(ReferenceUtil.toValidId(queue.getName())) + .address(queue.getName()) + .bindings(Map.of( + BINDING_NAME, + AMQPChannelBinding.builder() + .is(AMQPChannelType.QUEUE) + .queue(AMQPChannelQueueProperties.builder() + .name(queue.getName()) + .autoDelete(queue.isAutoDelete()) + .durable(queue.isDurable()) + .exclusive(queue.isExclusive()) + .build()) + .build())) + .build(); + } + private static Boolean parse(String value, Boolean defaultIfEmpty) { if ("".equals(value)) { return defaultIfEmpty; @@ -194,7 +215,7 @@ private static String getExchangeName( public static Map buildOperationBinding( RabbitListener annotation, StringValueResolver resolver, RabbitListenerUtilContext context) { return Map.of( - "amqp", + BINDING_NAME, AMQPOperationBinding.builder() .cc(getRoutingKeys(annotation, resolver, context)) .build()); @@ -234,7 +255,7 @@ private static List getRoutingKeys( public static Map buildMessageBinding() { // currently the feature to define amqp message binding is not implemented. - return Map.of("amqp", new AMQPMessageBinding()); + return Map.of(BINDING_NAME, new AMQPMessageBinding()); } public record RabbitListenerUtilContext( diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/channels/RabbitQueueBeanScanner.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/channels/RabbitQueueBeanScanner.java new file mode 100644 index 000000000..79ef8726a --- /dev/null +++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/channels/RabbitQueueBeanScanner.java @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.plugins.amqp.asyncapi.scanners.channels; + +import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelBinding; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; +import io.github.springwolf.plugins.amqp.asyncapi.scanners.bindings.RabbitListenerUtil; +import lombok.RequiredArgsConstructor; +import org.springframework.amqp.core.Queue; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@RequiredArgsConstructor +public class RabbitQueueBeanScanner implements ChannelsScanner { + private final List queues; + + @Override + public Map scan() { + return queues.stream() + .map(RabbitListenerUtil::buildChannelObject) + .collect(Collectors.toMap( + o -> ((AMQPChannelBinding) o.getBindings().get(RabbitListenerUtil.BINDING_NAME)) + .getQueue() + .getName(), + c -> c, + (a, b) -> a)); + } +} diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java index fa02891d0..67f84d920 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java +++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java @@ -14,6 +14,7 @@ import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationClassLevelOperationsScanner; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationMethodLevelOperationsScanner; import io.github.springwolf.plugins.amqp.asyncapi.scanners.bindings.AmqpBindingFactory; +import io.github.springwolf.plugins.amqp.asyncapi.scanners.channels.RabbitQueueBeanScanner; import io.github.springwolf.plugins.amqp.asyncapi.scanners.common.headers.AsyncHeadersForAmqpBuilder; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.Exchange; @@ -158,4 +159,14 @@ public SpringAnnotationOperationsScanner simpleRabbitMethodLevelListenerAnnotati return new SpringAnnotationOperationsScanner(springwolfClassScanner, strategy); } + + @Bean + @ConditionalOnProperty( + name = SPRINGWOLF_SCANNER_RABBIT_LISTENER_ENABLED, + havingValue = "true", + matchIfMissing = true) + @Order(value = ChannelPriority.AUTO_DISCOVERED) + public RabbitQueueBeanScanner rabbitQueueBeanScanner(List queues) { + return new RabbitQueueBeanScanner(queues); + } } diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/channels/RabbitQueueBeanScannerTest.java b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/channels/RabbitQueueBeanScannerTest.java new file mode 100644 index 000000000..d12d8244b --- /dev/null +++ b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/channels/RabbitQueueBeanScannerTest.java @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.plugins.amqp.asyncapi.scanners.channels; + +import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelBinding; +import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelQueueProperties; +import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelType; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import org.junit.jupiter.api.Test; +import org.springframework.amqp.core.Queue; + +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class RabbitQueueBeanScannerTest { + + @Test + void scan() { + // given + var queue = new Queue("name"); + var scanner = new RabbitQueueBeanScanner(List.of(queue)); + + // when + var result = scanner.scan(); + + // then + assertThat(result) + .isEqualTo(Map.of( + "name", + ChannelObject.builder() + .channelId("name") + .address("name") + .bindings(Map.of( + "amqp", + AMQPChannelBinding.builder() + .is(AMQPChannelType.QUEUE) + .queue(AMQPChannelQueueProperties.builder() + .name("name") + .autoDelete(false) + .durable(true) + .exclusive(false) + .build()) + .build())) + .build())); + } +} diff --git a/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.spec.ts b/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.spec.ts index 813afd2b9..dde13b8f8 100644 --- a/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.spec.ts +++ b/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.spec.ts @@ -12,7 +12,9 @@ import { AsyncApiService } from "../../../service/asyncapi/asyncapi.service"; import { PublisherService } from "../../../service/publisher.service"; describe("ChannelMainComponent", () => { - const mockData = mockedExampleSchemaMapped.channelOperations[0]; + const mockData = mockedExampleSchemaMapped.channelOperations + .slice(-1) + .pop()!!; beforeEach(async () => { mockedAsyncApiService.getAsyncApi.mockClear(); diff --git a/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.spec.ts b/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.spec.ts index 4a59e7f4e..bd8fa88c4 100644 --- a/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.spec.ts +++ b/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.spec.ts @@ -16,7 +16,9 @@ import { } from "../../../mock-components.spec"; describe("ChannelOperationComponent", () => { - const mockData = mockedExampleSchemaMapped.channelOperations[0]; + const mockData = mockedExampleSchemaMapped.channelOperations + .slice(-1) + .pop()!!; beforeEach(async () => { mockedAsyncApiService.getAsyncApi.mockClear(); diff --git a/springwolf-ui/src/app/components/new/channels/channels.component.html b/springwolf-ui/src/app/components/new/channels/channels.component.html index 7ee69ca09..b213b6100 100644 --- a/springwolf-ui/src/app/components/new/channels/channels.component.html +++ b/springwolf-ui/src/app/components/new/channels/channels.component.html @@ -3,6 +3,22 @@

Channels

@for (channel of channels; track channel) {

{{ channel.name }}

+ +
+
+
Channel Binding
+
+
+
+ +
+
+
+ @for (channelOperation of channel.operations; track channelOperation) { { this.channels = asyncapi.channels; }); + + this.uiService.isShowBindings$.subscribe( + (value) => (this.isShowBindings = value) + ); } } diff --git a/springwolf-ui/src/app/service/asyncapi/asyncapi-mapper.service.ts b/springwolf-ui/src/app/service/asyncapi/asyncapi-mapper.service.ts index 612aa0496..509fe78ca 100644 --- a/springwolf-ui/src/app/service/asyncapi/asyncapi-mapper.service.ts +++ b/springwolf-ui/src/app/service/asyncapi/asyncapi-mapper.service.ts @@ -258,7 +258,7 @@ export class AsyncApiMapperService { "message of channel " + channelName, () => { const messageId = this.resolveRefId(operationMessage.$ref); - const channelMessage = channel.messages[messageId]; + const channelMessage = channel.messages!![messageId]; const channelMessageId = this.resolveRefId(channelMessage.$ref); const message = messages[channelMessageId]; diff --git a/springwolf-ui/src/app/service/asyncapi/models/channels.model.ts b/springwolf-ui/src/app/service/asyncapi/models/channels.model.ts index caae40d9f..0a538c6dc 100644 --- a/springwolf-ui/src/app/service/asyncapi/models/channels.model.ts +++ b/springwolf-ui/src/app/service/asyncapi/models/channels.model.ts @@ -8,7 +8,7 @@ export interface ServerChannels { export interface ServerChannel { address: string; description?: string; - messages: { + messages?: { [key: string]: { $ref: string; }; diff --git a/springwolf-ui/src/app/service/mock/mock-asyncapi.service.ts b/springwolf-ui/src/app/service/mock/mock-asyncapi.service.ts index 6c140ad01..88be32023 100644 --- a/springwolf-ui/src/app/service/mock/mock-asyncapi.service.ts +++ b/springwolf-ui/src/app/service/mock/mock-asyncapi.service.ts @@ -8,7 +8,7 @@ const asyncApiMapperService = new AsyncApiMapperService({ showWarning: jest.fn(), }); export const mockedExampleSchemaMapped = asyncApiMapperService.toAsyncApi( - exampleSchemas[0].value + exampleSchemas.find((el) => el.plugin === "kafka")!!.value )!!; export const mockedAsyncApiService: { getAsyncApi: jest.Mock } = { getAsyncApi: jest.fn().mockReturnValue(of(mockedExampleSchemaMapped)), From 170b053882a2026d4d3773b6c03430d392ed7ab8 Mon Sep 17 00:00:00 2001 From: Timon Back Date: Fri, 13 Sep 2024 16:46:04 +0200 Subject: [PATCH 02/34] chore(kafka): hardcode cp-kafka (#969) Version is chosen randomly as the current cp-kafka:latest is not woring anymore --- .../springwolf-cloud-stream-example/docker-compose.yml | 2 +- springwolf-examples/springwolf-kafka-example/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/springwolf-examples/springwolf-cloud-stream-example/docker-compose.yml b/springwolf-examples/springwolf-cloud-stream-example/docker-compose.yml index 2d44edd03..77116a728 100644 --- a/springwolf-examples/springwolf-cloud-stream-example/docker-compose.yml +++ b/springwolf-examples/springwolf-cloud-stream-example/docker-compose.yml @@ -11,7 +11,7 @@ services: - kafka kafka: - image: confluentinc/cp-kafka:latest + image: confluentinc/cp-kafka:7.4.6 ports: - "9095:9095" # plaintext - no authentication (port 9095 avoids conflict with kafka plugin) volumes: diff --git a/springwolf-examples/springwolf-kafka-example/docker-compose.yml b/springwolf-examples/springwolf-kafka-example/docker-compose.yml index d14a986ab..f9f6c7a33 100644 --- a/springwolf-examples/springwolf-kafka-example/docker-compose.yml +++ b/springwolf-examples/springwolf-kafka-example/docker-compose.yml @@ -13,7 +13,7 @@ services: - kafka kafka: - image: confluentinc/cp-kafka:latest + image: confluentinc/cp-kafka:7.4.6 ports: - "9092:9092" # plaintext - no authentication - "9093:9093" # sasl From 867201f355b81523bb8d6341f58e7805f8c79d7c Mon Sep 17 00:00:00 2001 From: Timon Back Date: Fri, 13 Sep 2024 16:46:20 +0200 Subject: [PATCH 03/34] feat(core): handle example root schema lazily (#968) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: David Müller --- .../examples/walkers/DefaultSchemaWalker.java | 33 ++++++++++--------- .../walkers/ExampleValueGenerator.java | 4 +-- .../json/ExampleJsonValueGenerator.java | 4 +-- .../walkers/xml/ExampleXmlValueGenerator.java | 16 ++++----- .../yaml/ExampleYamlValueGenerator.java | 4 +-- .../xml/ExampleXmlValueGeneratorTest.java | 16 ++++++--- 6 files changed, 43 insertions(+), 34 deletions(-) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalker.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalker.java index 316c4e055..939515bab 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalker.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/DefaultSchemaWalker.java @@ -56,10 +56,7 @@ public R fromSchema(Schema schema, Map definitions) { exampleValueGenerator.initialize(); try { - String schemaName = exampleValueGenerator - .lookupSchemaName(schema) - .orElseThrow(() -> - new ExampleGeneratingException("There is no name set for Schema: " + schema.toString())); + Optional schemaName = exampleValueGenerator.lookupSchemaName(schema); T generatedExample = buildExample(schemaName, schema, definitions, new HashSet<>()) .orElseThrow(() -> new ExampleGeneratingException("Something went wrong")); @@ -71,7 +68,8 @@ public R fromSchema(Schema schema, Map definitions) { return null; } - private Optional buildExample(String name, Schema schema, Map definitions, Set visited) { + private Optional buildExample( + Optional name, Schema schema, Map definitions, Set visited) { log.debug("Building example for schema {}", schema); Optional exampleValue = getExampleFromSchemaAnnotation(name, schema); @@ -88,12 +86,13 @@ private Optional buildExample(String name, Schema schema, Map return example; } - private Optional getExampleFromSchemaAnnotation(String fieldName, Schema schema) { + private Optional getExampleFromSchemaAnnotation(Optional fieldName, Schema schema) { return getExampleValueFromSchemaAnnotation(fieldName, schema, schema.getExample()) .or(() -> getExampleValueFromSchemaAnnotation(fieldName, schema, schema.getDefault())); } - private Optional getExampleValueFromSchemaAnnotation(String fieldName, Schema schema, Object exampleValue) { + private Optional getExampleValueFromSchemaAnnotation( + Optional fieldName, Schema schema, Object exampleValue) { // schema is a map of properties from a nested object, whose example cannot be inferred if (exampleValue == null) { return Optional.empty(); @@ -159,7 +158,7 @@ private Optional getExampleValueFromSchemaAnnotation(String fieldName, Schema * The caller must ensure that the schema has not been visited before to avoid infinite recursion */ private Optional buildExampleFromUnvisitedSchema( - String name, Schema schema, Map definitions, Set visited) { + Optional name, Schema schema, Map definitions, Set visited) { Optional> resolvedSchema = resolveSchemaFromRef(schema, definitions); if (resolvedSchema.isPresent()) { return buildExample(name, resolvedSchema.get(), definitions, visited); @@ -192,7 +191,8 @@ private Optional buildArrayExample(Schema schema, Map definit return exampleValueGenerator .lookupSchemaName(arrayItemSchema) .or(() -> arrayName) - .flatMap(arrayItemName -> buildExample(arrayItemName, arrayItemSchema, definitions, visited)) + .flatMap(arrayItemName -> + buildExample(Optional.of(arrayItemName), arrayItemSchema, definitions, visited)) .map(arrayItem -> exampleValueGenerator.createArrayExample(arrayName, arrayItem)); } @@ -231,7 +231,7 @@ private String getFirstEnumValue(Schema schema) { } private Optional buildFromComposedSchema( - String name, Schema schema, Map definitions, Set visited) { + Optional name, Schema schema, Map definitions, Set visited) { final List schemasAllOf = schema.getAllOf(); final List schemasAnyOf = schema.getAnyOf(); final List schemasOneOf = schema.getOneOf(); @@ -247,7 +247,7 @@ private Optional buildFromComposedSchema( } private Optional buildFromObjectSchema( - String name, Schema schema, Map definitions, Set visited) { + Optional name, Schema schema, Map definitions, Set visited) { final Optional exampleValue; final Map properties = schema.getProperties(); @@ -264,7 +264,7 @@ private Optional buildFromObjectSchema( } private Optional buildMapExample( - String name, Schema additionalProperties, Map definitions, Set visited) { + Optional name, Schema additionalProperties, Map definitions, Set visited) { T object = exampleValueGenerator.startObject(name); Map mapProperties = Map.of(DEFAULT_MAP_KEY_EXAMPLE, additionalProperties); exampleValueGenerator.addPropertyExamples( @@ -275,7 +275,10 @@ private Optional buildMapExample( } private Optional buildFromObjectSchemaWithProperties( - String name, Map properties, Map definitions, Set visited) { + Optional name, + Map properties, + Map definitions, + Set visited) { T object = exampleValueGenerator.startObject(name); exampleValueGenerator.addPropertyExamples( object, buildPropertyExampleListFromSchema(properties, definitions, visited)); @@ -285,7 +288,7 @@ private Optional buildFromObjectSchemaWithProperties( } private Optional buildFromObjectSchemaWithAllOf( - String name, List schemasAllOf, Map definitions, Set visited) { + Optional name, List schemasAllOf, Map definitions, Set visited) { T object = exampleValueGenerator.startObject(name); exampleValueGenerator.addPropertyExamples( object, buildPropertyExampleListFromSchemas(schemasAllOf, definitions, visited)); @@ -305,7 +308,7 @@ private List> buildPropertyExampleListFromSchema( .orElse(propertySchema.getKey()); Optional propertyValue = - buildExample(propertyKey, propertySchema.getValue(), definitions, visited); + buildExample(Optional.of(propertyKey), propertySchema.getValue(), definitions, visited); return propertyValue .map(optionalElem -> new PropertyExample<>(propertyKey, optionalElem)) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/ExampleValueGenerator.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/ExampleValueGenerator.java index 33b948a88..df4fe3adf 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/ExampleValueGenerator.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/ExampleValueGenerator.java @@ -44,7 +44,7 @@ default void initialize() {} Optional createUnknownSchemaStringFormatExample(String schemaFormat); - T startObject(String name); + T startObject(Optional name); default void endObject() {} @@ -54,5 +54,5 @@ default void endObject() {} T createRaw(Object exampleValueString); - T getExampleOrNull(String fieldName, Schema schema, Object example); + T getExampleOrNull(Optional fieldName, Schema schema, Object example); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/json/ExampleJsonValueGenerator.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/json/ExampleJsonValueGenerator.java index fef8ca94f..d24d17cc8 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/json/ExampleJsonValueGenerator.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/json/ExampleJsonValueGenerator.java @@ -97,7 +97,7 @@ public JsonNode createRaw(Object exampleValue) { } @Override - public JsonNode getExampleOrNull(String fieldName, Schema schema, Object example) { + public JsonNode getExampleOrNull(Optional fieldName, Schema schema, Object example) { if (example instanceof JsonNode) { return (JsonNode) example; } @@ -106,7 +106,7 @@ public JsonNode getExampleOrNull(String fieldName, Schema schema, Object example } @Override - public JsonNode startObject(String name) { + public JsonNode startObject(Optional name) { return objectMapper.createObjectNode(); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGenerator.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGenerator.java index a6a74813b..7f24c595d 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGenerator.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGenerator.java @@ -87,12 +87,9 @@ public Optional createBooleanExample(Boolean value, Schema schema) { } @Override - public Element startObject(String name) { - if (name == null) { - throw new IllegalArgumentException("Object name must not be empty"); - } - - return nodeStack.push(document.createElement(name)); + public Element startObject(Optional name) { + return nodeStack.push(document.createElement(name.orElseThrow( + () -> new SchemaWalker.ExampleGeneratingException("There is no name set for Schema")))); } @Override @@ -198,7 +195,7 @@ public Node createRaw(Object exampleValue) { } @Override - public Node getExampleOrNull(String fieldName, Schema schema, Object example) { + public Node getExampleOrNull(Optional fieldName, Schema schema, Object example) { String name = getCacheKey(schema); if (example instanceof Node) { @@ -207,7 +204,10 @@ public Node getExampleOrNull(String fieldName, Schema schema, Object example) { if (exampleCache.containsKey(name)) { Node oldElement = exampleCache.get(name); - Node newElement = modifyElementFromCacheIfNeeded(oldElement, fieldName); + Node newElement = modifyElementFromCacheIfNeeded( + oldElement, + fieldName.orElseThrow( + () -> new SchemaWalker.ExampleGeneratingException("There is no name set for Schema"))); return this.document.importNode(newElement, true); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/yaml/ExampleYamlValueGenerator.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/yaml/ExampleYamlValueGenerator.java index 135e16610..b19069e52 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/yaml/ExampleYamlValueGenerator.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/examples/walkers/yaml/ExampleYamlValueGenerator.java @@ -71,7 +71,7 @@ public Optional createBooleanExample(Boolean value, Schema schema) { } @Override - public JsonNode startObject(String name) { + public JsonNode startObject(Optional name) { return this.exampleJsonValueGenerator.startObject(name); } @@ -116,7 +116,7 @@ public JsonNode createRaw(Object exampleValueString) { } @Override - public JsonNode getExampleOrNull(String fieldName, Schema schema, Object example) { + public JsonNode getExampleOrNull(Optional fieldName, Schema schema, Object example) { return this.exampleJsonValueGenerator.getExampleOrNull(fieldName, schema, example); } } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGeneratorTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGeneratorTest.java index eec84a847..7c0259f81 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGeneratorTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGeneratorTest.java @@ -7,6 +7,8 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; +import java.util.Optional; + import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -33,11 +35,13 @@ void cacheShouldResolveBySchemaName() { .get(); generator.prepareForSerialization(schema1, example1); - Node cachedExample1 = generator.getExampleOrNull("fieldName1", schema1, "does-not-matter-for-test-1"); + Node cachedExample1 = + generator.getExampleOrNull(Optional.of("fieldName1"), schema1, "does-not-matter-for-test-1"); // when generator.initialize(); - Node exampleFromCache = generator.getExampleOrNull("fieldName2", schema2, "does-not-matter-for-test-2"); + Node exampleFromCache = + generator.getExampleOrNull(Optional.of("fieldName2"), schema2, "does-not-matter-for-test-2"); // then assertThat(exampleFromCache).isNotEqualTo(cachedExample1); @@ -62,11 +66,13 @@ void cacheShouldResolveBySchemaNameAndRenameToWrappingField() { Node example1 = generator.createRaw("aValue"); generator.prepareForSerialization(schema1, example1); - Node cachedExample1 = generator.getExampleOrNull("fieldName1", schema1, "does-not-matter-for-test-1"); + Node cachedExample1 = + generator.getExampleOrNull(Optional.of("fieldName1"), schema1, "does-not-matter-for-test-1"); // when generator.initialize(); - Node exampleFromCache = generator.getExampleOrNull("fieldName2", schema2, "does-not-matter-for-test-2"); + Node exampleFromCache = + generator.getExampleOrNull(Optional.of("fieldName2"), schema2, "does-not-matter-for-test-2"); // then assertThat(((Element) cachedExample1).getTagName()).isEqualTo("fieldName1"); @@ -90,7 +96,7 @@ void cacheShouldStoreExampleBySchemaName() { generator.prepareForSerialization(schema1, example1); generator.initialize(); - Node exampleFromCache = generator.getExampleOrNull("fieldName", schema2, "example-string"); + Node exampleFromCache = generator.getExampleOrNull(Optional.of("fieldName"), schema2, "example-string"); assertThat(exampleFromCache).isNull(); } From 096c8c4532bd66ebefa8df05de5db97d6bfff232 Mon Sep 17 00:00:00 2001 From: dabeck81 <79102969+dabeck81@users.noreply.github.com> Date: Fri, 13 Sep 2024 17:01:55 +0200 Subject: [PATCH 04/34] POC for Polymorphism (#890) * fix issue #874 * POC: adding polymorphism on payload * POC: adding polymorphism on payload * POC: refactoring for support for inline-schema's * POC: refactoring for support for inline-schema's * POC: refactoring for support for inline-schema's * feat(ui): update server model * feat(kafka): add ConsumerRecord to example * test(core): align test setup * test(core): minor changes * resolving pull-request remarks * chore: fixes after rebase * feat(core): extract types using extractableClasses * feat(ui): handle inline schemas * test(ui): update ui tests * feat(core): add inline schemas also add to schemas section to allow publishing * feat(ui): update mapping of example * feat(e2e): refactor publishing and simplify payloadName retrieval * feat(core): remove empty description * trim newline on yaml-file in kafka-test --------- Co-authored-by: David Beck --- .../components/ComponentsService.java | 10 +- .../components/DefaultComponentsService.java | 31 ++-- .../common/AsyncAnnotationScanner.java | 15 +- .../common/ClassLevelAnnotationScanner.java | 6 +- .../common/MethodLevelAnnotationScanner.java | 6 +- .../payload/PayloadAsyncOperationService.java | 3 +- .../PayloadMethodParameterService.java | 3 +- .../common/payload/PayloadSchemaObject.java | 25 ++- .../internal/PayloadClassExtractor.java | 51 +++++- .../payload/internal/PayloadService.java | 28 +-- .../schemas/SwaggerSchemaService.java | 157 ++++++++++++++-- .../asyncapi/schemas/SwaggerSchemaUtil.java | 6 + .../converters/SchemaTitleModelConverter.java | 37 ++++ .../SpringwolfAutoConfiguration.java | 11 +- ...faultComponentsServiceIntegrationTest.java | 1 + ...tJsonComponentsServiceIntegrationTest.java | 3 +- ...ltXmlComponentsServiceIntegrationTest.java | 15 +- ...tYamlComponentsServiceIntegrationTest.java | 3 +- .../xml/ExampleXmlValueGeneratorTest.java | 2 + .../AsyncAnnotationChannelsScannerTest.java | 14 +- ...notationClassLevelChannelsScannerTest.java | 4 +- ...otationMethodLevelChannelsScannerTest.java | 12 +- .../headers/HeaderClassExtractorTest.java | 5 +- .../PayloadAsyncOperationServiceTest.java | 22 ++- .../PayloadMethodParameterServiceTest.java | 8 +- .../PayloadMethodReturnServiceTest.java | 8 +- .../internal/PayloadClassExtractorTest.java | 21 +-- .../payload/internal/PayloadServiceTest.java | 3 +- .../AsyncAnnotationOperationsScannerTest.java | 4 +- ...tationClassLevelOperationsScannerTest.java | 4 +- ...ationMethodLevelOperationsScannerTest.java | 4 +- .../schemas/SwaggerSchemaServiceTest.java | 75 -------- .../AsyncApiDocumentIntegrationTest.java | 84 ++++++++- .../listener/ListenerApplication.java | 15 ++ .../publisher/PublisherApplication.java | 12 ++ .../schemas/json/annotation-definitions.json | 6 +- .../schemas/json/array-definitions.json | 4 +- .../schemas/json/complex-definitions.json | 6 +- .../resources/schemas/json/definitions.json | 5 +- .../schemas/json/documented-definitions.json | 4 +- .../json/generics-wrapper-definitions.json | 2 +- .../schemas/json/json-type-definitions.json | 2 + .../xml/annotation-definitions-xml.json | 6 +- .../schemas/xml/array-definitions-xml.json | 4 +- ...mplex-definitions-with-attributes-xml.json | 3 + .../schemas/xml/complex-definitions-xml.json | 4 + .../schemas/xml/definitions-xml.json | 5 +- .../xml/documented-definitions-xml.json | 4 +- .../xml/generics-wrapper-definitions-xml.json | 2 +- .../xml/schema-with-shared-property.json | 5 +- .../yaml/annotation-definitions-yaml.json | 4 + .../schemas/yaml/array-definitions-yaml.json | 2 + .../yaml/complex-definitions-yaml.json | 4 + .../schemas/yaml/definitions-yaml.json | 3 + .../yaml/documented-definitions-yaml.json | 2 + .../yaml/json-type-definitions-yaml.json | 2 + .../e2e/tests/publishing.spec.ts | 32 ++-- .../src/test/resources/asyncapi.json | 1 - .../src/test/resources/asyncapi.json | 1 - .../ExampleClassLevelKafkaListener.java | 2 +- .../examples/kafka/ApiIntegrationTest.java | 4 +- .../src/test/resources/asyncapi.json | 171 +++++++++--------- .../src/test/resources/asyncapi.yaml | 150 +++++++-------- .../src/test/resources/asyncapi.json | 2 - .../src/test/resources/asyncapi.json | 1 - .../src/test/resources/asyncapi.json | 1 - ...unctionChannelsScannerIntegrationTest.java | 4 +- .../annotations/SendToCustomizerTest.java | 2 +- .../annotations/SendToUserCustomizerTest.java | 2 +- .../channel-main.component.spec.ts | 5 +- .../channel-main/channel-main.component.ts | 17 +- .../channel-operation.component.html | 2 +- .../channel-operation.component.spec.ts | 5 +- .../channel-operation.component.ts | 28 ++- .../range/schema-range.component.spec.ts | 2 + springwolf-ui/src/app/models/message.model.ts | 14 +- springwolf-ui/src/app/models/schema.model.ts | 10 + .../asyncapi/asyncapi-mapper.service.ts | 41 +++-- .../service/asyncapi/models/message.model.ts | 9 +- .../src/app/service/mock/init-values.ts | 17 +- 80 files changed, 849 insertions(+), 461 deletions(-) create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/converters/SchemaTitleModelConverter.java diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/ComponentsService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/ComponentsService.java index 6ce13ca29..f81944502 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/ComponentsService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/ComponentsService.java @@ -4,9 +4,11 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.Message; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import jakarta.annotation.Nullable; +import java.lang.reflect.Type; import java.util.Map; public interface ComponentsService { @@ -14,13 +16,15 @@ public interface ComponentsService { Map getSchemas(); @Nullable - SchemaObject resolveSchema(String schemaName); + ComponentSchema resolvePayloadSchema(Type type, String contentType); String registerSchema(SchemaObject headers); - String resolvePayloadSchema(Class type, String contentType); - Map getMessages(); MessageReference registerMessage(MessageObject message); + + String getSchemaName(Type type); + + String getSimpleSchemaName(Type type); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsService.java index c842cd41b..94ef0b16f 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsService.java @@ -4,11 +4,13 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.Message; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; +import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; @@ -27,11 +29,10 @@ public Map getSchemas() { } @Override - public SchemaObject resolveSchema(String schemaName) { - if (schemas.containsKey(schemaName)) { - return schemas.get(schemaName); - } - return null; + public ComponentSchema resolvePayloadSchema(Type type, String contentType) { + SwaggerSchemaService.Payload payload = schemaService.resolvePayloadSchema(type, contentType); + payload.referencedSchemas().forEach(this.schemas::putIfAbsent); + return payload.payloadSchema(); } @Override @@ -44,16 +45,6 @@ public String registerSchema(SchemaObject headers) { return headers.getTitle(); } - @Override - public String resolvePayloadSchema(Class type, String contentType) { - log.debug("Registering schema for {}", type.getSimpleName()); - - SwaggerSchemaService.ExtractedSchemas schemas = schemaService.extractSchema(type, contentType); - schemas.schemas().forEach(this.schemas::putIfAbsent); - - return schemas.rootSchemaName(); - } - @Override public Map getMessages() { return this.messages; @@ -67,4 +58,14 @@ public MessageReference registerMessage(MessageObject message) { return MessageReference.toComponentMessage(message); } + + @Override + public String getSchemaName(Type type) { + return schemaService.getNameFromType(type); + } + + @Override + public String getSimpleSchemaName(Type type) { + return schemaService.getSimpleNameFromType(type); + } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java index 7bd72c08f..f876141bd 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java @@ -12,7 +12,6 @@ import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; @@ -99,17 +98,21 @@ protected MessageObject buildMessage(AsyncOperation operationData, Method method Map messageBinding = AsyncAnnotationUtil.processMessageBindingFromAnnotation(method, messageBindingProcessors); - var messagePayload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(payloadSchema.name())) - .build()); + var messagePayload = MessagePayload.of( + MultiFormatSchema.builder().schema(payloadSchema.payload()).build()); String description = operationData.message().description(); - if (StringUtils.isBlank(description) && payloadSchema.schema() != null) { - description = payloadSchema.schema().getDescription(); + if (StringUtils.isBlank(description) && payloadSchema.payload() instanceof SchemaObject) { + String payloadDescription = ((SchemaObject) payloadSchema.payload()).getDescription(); + if (StringUtils.isNotBlank(payloadDescription)) { + description = payloadDescription; + } } if (StringUtils.isNotBlank(description)) { description = this.resolver.resolveStringValue(description); description = TextUtils.trimIndent(description); + } else { + description = null; } var builder = MessageObject.builder() diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java index df6aa22bb..25857d0c2 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java @@ -8,7 +8,6 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersBuilder; @@ -102,9 +101,8 @@ protected MessageObject buildMessage( Map messageBinding = bindingFactory.buildMessageBinding(classAnnotation, headerSchema); - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(payloadSchema.name())) - .build()); + MessagePayload payload = MessagePayload.of( + MultiFormatSchema.builder().schema(payloadSchema.payload()).build()); MessageObject message = MessageObject.builder() .messageId(payloadSchema.name()) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java index 7531eebed..95cd1f2cc 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java @@ -8,7 +8,6 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersBuilder; @@ -36,9 +35,8 @@ protected MessageObject buildMessage( Map messageBinding = bindingFactory.buildMessageBinding(annotation, mergedHeaderSchema); - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(payloadSchema.name())) - .build()); + MessagePayload payload = MessagePayload.of( + MultiFormatSchema.builder().schema(payloadSchema.payload()).build()); MessageObject message = MessageObject.builder() .messageId(payloadSchema.name()) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadAsyncOperationService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadAsyncOperationService.java index b18f21d8a..efed03c6d 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadAsyncOperationService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadAsyncOperationService.java @@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.Optional; @RequiredArgsConstructor @@ -15,7 +16,7 @@ public class PayloadAsyncOperationService { private final PayloadService payloadService; public PayloadSchemaObject extractSchema(AsyncOperation operationData, Method method) { - Optional> payloadType = operationData.payloadType() != Object.class + Optional payloadType = operationData.payloadType() != Object.class ? Optional.of(operationData.payloadType()) : payloadClassExtractor.extractFrom(method); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodParameterService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodParameterService.java index 6aedca93a..11385c50f 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodParameterService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodParameterService.java @@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.Optional; @RequiredArgsConstructor @@ -14,7 +15,7 @@ public class PayloadMethodParameterService implements PayloadMethodService { private final PayloadService payloadService; public PayloadSchemaObject extractSchema(Method method) { - Optional> payloadType = payloadClassExtractor.extractFrom(method); + Optional payloadType = payloadClassExtractor.extractFrom(method); return payloadType.map(payloadService::buildSchema).orElseGet(payloadService::useUnusedPayload); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadSchemaObject.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadSchemaObject.java index 3832d9eaa..1744f7682 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadSchemaObject.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadSchemaObject.java @@ -1,16 +1,35 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.payload; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import jakarta.annotation.Nullable; /** * Encapsulates the resolved name for the contained schema. + * * @param name The fully qualified name or the simple name of the schema. + * @param simpleSchemaName * @param schema The SchemaObject. + * @param schemaPayload The schema-payload to be inserted in the message, when not null this schema will override the payload of the message. */ -public record PayloadSchemaObject(String name, @Nullable SchemaObject schema) { +public record PayloadSchemaObject(String name, String simpleSchemaName, @Nullable ComponentSchema schema) { public String title() { - return schema != null ? schema.getTitle() : name(); + return (simpleSchemaName() != null) ? simpleSchemaName() : name(); + } + + public Object payload() { + if (schema() != null) { + if (schema().getSchema() != null) { + return schema().getSchema(); + } + if (schema().getReference() != null) { + return schema().getReference(); + } + if (schema().getMultiFormatSchema() != null) { + return schema().getMultiFormatSchema(); + } + } + return MessageReference.toSchema(name()); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadClassExtractor.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadClassExtractor.java index ef1d7da3b..bfce7a0ab 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadClassExtractor.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadClassExtractor.java @@ -1,27 +1,38 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.payload.internal; -import lombok.RequiredArgsConstructor; +import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.handler.annotation.Payload; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.WildcardType; import java.util.Arrays; +import java.util.Map; import java.util.Optional; -@RequiredArgsConstructor @Slf4j public class PayloadClassExtractor { - private final TypeToClassConverter typeToClassConverter; + private final Map extractableClassToArgumentIndex; - public Optional> extractFrom(Method method) { + public PayloadClassExtractor(SpringwolfConfigProperties properties) { + if (properties.getPayload() != null) { + extractableClassToArgumentIndex = properties.getPayload().getExtractableClasses(); + } else { + extractableClassToArgumentIndex = Map.of(); + } + } + + public Optional extractFrom(Method method) { String methodName = String.format("%s::%s", method.getDeclaringClass().getSimpleName(), method.getName()); log.debug("Finding payload type for {}", methodName); return getPayloadParameterIndex(method.getParameterTypes(), method.getParameterAnnotations(), methodName) - .map((parameterPayloadIndex) -> - typeToClassConverter.extractClass(method.getGenericParameterTypes()[parameterPayloadIndex])); + .map((parameterPayloadIndex) -> method.getGenericParameterTypes()[parameterPayloadIndex]) + .map(this::extractActualType); } private Optional getPayloadParameterIndex( @@ -56,4 +67,32 @@ private int getPayloadAnnotatedParameterIndex(Annotation[][] parameterAnnotation return -1; } + + private Type extractActualType(Type parameterType) { + // TODO: add tests / adapt from TypeToClassConverterTest + Type type = parameterType; + + while (type instanceof ParameterizedType typeParameterized) { + String typeName = ((ParameterizedType) type).getRawType().getTypeName(); + if (!extractableClassToArgumentIndex.containsKey(typeName)) { + break; + } + + Integer index = extractableClassToArgumentIndex.get(typeName); + type = typeParameterized.getActualTypeArguments()[index]; + + if (type instanceof WildcardType) { + Type[] upperBounds = ((WildcardType) type).getUpperBounds(); + Type[] lowerBounds = ((WildcardType) type).getLowerBounds(); + if (upperBounds.length > 0 && upperBounds[0] != Object.class) { + type = upperBounds[0]; + } + if (lowerBounds.length > 0 && lowerBounds[0] != Object.class) { + type = lowerBounds[0]; + } + } + } + + return type; + } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadService.java index 05b687219..14ce82f4c 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadService.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.payload.internal; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; import io.github.springwolf.core.asyncapi.components.ComponentsService; @@ -9,6 +10,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import java.lang.reflect.Type; import java.util.Map; @Slf4j @@ -20,34 +22,32 @@ public class PayloadService { private static final String PAYLOAD_NOT_USED_KEY = "PayloadNotUsed"; public static final PayloadSchemaObject PAYLOAD_NOT_USED = new PayloadSchemaObject( PAYLOAD_NOT_USED_KEY, - SchemaObject.builder() + PAYLOAD_NOT_USED_KEY, + ComponentSchema.of(SchemaObject.builder() .type(SchemaType.OBJECT) .title(PAYLOAD_NOT_USED_KEY) .description("No payload specified") .properties(Map.of()) - .build()); + .build())); - public PayloadSchemaObject buildSchema(Class payloadType) { + public PayloadSchemaObject buildSchema(Type payloadType) { String contentType = properties.getDocket().getDefaultContentType(); return buildSchema(contentType, payloadType); } - public PayloadSchemaObject buildSchema(String contentType, Class payloadType) { - String componentsSchemaName = this.componentsService.resolvePayloadSchema(payloadType, contentType); - - SchemaObject schema = componentsService.resolveSchema(componentsSchemaName); - if (schema != null) { - schema.setTitle(payloadType.getSimpleName()); - } + public PayloadSchemaObject buildSchema(String contentType, Type payloadType) { + String schemaName = componentsService.getSchemaName(payloadType); + String simpleSchemaName = componentsService.getSimpleSchemaName(payloadType); - return new PayloadSchemaObject(componentsSchemaName, schema); + ComponentSchema schema = componentsService.resolvePayloadSchema(payloadType, contentType); + return new PayloadSchemaObject(schemaName, simpleSchemaName, schema); } public PayloadSchemaObject useUnusedPayload() { - SchemaObject schema = PAYLOAD_NOT_USED.schema(); - if (schema != null) { - this.componentsService.registerSchema(schema); + ComponentSchema schema = PAYLOAD_NOT_USED.schema(); + if (schema != null && schema.getSchema() != null) { + this.componentsService.registerSchema(schema.getSchema()); } return PAYLOAD_NOT_USED; } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaService.java index 13d20603b..32036d0de 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaService.java @@ -1,13 +1,20 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.schemas; +import com.fasterxml.jackson.databind.JavaType; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.annotations.AsyncApiPayload; import io.github.springwolf.core.asyncapi.components.postprocessors.SchemasPostProcessor; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; +import io.swagger.v3.core.converter.AnnotatedType; import io.swagger.v3.core.converter.ModelConverter; import io.swagger.v3.core.converter.ModelConverters; +import io.swagger.v3.core.converter.ResolvedSchema; import io.swagger.v3.core.jackson.TypeNameResolver; +import io.swagger.v3.core.util.Json; +import io.swagger.v3.core.util.PrimitiveType; +import io.swagger.v3.core.util.RefUtils; import io.swagger.v3.oas.models.media.BooleanSchema; import io.swagger.v3.oas.models.media.NumberSchema; import io.swagger.v3.oas.models.media.ObjectSchema; @@ -17,6 +24,7 @@ import org.apache.commons.lang3.StringUtils; import java.lang.reflect.Field; +import java.lang.reflect.Type; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; @@ -53,6 +61,8 @@ public SchemaObject getRootSchema() { } } + public record Payload(ComponentSchema payloadSchema, Map referencedSchemas) {} + public SchemaObject extractSchema(SchemaObject headers) { String schemaName = headers.getTitle(); @@ -90,12 +100,34 @@ public ExtractedSchemas extractSchema(Class type, String contentType) { postProcessSchema(schema, postProcessedSchemas, actualContentType); } - Map schemas = postProcessedSchemas.entrySet().stream() - .map(entry -> Map.entry(entry.getKey(), swaggerSchemaUtil.mapSchema(entry.getValue()))) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + Map schemas = swaggerSchemaUtil.mapSchemasMap(postProcessedSchemas); return new ExtractedSchemas(schemaName, schemas); } + public Payload resolvePayloadSchema(Type type, String contentType) { + String actualContentType = + StringUtils.isBlank(contentType) ? properties.getDocket().getDefaultContentType() : contentType; + ResolvedSchema resolvedSchema = runWithFqnSetting( + (unused) -> converter.resolveAsResolvedSchema(new AnnotatedType(type).resolveAsRef(true))); + + if (resolvedSchema == null) { + // defaulting to stringSchema when resolvedSchema is null + SchemaObject payloadSchema = swaggerSchemaUtil.mapSchema( + PrimitiveType.fromType(String.class).createProperty()); + return new Payload(ComponentSchema.of(payloadSchema), Map.of()); + } else { + Map preProcessSchemas = new LinkedHashMap<>(resolvedSchema.referencedSchemas); + Schema payloadSchema = resolvedSchema.schema; + preProcessSchemas.putIfAbsent(getNameFromType(type), payloadSchema); + preProcessSchemas(payloadSchema, preProcessSchemas, type); + HashMap postProcessSchemas = new HashMap<>(preProcessSchemas); + postProcessSchema(preProcessSchemas, postProcessSchemas, actualContentType); + return new Payload( + swaggerSchemaUtil.mapSchemaOrRef(payloadSchema), + swaggerSchemaUtil.mapSchemasMap(postProcessSchemas)); + } + } + private String getSchemaName(Class type, Map schemas) { if (schemas.isEmpty()) { // swagger-parser does not create schemas for primitives @@ -126,12 +158,28 @@ private String getSchemaName(Class type, Map schemas) { return getNameFromClass(type); } + private String registerPrimitive(Class type, Schema schema, Map schemas) { + String schemaName = getNameFromClass(type); + schema.setName(schemaName); + + schemas.put(schemaName, schema); + postProcessSchema(schema, schemas, DEFAULT_CONTENT_TYPE); + + return schemaName; + } + private void preProcessSchemas(Map schemas, String schemaName, Class type) { processCommonModelConverters(schemas); processAsyncApiPayloadAnnotation(schemas, schemaName, type); processSchemaAnnotation(schemas, schemaName, type); } + private void preProcessSchemas(Schema payloadSchema, Map schemas, Type type) { + processCommonModelConverters(payloadSchema, schemas); + processAsyncApiPayloadAnnotation(schemas, type); + processSchemaAnnotation(payloadSchema, type); + } + private void processCommonModelConverters(Map schemas) { schemas.values().stream() .filter(schema -> schema.getType() == null) @@ -149,6 +197,34 @@ private void processCommonModelConverters(Map schemas) { }); } + private void processCommonModelConverters(Schema payloadSchema, Map schemas) { + schemas.values().stream() + .filter(schema -> schema.getType() == null) + .filter(schema -> schema.get$ref() != null) + .forEach(schema -> { + String targetSchemaName = schema.getName(); + String sourceSchemaName = StringUtils.substringAfterLast(schema.get$ref(), "/"); + + Schema actualSchema = schemas.get(sourceSchemaName); + + if (actualSchema != null) { + schemas.put(targetSchemaName, actualSchema); + schemas.remove(sourceSchemaName); + + adaptPayloadSchema(payloadSchema, targetSchemaName, sourceSchemaName); + } + }); + } + + private void adaptPayloadSchema(Schema schema, String targetSchemaName, String sourceSchemaName) { + if (schema != null && schema.get$ref() != null) { + String refTypeName = StringUtils.substringAfterLast(schema.get$ref(), "/"); + if (refTypeName.equals(sourceSchemaName)) { + schema.$ref(RefUtils.constructRef(targetSchemaName)); + } + } + } + private void processSchemaAnnotation(Map schemas, String schemaName, Class type) { Schema schemaForType = schemas.get(schemaName); if (schemaForType != null) { @@ -162,6 +238,17 @@ private void processSchemaAnnotation(Map schemas, String schemaN } } + private void processSchemaAnnotation(Schema payloadSchema, Type type) { + JavaType javaType = Json.mapper().constructType(type); + Class clazz = javaType.getRawClass(); + if (payloadSchema != null) { + var schemaAnnotation = clazz.getAnnotation(io.swagger.v3.oas.annotations.media.Schema.class); + if (schemaAnnotation != null && StringUtils.isNotBlank(schemaAnnotation.description())) { + payloadSchema.setDescription(schemaAnnotation.description()); + } + } + } + private void processAsyncApiPayloadAnnotation(Map schemas, String schemaName, Class type) { List withPayloadAnnotatedFields = Arrays.stream(type.getDeclaredFields()) .filter(field -> field.isAnnotationPresent(AsyncApiPayload.class)) @@ -185,14 +272,28 @@ private void processAsyncApiPayloadAnnotation(Map schemas, Strin } } - private String registerPrimitive(Class type, Schema schema, Map schemas) { - String schemaName = getNameFromClass(type); - schema.setName(schemaName); - - schemas.put(schemaName, schema); - postProcessSchema(schema, schemas, DEFAULT_CONTENT_TYPE); + private void processAsyncApiPayloadAnnotation(Map schemas, Type type) { + JavaType javaType = Json.mapper().constructType(type); + Class clazz = javaType.getRawClass(); + List withPayloadAnnotatedFields = Arrays.stream(clazz.getDeclaredFields()) + .filter(field -> field.isAnnotationPresent(AsyncApiPayload.class)) + .toList(); - return schemaName; + if (withPayloadAnnotatedFields.size() == 1) { + String schemaName = getNameFromType(type); + String fieldName = withPayloadAnnotatedFields.get(0).getName(); + schemas.entrySet().stream() + .filter(e -> e.getKey().equals(schemaName)) + .filter(e -> e.getValue() != null) + .filter(e -> e.getValue().getProperties() != null) + .forEach(e -> + e.setValue((Schema) e.getValue().getProperties().get(fieldName))); + } else if (withPayloadAnnotatedFields.size() > 1) { + log.warn( + ("Found more than one field with @AsyncApiPayload annotation in class {}. " + + "Falling back and ignoring annotation."), + type.getTypeName()); + } } private R runWithFqnSetting(Function callable) { @@ -212,13 +313,47 @@ private String getNameFromClass(Class type) { return type.getSimpleName(); } + public String getNameFromType(Type type) { + PrimitiveType primitiveType = PrimitiveType.fromType(type); + if (primitiveType != null && properties.isUseFqn()) { + return primitiveType.getKeyClass().getName(); + } + JavaType javaType = Json.mapper().constructType(type); + return runWithFqnSetting((unused) -> TypeNameResolver.std.nameForType(javaType)); + } + + public String getSimpleNameFromType(Type type) { + JavaType javaType = Json.mapper().constructType(type); + TypeNameResolver.std.setUseFqn(false); + String name = TypeNameResolver.std.nameForType(javaType); + TypeNameResolver.std.setUseFqn(properties.isUseFqn()); + return name; + } + private void postProcessSchema(Schema schema, Map schemas, String contentType) { + boolean schemasHadEntries = !schemas.isEmpty(); for (SchemasPostProcessor processor : schemaPostProcessors) { processor.process(schema, schemas, contentType); - if (!schemas.containsValue(schema)) { + if (schemasHadEntries && !schemas.containsValue(schema)) { + // If the post-processor removed the schema, we can stop processing break; } } } + + private void postProcessSchema( + Map preProcess, Map postProcess, String contentType) { + boolean schemasHadEntries = !postProcess.isEmpty(); + for (Schema schema : preProcess.values()) { + for (SchemasPostProcessor processor : schemaPostProcessors) { + processor.process(schema, postProcess, contentType); + + if (schemasHadEntries && !postProcess.containsValue(schema)) { + // If the post-processor removed the schema, we can stop processing + break; + } + } + } + } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaUtil.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaUtil.java index db66c59b8..cf1150413 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaUtil.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaUtil.java @@ -15,6 +15,12 @@ @RequiredArgsConstructor public class SwaggerSchemaUtil { + public Map mapSchemasMap(Map schemaMap) { + return schemaMap.entrySet().stream() + .map(entry -> Map.entry(entry.getKey(), mapSchema(entry.getValue()))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + public ComponentSchema mapSchemaOrRef(Schema schema) { if (schema.get$ref() != null) { return ComponentSchema.of(new MessageReference(schema.get$ref())); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/converters/SchemaTitleModelConverter.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/converters/SchemaTitleModelConverter.java new file mode 100644 index 000000000..ad3e9e53d --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/schemas/converters/SchemaTitleModelConverter.java @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.schemas.converters; + +import com.fasterxml.jackson.databind.JavaType; +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.core.util.Json; +import io.swagger.v3.core.util.PrimitiveType; +import io.swagger.v3.oas.models.media.Schema; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.Iterator; + +@NoArgsConstructor +@Slf4j +public class SchemaTitleModelConverter implements ModelConverter { + @Override + public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator chain) { + JavaType javaType = Json.mapper().constructType(type.getType()); + if (chain.hasNext()) { + Schema schema = chain.next().resolve(type, context, chain); + boolean isPrimitiveType = PrimitiveType.createProperty(type.getType()) != null; + if (schema != null && !isPrimitiveType) { + if (schema.get$ref() != null) { + Schema definedModel = context.resolve(type); + if (definedModel != null && definedModel.getTitle() == null) { + definedModel.setTitle(javaType.getRawClass().getSimpleName()); + } + } + } + return schema; + } + return null; + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java index 7c63ec713..50e2e8e2e 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java @@ -35,6 +35,7 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeToClassConverter; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; +import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; import io.github.springwolf.core.configuration.docket.DefaultAsyncApiDocketService; import io.github.springwolf.core.configuration.properties.SpringwolfConfigConstants; @@ -138,6 +139,12 @@ public ExampleGeneratorPostProcessor exampleGeneratorPostProcessor(SchemaWalkerP return new ExampleGeneratorPostProcessor(schemaWalkerProvider); } + @Bean + @ConditionalOnMissingBean + public SchemaTitleModelConverter schemaTitleModelConverter() { + return new SchemaTitleModelConverter(); + } + @Bean @ConditionalOnMissingBean public SchemaWalkerProvider schemaWalkerProvider(List schemaWalkers) { @@ -182,8 +189,8 @@ public TypeToClassConverter typeToClassConverter(SpringwolfConfigProperties spri @Bean @ConditionalOnMissingBean - public PayloadClassExtractor payloadClassExtractor(TypeToClassConverter typeToClassConverter) { - return new PayloadClassExtractor(typeToClassConverter); + public PayloadClassExtractor payloadClassExtractor(SpringwolfConfigProperties springwolfConfigProperties) { + return new PayloadClassExtractor(springwolfConfigProperties); } @Bean diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsServiceIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsServiceIntegrationTest.java index 0d1858d5e..1e406afda 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsServiceIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultComponentsServiceIntegrationTest.java @@ -268,6 +268,7 @@ void illegalEnvelopTest() { assertThat(schema) .isEqualTo(SchemaObject.builder() .type(SchemaType.OBJECT) + .title("EnvelopWithMultipleAsyncApiPayloadAnnotations") .properties(Map.of( "otherField", ComponentSchema.of(SchemaObject.builder() diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultJsonComponentsServiceIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultJsonComponentsServiceIntegrationTest.java index 62cb3f773..b90759225 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultJsonComponentsServiceIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultJsonComponentsServiceIntegrationTest.java @@ -16,6 +16,7 @@ import io.github.springwolf.core.asyncapi.components.postprocessors.ExampleGeneratorPostProcessor; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; +import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import io.github.springwolf.core.fixtures.ClasspathUtil; import io.swagger.v3.core.util.Json; @@ -47,7 +48,7 @@ class DefaultJsonComponentsServiceIntegrationTest { private static final String CONTENT_TYPE_APPLICATION_JSON = "application/json"; private final SwaggerSchemaService schemaService = new SwaggerSchemaService( - List.of(), + List.of(new SchemaTitleModelConverter()), List.of(new ExampleGeneratorPostProcessor( new SchemaWalkerProvider(List.of(new DefaultSchemaWalker<>(new ExampleJsonValueGenerator()))))), new SwaggerSchemaUtil(), diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultXmlComponentsServiceIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultXmlComponentsServiceIntegrationTest.java index fe1eac8fa..9522f6262 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultXmlComponentsServiceIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultXmlComponentsServiceIntegrationTest.java @@ -13,6 +13,7 @@ import io.github.springwolf.core.asyncapi.components.postprocessors.ExampleGeneratorPostProcessor; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; +import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import io.github.springwolf.core.fixtures.ClasspathUtil; import io.swagger.v3.core.util.Json; @@ -39,19 +40,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals; class DefaultXmlComponentsServiceIntegrationTest { - private final SwaggerSchemaService schemaService = new SwaggerSchemaService( - List.of(), - List.of(new ExampleGeneratorPostProcessor(new SchemaWalkerProvider(List.of( - new DefaultSchemaWalker<>(new ExampleXmlValueGenerator(new DefaultExampleXmlValueSerializer())))))), - new SwaggerSchemaUtil(), - new SpringwolfConfigProperties()); - private final ComponentsService componentsService = new DefaultComponentsService(schemaService); private static final ObjectMapper objectMapper = Json.mapper().enable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS); private static final PrettyPrinter printer = new DefaultPrettyPrinter().withObjectIndenter(new DefaultIndenter(" ", DefaultIndenter.SYS_LF)); + private final SwaggerSchemaService schemaService = new SwaggerSchemaService( + List.of(new SchemaTitleModelConverter()), + List.of(new ExampleGeneratorPostProcessor(new SchemaWalkerProvider(List.of( + new DefaultSchemaWalker<>(new ExampleXmlValueGenerator(new DefaultExampleXmlValueSerializer())))))), + new SwaggerSchemaUtil(), + new SpringwolfConfigProperties()); + private final ComponentsService componentsService = new DefaultComponentsService(schemaService); @Test void getSchemas() throws IOException { diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultYamlComponentsServiceIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultYamlComponentsServiceIntegrationTest.java index 82966ab22..d523fbfc2 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultYamlComponentsServiceIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/DefaultYamlComponentsServiceIntegrationTest.java @@ -18,6 +18,7 @@ import io.github.springwolf.core.asyncapi.components.postprocessors.ExampleGeneratorPostProcessor; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; +import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import io.github.springwolf.core.fixtures.ClasspathUtil; import io.swagger.v3.core.util.Json; @@ -53,7 +54,7 @@ class DefaultYamlComponentsServiceIntegrationTest { new ExampleJsonValueGenerator(), new DefaultExampleYamlValueSerializer(), springwolfConfigProperties); private final SwaggerSchemaService schemaService = new SwaggerSchemaService( - List.of(), + List.of(new SchemaTitleModelConverter()), List.of(new ExampleGeneratorPostProcessor( new SchemaWalkerProvider(List.of(new DefaultSchemaWalker<>(exampleYamlValueGenerator))))), new SwaggerSchemaUtil(), diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGeneratorTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGeneratorTest.java index 7c0259f81..81ff922bc 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGeneratorTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/components/examples/walkers/xml/ExampleXmlValueGeneratorTest.java @@ -18,6 +18,7 @@ class ExampleXmlValueGeneratorTest { @Test void cacheShouldResolveBySchemaName() { // given + DefaultExampleXmlValueSerializer serializer = new DefaultExampleXmlValueSerializer(); ExampleXmlValueGenerator generator = new ExampleXmlValueGenerator(serializer); StringSchema schema1 = new StringSchema(); @@ -104,6 +105,7 @@ void cacheShouldStoreExampleBySchemaName() { @Test void shouldCreateRawFromXmlString() { // given + DefaultExampleXmlValueSerializer serializer = new DefaultExampleXmlValueSerializer(); ExampleXmlValueGenerator generator = new ExampleXmlValueGenerator(serializer); generator.initialize(); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java index d8bf2c0d5..02e5f888d 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java @@ -28,7 +28,6 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadClassExtractor; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; -import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeToClassConverter; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.configuration.docket.AsyncApiDocket; @@ -90,8 +89,7 @@ public OperationAction getOperationType() { new SwaggerSchemaService(emptyList(), emptyList(), swaggerSchemaUtil, properties); private final ComponentsService componentsService = new DefaultComponentsService(schemaService); private final AsyncApiDocketService asyncApiDocketService = mock(AsyncApiDocketService.class); - private final TypeToClassConverter typeToClassConverter = new TypeToClassConverter(properties); - private final PayloadClassExtractor payloadClassExtractor = new PayloadClassExtractor(typeToClassConverter); + private final PayloadClassExtractor payloadClassExtractor = new PayloadClassExtractor(properties); private final PayloadService payloadService = new PayloadService(componentsService, properties); private final PayloadAsyncOperationService payloadAsyncOperationService = new PayloadAsyncOperationService(payloadClassExtractor, payloadService); @@ -200,13 +198,13 @@ void scan_componentHasListenerMethodWithAllAttributes() { // Then the returned collection contains the channel MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) + .schema(SchemaReference.fromSchema(List.class.getSimpleName())) .build()); MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) + .messageId(List.class.getName()) + .name(List.class.getName()) + .title(List.class.getSimpleName()) .description(null) .payload(payload) .headers(MessageHeaders.of(MessageReference.toSchema("TestSchema"))) @@ -333,7 +331,7 @@ private static class ClassWithListenerAnnotationWithAllAttributes { @AsyncOperation( channelName = "${test.property.test-channel}", description = "${test.property.description}", - payloadType = String.class, + payloadType = List.class, servers = {"${test.property.server1}", "${test.property.server2}"}, headers = @AsyncOperation.Headers( diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java index 4d2030f7f..19f63165a 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java @@ -12,6 +12,7 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; @@ -74,7 +75,8 @@ void setUp() { doReturn(defaultMessageBinding).when(bindingFactory).buildMessageBinding(any(), any()); when(payloadMethodService.extractSchema(any())) - .thenReturn(new PayloadSchemaObject(String.class.getName(), new SchemaObject())); + .thenReturn(new PayloadSchemaObject( + String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); doAnswer(invocation -> AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) .when(componentsService) .registerSchema(any(SchemaObject.class)); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java index 56cce2407..ebf44ee20 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java @@ -13,6 +13,7 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; @@ -80,7 +81,8 @@ void setUp() throws NoSuchMethodException { doReturn(defaultMessageBinding).when(bindingFactory).buildMessageBinding(any(), any()); when(payloadMethodService.extractSchema(any())) - .thenReturn(new PayloadSchemaObject(String.class.getName(), new SchemaObject())); + .thenReturn(new PayloadSchemaObject( + String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); doAnswer(invocation -> AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) .when(componentsService) .registerSchema(any(SchemaObject.class)); @@ -88,11 +90,15 @@ void setUp() throws NoSuchMethodException { var stringMethod = ClassWithMultipleTestListenerAnnotation.class.getDeclaredMethod("methodWithAnnotation", String.class); when(payloadMethodService.extractSchema(stringMethod)) - .thenReturn(new PayloadSchemaObject(String.class.getName(), new SchemaObject())); + .thenReturn(new PayloadSchemaObject( + String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); var simpleFooMethod = ClassWithMultipleTestListenerAnnotation.class.getDeclaredMethod( "anotherMethodWithAnnotation", SimpleFoo.class); when(payloadMethodService.extractSchema(simpleFooMethod)) - .thenReturn(new PayloadSchemaObject(SimpleFoo.class.getName(), new SchemaObject())); + .thenReturn(new PayloadSchemaObject( + SimpleFoo.class.getName(), + SimpleFoo.class.getSimpleName(), + ComponentSchema.of(new SchemaObject()))); } @Test diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorTest.java index f0e7825f5..beec45128 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/headers/HeaderClassExtractorTest.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.headers; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; @@ -22,8 +23,8 @@ class HeaderClassExtractorTest { private final SwaggerSchemaService schemaService = mock(SwaggerSchemaService.class); private final HeaderClassExtractor headerClassExtractor = new HeaderClassExtractor(schemaService); - private final PayloadSchemaObject payloadSchemaName = - new PayloadSchemaObject("payloadSchemaName", new SchemaObject()); + private final PayloadSchemaObject payloadSchemaName = new PayloadSchemaObject( + "payloadSchemaName", String.class.getSimpleName(), ComponentSchema.of(new SchemaObject())); private final SchemaObject stringSchema = SchemaObject.builder().type(SchemaType.STRING).build(); private final SchemaObject stringSwaggerSchema = diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadAsyncOperationServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadAsyncOperationServiceTest.java index e8cae4450..de280d5df 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadAsyncOperationServiceTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadAsyncOperationServiceTest.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.payload; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.annotations.AsyncMessage; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; @@ -17,6 +18,7 @@ import static io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService.PAYLOAD_NOT_USED; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -47,10 +49,10 @@ public void shouldUsePayloadFromAsyncOperationAnnotation() { when(asyncOperation.message()).thenReturn(asyncMessage); String schemaName = "my-schema-name"; - when(componentsService.resolvePayloadSchema(any(), any())).thenReturn(schemaName); + when(componentsService.getSchemaName(String.class)).thenReturn(schemaName); - SchemaObject schemaObject = SchemaObject.builder().build(); - when(componentsService.resolveSchema(schemaName)).thenReturn(schemaObject); + ComponentSchema schemaObject = ComponentSchema.of(SchemaObject.builder().build()); + when(componentsService.resolvePayloadSchema(eq(String.class), any())).thenReturn(schemaObject); // when var result = payloadAsyncOperationService.extractSchema(asyncOperation, null); @@ -74,10 +76,10 @@ public void shouldExtractPayloadFromMethodWithAnnotation() { when(payloadClassExtractor.extractFrom(method)).thenReturn(Optional.of(String.class)); String schemaName = "my-schema-name"; - when(componentsService.resolvePayloadSchema(any(), any())).thenReturn(schemaName); + when(componentsService.getSchemaName(String.class)).thenReturn(schemaName); - SchemaObject schemaObject = SchemaObject.builder().build(); - when(componentsService.resolveSchema(schemaName)).thenReturn(schemaObject); + ComponentSchema schemaObject = ComponentSchema.of(SchemaObject.builder().build()); + when(componentsService.resolvePayloadSchema(eq(String.class), any())).thenReturn(schemaObject); // when var result = payloadAsyncOperationService.extractSchema(asyncOperation, method); @@ -105,8 +107,10 @@ public void shouldReturnPayloadNotUsed() { // then assertThat(result.name()).isEqualTo("PayloadNotUsed"); - assertThat(result.schema().getTitle()).isEqualTo("PayloadNotUsed"); - assertThat(result.schema().getDescription()).isEqualTo("No payload specified"); - verify(componentsService).registerSchema(PAYLOAD_NOT_USED.schema()); + assertThat(result.schema()).isNotNull(); + SchemaObject schema = result.schema().getSchema(); + assertThat(schema.getTitle()).isEqualTo("PayloadNotUsed"); + assertThat(schema.getDescription()).isEqualTo("No payload specified"); + verify(componentsService).registerSchema(PAYLOAD_NOT_USED.schema().getSchema()); } } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodParameterServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodParameterServiceTest.java index 554a15b20..9b0c2c34e 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodParameterServiceTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodParameterServiceTest.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.payload; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadClassExtractor; @@ -14,6 +15,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -42,10 +44,10 @@ public void shouldExtractPayloadFromMethod() { when(payloadClassExtractor.extractFrom(method)).thenReturn(Optional.of(String.class)); String schemaName = "my-schema-name"; - when(componentsService.resolvePayloadSchema(any(), any())).thenReturn(schemaName); + when(componentsService.getSchemaName(String.class)).thenReturn(schemaName); - SchemaObject schemaObject = SchemaObject.builder().build(); - when(componentsService.resolveSchema(schemaName)).thenReturn(schemaObject); + ComponentSchema schemaObject = ComponentSchema.of(SchemaObject.builder().build()); + when(componentsService.resolvePayloadSchema(eq(String.class), any())).thenReturn(schemaObject); // when var result = payloadMethodParameterService.extractSchema(method); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodReturnServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodReturnServiceTest.java index 7eaca9205..555ab8447 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodReturnServiceTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/PayloadMethodReturnServiceTest.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.payload; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; @@ -12,6 +13,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -40,10 +42,10 @@ public void shouldExtractPayloadFromMethod() { doReturn(String.class).when(method).getReturnType(); String schemaName = "my-schema-name"; - when(componentsService.resolvePayloadSchema(any(), any())).thenReturn(schemaName); + when(componentsService.getSchemaName(String.class)).thenReturn(schemaName); - SchemaObject schemaObject = SchemaObject.builder().build(); - when(componentsService.resolveSchema(schemaName)).thenReturn(schemaObject); + ComponentSchema schemaObject = ComponentSchema.of(SchemaObject.builder().build()); + when(componentsService.resolvePayloadSchema(eq(String.class), any())).thenReturn(schemaObject); // when var result = payloadMethodReturnService.extractSchema(method); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadClassExtractorTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadClassExtractorTest.java index a32a56237..3e5c80ca7 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadClassExtractorTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadClassExtractorTest.java @@ -1,35 +1,26 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.payload.internal; -import org.junit.jupiter.api.BeforeEach; +import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; import org.junit.jupiter.api.Test; import org.springframework.messaging.handler.annotation.Payload; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; class PayloadClassExtractorTest { - private final TypeToClassConverter typeToClassConverter = mock(TypeToClassConverter.class); - - private final PayloadClassExtractor extractor = new PayloadClassExtractor(typeToClassConverter); - - @BeforeEach - void setUp() { - doReturn(String.class).when(typeToClassConverter).extractClass(any()); - } + private final PayloadClassExtractor extractor = new PayloadClassExtractor(new SpringwolfConfigProperties()); @Test void getPayloadType() throws NoSuchMethodException { Method m = TestClass.class.getDeclaredMethod("consumeWithString", String.class); - Optional> result = extractor.extractFrom(m); + Optional result = extractor.extractFrom(m); assertThat(result).hasValue(String.class); } @@ -38,7 +29,7 @@ void getPayloadType() throws NoSuchMethodException { void getPayloadTypeWithPayloadAnnotation() throws NoSuchMethodException { Method m = TestClass.class.getDeclaredMethod("consumeWithPayloadAnnotation", String.class, Integer.class); - Optional> result = extractor.extractFrom(m); + Optional result = extractor.extractFrom(m); assertThat(result).hasValue(String.class); } @@ -60,7 +51,7 @@ void getPayloadTypeWithoutPayloadAnnotation() throws NoSuchMethodException { void getNoPayload() throws NoSuchMethodException { Method m = TestClass.class.getDeclaredMethod("consumeWithoutPayload"); - Optional> result = extractor.extractFrom(m); + Optional result = extractor.extractFrom(m); assertThat(result).isEmpty(); } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadServiceTest.java index d68d7f555..01359c02a 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadServiceTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/payload/internal/PayloadServiceTest.java @@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -24,7 +23,7 @@ public void shouldExtractSchemaForInteger() { when(docket.getDefaultContentType()).thenReturn("application/json"); String schemaName = "my-schema-name"; - when(componentsService.resolvePayloadSchema(any(), any())).thenReturn(schemaName); + when(componentsService.getSchemaName(Integer.class)).thenReturn(schemaName); // when var result = payloadService.buildSchema(Integer.class); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScannerTest.java index ac409a91b..8622c91a5 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScannerTest.java @@ -27,7 +27,6 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadClassExtractor; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; -import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeToClassConverter; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.configuration.docket.AsyncApiDocket; @@ -87,8 +86,7 @@ public OperationAction getOperationType() { new SwaggerSchemaService(emptyList(), emptyList(), swaggerSchemaUtil, properties); private final ComponentsService componentsService = new DefaultComponentsService(schemaService); private final AsyncApiDocketService asyncApiDocketService = mock(AsyncApiDocketService.class); - private final TypeToClassConverter typeToClassConverter = new TypeToClassConverter(properties); - private final PayloadClassExtractor payloadClassExtractor = new PayloadClassExtractor(typeToClassConverter); + private final PayloadClassExtractor payloadClassExtractor = new PayloadClassExtractor(properties); private final PayloadService payloadService = new PayloadService(componentsService, properties); private final PayloadAsyncOperationService payloadAsyncOperationService = new PayloadAsyncOperationService(payloadClassExtractor, payloadService); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java index 0e3f0c9dc..d44559234 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java @@ -12,6 +12,7 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; @@ -75,7 +76,8 @@ void setUp() { doReturn(defaultMessageBinding).when(bindingFactory).buildMessageBinding(any(), any()); when(payloadMethodService.extractSchema(any())) - .thenReturn(new PayloadSchemaObject(String.class.getName(), new SchemaObject())); + .thenReturn(new PayloadSchemaObject( + String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); doAnswer(invocation -> AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) .when(componentsService) .registerSchema(any(SchemaObject.class)); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScannerTest.java index faa2bbef3..a947ebb4b 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScannerTest.java @@ -12,6 +12,7 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; @@ -74,7 +75,8 @@ void setUp() { doReturn(defaultMessageBinding).when(bindingFactory).buildMessageBinding(any(), any()); when(payloadMethodParameterService.extractSchema(any())) - .thenReturn(new PayloadSchemaObject(String.class.getName(), new SchemaObject())); + .thenReturn(new PayloadSchemaObject( + String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); doAnswer(invocation -> AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) .when(componentsService) .registerSchema(any(SchemaObject.class)); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaServiceTest.java index 38b829b30..499fd4f43 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaServiceTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/schemas/SwaggerSchemaServiceTest.java @@ -14,7 +14,6 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -111,80 +110,6 @@ void postProcessorIsSkippedWhenSchemaWasRemoved() { verifyNoInteractions(schemasPostProcessor2); } - @Nested - class createSchema { - - @Test - void Integer() { - // when - Map schemas = schemaService - .extractSchema(Integer.class, "content-type-not-relevant") - .schemas(); - - // then - assertThat(schemas).hasSize(1).containsKey("java.lang.Number"); - assertThat(schemas.get("java.lang.Number").getType()).isEqualTo("number"); - } - - @Test - void Double() { - // when - Map schemas = schemaService - .extractSchema(Double.class, "content-type-not-relevant") - .schemas(); - - // then - assertThat(schemas).hasSize(1).containsKey("java.lang.Number"); - assertThat(schemas.get("java.lang.Number").getType()).isEqualTo("number"); - } - - @Test - void String() { - // when - Map schemas = schemaService - .extractSchema(String.class, "content-type-not-relevant") - .schemas(); - - // then - assertThat(schemas).hasSize(1).containsKey("java.lang.String"); - assertThat(schemas.get("java.lang.String").getType()).isEqualTo("string"); - } - - @Test - void Byte() { - // when - Map schemas = schemaService - .extractSchema(Byte.class, "content-type-not-relevant") - .schemas(); - - // then - assertThat(schemas).hasSize(1).containsKey("java.lang.String"); - assertThat(schemas.get("java.lang.String").getType()).isEqualTo("string"); - } - - @Test - void Boolean() { - // when - Map schemas = schemaService - .extractSchema(Boolean.class, "content-type-not-relevant") - .schemas(); - - // then - assertThat(schemas).hasSize(1).containsKey("java.lang.Boolean"); - } - - @Test - void Object() { - // when - Map schemas = schemaService - .extractSchema(Object.class, "content-type-not-relevant") - .schemas(); - - // then - assertThat(schemas).hasSize(1).containsKey("java.lang.Object"); - } - } - @Data @NoArgsConstructor @Schema(name = "DifferentName") diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java index 471ac3253..0efe3c7ad 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java @@ -3,6 +3,8 @@ import io.github.springwolf.asyncapi.v3.model.AsyncAPI; import io.github.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.AsyncApiService; import io.github.springwolf.core.fixtures.MinimalIntegrationTestContextConfiguration; @@ -39,10 +41,45 @@ void asyncListenerAnnotationIsFound() { assertThat(asyncAPI).isNotNull(); assertThat(asyncAPI.getChannels()).containsOnlyKeys("listener-channel"); - assertThat(asyncAPI.getOperations()).containsOnlyKeys("listener-channel_receive_listen"); - assertThat(asyncAPI.getComponents().getMessages()).containsOnlyKeys("java.lang.String"); + assertThat(asyncAPI.getChannels().get("listener-channel").getMessages()) + .containsOnlyKeys( + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); + assertThat(asyncAPI.getOperations()) + .containsOnlyKeys( + "listener-channel_receive_listen", + "listener-channel_receive_listen2", + "listener-channel_receive_listen3", + "listener-channel_receive_listen4"); + assertThat(asyncAPI.getComponents().getMessages()) + .containsOnlyKeys( + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); assertThat(asyncAPI.getComponents().getSchemas()) - .containsOnlyKeys("HeadersNotDocumented", "java.lang.String"); + .containsOnlyKeys( + "HeadersNotDocumented", + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Bar", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); + + MessageObject stringMessage = + (MessageObject) asyncAPI.getComponents().getMessages().get("java.lang.String"); + assertThat(stringMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(SchemaObject.class); + SchemaObject inlineStringSchema = (SchemaObject) + stringMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(inlineStringSchema.getType()).isEqualTo("string"); + + MessageObject fooMessage = (MessageObject) asyncAPI.getComponents() + .getMessages() + .get("io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); + assertThat(fooMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(MessageReference.class); + MessageReference fooRefMessage = (MessageReference) + fooMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(fooRefMessage.getRef()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); } } @@ -63,10 +100,45 @@ void asyncPublisherAnnotationIsFound() { assertThat(asyncAPI).isNotNull(); assertThat(asyncAPI.getChannels()).containsOnlyKeys("publisher-channel"); - assertThat(asyncAPI.getOperations()).containsOnlyKeys("publisher-channel_send_publish"); - assertThat(asyncAPI.getComponents().getMessages()).containsOnlyKeys("java.lang.String"); + assertThat(asyncAPI.getChannels().get("publisher-channel").getMessages()) + .containsOnlyKeys( + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); + assertThat(asyncAPI.getOperations()) + .containsOnlyKeys( + "publisher-channel_send_publish", + "publisher-channel_send_publish2", + "publisher-channel_send_publish3", + "publisher-channel_send_publish4"); + assertThat(asyncAPI.getComponents().getMessages()) + .containsOnlyKeys( + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); assertThat(asyncAPI.getComponents().getSchemas()) - .containsOnlyKeys("HeadersNotDocumented", "java.lang.String"); + .containsOnlyKeys( + "HeadersNotDocumented", + "java.lang.String", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Bar", + "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); + + MessageObject stringMessage = + (MessageObject) asyncAPI.getComponents().getMessages().get("java.lang.String"); + assertThat(stringMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(SchemaObject.class); + SchemaObject inlineStringSchema = (SchemaObject) + stringMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(inlineStringSchema.getType()).isEqualTo("string"); + + MessageObject fooMessage = (MessageObject) asyncAPI.getComponents() + .getMessages() + .get("io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); + assertThat(fooMessage.getPayload().getMultiFormatSchema().getSchema()) + .isInstanceOf(MessageReference.class); + MessageReference fooRefMessage = (MessageReference) + fooMessage.getPayload().getMultiFormatSchema().getSchema(); + assertThat(fooRefMessage.getRef()) + .isEqualTo( + "#/components/schemas/io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); } } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/listener/ListenerApplication.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/listener/ListenerApplication.java index 230c6ef03..a42df2ead 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/listener/ListenerApplication.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/listener/ListenerApplication.java @@ -6,6 +6,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import java.util.List; + @SpringBootApplication public class ListenerApplication { @Bean @@ -16,5 +18,18 @@ public Listener listener() { static class Listener { @AsyncListener(operation = @AsyncOperation(channelName = "listener-channel")) public void listen(String payload) {} + + @AsyncListener(operation = @AsyncOperation(channelName = "listener-channel")) + public void listen2(List payload) {} + + @AsyncListener(operation = @AsyncOperation(channelName = "listener-channel")) + public void listen3(Foo payload) {} + + @AsyncListener(operation = @AsyncOperation(channelName = "listener-channel")) + public void listen4(List payload) {} } + + public record Foo(Bar aFieldInFooRecord) {} + + public record Bar(String aFieldInBarRecord) {} } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/publisher/PublisherApplication.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/publisher/PublisherApplication.java index c48cde707..6eff47314 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/publisher/PublisherApplication.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/publisher/PublisherApplication.java @@ -3,9 +3,12 @@ import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.annotations.AsyncPublisher; +import io.github.springwolf.core.integrationtests.application.listener.ListenerApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +import java.util.List; + @SpringBootApplication public class PublisherApplication { @Bean @@ -16,5 +19,14 @@ public Publisher publisher() { static class Publisher { @AsyncPublisher(operation = @AsyncOperation(channelName = "publisher-channel")) public void publish(String payload) {} + + @AsyncPublisher(operation = @AsyncOperation(channelName = "publisher-channel")) + public void publish2(List payload) {} + + @AsyncPublisher(operation = @AsyncOperation(channelName = "publisher-channel")) + public void publish3(ListenerApplication.Foo payload) {} + + @AsyncPublisher(operation = @AsyncOperation(channelName = "publisher-channel")) + public void publish4(List payload) {} } } diff --git a/springwolf-core/src/test/resources/schemas/json/annotation-definitions.json b/springwolf-core/src/test/resources/schemas/json/annotation-definitions.json index 4dd493dd8..c0e7c1741 100644 --- a/springwolf-core/src/test/resources/schemas/json/annotation-definitions.json +++ b/springwolf-core/src/test/resources/schemas/json/annotation-definitions.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$SchemaWithOneOf$AllOf" : { + "title" : "AllOf", "type" : "object", "examples" : [ { "firstOne" : "string", @@ -14,6 +15,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$SchemaWithOneOf$AnyOf" : { + "title" : "AnyOf", "type" : "object", "examples" : [ { "firstOne" : "string", @@ -57,6 +59,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$SchemaWithOneOf$OneOf" : { + "title" : "OneOf", "type" : "object", "examples" : [ { "firstOne" : "string", @@ -69,6 +72,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$SchemaWithOneOf$SchemaAnnotationFoo" : { + "title" : "SchemaAnnotationFoo", "type" : "object", "properties" : { "allOf" : { @@ -102,4 +106,4 @@ } } ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/json/array-definitions.json b/springwolf-core/src/test/resources/schemas/json/array-definitions.json index 399534b79..132a1f011 100644 --- a/springwolf-core/src/test/resources/schemas/json/array-definitions.json +++ b/springwolf-core/src/test/resources/schemas/json/array-definitions.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$ArrayFoo" : { + "title" : "ArrayFoo", "type" : "object", "properties" : { "flist" : { @@ -17,6 +18,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$SimpleFoo" : { + "title" : "SimpleFoo", "type" : "object", "properties" : { "b" : { @@ -31,4 +33,4 @@ "s" : "string" } ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/json/complex-definitions.json b/springwolf-core/src/test/resources/schemas/json/complex-definitions.json index ce7b25145..7aaf8205b 100644 --- a/springwolf-core/src/test/resources/schemas/json/complex-definitions.json +++ b/springwolf-core/src/test/resources/schemas/json/complex-definitions.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$ComplexFoo" : { + "title" : "ComplexFoo", "type" : "object", "properties" : { "b" : { @@ -55,6 +56,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$ComplexFoo$Nested" : { + "title" : "Nested", "type" : "object", "properties" : { "nba" : { @@ -111,6 +113,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$ComplexFoo$Nested$Cyclic" : { + "title" : "Cyclic", "type" : "object", "properties" : { "cyclic" : { @@ -122,6 +125,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$ComplexFoo$Nested$MyClass" : { + "title" : "MyClass", "type" : "object", "properties" : { "s" : { @@ -132,4 +136,4 @@ "s" : "string" } ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/json/definitions.json b/springwolf-core/src/test/resources/schemas/json/definitions.json index 439a7cd7e..573045dde 100644 --- a/springwolf-core/src/test/resources/schemas/json/definitions.json +++ b/springwolf-core/src/test/resources/schemas/json/definitions.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$CompositeFoo" : { + "title" : "CompositeFoo", "type" : "object", "properties" : { "f" : { @@ -18,6 +19,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$FooWithEnum" : { + "title" : "FooWithEnum", "type" : "object", "properties" : { "b" : { @@ -34,6 +36,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$SimpleFoo" : { + "title" : "SimpleFoo", "type" : "object", "properties" : { "b" : { @@ -48,4 +51,4 @@ "s" : "string" } ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/json/documented-definitions.json b/springwolf-core/src/test/resources/schemas/json/documented-definitions.json index 208968e50..093dcedc9 100644 --- a/springwolf-core/src/test/resources/schemas/json/documented-definitions.json +++ b/springwolf-core/src/test/resources/schemas/json/documented-definitions.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$DocumentedSimpleFoo" : { + "title" : "DocumentedSimpleFoo", "type" : "object", "properties" : { "bi" : { @@ -73,6 +74,7 @@ "required" : [ "dt", "f", "s" ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$SimpleFoo" : { + "title" : "SimpleFoo", "type" : "object", "properties" : { "b" : { @@ -87,4 +89,4 @@ "s" : "string" } ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/json/generics-wrapper-definitions.json b/springwolf-core/src/test/resources/schemas/json/generics-wrapper-definitions.json index 0560ea5e0..1d271c05a 100644 --- a/springwolf-core/src/test/resources/schemas/json/generics-wrapper-definitions.json +++ b/springwolf-core/src/test/resources/schemas/json/generics-wrapper-definitions.json @@ -11,4 +11,4 @@ "type" : "string" } } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/json/json-type-definitions.json b/springwolf-core/src/test/resources/schemas/json/json-type-definitions.json index 849432803..1e728b216 100644 --- a/springwolf-core/src/test/resources/schemas/json/json-type-definitions.json +++ b/springwolf-core/src/test/resources/schemas/json/json-type-definitions.json @@ -41,6 +41,7 @@ }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$JsonTypeTest$JsonTypeInfoInterface" : { "discriminator" : "type", + "title" : "JsonTypeInfoInterface", "type" : "object", "properties" : { "type" : { @@ -59,6 +60,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultJsonComponentsServiceIntegrationTest$JsonTypeTest$JsonTypeInfoPayloadDto" : { + "title" : "JsonTypeInfoPayloadDto", "type" : "object", "properties" : { "jsonTypeInfoInterface" : { diff --git a/springwolf-core/src/test/resources/schemas/xml/annotation-definitions-xml.json b/springwolf-core/src/test/resources/schemas/xml/annotation-definitions-xml.json index 79a787211..673cc38cf 100644 --- a/springwolf-core/src/test/resources/schemas/xml/annotation-definitions-xml.json +++ b/springwolf-core/src/test/resources/schemas/xml/annotation-definitions-xml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SchemaWithOneOf$AllOf" : { + "title" : "AllOf", "type" : "string", "examples" : [ "string0stringtrue" ], "allOf" : [ { @@ -9,6 +10,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SchemaWithOneOf$AnyOf" : { + "title" : "AnyOf", "type" : "string", "examples" : [ "stringstring" ], "anyOf" : [ { @@ -43,6 +45,7 @@ "examples" : [ "0true" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SchemaWithOneOf$OneOf" : { + "title" : "OneOf", "type" : "string", "examples" : [ "stringstring" ], "oneOf" : [ { @@ -52,6 +55,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SchemaWithOneOf$SchemaAnnotationFoo" : { + "title" : "SchemaAnnotationFoo", "type" : "string", "properties" : { "allOf" : { @@ -69,4 +73,4 @@ }, "examples" : [ "string0stringtruestringstringstringstringstring" ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/xml/array-definitions-xml.json b/springwolf-core/src/test/resources/schemas/xml/array-definitions-xml.json index 153a62f8d..fc18830f2 100644 --- a/springwolf-core/src/test/resources/schemas/xml/array-definitions-xml.json +++ b/springwolf-core/src/test/resources/schemas/xml/array-definitions-xml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$ArrayFoo" : { + "title" : "ArrayFoo", "type" : "string", "properties" : { "flist" : { @@ -12,6 +13,7 @@ "examples" : [ "truestring" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SimpleFoo" : { + "title" : "SimpleFoo", "type" : "string", "properties" : { "b" : { @@ -23,4 +25,4 @@ }, "examples" : [ "truestring" ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/xml/complex-definitions-with-attributes-xml.json b/springwolf-core/src/test/resources/schemas/xml/complex-definitions-with-attributes-xml.json index a03dfb671..4f4f80988 100644 --- a/springwolf-core/src/test/resources/schemas/xml/complex-definitions-with-attributes-xml.json +++ b/springwolf-core/src/test/resources/schemas/xml/complex-definitions-with-attributes-xml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$ComplexAttributesFoo" : { + "title" : "ComplexAttributesFoo", "type" : "string", "properties" : { "b" : { @@ -31,6 +32,7 @@ "examples" : [ "0stringstring" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$ComplexAttributesFoo$Nested" : { + "title" : "Nested", "type" : "string", "properties" : { "nli" : { @@ -60,6 +62,7 @@ "examples" : [ "0stringstring" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$ComplexAttributesFoo$Nested$MyClassWithAttribute" : { + "title" : "MyClassWithAttribute", "type" : "string", "properties" : { "s_attribute" : { diff --git a/springwolf-core/src/test/resources/schemas/xml/complex-definitions-xml.json b/springwolf-core/src/test/resources/schemas/xml/complex-definitions-xml.json index a09f8f3c1..745f3d21d 100644 --- a/springwolf-core/src/test/resources/schemas/xml/complex-definitions-xml.json +++ b/springwolf-core/src/test/resources/schemas/xml/complex-definitions-xml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$ComplexFoo" : { + "title" : "ComplexFoo", "type" : "string", "properties" : { "b" : { @@ -31,6 +32,7 @@ "examples" : [ "true1.1
2015-07-20T15:49:04-07:00
1.10YmFzZTY0LWV4YW1wbGU=0stringstringstring3fa85f64-5717-4562-b3fc-2c963f66afa6string
" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$ComplexFoo$Nested" : { + "title" : "Nested", "type" : "string", "properties" : { "nba" : { @@ -71,6 +73,7 @@ "examples" : [ "YmFzZTY0LWV4YW1wbGU=0stringstringstring3fa85f64-5717-4562-b3fc-2c963f66afa6" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$ComplexFoo$Nested$Cyclic" : { + "title" : "Cyclic", "type" : "string", "properties" : { "cyclic" : { @@ -80,6 +83,7 @@ "examples" : [ "" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$ComplexFoo$Nested$MyClass" : { + "title" : "MyClass", "type" : "string", "properties" : { "s" : { diff --git a/springwolf-core/src/test/resources/schemas/xml/definitions-xml.json b/springwolf-core/src/test/resources/schemas/xml/definitions-xml.json index 75a1a0f4f..7331f346a 100644 --- a/springwolf-core/src/test/resources/schemas/xml/definitions-xml.json +++ b/springwolf-core/src/test/resources/schemas/xml/definitions-xml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$CompositeFoo" : { + "title" : "CompositeFoo", "type" : "string", "properties" : { "f" : { @@ -12,6 +13,7 @@ "examples" : [ "truestringstring" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$FooWithEnum" : { + "title" : "FooWithEnum", "type" : "string", "properties" : { "b" : { @@ -25,6 +27,7 @@ "examples" : [ "BAR1string" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SimpleFoo" : { + "title" : "SimpleFoo", "type" : "string", "properties" : { "b" : { @@ -36,4 +39,4 @@ }, "examples" : [ "truestring" ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/xml/documented-definitions-xml.json b/springwolf-core/src/test/resources/schemas/xml/documented-definitions-xml.json index 5ec3027d6..e6f7347bd 100644 --- a/springwolf-core/src/test/resources/schemas/xml/documented-definitions-xml.json +++ b/springwolf-core/src/test/resources/schemas/xml/documented-definitions-xml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$DocumentedSimpleFoo" : { + "title" : "DocumentedSimpleFoo", "type" : "string", "properties" : { "bi" : { @@ -55,6 +56,7 @@ "required" : [ "dt", "f", "s" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$SimpleFoo" : { + "title" : "SimpleFoo", "type" : "string", "properties" : { "b" : { @@ -66,4 +68,4 @@ }, "examples" : [ "truestring" ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/xml/generics-wrapper-definitions-xml.json b/springwolf-core/src/test/resources/schemas/xml/generics-wrapper-definitions-xml.json index 663fae6f0..3675204a5 100644 --- a/springwolf-core/src/test/resources/schemas/xml/generics-wrapper-definitions-xml.json +++ b/springwolf-core/src/test/resources/schemas/xml/generics-wrapper-definitions-xml.json @@ -8,4 +8,4 @@ }, "examples" : [ "string" ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/xml/schema-with-shared-property.json b/springwolf-core/src/test/resources/schemas/xml/schema-with-shared-property.json index 439142879..c2cf9a7ff 100644 --- a/springwolf-core/src/test/resources/schemas/xml/schema-with-shared-property.json +++ b/springwolf-core/src/test/resources/schemas/xml/schema-with-shared-property.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$XmlSchemaName$ClassA" : { + "title" : "ClassA", "type" : "string", "properties" : { "classB" : { @@ -12,6 +13,7 @@ "examples" : [ "" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$XmlSchemaName$ClassB" : { + "title" : "ClassB", "type" : "string", "properties" : { "reference" : { @@ -21,7 +23,8 @@ "examples" : [ "" ] }, "io.github.springwolf.core.asyncapi.components.DefaultXmlComponentsServiceIntegrationTest$XmlSchemaName$Reference" : { + "title" : "Reference", "type" : "string", "examples" : [ "" ] } -} +} \ No newline at end of file diff --git a/springwolf-core/src/test/resources/schemas/yaml/annotation-definitions-yaml.json b/springwolf-core/src/test/resources/schemas/yaml/annotation-definitions-yaml.json index 589bd2ba4..cbd75cce5 100644 --- a/springwolf-core/src/test/resources/schemas/yaml/annotation-definitions-yaml.json +++ b/springwolf-core/src/test/resources/schemas/yaml/annotation-definitions-yaml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$SchemaWithOneOf$AllOf" : { + "title" : "AllOf", "type" : "string", "examples" : [ "firstOne: string\nfirstTwo: 0\nsecondOne: string\nsecondTwo: true\n" ], "allOf" : [ { @@ -9,6 +10,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$SchemaWithOneOf$AnyOf" : { + "title" : "AnyOf", "type" : "string", "examples" : [ "firstOne: string\nsecondOne: string\n" ], "anyOf" : [ { @@ -43,6 +45,7 @@ "examples" : [ "firstTwo: 0\nsecondTwo: true\n" ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$SchemaWithOneOf$OneOf" : { + "title" : "OneOf", "type" : "string", "examples" : [ "|\n firstOne: string\n secondOne: string\n" ], "oneOf" : [ { @@ -52,6 +55,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$SchemaWithOneOf$SchemaAnnotationFoo" : { + "title" : "SchemaAnnotationFoo", "type" : "string", "properties" : { "allOf" : { diff --git a/springwolf-core/src/test/resources/schemas/yaml/array-definitions-yaml.json b/springwolf-core/src/test/resources/schemas/yaml/array-definitions-yaml.json index 9c2f47816..85dcc6305 100644 --- a/springwolf-core/src/test/resources/schemas/yaml/array-definitions-yaml.json +++ b/springwolf-core/src/test/resources/schemas/yaml/array-definitions-yaml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$ArrayFoo" : { + "title" : "ArrayFoo", "type" : "string", "properties" : { "flist" : { @@ -12,6 +13,7 @@ "examples" : [ "flist:\n- b: true\n s: string\n" ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$SimpleFoo" : { + "title" : "SimpleFoo", "type" : "string", "properties" : { "b" : { diff --git a/springwolf-core/src/test/resources/schemas/yaml/complex-definitions-yaml.json b/springwolf-core/src/test/resources/schemas/yaml/complex-definitions-yaml.json index 1aef6649a..2e3009144 100644 --- a/springwolf-core/src/test/resources/schemas/yaml/complex-definitions-yaml.json +++ b/springwolf-core/src/test/resources/schemas/yaml/complex-definitions-yaml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$ComplexFoo" : { + "title" : "ComplexFoo", "type" : "string", "properties" : { "b" : { @@ -31,6 +32,7 @@ "examples" : [ "b: true\nd: 1.1\ndt: 2015-07-20T15:49:04-07:00\nf: 1.1\ni: 0\n\"n\":\n nba: YmFzZTY0LWV4YW1wbGU=\n nc:\n cyclic: {}\n nli:\n - 0\n nmfm:\n key:\n s: string\n ns: string\n nsm:\n - s: string\n nu: 3fa85f64-5717-4562-b3fc-2c963f66afa6\ns: string\n" ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$ComplexFoo$Nested" : { + "title" : "Nested", "type" : "string", "properties" : { "nba" : { @@ -71,6 +73,7 @@ "examples" : [ "nba: YmFzZTY0LWV4YW1wbGU=\nnc:\n cyclic: {}\nnli:\n- 0\nnmfm:\n key:\n s: string\nns: string\nnsm:\n- s: string\nnu: 3fa85f64-5717-4562-b3fc-2c963f66afa6\n" ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$ComplexFoo$Nested$Cyclic" : { + "title" : "Cyclic", "type" : "string", "properties" : { "cyclic" : { @@ -80,6 +83,7 @@ "examples" : [ "cyclic: {}\n" ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$ComplexFoo$Nested$MyClass" : { + "title" : "MyClass", "type" : "string", "properties" : { "s" : { diff --git a/springwolf-core/src/test/resources/schemas/yaml/definitions-yaml.json b/springwolf-core/src/test/resources/schemas/yaml/definitions-yaml.json index 6f179bcac..81d9c5a99 100644 --- a/springwolf-core/src/test/resources/schemas/yaml/definitions-yaml.json +++ b/springwolf-core/src/test/resources/schemas/yaml/definitions-yaml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$CompositeFoo" : { + "title" : "CompositeFoo", "type" : "string", "properties" : { "f" : { @@ -12,6 +13,7 @@ "examples" : [ "f:\n b: true\n s: string\ns: string\n" ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$FooWithEnum" : { + "title" : "FooWithEnum", "type" : "string", "properties" : { "b" : { @@ -25,6 +27,7 @@ "examples" : [ "b: BAR1\ns: string\n" ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$SimpleFoo" : { + "title" : "SimpleFoo", "type" : "string", "properties" : { "b" : { diff --git a/springwolf-core/src/test/resources/schemas/yaml/documented-definitions-yaml.json b/springwolf-core/src/test/resources/schemas/yaml/documented-definitions-yaml.json index c75be5c4b..4c9d45288 100644 --- a/springwolf-core/src/test/resources/schemas/yaml/documented-definitions-yaml.json +++ b/springwolf-core/src/test/resources/schemas/yaml/documented-definitions-yaml.json @@ -1,5 +1,6 @@ { "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$DocumentedSimpleFoo" : { + "title" : "DocumentedSimpleFoo", "type" : "string", "properties" : { "bi" : { @@ -57,6 +58,7 @@ "required" : [ "dt", "f", "s" ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$SimpleFoo" : { + "title" : "SimpleFoo", "type" : "string", "properties" : { "b" : { diff --git a/springwolf-core/src/test/resources/schemas/yaml/json-type-definitions-yaml.json b/springwolf-core/src/test/resources/schemas/yaml/json-type-definitions-yaml.json index 5b40f017e..e3f4978be 100644 --- a/springwolf-core/src/test/resources/schemas/yaml/json-type-definitions-yaml.json +++ b/springwolf-core/src/test/resources/schemas/yaml/json-type-definitions-yaml.json @@ -35,6 +35,7 @@ }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$JsonTypeTest$JsonTypeInfoInterface" : { "discriminator" : "type", + "title" : "JsonTypeInfoInterface", "type" : "string", "properties" : { "type" : { @@ -50,6 +51,7 @@ } ] }, "io.github.springwolf.core.asyncapi.components.DefaultYamlComponentsServiceIntegrationTest$JsonTypeTest$JsonTypeInfoPayloadDto" : { + "title" : "JsonTypeInfoPayloadDto", "type" : "string", "properties" : { "jsonTypeInfoInterface" : { diff --git a/springwolf-examples/e2e/tests/publishing.spec.ts b/springwolf-examples/e2e/tests/publishing.spec.ts index 14c9c9f95..a8d9488dd 100644 --- a/springwolf-examples/e2e/tests/publishing.spec.ts +++ b/springwolf-examples/e2e/tests/publishing.spec.ts @@ -59,22 +59,18 @@ function testPublishingEveryChannelItem() { const action = operation.action; const protocol = Object.keys(operation.bindings)[0]; const channelName = operation.channel.$ref.split("/").pop(); - const schemaType = messageReference.$ref.split("/").pop(); - const payload = asyncApiDoc.components.messages[schemaType]?.title; - const payloadType = asyncApiDoc.components.messages[ - schemaType - ]?.payload.schema.$ref - .split("/") - .pop(); + const messageName = messageReference.$ref.split("/").pop(); + const messageTitle = asyncApiDoc.components.messages[messageName]?.title; + const payloadName = messageName; if ( - payload === "AnotherPayloadAvroDto" || // Avro publishing is not supported - payload === "XmlPayloadDto" || // Unable to create correct xml payload - 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 - payload === "GenericPayloadDto" || // Unable to publish generic payload (amqp) + messageTitle === "AnotherPayloadAvroDto" || // Avro publishing is not supported + messageTitle === "XmlPayloadDto" || // Unable to create correct xml payload + messageTitle === "YamlPayloadDto" || // Unable to create correct yaml payload + messageTitle === "MonetaryAmount" || // Issue with either MonetaryAmount of ModelConverters + messageTitle === "Message" || // Unable to instantiate ExamplePayloadProtobufDto$Message class + messageTitle === "VehicleBase" || // Unable to publish abstract class for discriminator demo + messageTitle === "GenericPayloadDto" || // Unable to publish generic payload (amqp) channelName === "#" || // Publishing through amqp exchange is not supported, see GH-366 channelName === "example-topic-routing-key" // Publishing through amqp exchange is not supported, see GH-366 ) { @@ -82,14 +78,14 @@ function testPublishingEveryChannelItem() { } test( - action + " " + channelName + " with " + payload, + action + " " + channelName + " with " + messageTitle, async ({ page }) => { const channel = locateChannel( page, protocol, channelName, action, - payload + messageTitle ); await channel.click(); @@ -108,14 +104,14 @@ function testPublishingEveryChannelItem() { const found = dockerLogs.messages .filter((m) => m.includes("Publishing to")) .filter((m) => m.includes(channelName)) - .filter((m) => m.includes(payloadType)).length; + .filter((m) => m.includes(payloadName)).length; console.debug( `Polling for publish message and found=${found}` ); return found; }, { - message: `Expected publishing message in application logs in channel ${channelName} with type ${payloadType}`, + message: `Expected publishing message in application logs in channel ${channelName} with type ${payloadName}`, } ) .toBeGreaterThanOrEqual(1); 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 8deb3416f..510407f6d 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json @@ -364,7 +364,6 @@ }, "name": "io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto", "title": "AnotherPayloadDto", - "description": "Another payload model", "bindings": { "amqp": { "bindingVersion": "0.3.0" diff --git a/springwolf-examples/springwolf-jms-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-jms-example/src/test/resources/asyncapi.json index c79361e1f..f3559e893 100644 --- a/springwolf-examples/springwolf-jms-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-jms-example/src/test/resources/asyncapi.json @@ -146,7 +146,6 @@ }, "name": "io.github.springwolf.examples.jms.dtos.AnotherPayloadDto", "title": "AnotherPayloadDto", - "description": "Another payload model", "bindings": { "jms": { "bindingVersion": "0.0.1" diff --git a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/consumers/ExampleClassLevelKafkaListener.java b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/consumers/ExampleClassLevelKafkaListener.java index a126e4b1d..4a7ae050c 100644 --- a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/consumers/ExampleClassLevelKafkaListener.java +++ b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/springwolf/examples/kafka/consumers/ExampleClassLevelKafkaListener.java @@ -36,7 +36,7 @@ public void receiveExamplePayload( @KafkaHandler public void receiveAnotherPayload(ConsumerRecord payload) { - log.info("Received new message in {}: {}", TOPIC, payload.toString()); + log.info("Received new message in {}: {}", TOPIC, payload.value().toString()); } @KafkaHandler diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java index 255f5ebc4..63dd0da6d 100644 --- a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java +++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java @@ -49,11 +49,11 @@ void asyncApiResourceArtifactYamlTest() throws IOException { String url = "/springwolf/docs.yaml"; String actual = restTemplate.getForObject(url, String.class); // When running with EmbeddedKafka, the kafka bootstrap server does run on random ports - String actualPatched = actual.replace(bootstrapServers, "kafka:29092"); + String actualPatched = actual.replace(bootstrapServers, "kafka:29092").trim(); Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.yaml"), actualPatched); InputStream s = this.getClass().getResourceAsStream("/asyncapi.yaml"); - String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8); + String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim(); assertEquals(expected, actualPatched); } 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 36591c1a3..4d30e319d 100644 --- a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json @@ -59,8 +59,8 @@ "integer-topic": { "address": "integer-topic", "messages": { - "java.lang.Number": { - "$ref": "#/components/messages/java.lang.Number" + "java.lang.Integer": { + "$ref": "#/components/messages/java.lang.Integer" } }, "bindings": { @@ -498,24 +498,24 @@ "type": "object" } }, - "SpringKafkaDefaultHeaders-Integer": { - "title": "SpringKafkaDefaultHeaders-Integer", + "SpringKafkaDefaultHeaders-Message": { + "title": "SpringKafkaDefaultHeaders-Message", "type": "object", "properties": { "__TypeId__": { "type": "string", "description": "Spring Type Id Header", "enum": [ - "java.lang.Number" + "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message" ], "examples": [ - "java.lang.Number" + "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message" ] } }, "examples": [ { - "__TypeId__": "java.lang.Number" + "__TypeId__": "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message" } ], "x-json-schema": { @@ -524,33 +524,33 @@ "__TypeId__": { "description": "Spring Type Id Header", "enum": [ - "java.lang.Number" + "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message" ], "type": "string" } }, - "title": "SpringKafkaDefaultHeaders-Integer", + "title": "SpringKafkaDefaultHeaders-Message", "type": "object" } }, - "SpringKafkaDefaultHeaders-Message": { - "title": "SpringKafkaDefaultHeaders-Message", + "SpringKafkaDefaultHeaders-MonetaryAmount": { + "title": "SpringKafkaDefaultHeaders-MonetaryAmount", "type": "object", "properties": { "__TypeId__": { "type": "string", "description": "Spring Type Id Header", "enum": [ - "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message" + "javax.money.MonetaryAmount" ], "examples": [ - "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message" + "javax.money.MonetaryAmount" ] } }, "examples": [ { - "__TypeId__": "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message" + "__TypeId__": "javax.money.MonetaryAmount" } ], "x-json-schema": { @@ -559,33 +559,33 @@ "__TypeId__": { "description": "Spring Type Id Header", "enum": [ - "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message" + "javax.money.MonetaryAmount" ], "type": "string" } }, - "title": "SpringKafkaDefaultHeaders-Message", + "title": "SpringKafkaDefaultHeaders-MonetaryAmount", "type": "object" } }, - "SpringKafkaDefaultHeaders-MonetaryAmount": { - "title": "SpringKafkaDefaultHeaders-MonetaryAmount", + "SpringKafkaDefaultHeaders-PayloadNotUsed": { + "title": "SpringKafkaDefaultHeaders-PayloadNotUsed", "type": "object", "properties": { "__TypeId__": { "type": "string", "description": "Spring Type Id Header", "enum": [ - "javax.money.MonetaryAmount" + "PayloadNotUsed" ], "examples": [ - "javax.money.MonetaryAmount" + "PayloadNotUsed" ] } }, "examples": [ { - "__TypeId__": "javax.money.MonetaryAmount" + "__TypeId__": "PayloadNotUsed" } ], "x-json-schema": { @@ -594,33 +594,33 @@ "__TypeId__": { "description": "Spring Type Id Header", "enum": [ - "javax.money.MonetaryAmount" + "PayloadNotUsed" ], "type": "string" } }, - "title": "SpringKafkaDefaultHeaders-MonetaryAmount", + "title": "SpringKafkaDefaultHeaders-PayloadNotUsed", "type": "object" } }, - "SpringKafkaDefaultHeaders-PayloadNotUsed": { - "title": "SpringKafkaDefaultHeaders-PayloadNotUsed", + "SpringKafkaDefaultHeaders-VehicleBase": { + "title": "SpringKafkaDefaultHeaders-VehicleBase", "type": "object", "properties": { "__TypeId__": { "type": "string", "description": "Spring Type Id Header", "enum": [ - "PayloadNotUsed" + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" ], "examples": [ - "PayloadNotUsed" + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" ] } }, "examples": [ { - "__TypeId__": "PayloadNotUsed" + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" } ], "x-json-schema": { @@ -629,33 +629,33 @@ "__TypeId__": { "description": "Spring Type Id Header", "enum": [ - "PayloadNotUsed" + "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" ], "type": "string" } }, - "title": "SpringKafkaDefaultHeaders-PayloadNotUsed", + "title": "SpringKafkaDefaultHeaders-VehicleBase", "type": "object" } }, - "SpringKafkaDefaultHeaders-String": { - "title": "SpringKafkaDefaultHeaders-String", + "SpringKafkaDefaultHeaders-XmlPayloadDto": { + "title": "SpringKafkaDefaultHeaders-XmlPayloadDto", "type": "object", "properties": { "__TypeId__": { "type": "string", "description": "Spring Type Id Header", "enum": [ - "java.lang.String" + "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" ], "examples": [ - "java.lang.String" + "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" ] } }, "examples": [ { - "__TypeId__": "java.lang.String" + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" } ], "x-json-schema": { @@ -664,33 +664,33 @@ "__TypeId__": { "description": "Spring Type Id Header", "enum": [ - "java.lang.String" + "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" ], "type": "string" } }, - "title": "SpringKafkaDefaultHeaders-String", + "title": "SpringKafkaDefaultHeaders-XmlPayloadDto", "type": "object" } }, - "SpringKafkaDefaultHeaders-VehicleBase": { - "title": "SpringKafkaDefaultHeaders-VehicleBase", + "SpringKafkaDefaultHeaders-YamlPayloadDto": { + "title": "SpringKafkaDefaultHeaders-YamlPayloadDto", "type": "object", "properties": { "__TypeId__": { "type": "string", "description": "Spring Type Id Header", "enum": [ - "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" ], "examples": [ - "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" ] } }, "examples": [ { - "__TypeId__": "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + "__TypeId__": "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" } ], "x-json-schema": { @@ -699,33 +699,33 @@ "__TypeId__": { "description": "Spring Type Id Header", "enum": [ - "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" + "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" ], "type": "string" } }, - "title": "SpringKafkaDefaultHeaders-VehicleBase", + "title": "SpringKafkaDefaultHeaders-YamlPayloadDto", "type": "object" } }, - "SpringKafkaDefaultHeaders-XmlPayloadDto": { - "title": "SpringKafkaDefaultHeaders-XmlPayloadDto", + "SpringKafkaDefaultHeaders-integer": { + "title": "SpringKafkaDefaultHeaders-integer", "type": "object", "properties": { "__TypeId__": { "type": "string", "description": "Spring Type Id Header", "enum": [ - "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + "java.lang.Integer" ], "examples": [ - "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + "java.lang.Integer" ] } }, "examples": [ { - "__TypeId__": "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + "__TypeId__": "java.lang.Integer" } ], "x-json-schema": { @@ -734,33 +734,33 @@ "__TypeId__": { "description": "Spring Type Id Header", "enum": [ - "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" + "java.lang.Integer" ], "type": "string" } }, - "title": "SpringKafkaDefaultHeaders-XmlPayloadDto", + "title": "SpringKafkaDefaultHeaders-integer", "type": "object" } }, - "SpringKafkaDefaultHeaders-YamlPayloadDto": { - "title": "SpringKafkaDefaultHeaders-YamlPayloadDto", + "SpringKafkaDefaultHeaders-string": { + "title": "SpringKafkaDefaultHeaders-string", "type": "object", "properties": { "__TypeId__": { "type": "string", "description": "Spring Type Id Header", "enum": [ - "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + "java.lang.String" ], "examples": [ - "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + "java.lang.String" ] } }, "examples": [ { - "__TypeId__": "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + "__TypeId__": "java.lang.String" } ], "x-json-schema": { @@ -769,17 +769,16 @@ "__TypeId__": { "description": "Spring Type Id Header", "enum": [ - "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + "java.lang.String" ], "type": "string" } }, - "title": "SpringKafkaDefaultHeaders-YamlPayloadDto", + "title": "SpringKafkaDefaultHeaders-string", "type": "object" } }, "io.github.springwolf.examples.kafka.consumers.StringConsumer$StringEnvelope": { - "title": "StringEnvelope", "type": "string", "description": "Payload description using @Schema annotation and @AsyncApiPayload within envelope class", "maxLength": 100, @@ -790,7 +789,6 @@ "$schema": "https://json-schema.org/draft-04/schema#", "description": "Payload description using @Schema annotation and @AsyncApiPayload within envelope class", "maxLength": 100, - "title": "StringEnvelope", "type": "string" } }, @@ -832,6 +830,7 @@ "type": "string" } }, + "title": "ExamplePayloadAvroDto", "type": "object" }, "someEnum": { @@ -848,6 +847,7 @@ } }, "io.github.springwolf.examples.kafka.dto.avro.ExamplePayloadAvroDto": { + "title": "ExamplePayloadAvroDto", "type": "object", "properties": { "someLong": { @@ -875,6 +875,7 @@ "type": "string" } }, + "title": "ExamplePayloadAvroDto", "type": "object" } }, @@ -1422,32 +1423,29 @@ "type": "object" } }, - "java.lang.Number": { - "title": "Integer", - "type": "number", + "java.lang.Integer": { + "type": "integer", + "format": "int32", "examples": [ - 1.1 + 0 ], "x-json-schema": { "$schema": "https://json-schema.org/draft-04/schema#", - "title": "Integer", - "type": "number" + "format": "int32", + "type": "integer" } }, "java.lang.String": { - "title": "String", "type": "string", "examples": [ "\"string\"" ], "x-json-schema": { "$schema": "https://json-schema.org/draft-04/schema#", - "title": "String", "type": "string" } }, "javax.money.MonetaryAmount": { - "title": "MonetaryAmount", "type": "object", "properties": { "amount": { @@ -1481,7 +1479,6 @@ "type": "string" } }, - "title": "MonetaryAmount", "type": "object" } } @@ -1494,7 +1491,10 @@ "payload": { "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", "schema": { - "$ref": "#/components/schemas/PayloadNotUsed" + "title": "PayloadNotUsed", + "type": "object", + "properties": { }, + "description": "No payload specified" } }, "name": "PayloadNotUsed", @@ -1517,7 +1517,6 @@ }, "name": "StringPayload", "title": "StringEnvelope", - "description": "Payload description using @Schema annotation and @AsyncApiPayload within envelope class", "bindings": { "kafka": { "bindingVersion": "0.5.0" @@ -1608,7 +1607,6 @@ }, "name": "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto", "title": "NestedPayloadDto", - "description": "Payload model with nested complex types", "bindings": { "kafka": { "key": { @@ -1680,18 +1678,22 @@ } } }, - "java.lang.Number": { + "java.lang.Integer": { "headers": { - "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-Integer" + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-integer" }, "payload": { "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", "schema": { - "$ref": "#/components/schemas/java.lang.Number" + "type": "integer", + "format": "int32", + "examples": [ + 0 + ] } }, - "name": "java.lang.Number", - "title": "Integer", + "name": "java.lang.Integer", + "title": "integer", "bindings": { "kafka": { "bindingVersion": "0.5.0" @@ -1700,16 +1702,19 @@ }, "java.lang.String": { "headers": { - "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-String" + "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-string" }, "payload": { "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", "schema": { - "$ref": "#/components/schemas/java.lang.String" + "type": "string", + "examples": [ + "\"string\"" + ] } }, "name": "java.lang.String", - "title": "String", + "title": "string", "bindings": { "kafka": { "bindingVersion": "0.5.0" @@ -1812,7 +1817,7 @@ }, "messages": [ { - "$ref": "#/channels/integer-topic/messages/java.lang.Number" + "$ref": "#/channels/integer-topic/messages/java.lang.Integer" } ] }, @@ -1998,4 +2003,4 @@ ] } } -} +} \ No newline at end of file diff --git a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.yaml b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.yaml index a30c80ede..0848ab5b6 100644 --- a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.yaml +++ b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.yaml @@ -41,8 +41,8 @@ channels: integer-topic: address: integer-topic messages: - java.lang.Number: - $ref: "#/components/messages/java.lang.Number" + java.lang.Integer: + $ref: "#/components/messages/java.lang.Integer" bindings: kafka: bindingVersion: 0.5.0 @@ -340,29 +340,6 @@ components: type: string title: SpringKafkaDefaultHeaders-ExamplePayloadDto-220435997 type: object - SpringKafkaDefaultHeaders-Integer: - title: SpringKafkaDefaultHeaders-Integer - type: object - properties: - __TypeId__: - type: string - description: Spring Type Id Header - enum: - - java.lang.Number - examples: - - java.lang.Number - examples: - - __TypeId__: java.lang.Number - x-json-schema: - $schema: https://json-schema.org/draft-04/schema# - properties: - __TypeId__: - description: Spring Type Id Header - enum: - - java.lang.Number - type: string - title: SpringKafkaDefaultHeaders-Integer - type: object SpringKafkaDefaultHeaders-Message: title: SpringKafkaDefaultHeaders-Message type: object @@ -432,29 +409,6 @@ components: type: string title: SpringKafkaDefaultHeaders-PayloadNotUsed type: object - SpringKafkaDefaultHeaders-String: - title: SpringKafkaDefaultHeaders-String - type: object - properties: - __TypeId__: - type: string - description: Spring Type Id Header - enum: - - java.lang.String - examples: - - java.lang.String - examples: - - __TypeId__: java.lang.String - x-json-schema: - $schema: https://json-schema.org/draft-04/schema# - properties: - __TypeId__: - description: Spring Type Id Header - enum: - - java.lang.String - type: string - title: SpringKafkaDefaultHeaders-String - type: object SpringKafkaDefaultHeaders-VehicleBase: title: SpringKafkaDefaultHeaders-VehicleBase type: object @@ -524,8 +478,53 @@ components: type: string title: SpringKafkaDefaultHeaders-YamlPayloadDto type: object + SpringKafkaDefaultHeaders-integer: + title: SpringKafkaDefaultHeaders-integer + type: object + properties: + __TypeId__: + type: string + description: Spring Type Id Header + enum: + - java.lang.Integer + examples: + - java.lang.Integer + examples: + - __TypeId__: java.lang.Integer + x-json-schema: + $schema: https://json-schema.org/draft-04/schema# + properties: + __TypeId__: + description: Spring Type Id Header + enum: + - java.lang.Integer + type: string + title: SpringKafkaDefaultHeaders-integer + type: object + SpringKafkaDefaultHeaders-string: + title: SpringKafkaDefaultHeaders-string + type: object + properties: + __TypeId__: + type: string + description: Spring Type Id Header + enum: + - java.lang.String + examples: + - java.lang.String + examples: + - __TypeId__: java.lang.String + x-json-schema: + $schema: https://json-schema.org/draft-04/schema# + properties: + __TypeId__: + description: Spring Type Id Header + enum: + - java.lang.String + type: string + title: SpringKafkaDefaultHeaders-string + type: object io.github.springwolf.examples.kafka.consumers.StringConsumer$StringEnvelope: - title: StringEnvelope type: string description: Payload description using @Schema annotation and @AsyncApiPayload within envelope class @@ -537,7 +536,6 @@ components: description: Payload description using @Schema annotation and @AsyncApiPayload within envelope class maxLength: 100 - title: StringEnvelope type: string io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto: title: AnotherPayloadAvroDto @@ -566,6 +564,7 @@ components: type: integer someString: type: string + title: ExamplePayloadAvroDto type: object someEnum: enum: @@ -576,6 +575,7 @@ components: title: AnotherPayloadAvroDto type: object io.github.springwolf.examples.kafka.dto.avro.ExamplePayloadAvroDto: + title: ExamplePayloadAvroDto type: object properties: someLong: @@ -594,6 +594,7 @@ components: type: integer someString: type: string + title: ExamplePayloadAvroDto type: object io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message: title: Message @@ -1038,26 +1039,23 @@ components: type: object description: Gasoline vehicle implementation of VehicleBase type: object - java.lang.Number: - title: Integer - type: number + java.lang.Integer: + type: integer + format: int32 examples: - - 1.1 + - 0 x-json-schema: $schema: https://json-schema.org/draft-04/schema# - title: Integer - type: number + format: int32 + type: integer java.lang.String: - title: String type: string examples: - '"string"' x-json-schema: $schema: https://json-schema.org/draft-04/schema# - title: String type: string javax.money.MonetaryAmount: - title: MonetaryAmount type: object properties: amount: @@ -1080,7 +1078,6 @@ components: type: number currency: type: string - title: MonetaryAmount type: object messages: PayloadNotUsed: @@ -1089,7 +1086,10 @@ components: payload: schemaFormat: application/vnd.aai.asyncapi+json;version=3.0.0 schema: - $ref: "#/components/schemas/PayloadNotUsed" + title: PayloadNotUsed + type: object + properties: {} + description: No payload specified name: PayloadNotUsed title: PayloadNotUsed bindings: @@ -1104,8 +1104,6 @@ components: $ref: "#/components/schemas/io.github.springwolf.examples.kafka.consumers.StringConsumer$StringEnvelope" name: StringPayload title: StringEnvelope - description: Payload description using @Schema annotation and @AsyncApiPayload - within envelope class bindings: kafka: bindingVersion: 0.5.0 @@ -1166,7 +1164,6 @@ components: $ref: "#/components/schemas/io.github.springwolf.examples.kafka.dtos.NestedPayloadDto" name: io.github.springwolf.examples.kafka.dtos.NestedPayloadDto title: NestedPayloadDto - description: Payload model with nested complex types bindings: kafka: key: @@ -1215,27 +1212,32 @@ components: bindings: kafka: bindingVersion: 0.5.0 - java.lang.Number: + java.lang.Integer: headers: - $ref: "#/components/schemas/SpringKafkaDefaultHeaders-Integer" + $ref: "#/components/schemas/SpringKafkaDefaultHeaders-integer" payload: schemaFormat: application/vnd.aai.asyncapi+json;version=3.0.0 schema: - $ref: "#/components/schemas/java.lang.Number" - name: java.lang.Number - title: Integer + type: integer + format: int32 + examples: + - 0 + name: java.lang.Integer + title: integer bindings: kafka: bindingVersion: 0.5.0 java.lang.String: headers: - $ref: "#/components/schemas/SpringKafkaDefaultHeaders-String" + $ref: "#/components/schemas/SpringKafkaDefaultHeaders-string" payload: schemaFormat: application/vnd.aai.asyncapi+json;version=3.0.0 schema: - $ref: "#/components/schemas/java.lang.String" + type: string + examples: + - '"string"' name: java.lang.String - title: String + title: string bindings: kafka: bindingVersion: 0.5.0 @@ -1299,7 +1301,7 @@ operations: kafka: bindingVersion: 0.5.0 messages: - - $ref: "#/channels/integer-topic/messages/java.lang.Number" + - $ref: "#/channels/integer-topic/messages/java.lang.Integer" multi-payload-topic_receive_ExampleClassLevelKafkaListener: action: receive channel: @@ -1407,4 +1409,4 @@ operations: kafka: bindingVersion: 0.5.0 messages: - - $ref: "#/channels/yaml-topic/messages/io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" + - $ref: "#/channels/yaml-topic/messages/io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" \ No newline at end of file diff --git a/springwolf-examples/springwolf-sns-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-sns-example/src/test/resources/asyncapi.json index d98eeed83..e6b60b841 100644 --- a/springwolf-examples/springwolf-sns-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-sns-example/src/test/resources/asyncapi.json @@ -224,7 +224,6 @@ }, "name": "io.github.springwolf.examples.sns.dtos.AnotherPayloadDto", "title": "AnotherPayloadDto", - "description": "Another payload model", "bindings": { "sns": { } } @@ -241,7 +240,6 @@ }, "name": "io.github.springwolf.examples.sns.dtos.ExamplePayloadDto", "title": "ExamplePayloadDto", - "description": "Example payload model", "bindings": { "sns": { } } diff --git a/springwolf-examples/springwolf-sqs-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-sqs-example/src/test/resources/asyncapi.json index 07d3652d1..6bcfde099 100644 --- a/springwolf-examples/springwolf-sqs-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-sqs-example/src/test/resources/asyncapi.json @@ -154,7 +154,6 @@ }, "name": "io.github.springwolf.examples.sqs.dtos.AnotherPayloadDto", "title": "AnotherPayloadDto", - "description": "Another payload model", "bindings": { "sqs": { } } diff --git a/springwolf-examples/springwolf-stomp-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-stomp-example/src/test/resources/asyncapi.json index dfe1fc9d0..15f428340 100644 --- a/springwolf-examples/springwolf-stomp-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-stomp-example/src/test/resources/asyncapi.json @@ -196,7 +196,6 @@ }, "name": "io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto", "title": "AnotherPayloadDto", - "description": "Another payload model", "bindings": { "stomp": { } } diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java index 25d4abe08..8b2721825 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java @@ -317,7 +317,7 @@ void testKStreamFunctionBinding() { .name(Integer.class.getName()) .title(Integer.class.getSimpleName()) .payload(MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(Number.class.getName())) + .schema(SchemaReference.fromSchema(Integer.class.getName())) .build())) .headers(MessageHeaders.of( MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) @@ -402,7 +402,7 @@ void testFunctionBindingWithSameTopicName() { .name(Integer.class.getName()) .title(Integer.class.getSimpleName()) .payload(MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(Number.class.getName())) + .schema(SchemaReference.fromSchema(Integer.class.getName())) .build())) .headers(MessageHeaders.of( MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToCustomizerTest.java b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToCustomizerTest.java index 98af9a0ea..a8a52f4a6 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToCustomizerTest.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToCustomizerTest.java @@ -32,7 +32,7 @@ void customize() throws NoSuchMethodException { // given Operation operation = new Operation(); when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL_ID); - when(payloadService.extractSchema(any())).thenReturn(new PayloadSchemaObject(MESSAGE_ID, null)); + when(payloadService.extractSchema(any())).thenReturn(new PayloadSchemaObject(MESSAGE_ID, MESSAGE_ID, null)); // when sendToCustomizer.customize(operation, this.getClass().getDeclaredMethod("testMethod")); diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToUserCustomizerTest.java b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToUserCustomizerTest.java index 960973648..486e47466 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToUserCustomizerTest.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToUserCustomizerTest.java @@ -32,7 +32,7 @@ void customize() throws NoSuchMethodException { // given Operation operation = new Operation(); when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL_ID); - when(payloadService.extractSchema(any())).thenReturn(new PayloadSchemaObject(MESSAGE_ID, null)); + when(payloadService.extractSchema(any())).thenReturn(new PayloadSchemaObject(MESSAGE_ID, MESSAGE_ID, null)); // when sendToCustomizer.customize(operation, this.getClass().getDeclaredMethod("testMethod")); diff --git a/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.spec.ts b/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.spec.ts index dde13b8f8..8158e110c 100644 --- a/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.spec.ts +++ b/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.spec.ts @@ -34,8 +34,7 @@ describe("ChannelMainComponent", () => { }); it("should render the component and data", () => { - expect( - screen.getByText(mockData.operation.message.description!!) - ).toBeTruthy(); + expect(screen.getByText("Example")).toBeTruthy(); + expect(screen.getByText("Message Binding")).toBeTruthy(); }); }); diff --git a/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.ts b/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.ts index 402b8bd94..0c4e3fc90 100644 --- a/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.ts +++ b/springwolf-ui/src/app/components/channels/channel-main/channel-main.component.ts @@ -46,12 +46,19 @@ export class ChannelMainComponent implements OnInit { ngOnInit(): void { this.asyncApiService.getAsyncApi().subscribe((asyncapi) => { const schemas: Map = asyncapi.components.schemas; - this.schemaIdentifier = this.operation().message.payload.name.slice( - this.operation().message.payload.name.lastIndexOf("/") + 1 - ); - this.schema = schemas.get(this.schemaIdentifier)!!; - this.defaultExample = this.schema.example || noExample; + const payload = this.operation().message.payload; + if (payload.ts_type === "ref") { + const schemaIdentifier = payload.name.slice( + payload.name.lastIndexOf("/") + 1 + ); + const schema = schemas.get(schemaIdentifier)!!; + this.schema = schema; + this.defaultExample = schema.example || noExample; + } else { + this.schema = payload; + this.defaultExample = payload.example || noExample; + } this.exampleTextAreaLineCount = this.defaultExample?.lineCount || 1; this.defaultExampleType = this.operation().message.payload.name; diff --git a/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.html b/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.html index 9e98cd7ea..5ee21ef38 100644 --- a/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.html +++ b/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.html @@ -132,7 +132,7 @@
Payload
diff --git a/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.spec.ts b/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.spec.ts index bd8fa88c4..bb239b5e4 100644 --- a/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.spec.ts +++ b/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.spec.ts @@ -42,8 +42,11 @@ describe("ChannelOperationComponent", () => { }); it("should render the component and data", () => { + expect(screen.getByText(mockData.operation.channelName)).toBeTruthy(); + expect(screen.getByText(mockData.operation.message.title)).toBeTruthy(); expect( - screen.getByText(mockData.operation.message.description!!) + screen.getByText(mockData.operation.message.contentType) ).toBeTruthy(); + expect(screen.getByText(mockData.operation.servers[0].name)).toBeTruthy(); }); }); diff --git a/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.ts b/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.ts index 96ec6f3aa..e48d7e92d 100644 --- a/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.ts +++ b/springwolf-ui/src/app/components/new/channels/channel-main/channel-operation.component.ts @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: Apache-2.0 */ -import { Component, input, OnInit } from "@angular/core"; +import { Component, input, computed, OnInit } from "@angular/core"; import { MatSnackBar } from "@angular/material/snack-bar"; import { STATUS } from "angular-in-memory-web-api"; import { Binding } from "../../../../models/bindings.model"; @@ -28,7 +28,9 @@ export class ChannelOperationComponent implements OnInit { defaultSchema: Schema = initSchema; defaultExample: Example = initExample; originalDefaultExample: Example = this.defaultExample; - exampleContentType: string = "json"; + exampleContentType = computed( + () => this.operation().message.contentType.split("/").pop() || "json" + ); headers: Schema = initSchema; headersExample: Example = initExample; @@ -52,14 +54,20 @@ export class ChannelOperationComponent implements OnInit { this.asyncApiService.getAsyncApi().subscribe((asyncapi) => { const schemas: Map = asyncapi.components.schemas; - const schemaIdentifier = this.operation().message.payload.name.slice( - this.operation().message.payload.name.lastIndexOf("/") + 1 - ); - const schema = schemas.get(schemaIdentifier)!!; - this.defaultSchema = schema; - this.originalDefaultExample = schema.example || noExample; - this.exampleContentType = - this.operation().message.contentType.split("/").pop() || "json"; + const payload = this.operation().message.payload; + if (payload.ts_type === "ref") { + const schemaIdentifier = payload.name.slice( + payload.name.lastIndexOf("/") + 1 + ); + const schema = schemas.get(schemaIdentifier)!!; + this.defaultSchema = schema; + this.defaultExample = schema.example || noExample; + this.originalDefaultExample = this.defaultExample; + } else { + this.defaultSchema = payload; + this.defaultExample = payload.example || noExample; + this.originalDefaultExample = this.defaultExample; + } const headersSchemaIdentifier = this.operation().message.headers.name; this.headers = schemas.get(headersSchemaIdentifier)!!; diff --git a/springwolf-ui/src/app/components/schemas/range/schema-range.component.spec.ts b/springwolf-ui/src/app/components/schemas/range/schema-range.component.spec.ts index 32ca9a16e..9e25afee4 100644 --- a/springwolf-ui/src/app/components/schemas/range/schema-range.component.spec.ts +++ b/springwolf-ui/src/app/components/schemas/range/schema-range.component.spec.ts @@ -13,6 +13,8 @@ describe("SchemaRangeComponent", function () { }; const minimalSchema: Schema = { + ts_type: "object", + title: "test", name: "test", anchorUrl: "test", diff --git a/springwolf-ui/src/app/models/message.model.ts b/springwolf-ui/src/app/models/message.model.ts index 81c8bc2f8..db1796dee 100644 --- a/springwolf-ui/src/app/models/message.model.ts +++ b/springwolf-ui/src/app/models/message.model.ts @@ -1,21 +1,15 @@ /* SPDX-License-Identifier: Apache-2.0 */ import { Binding } from "./bindings.model"; +import { Schema, SchemaRef } from "./schema.model"; export interface Message { name: string; title: string; description?: string; contentType: string; - payload: { - name: string; - title: string; - anchorUrl: string; - }; - headers: { - name: string; - title: string; - anchorUrl: string; - }; + /** Schemas of primitive types are inlined, others referenced */ + payload: SchemaRef | Schema; + headers: SchemaRef; bindings: Map; rawBindings: { [protocol: string]: object }; } diff --git a/springwolf-ui/src/app/models/schema.model.ts b/springwolf-ui/src/app/models/schema.model.ts index 7148107dc..e5c7f22c8 100644 --- a/springwolf-ui/src/app/models/schema.model.ts +++ b/springwolf-ui/src/app/models/schema.model.ts @@ -1,7 +1,17 @@ /* SPDX-License-Identifier: Apache-2.0 */ import { Example } from "./example.model"; +export interface SchemaRef { + ts_type: "ref"; + + name: string; + title: string; + anchorUrl: string; +} + export interface Schema { + ts_type: "object"; + /** * Fully qualified schema name */ diff --git a/springwolf-ui/src/app/service/asyncapi/asyncapi-mapper.service.ts b/springwolf-ui/src/app/service/asyncapi/asyncapi-mapper.service.ts index 509fe78ca..7059ab779 100644 --- a/springwolf-ui/src/app/service/asyncapi/asyncapi-mapper.service.ts +++ b/springwolf-ui/src/app/service/asyncapi/asyncapi-mapper.service.ts @@ -264,25 +264,18 @@ export class AsyncApiMapperService { this.verifyBindings(message.bindings, "message " + message.name); - let payloadName = this.resolveRefId(message.payload.schema.$ref); + const headerName = this.resolveRefId(message.headers.$ref); const mappedMessage: Message = { name: message.name, title: message.title, description: message.description, contentType: message.contentType || defaultContentType, - payload: { - name: payloadName, - title: this.resolveTitleFromName(payloadName), - anchorUrl: AsyncApiMapperService.BASE_URL + payloadName, - }, + payload: this.mapPayload(message.name, message.payload.schema), headers: { - name: this.resolveRefId(message.headers.$ref), - title: - this.resolveRefId(message.headers.$ref) || - "undefined-header-title", - anchorUrl: - AsyncApiMapperService.BASE_URL + - this.resolveRefId(message.headers.$ref), + ts_type: "ref", + name: headerName, + title: headerName, + anchorUrl: AsyncApiMapperService.BASE_URL + headerName, }, bindings: this.mapServerAsyncApiMessageBindings(message.bindings), rawBindings: message.bindings || {}, @@ -294,6 +287,24 @@ export class AsyncApiMapperService { .filter((el) => el !== undefined); } + private mapPayload( + payloadName: string, + schema: { $ref: string } | ServerAsyncApiSchema + ): Message["payload"] { + if ("$ref" in schema) { + const payloadName = this.resolveRefId(schema.$ref); + return { + ts_type: "ref", + + name: payloadName, + title: this.resolveTitleFromName(payloadName), + anchorUrl: AsyncApiMapperService.BASE_URL + payloadName, + }; + } + + return this.mapSchemaObj(payloadName, schema, {}); + } + private mapServerAsyncApiMessageBindings( serverMessageBindings: ServerBindings | undefined ): Map { @@ -443,6 +454,8 @@ export class AsyncApiMapperService { : undefined; return { + ts_type: "object", + name: schemaName, title: this.resolveTitleFromName(schemaName) || "undefined-title", usedBy: [], @@ -516,6 +529,8 @@ export class AsyncApiMapperService { private mapSchemaRef(schemaName: string, schema: { $ref: string }): Schema { let schemaRefId = this.resolveRefId(schema.$ref); return { + ts_type: "object", + name: schemaName, title: this.resolveTitleFromName(schemaName), usedBy: [], diff --git a/springwolf-ui/src/app/service/asyncapi/models/message.model.ts b/springwolf-ui/src/app/service/asyncapi/models/message.model.ts index 021539510..4f07f3b9c 100644 --- a/springwolf-ui/src/app/service/asyncapi/models/message.model.ts +++ b/springwolf-ui/src/app/service/asyncapi/models/message.model.ts @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: Apache-2.0 */ import { ServerBindings } from "./bindings.model"; +import { ServerAsyncApiSchema } from "./schema.model"; export interface ServerAsyncApiMessage { name: string; @@ -8,9 +9,11 @@ export interface ServerAsyncApiMessage { contentType?: string; payload: { schemaFormat: string; - schema: { - $ref: string; - }; + schema: + | { + $ref: string; + } + | ServerAsyncApiSchema; }; headers: { $ref: string }; bindings?: ServerBindings; diff --git a/springwolf-ui/src/app/service/mock/init-values.ts b/springwolf-ui/src/app/service/mock/init-values.ts index 4bc1f04f1..e0fb841bc 100644 --- a/springwolf-ui/src/app/service/mock/init-values.ts +++ b/springwolf-ui/src/app/service/mock/init-values.ts @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: Apache-2.0 */ import { Example } from "../../models/example.model"; -import { Schema } from "../../models/schema.model"; +import { Schema, SchemaRef } from "../../models/schema.model"; import { Operation } from "../../models/operation.model"; import { Binding, Bindings } from "../../models/bindings.model"; import { Message } from "../../models/message.model"; @@ -8,7 +8,7 @@ import { Info } from "../../models/info.model"; // TODO: are the init values needed? export const initExample = new Example("init"); -export const noExample = new Example("no-example-found"); +export const noExample = new Example(""); export const initBindings: Bindings = {}; export const initInfo: Info = { @@ -19,11 +19,18 @@ export const initInfo: Info = { version: "", }; +export const initSchemaRef: SchemaRef = { + ts_type: "ref", + anchorUrl: "", + name: "", + title: "", +}; + export const initMessage: Message = { bindings: new Map(), - headers: { anchorUrl: "", name: "", title: "" }, + headers: initSchemaRef, name: "", - payload: { anchorUrl: "", name: "", title: "" }, + payload: initSchemaRef, rawBindings: {}, title: "", contentType: "", @@ -38,6 +45,8 @@ export const initOperation: Operation = { }; export const initSchema: Schema = { + ts_type: "object", + title: "", name: "", anchorUrl: "", From d4c7115ebb5e273eee9f7451ed6a0bf0391962ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Fri, 13 Sep 2024 17:24:21 +0200 Subject: [PATCH 05/34] test(amqp): fix expected asyncapi.json/yaml after merge Co-authored-by: Timon Back --- .../src/test/resources/asyncapi.json | 112 +++++++++++++++--- .../src/test/resources/asyncapi.yaml | 84 ++++++++++--- 2 files changed, 162 insertions(+), 34 deletions(-) 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 510407f6d..3603516be 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json @@ -31,8 +31,8 @@ "io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" }, - "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { - "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" } }, "bindings": { @@ -163,8 +163,8 @@ "queue-create": { "address": "queue-create", "messages": { - "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { - "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String": { + "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String" } }, "bindings": { @@ -184,8 +184,8 @@ "queue-delete": { "address": "queue-delete", "messages": { - "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { - "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long": { + "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long" } }, "bindings": { @@ -331,19 +331,61 @@ "someString" ] }, - "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto": { "title": "GenericPayloadDto", "type": "object", "properties": { "genericValue": { - "type": "object", + "$ref": "#/components/schemas/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + } + }, + "description": "Generic payload model", + "examples": [ + { + "genericValue": { + "someEnum": "FOO2", + "someLong": 5, + "someString": "some string value" + } + } + ], + "required": [ + "genericValue" + ] + }, + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long": { + "title": "GenericPayloadDto", + "type": "object", + "properties": { + "genericValue": { + "type": "integer", + "description": "Generic Payload field", + "format": "int64" + } + }, + "description": "Generic payload model", + "examples": [ + { + "genericValue": 0 + } + ], + "required": [ + "genericValue" + ] + }, + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String": { + "title": "GenericPayloadDto", + "type": "object", + "properties": { + "genericValue": { + "type": "string", "description": "Generic Payload field" } }, "description": "Generic payload model", "examples": [ { - "genericValue": { } + "genericValue": "string" } ], "required": [ @@ -388,18 +430,54 @@ } } }, - "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto": { + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto": { "headers": { "$ref": "#/components/schemas/SpringRabbitListenerDefaultHeaders" }, "payload": { "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", "schema": { - "$ref": "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + "$ref": "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" } }, - "name": "io.github.springwolf.examples.amqp.dtos.GenericPayloadDto", - "title": "GenericPayloadDto", + "name": "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto", + "title": "GenericPayloadDtoExamplePayloadDto", + "bindings": { + "amqp": { + "bindingVersion": "0.3.0" + } + } + }, + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long": { + "headers": { + "$ref": "#/components/schemas/SpringRabbitListenerDefaultHeaders" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long" + } + }, + "name": "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long", + "title": "GenericPayloadDtoLong", + "bindings": { + "amqp": { + "bindingVersion": "0.3.0" + } + } + }, + "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String": { + "headers": { + "$ref": "#/components/schemas/SpringRabbitListenerDefaultHeaders" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String" + } + }, + "name": "io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String", + "title": "GenericPayloadDtoString", "bindings": { "amqp": { "bindingVersion": "0.3.0" @@ -445,7 +523,7 @@ }, "messages": [ { - "$ref": "#/channels/#/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + "$ref": "#/channels/#/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" } ] }, @@ -573,7 +651,7 @@ }, "messages": [ { - "$ref": "#/channels/queue-create/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + "$ref": "#/channels/queue-create/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String" } ] }, @@ -593,9 +671,9 @@ }, "messages": [ { - "$ref": "#/channels/queue-delete/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + "$ref": "#/channels/queue-delete/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long" } ] } } -} \ No newline at end of file +} diff --git a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml index ca18082d5..a097dbdd7 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml @@ -24,8 +24,8 @@ channels: messages: io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto: $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" - io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: - $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" bindings: amqp: is: routingKey @@ -118,8 +118,8 @@ channels: queue-create: address: queue-create messages: - io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: - $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String" bindings: amqp: is: queue @@ -133,8 +133,8 @@ channels: queue-delete: address: queue-delete messages: - io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: - $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long: + $ref: "#/components/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long" bindings: amqp: is: queue @@ -238,16 +238,43 @@ components: required: - someEnum - someString - io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: + io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto: title: GenericPayloadDto type: object properties: genericValue: - type: object + $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + description: Generic payload model + examples: + - genericValue: + someEnum: FOO2 + someLong: 5 + someString: some string value + required: + - genericValue + io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long: + title: GenericPayloadDto + type: object + properties: + genericValue: + type: integer + description: Generic Payload field + format: int64 + description: Generic payload model + examples: + - genericValue: 0 + required: + - genericValue + io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String: + title: GenericPayloadDto + type: object + properties: + genericValue: + type: string description: Generic Payload field description: Generic payload model examples: - - genericValue: {} + - genericValue: string required: - genericValue messages: @@ -260,7 +287,6 @@ components: $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" name: io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto title: AnotherPayloadDto - description: Another payload model bindings: amqp: bindingVersion: 0.3.0 @@ -276,15 +302,39 @@ components: bindings: amqp: bindingVersion: 0.3.0 - io.github.springwolf.examples.amqp.dtos.GenericPayloadDto: + io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto: headers: $ref: "#/components/schemas/SpringRabbitListenerDefaultHeaders" payload: schemaFormat: application/vnd.aai.asyncapi+json;version=3.0.0 schema: - $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" - name: io.github.springwolf.examples.amqp.dtos.GenericPayloadDto - title: GenericPayloadDto + $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" + name: io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto + title: GenericPayloadDtoExamplePayloadDto + bindings: + amqp: + bindingVersion: 0.3.0 + io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long: + headers: + $ref: "#/components/schemas/SpringRabbitListenerDefaultHeaders" + payload: + schemaFormat: application/vnd.aai.asyncapi+json;version=3.0.0 + schema: + $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long" + name: io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long + title: GenericPayloadDtoLong + bindings: + amqp: + bindingVersion: 0.3.0 + io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String: + headers: + $ref: "#/components/schemas/SpringRabbitListenerDefaultHeaders" + payload: + schemaFormat: application/vnd.aai.asyncapi+json;version=3.0.0 + schema: + $ref: "#/components/schemas/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String" + name: io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String + title: GenericPayloadDtoString bindings: amqp: bindingVersion: 0.3.0 @@ -312,7 +362,7 @@ operations: - "#" bindingVersion: 0.3.0 messages: - - $ref: "#/channels/#/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + - $ref: "#/channels/#/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoIo.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" another-queue_receive_receiveAnotherPayload: action: receive channel: @@ -391,7 +441,7 @@ operations: - queue-create bindingVersion: 0.3.0 messages: - - $ref: "#/channels/queue-create/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + - $ref: "#/channels/queue-create/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.String" queue-delete_receive_queuesToDeclareDelete: action: receive channel: @@ -403,4 +453,4 @@ operations: - queue-delete bindingVersion: 0.3.0 messages: - - $ref: "#/channels/queue-delete/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDto" + - $ref: "#/channels/queue-delete/messages/io.github.springwolf.examples.amqp.dtos.GenericPayloadDtoJava.lang.Long" From 58c0390b42702e6e9fcb30769bc9f4b05e0ff7c6 Mon Sep 17 00:00:00 2001 From: sam0r040 <93372330+sam0r040@users.noreply.github.com> Date: Fri, 13 Sep 2024 18:24:31 +0200 Subject: [PATCH 06/34] test(amqp): update rabbitmq (#971) * test(amqp): update rabbitmq Co-authored-by: Timon Back * test(e2e): fix filter for messages with title "GenericPayload" Co-authored-by: Timon Back --------- Co-authored-by: Timon Back --- springwolf-examples/e2e/tests/publishing.spec.ts | 5 +++-- .../springwolf-amqp-example/docker-compose.yml | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/springwolf-examples/e2e/tests/publishing.spec.ts b/springwolf-examples/e2e/tests/publishing.spec.ts index a8d9488dd..c177efa6b 100644 --- a/springwolf-examples/e2e/tests/publishing.spec.ts +++ b/springwolf-examples/e2e/tests/publishing.spec.ts @@ -60,7 +60,8 @@ function testPublishingEveryChannelItem() { const protocol = Object.keys(operation.bindings)[0]; const channelName = operation.channel.$ref.split("/").pop(); const messageName = messageReference.$ref.split("/").pop(); - const messageTitle = asyncApiDoc.components.messages[messageName]?.title; + const messageTitle: string = + asyncApiDoc.components.messages[messageName]?.title; const payloadName = messageName; if ( @@ -70,7 +71,7 @@ function testPublishingEveryChannelItem() { messageTitle === "MonetaryAmount" || // Issue with either MonetaryAmount of ModelConverters messageTitle === "Message" || // Unable to instantiate ExamplePayloadProtobufDto$Message class messageTitle === "VehicleBase" || // Unable to publish abstract class for discriminator demo - messageTitle === "GenericPayloadDto" || // Unable to publish generic payload (amqp) + messageTitle.startsWith("GenericPayload") || // Unable to publish generic payload (amqp) channelName === "#" || // Publishing through amqp exchange is not supported, see GH-366 channelName === "example-topic-routing-key" // Publishing through amqp exchange is not supported, see GH-366 ) { diff --git a/springwolf-examples/springwolf-amqp-example/docker-compose.yml b/springwolf-examples/springwolf-amqp-example/docker-compose.yml index 857ce12ec..7ef3d9143 100644 --- a/springwolf-examples/springwolf-amqp-example/docker-compose.yml +++ b/springwolf-examples/springwolf-amqp-example/docker-compose.yml @@ -11,10 +11,9 @@ services: - amqp amqp: - image: rabbitmq:3.8-management-alpine + image: rabbitmq:3.9-management-alpine ports: # AMQP protocol port - '5672:5672' # HTTP management UI - '15672:15672' - From aacd4a3f3e9d250950ceb0237b2a579af2445836 Mon Sep 17 00:00:00 2001 From: Timon Back Date: Sat, 14 Sep 2024 14:52:13 +0200 Subject: [PATCH 07/34] chore(gh): publish test reports (#972) --- .github/workflows/springwolf-core.yml | 12 +++++++++ .github/workflows/springwolf-plugins.yml | 15 ++++++++++- .github/workflows/springwolf-ui.yml | 11 ++++++++ springwolf-ui/jest.config.js | 4 +++ springwolf-ui/package-lock.json | 34 ++++++++++++++++++++++++ springwolf-ui/package.json | 9 +++++++ 6 files changed, 84 insertions(+), 1 deletion(-) diff --git a/.github/workflows/springwolf-core.yml b/.github/workflows/springwolf-core.yml index 5f270987a..56a937de9 100644 --- a/.github/workflows/springwolf-core.yml +++ b/.github/workflows/springwolf-core.yml @@ -8,6 +8,11 @@ on: types: [ opened, synchronize, ready_for_review ] workflow_dispatch: +permissions: + contents: read + checks: write + id-token: write + jobs: build: @@ -32,6 +37,13 @@ jobs: - name: Run build, check, analyzeDependencies run: ./gradlew -p springwolf-core build + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: success() || failure() + with: + check_name: test-core + report_paths: '**/build/test-results/test/TEST-*.xml' + - name: Publish package if: github.ref == 'refs/heads/master' run: ./gradlew -p springwolf-core publish diff --git a/.github/workflows/springwolf-plugins.yml b/.github/workflows/springwolf-plugins.yml index b1ba2b2b7..3be2fe714 100644 --- a/.github/workflows/springwolf-plugins.yml +++ b/.github/workflows/springwolf-plugins.yml @@ -8,6 +8,11 @@ on: types: [ opened, synchronize, ready_for_review ] workflow_dispatch: +permissions: + contents: read + checks: write + id-token: write + jobs: build: @@ -53,6 +58,14 @@ jobs: - name: Run build, check, analyzeDependencies on example run: ./gradlew -p ${{ env.example }} build + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: success() || failure() + with: + check_name: test-${{ matrix.plugin }}-junit + require_tests: true + report_paths: '**/build/test-results/test/TEST-*.xml' + - name: Run e2e tests run: ./gradlew -p springwolf-examples/e2e npm_run_test env: @@ -60,7 +73,7 @@ jobs: - uses: actions/upload-artifact@v4 if: always() with: - name: playwright-report-${{ matrix.plugin }} + name: test-${{ matrix.plugin }}-playwright path: springwolf-examples/e2e/playwright-report/ retention-days: 14 diff --git a/.github/workflows/springwolf-ui.yml b/.github/workflows/springwolf-ui.yml index 3611523bd..299111325 100644 --- a/.github/workflows/springwolf-ui.yml +++ b/.github/workflows/springwolf-ui.yml @@ -8,6 +8,11 @@ on: types: [ opened, synchronize, ready_for_review ] workflow_dispatch: +permissions: + contents: read + checks: write + id-token: write + env: project: springwolf-ui @@ -34,6 +39,12 @@ jobs: - name: Test run: ./gradlew -p ${{ env.project }} npm_run_test + - name: Publish Test Report + uses: mikepenz/action-junit-report@v4 + if: success() || failure() + with: + check_name: test-ui-jest + report_paths: '**/build/test-results/test/*.xml' - name: Build run: ./gradlew -p ${{ env.project }} build diff --git a/springwolf-ui/jest.config.js b/springwolf-ui/jest.config.js index 4c942e754..2df6d5cb3 100644 --- a/springwolf-ui/jest.config.js +++ b/springwolf-ui/jest.config.js @@ -4,6 +4,10 @@ const esModules = ['@angular', 'jsonpath-plus', '@stoplight', 'nimma', 'prism-co const config = { preset: 'jest-preset-angular', + reporters: [ + "default", + "jest-junit" + ], setupFilesAfterEnv: ['/setup-jest.ts'], "modulePathIgnorePatterns": [ "/build/" diff --git a/springwolf-ui/package-lock.json b/springwolf-ui/package-lock.json index e8715dad0..5edc41b90 100644 --- a/springwolf-ui/package-lock.json +++ b/springwolf-ui/package-lock.json @@ -37,6 +37,7 @@ "angular-in-memory-web-api": "^0.18.0", "esbuild": "^0.23.1", "jest": "^29.7.0", + "jest-junit": "^16.0.0", "jest-preset-angular": "^14.2.2", "typescript": "^5.5.4" } @@ -13183,6 +13184,32 @@ "fsevents": "^2.3.2" } }, + "node_modules/jest-junit": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/jest-junit/-/jest-junit-16.0.0.tgz", + "integrity": "sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mkdirp": "^1.0.4", + "strip-ansi": "^6.0.1", + "uuid": "^8.3.2", + "xml": "^1.0.1" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/jest-junit/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/jest-leak-detector": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", @@ -21234,6 +21261,13 @@ } } }, + "node_modules/xml": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true, + "license": "MIT" + }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", diff --git a/springwolf-ui/package.json b/springwolf-ui/package.json index 59c333513..822b8affd 100644 --- a/springwolf-ui/package.json +++ b/springwolf-ui/package.json @@ -40,7 +40,16 @@ "angular-in-memory-web-api": "^0.18.0", "esbuild": "^0.23.1", "jest": "^29.7.0", + "jest-junit": "^16.0.0", "jest-preset-angular": "^14.2.2", "typescript": "^5.5.4" + }, + "jest-junit": { + "ancestorSeparator": " › ", + "outputDirectory": "build/test-results/test", + "uniqueOutputName": "false", + "suiteNameTemplate": "{filepath}", + "classNameTemplate": "{classname}", + "titleTemplate": "{title}" } } From 3b4a3ea33739984b52be19a1313d1fa5830d03a0 Mon Sep 17 00:00:00 2001 From: Timon Back Date: Sat, 14 Sep 2024 15:07:10 +0200 Subject: [PATCH 08/34] chore(gh): add dependabot for docker (#970) --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4a689ba87..77788438d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,6 +11,12 @@ updates: schedule: interval: "weekly" + - package-ecosystem: "docker" + directory: "/" + rebase-strategy: "disabled" + schedule: + interval: "weekly" + - package-ecosystem: "gradle" directory: "/" rebase-strategy: "disabled" From 15b57497cbe618f212a1f1d11081eb2075292a46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 15:11:18 +0200 Subject: [PATCH 09/34] chore(deps-dev): Bump @types/node in /springwolf-ui (#965) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 18.19.48 to 18.19.50. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- springwolf-ui/package-lock.json | 8 ++++---- springwolf-ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/springwolf-ui/package-lock.json b/springwolf-ui/package-lock.json index 5edc41b90..fce1a5e89 100644 --- a/springwolf-ui/package-lock.json +++ b/springwolf-ui/package-lock.json @@ -33,7 +33,7 @@ "@asyncapi/parser": "^3.2.2", "@testing-library/angular": "^17.3.1", "@types/jest": "^29.5.12", - "@types/node": "^18.19.48", + "@types/node": "^18.19.50", "angular-in-memory-web-api": "^0.18.0", "esbuild": "^0.23.1", "jest": "^29.7.0", @@ -6820,9 +6820,9 @@ } }, "node_modules/@types/node": { - "version": "18.19.48", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.48.tgz", - "integrity": "sha512-7WevbG4ekUcRQSZzOwxWgi5dZmTak7FaxXDoW7xVxPBmKx1rTzfmRLkeCgJzcbBnOV2dkhAPc8cCeT6agocpjg==", + "version": "18.19.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.50.tgz", + "integrity": "sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg==", "dev": true, "dependencies": { "undici-types": "~5.26.4" diff --git a/springwolf-ui/package.json b/springwolf-ui/package.json index 822b8affd..9010480ea 100644 --- a/springwolf-ui/package.json +++ b/springwolf-ui/package.json @@ -36,7 +36,7 @@ "@asyncapi/parser": "^3.2.2", "@testing-library/angular": "^17.3.1", "@types/jest": "^29.5.12", - "@types/node": "^18.19.48", + "@types/node": "^18.19.50", "angular-in-memory-web-api": "^0.18.0", "esbuild": "^0.23.1", "jest": "^29.7.0", From 7c3be747d1f65771c0b9e6ad4ec0e93967141346 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 15:43:10 +0200 Subject: [PATCH 10/34] chore(deps): Bump io.confluent:kafka-protobuf-serializer (#978) Bumps [io.confluent:kafka-protobuf-serializer](https://github.com/confluentinc/schema-registry) from 7.7.0 to 7.7.1. - [Commits](https://github.com/confluentinc/schema-registry/commits) --- updated-dependencies: - dependency-name: io.confluent:kafka-protobuf-serializer dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 535c5d704..ef7375c5e 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -42,7 +42,7 @@ ext { kafkaClientsVersion = '3.7.1' kafkaStreamsVersion = '3.8.0' - kafkaProtobufSerializerVersion = '7.7.0' + kafkaProtobufSerializerVersion = '7.7.1' jacksonVersion = '2.17.2' jacksonDatatypeProtobufVersion = '0.9.15' From 60bec93d87f1f3a8ebea47803d9c3b713e790ac4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 15:43:28 +0200 Subject: [PATCH 11/34] chore(deps): Bump io.confluent:kafka-avro-serializer from 7.7.0 to 7.7.1 (#977) Bumps [io.confluent:kafka-avro-serializer](https://github.com/confluentinc/schema-registry) from 7.7.0 to 7.7.1. - [Commits](https://github.com/confluentinc/schema-registry/commits) --- updated-dependencies: - dependency-name: io.confluent:kafka-avro-serializer dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index ef7375c5e..f908b420f 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -37,7 +37,7 @@ ext { commonsLang3Version = '3.17.0' - kafkaAvroSerializerVersion = '7.7.0' + kafkaAvroSerializerVersion = '7.7.1' kafkaClientsVersion = '3.7.1' kafkaStreamsVersion = '3.8.0' From fa63e49f02a27762c38b49fd6f25251e08676b98 Mon Sep 17 00:00:00 2001 From: Timon Back Date: Sun, 15 Sep 2024 17:50:08 +0200 Subject: [PATCH 12/34] Refactor/prepare async class level scanner (#964) * refactor(core): align AsyncAnnotationScanner as MethodLevel * refactor(core): centralize getRelevantMethods in AnnotationScannerUtil * refactor(core): align Spring and Async Scanners * refactor(core): cleanup * test(core): add AnnotationScannerUtilTest * refactor(core): extract findAnnotatedMethods for class to AnnotationScannerUtil * refactor(core): break up class hierarchy of scanners * refactor(core): move annotation utils to own package * feat(core): add class level AsyncListener/AsyncPublisher support * test(core): update after rebase * feat(core): apply review comments * feat(core): use beans instead of custom di --- .../asyncapi/annotations/AsyncListener.java | 2 +- .../asyncapi/annotations/AsyncPublisher.java | 2 +- .../channels/DefaultChannelsService.java | 4 +- .../asyncapi/scanners/ChannelsScanner.java | 2 + .../beans/DefaultBeanMethodsScanner.java | 4 +- .../scanners/channels/ChannelMerger.java | 18 +- .../channels/ChannelsInClassScanner.java | 10 + ...ava => ChannelsInClassScannerAdapter.java} | 13 +- ...ncAnnotationClassLevelChannelsScanner.java | 40 ++ ...cAnnotationMethodLevelChannelsScanner.java | 34 + ...ingAnnotationChannelsScannerDelegator.java | 11 - ...ngAnnotationClassLevelChannelsScanner.java | 93 +-- ...gAnnotationMethodLevelChannelsScanner.java | 86 +-- .../spring/ConfigurationClassScanner.java | 4 +- .../common/AsyncAnnotationProvider.java | 13 + .../common/AsyncAnnotationScanner.java | 145 ----- .../scanners/common/MessageHelper.java | 22 +- .../common/annotation/AllMethods.java | 8 + .../annotation/AnnotationScannerUtil.java | 92 +++ .../AnnotationUtil.java} | 30 +- .../AsyncAnnotationUtil.java | 3 +- .../annotation/MethodAndAnnotation.java | 6 + .../AsyncAnnotationChannelService.java} | 73 +-- .../SpringAnnotationChannelService.java | 32 + .../AsyncAnnotationMessageService.java | 81 +++ .../SpringAnnotationMessageService.java} | 12 +- .../SpringAnnotationMessagesService.java} | 66 +- .../AsyncAnnotationOperationService.java | 78 +++ .../SpringAnnotationOperationService.java | 42 ++ .../SpringAnnotationOperationsService.java | 45 ++ .../utils/StringValueResolverProxy.java | 22 + ...tor.java => OperationsInClassScanner.java} | 4 +- ...a => OperationsInClassScannerAdapter.java} | 5 +- ...AnnotationClassLevelOperationsScanner.java | 71 +++ ...nnotationMethodLevelOperationsScanner.java | 57 ++ .../AsyncAnnotationOperationsScanner.java | 73 --- .../annotations/OperationCustomizer.java | 2 + ...AnnotationClassLevelOperationsScanner.java | 96 +-- ...nnotationMethodLevelOperationsScanner.java | 82 +-- .../SpringwolfAutoConfiguration.java | 20 + .../SpringwolfScannerConfiguration.java | 243 ++++++-- ...DefaultChannelsServiceIntegrationTest.java | 21 +- .../scanners/channels/ChannelMergerTest.java | 45 +- .../ChannelsInClassScannerAdapterTest.java | 83 +++ .../SpringAnnotationChannelsScannerTest.java | 83 --- .../AsyncAnnotationChannelsScannerTest.java | 495 --------------- ...notationClassLevelChannelsScannerTest.java | 82 +++ ...otationMethodLevelChannelsScannerTest.java | 84 +++ ...ssLevelChannelsScannerIntegrationTest.java | 35 +- ...notationClassLevelChannelsScannerTest.java | 142 +---- ...odLevelChannelsScannerIntegrationTest.java | 35 +- ...otationMethodLevelChannelsScannerTest.java | 238 +------ .../annotation/AnnotationScannerUtilTest.java | 174 ++++++ .../AnnotationUtilTest.java} | 93 ++- .../AsyncAnnotationUtilTest.java | 2 +- .../AsyncAnnotationChannelServiceTest.java | 189 ++++++ .../AsyncAnnotationMessageServiceTest.java | 159 +++++ .../SpringAnnotationOperationServiceTest.java | 82 +++ .../operations/OperationMergerTest.java | 8 +- ... OperationsInClassScannerAdapterTest.java} | 18 +- ...tationClassLevelOperationsScannerTest.java | 94 +++ ...ationMethodLevelOperationsScannerTest.java | 102 +++ .../AsyncAnnotationOperationsScannerTest.java | 586 ------------------ ...tationClassLevelOperationsScannerTest.java | 88 +-- ...ationMethodLevelOperationsScannerTest.java | 89 +-- .../AsyncApiDocumentIntegrationTest.java | 20 +- .../listener/ListenerApplication.java | 10 + .../publisher/PublisherApplication.java | 10 + .../amqp/SpringContextIntegrationTest.java | 14 +- .../kafka/SpringContextIntegrationTest.java | 15 +- .../SpringwolfAmqpScannerConfiguration.java | 74 ++- .../CloudStreamFunctionChannelsScanner.java | 10 +- .../SpringwolfJmsScannerConfiguration.java | 37 +- .../SpringwolfKafkaScannerConfiguration.java | 75 ++- .../SpringwolfSqsScannerConfiguration.java | 38 +- .../annotations/SendToCustomizer.java | 4 +- .../annotations/SendToUserCustomizer.java | 4 +- .../SpringwolfStompScannerConfiguration.java | 109 ++-- 78 files changed, 2614 insertions(+), 2579 deletions(-) create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScanner.java rename springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/{SpringAnnotationChannelsScanner.java => ChannelsInClassScannerAdapter.java} (57%) create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationClassLevelChannelsScanner.java create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationMethodLevelChannelsScanner.java delete mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationChannelsScannerDelegator.java create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationProvider.java delete mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AllMethods.java create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationScannerUtil.java rename springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/{utils/AnnotationScannerUtil.java => annotation/AnnotationUtil.java} (56%) rename springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/{utils => annotation}/AsyncAnnotationUtil.java (98%) create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/MethodAndAnnotation.java rename springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/{channels/AsyncAnnotationChannelsScanner.java => common/channel/AsyncAnnotationChannelService.java} (57%) create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/SpringAnnotationChannelService.java create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java rename springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/{MethodLevelAnnotationScanner.java => message/SpringAnnotationMessageService.java} (85%) rename springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/{ClassLevelAnnotationScanner.java => message/SpringAnnotationMessagesService.java} (53%) create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/AsyncAnnotationOperationService.java create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationService.java create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationsService.java create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/StringValueResolverProxy.java rename springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/{annotations/SpringAnnotationOperationsScannerDelegator.java => OperationsInClassScanner.java} (62%) rename springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/{SpringAnnotationOperationsScanner.java => OperationsInClassScannerAdapter.java} (77%) create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationClassLevelOperationsScanner.java create mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScanner.java delete mode 100644 springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java create mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScannerAdapterTest.java delete mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/SpringAnnotationChannelsScannerTest.java delete mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java create mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationClassLevelChannelsScannerTest.java create mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationMethodLevelChannelsScannerTest.java create mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationScannerUtilTest.java rename springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/{utils/AnnotationScannerUtilTest.java => annotation/AnnotationUtilTest.java} (62%) rename springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/{utils => annotation}/AsyncAnnotationUtilTest.java (99%) create mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelServiceTest.java create mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageServiceTest.java create mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationServiceTest.java rename springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/{SpringAnnotationOperationsScannerTest.java => OperationsInClassScannerAdapterTest.java} (72%) create mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationClassLevelOperationsScannerTest.java create mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScannerTest.java delete mode 100644 springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScannerTest.java diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/annotations/AsyncListener.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/annotations/AsyncListener.java index 2a08d5751..3cb6fba28 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/annotations/AsyncListener.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/annotations/AsyncListener.java @@ -31,7 +31,7 @@ * Maintainer node: move to io.github.springwolf.core.asyncapi.annotation */ @Retention(RetentionPolicy.RUNTIME) -@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +@Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Repeatable(AsyncListeners.class) @Inherited public @interface AsyncListener { diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/annotations/AsyncPublisher.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/annotations/AsyncPublisher.java index 14a697452..b06e00a75 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/annotations/AsyncPublisher.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/annotations/AsyncPublisher.java @@ -28,7 +28,7 @@ * */ @Retention(RetentionPolicy.RUNTIME) -@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +@Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Repeatable(AsyncPublishers.class) @Inherited public @interface AsyncPublisher { diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/channels/DefaultChannelsService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/channels/DefaultChannelsService.java index bf7daee7f..c5c813c99 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/channels/DefaultChannelsService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/channels/DefaultChannelsService.java @@ -27,12 +27,12 @@ public class DefaultChannelsService implements ChannelsService { */ @Override public Map findChannels() { - List> foundChannelItems = new ArrayList<>(); + List foundChannelItems = new ArrayList<>(); for (ChannelsScanner scanner : channelsScanners) { try { Map channels = scanner.scan(); - foundChannelItems.addAll(channels.entrySet()); + foundChannelItems.addAll(channels.values()); } catch (Exception e) { log.error("An error was encountered during channel scanning with {}: {}", scanner, e.getMessage(), e); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/ChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/ChannelsScanner.java index e8bd9fc0e..f84b11814 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/ChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/ChannelsScanner.java @@ -9,6 +9,8 @@ public interface ChannelsScanner { /** * @return A mapping of channel names to their respective channel object for a given protocol. + * + * Maintainer note: Use {@link ChannelObject#getChannelId()} as the key for the map. */ Map scan(); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/beans/DefaultBeanMethodsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/beans/DefaultBeanMethodsScanner.java index c3b673841..c8f63dd77 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/beans/DefaultBeanMethodsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/beans/DefaultBeanMethodsScanner.java @@ -2,7 +2,7 @@ package io.github.springwolf.core.asyncapi.scanners.beans; import io.github.springwolf.core.asyncapi.scanners.classes.spring.ConfigurationClassScanner; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; @@ -24,7 +24,7 @@ public Set getBeanMethods() { .map(Class::getDeclaredMethods) .map(Arrays::asList) .flatMap(List::stream) - .filter(method -> AnnotationScannerUtil.findAnnotation(Bean.class, method) != null) + .filter(method -> AnnotationUtil.findFirstAnnotation(Bean.class, method) != null) .collect(toSet()); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMerger.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMerger.java index 2aedbe427..14cc7a639 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMerger.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMerger.java @@ -17,23 +17,23 @@ public class ChannelMerger { private ChannelMerger() {} /** - * Merges multiple channels by channel name + * Merges multiple channels *

- * Given two channels for the same channel name, the first seen Channel is used + * Given two channels for the same channel id, the first seen Channel is used * Messages within channels are merged * - * @param channelEntries Ordered pairs of channel name to Channel * @return A map of channelId to a single Channel */ - public static Map mergeChannels(List> channelEntries) { + public static Map mergeChannels(List channels) { Map mergedChannels = new HashMap<>(); - for (Map.Entry entry : channelEntries) { - if (!mergedChannels.containsKey(entry.getKey())) { - mergedChannels.put(entry.getKey(), entry.getValue()); + for (ChannelObject channel : channels) { + if (!mergedChannels.containsKey(channel.getChannelId())) { + mergedChannels.put(channel.getChannelId(), channel); } else { - ChannelObject channel = mergeChannel(mergedChannels.get(entry.getKey()), entry.getValue()); - mergedChannels.put(entry.getKey(), channel); + ChannelObject existingChannel = mergedChannels.get(channel.getChannelId()); + ChannelObject mergedChannel = mergeChannel(existingChannel, channel); + mergedChannels.put(mergedChannel.getChannelId(), mergedChannel); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScanner.java new file mode 100644 index 000000000..f647fd01b --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScanner.java @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.channels; + +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; + +import java.util.List; + +public interface ChannelsInClassScanner { + List scan(Class clazz); +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/SpringAnnotationChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScannerAdapter.java similarity index 57% rename from springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/SpringAnnotationChannelsScanner.java rename to springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScannerAdapter.java index c5b887f0a..563373601 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/SpringAnnotationChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScannerAdapter.java @@ -3,33 +3,34 @@ import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; -import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationChannelsScannerDelegator; import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; import lombok.RequiredArgsConstructor; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @RequiredArgsConstructor -public class SpringAnnotationChannelsScanner implements ChannelsScanner { +public class ChannelsInClassScannerAdapter implements ChannelsScanner { private final ClassScanner classScanner; - private final SpringAnnotationChannelsScannerDelegator springAnnotationChannelsScannerDelegator; + private final ChannelsInClassScanner channelsInClassScanner; @Override public Map scan() { Set> components = classScanner.scan(); - List> channels = mapToChannels(components); + List channels = mapToChannels(components); return ChannelMerger.mergeChannels(channels); } - private List> mapToChannels(Set> components) { + private List mapToChannels(Set> components) { return components.stream() - .flatMap(springAnnotationChannelsScannerDelegator::scan) + .map(channelsInClassScanner::scan) + .flatMap(Collection::stream) .toList(); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationClassLevelChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationClassLevelChannelsScanner.java new file mode 100644 index 000000000..7e2df93ec --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationClassLevelChannelsScanner.java @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.channels.annotations; + +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScanner; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AllMethods; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; +import io.github.springwolf.core.asyncapi.scanners.common.channel.AsyncAnnotationChannelService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.lang.annotation.Annotation; +import java.util.List; + +@Slf4j +@RequiredArgsConstructor +public class AsyncAnnotationClassLevelChannelsScanner + implements ChannelsInClassScanner { + + private final AsyncAnnotationProvider asyncAnnotationProvider; + private final AsyncAnnotationChannelService asyncAnnotationChannelService; + + @Override + public List scan(Class clazz) { + Class annotation = this.asyncAnnotationProvider.getAnnotation(); + return AnnotationScannerUtil.findAnnotatedMethods(clazz, annotation, AllMethods.class, (cl, m) -> { + ClassAnnotation classAnnotation = AnnotationUtil.findFirstAnnotation(annotation, clazz); + return m.stream().map(method -> new MethodAndAnnotation<>(method.method(), classAnnotation)); + }) + .map(this::mapMethodToChannel) + .toList(); + } + + private ChannelObject mapMethodToChannel(MethodAndAnnotation methodAndAnnotation) { + return this.asyncAnnotationChannelService.buildChannel(methodAndAnnotation); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationMethodLevelChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationMethodLevelChannelsScanner.java new file mode 100644 index 000000000..db405f54c --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationMethodLevelChannelsScanner.java @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.channels.annotations; + +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScanner; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; +import io.github.springwolf.core.asyncapi.scanners.common.channel.AsyncAnnotationChannelService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.lang.annotation.Annotation; +import java.util.List; + +@Slf4j +@RequiredArgsConstructor +public class AsyncAnnotationMethodLevelChannelsScanner + implements ChannelsInClassScanner { + + private final AsyncAnnotationProvider asyncAnnotationProvider; + private final AsyncAnnotationChannelService asyncAnnotationChannelService; + + @Override + public List scan(Class clazz) { + return AnnotationScannerUtil.findAnnotatedMethods(clazz, this.asyncAnnotationProvider.getAnnotation()) + .map(this::mapMethodToChannel) + .toList(); + } + + private ChannelObject mapMethodToChannel(MethodAndAnnotation methodAndAnnotation) { + return this.asyncAnnotationChannelService.buildChannel(methodAndAnnotation); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationChannelsScannerDelegator.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationChannelsScannerDelegator.java deleted file mode 100644 index 198f674de..000000000 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationChannelsScannerDelegator.java +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.channels.annotations; - -import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; - -import java.util.Map; -import java.util.stream.Stream; - -public interface SpringAnnotationChannelsScannerDelegator { - Stream> scan(Class clazz); -} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java index 0ed3c95c2..73b3853da 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java @@ -1,89 +1,56 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.channels.annotations; -import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; -import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; -import io.github.springwolf.core.asyncapi.components.ComponentsService; -import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import io.github.springwolf.core.asyncapi.scanners.common.ClassLevelAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersBuilder; -import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; +import io.github.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScanner; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessagesService; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; @Slf4j +@RequiredArgsConstructor public class SpringAnnotationClassLevelChannelsScanner< ClassAnnotation extends Annotation, MethodAnnotation extends Annotation> - extends ClassLevelAnnotationScanner - implements SpringAnnotationChannelsScannerDelegator { + implements ChannelsInClassScanner { - public SpringAnnotationClassLevelChannelsScanner( - Class classAnnotationClass, - Class methodAnnotationClass, - BindingFactory bindingFactory, - AsyncHeadersBuilder asyncHeadersBuilder, - PayloadMethodService payloadMethodService, - HeaderClassExtractor headerClassExtractor, - ComponentsService componentsService) { - super( - classAnnotationClass, - methodAnnotationClass, - bindingFactory, - asyncHeadersBuilder, - payloadMethodService, - headerClassExtractor, - componentsService); - } + private final Class classAnnotationClass; + private final Class methodAnnotationClass; + private final SpringAnnotationMessagesService springAnnotationMessagesService; + private final SpringAnnotationChannelService springAnnotationChannelService; @Override - public Stream> scan(Class clazz) { - log.debug( - "Scanning class \"{}\" for @\"{}\" annotated methods", clazz.getName(), classAnnotationClass.getName()); - - return Stream.of(clazz) - .filter(AnnotationScannerUtil::notHidden) - .filter(this::isClassAnnotated) - .flatMap(this::mapClassToChannel); + public List scan(Class clazz) { + return AnnotationScannerUtil.findAnnotatedMethods( + clazz, classAnnotationClass, methodAnnotationClass, this::mapClassToChannel) + .toList(); } - private Stream> mapClassToChannel(Class component) { - log.debug("Mapping class \"{}\" to channels", component.getName()); - - ClassAnnotation classAnnotation = AnnotationScannerUtil.findAnnotationOrThrow(classAnnotationClass, component); - - Set annotatedMethods = getAnnotatedMethods(component); - if (annotatedMethods.isEmpty()) { - return Stream.empty(); - } - - ChannelObject channelItem = buildChannelItem(classAnnotation, annotatedMethods); - return Stream.of(Map.entry(channelItem.getChannelId(), channelItem)); - } + private Stream mapClassToChannel( + Class component, Set> annotatedMethods) { + ClassAnnotation classAnnotation = AnnotationUtil.findFirstAnnotationOrThrow(classAnnotationClass, component); + Set methods = + annotatedMethods.stream().map(MethodAndAnnotation::method).collect(Collectors.toSet()); + Map messages = new HashMap<>(springAnnotationMessagesService.buildMessages( + classAnnotation, methods, SpringAnnotationMessagesService.MessageType.CHANNEL)); - private ChannelObject buildChannelItem(ClassAnnotation classAnnotation, Set methods) { - var messages = buildMessages(classAnnotation, methods, MessageType.CHANNEL); - return buildChannelItem(classAnnotation, messages); + return mapClassToChannel(classAnnotation, messages); } - private ChannelObject buildChannelItem(ClassAnnotation classAnnotation, Map messages) { - Map channelBinding = bindingFactory.buildChannelBinding(classAnnotation); - Map chBinding = channelBinding != null ? new HashMap<>(channelBinding) : null; - String channelName = bindingFactory.getChannelName(classAnnotation); - return ChannelObject.builder() - .channelId(ReferenceUtil.toValidId(channelName)) - .address(channelName) - .bindings(chBinding) - .messages(new HashMap<>(messages)) - .build(); + private Stream mapClassToChannel(ClassAnnotation classAnnotation, Map messages) { + return Stream.of(springAnnotationChannelService.buildChannel(classAnnotation, messages)); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java index e1b64ce60..2cf7cacf8 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java @@ -1,91 +1,53 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.channels.annotations; -import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; -import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.Message; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.core.asyncapi.components.ComponentsService; -import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import io.github.springwolf.core.asyncapi.scanners.common.MethodLevelAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersBuilder; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScanner; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.stream.Stream; @Slf4j +@RequiredArgsConstructor public class SpringAnnotationMethodLevelChannelsScanner - extends MethodLevelAnnotationScanner implements SpringAnnotationChannelsScannerDelegator { + implements ChannelsInClassScanner { private final Class methodAnnotationClass; private final PayloadMethodService payloadMethodService; private final HeaderClassExtractor headerClassExtractor; - - public SpringAnnotationMethodLevelChannelsScanner( - Class methodAnnotationClass, - BindingFactory bindingFactory, - AsyncHeadersBuilder asyncHeadersBuilder, - PayloadMethodService payloadMethodService, - HeaderClassExtractor headerClassExtractor, - ComponentsService componentsService) { - super(bindingFactory, asyncHeadersBuilder, componentsService); - this.methodAnnotationClass = methodAnnotationClass; - this.payloadMethodService = payloadMethodService; - this.headerClassExtractor = headerClassExtractor; - } + private final SpringAnnotationChannelService springAnnotationChannelService; + private final SpringAnnotationMessageService springAnnotationMessageService; @Override - public Stream> scan(Class clazz) { - log.debug( - "Scanning class \"{}\" for @\"{}\" annotated methods", - clazz.getName(), - methodAnnotationClass.getName()); - - return Arrays.stream(clazz.getDeclaredMethods()) - .filter(AnnotationScannerUtil::notHidden) - .filter(AnnotationScannerUtil::isMethodInSourceCode) - .filter(method -> AnnotationScannerUtil.findAnnotation(methodAnnotationClass, method) != null) - .map(this::mapMethodToChannel); + public List scan(Class clazz) { + return AnnotationScannerUtil.findAnnotatedMethods(clazz, methodAnnotationClass) + .map(this::mapMethodToChannel) + .toList(); } - private Map.Entry mapMethodToChannel(Method method) { - log.debug("Mapping method \"{}\" to channels", method.getName()); - - MethodAnnotation annotation = AnnotationScannerUtil.findAnnotationOrThrow(methodAnnotationClass, method); + private ChannelObject mapMethodToChannel(MethodAndAnnotation method) { + MethodAnnotation annotation = AnnotationUtil.findFirstAnnotationOrThrow(methodAnnotationClass, method.method()); - PayloadSchemaObject payloadSchema = payloadMethodService.extractSchema(method); - - SchemaObject headerSchema = headerClassExtractor.extractHeader(method, payloadSchema); - ChannelObject channelItem = buildChannelItem(annotation, payloadSchema, headerSchema); - return Map.entry(channelItem.getChannelId(), channelItem); - } - - private ChannelObject buildChannelItem( - MethodAnnotation annotation, PayloadSchemaObject payloadSchema, SchemaObject headerSchema) { - MessageObject message = buildMessage(annotation, payloadSchema, headerSchema); - return buildChannelItem(annotation, message); - } + PayloadSchemaObject payloadSchema = payloadMethodService.extractSchema(method.method()); + SchemaObject headerSchema = headerClassExtractor.extractHeader(method.method(), payloadSchema); + MessageObject message = springAnnotationMessageService.buildMessage(annotation, payloadSchema, headerSchema); + Map messages = Map.of(message.getMessageId(), MessageReference.toComponentMessage(message)); - private ChannelObject buildChannelItem(MethodAnnotation annotation, MessageObject message) { - Map channelBinding = bindingFactory.buildChannelBinding(annotation); - Map chBinding = channelBinding != null ? new HashMap<>(channelBinding) : null; - String channelName = bindingFactory.getChannelName(annotation); - return ChannelObject.builder() - .channelId(ReferenceUtil.toValidId(channelName)) - .address(channelName) - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .bindings(chBinding) - .build(); + return springAnnotationChannelService.buildChannel(annotation, messages); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/classes/spring/ConfigurationClassScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/classes/spring/ConfigurationClassScanner.java index 36bc139f2..1e1d6a987 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/classes/spring/ConfigurationClassScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/classes/spring/ConfigurationClassScanner.java @@ -2,7 +2,7 @@ package io.github.springwolf.core.asyncapi.scanners.classes.spring; import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; @@ -18,7 +18,7 @@ public class ConfigurationClassScanner implements ClassScanner { public Set> scan() { return scanner.scan().stream() // All Configurations are also Components - .filter((cls) -> AnnotationScannerUtil.findAnnotation(Configuration.class, cls) != null) + .filter((cls) -> AnnotationUtil.findFirstAnnotation(Configuration.class, cls) != null) .collect(Collectors.toSet()); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationProvider.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationProvider.java new file mode 100644 index 000000000..87895bb65 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationProvider.java @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common; + +import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; + +public interface AsyncAnnotationProvider { + Class getAnnotation(); + + AsyncOperation getAsyncOperation(A annotation); + + OperationAction getOperationType(); +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java deleted file mode 100644 index f876141bd..000000000 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java +++ /dev/null @@ -1,145 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.common; - -import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; -import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; -import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; -import io.github.springwolf.asyncapi.v3.model.operation.Operation; -import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; -import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; -import io.github.springwolf.core.asyncapi.components.ComponentsService; -import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.bindings.operations.OperationBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AsyncAnnotationUtil; -import io.github.springwolf.core.asyncapi.scanners.common.utils.TextUtils; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringValueResolver; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; - -@Slf4j -@RequiredArgsConstructor -public abstract class AsyncAnnotationScanner implements EmbeddedValueResolverAware { - - protected final AsyncAnnotationProvider asyncAnnotationProvider; - protected final PayloadAsyncOperationService payloadAsyncOperationService; - protected final ComponentsService componentsService; - protected final List operationBindingProcessors; - protected final List messageBindingProcessors; - protected StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } - - protected Stream> getAnnotatedMethods(Class type) { - Class annotationClass = this.asyncAnnotationProvider.getAnnotation(); - log.debug("Scanning class \"{}\" for @\"{}\" annotated methods", type.getName(), annotationClass.getName()); - - return Arrays.stream(ReflectionUtils.getAllDeclaredMethods(type)) - .filter(AnnotationScannerUtil::isMethodInSourceCode) - .filter(method -> AnnotationScannerUtil.findAnnotation(annotationClass, method) != null) - .peek(method -> log.debug("Mapping method \"{}\" to channels", method.getName())) - .flatMap(method -> AnnotationScannerUtil.findAnnotations(annotationClass, method).stream() - .map(annotation -> new MethodAndAnnotation<>(method, annotation))); - } - - protected Operation buildOperation(AsyncOperation asyncOperation, Method method, String channelId) { - String description = this.resolver.resolveStringValue(asyncOperation.description()); - if (StringUtils.isBlank(description)) { - description = "Auto-generated description"; - } else { - description = TextUtils.trimIndent(description); - } - - String operationTitle = - StringUtils.joinWith("_", channelId, this.asyncAnnotationProvider.getOperationType().type); - - Map operationBinding = - AsyncAnnotationUtil.processOperationBindingFromAnnotation(method, operationBindingProcessors); - Map opBinding = operationBinding != null ? new HashMap<>(operationBinding) : null; - MessageObject message = buildMessage(asyncOperation, method); - - return Operation.builder() - .channel(ChannelReference.fromChannel(channelId)) - .description(description) - .title(operationTitle) - .messages(List.of(MessageReference.toChannelMessage(channelId, message))) - .bindings(opBinding) - .build(); - } - - protected MessageObject buildMessage(AsyncOperation operationData, Method method) { - PayloadSchemaObject payloadSchema = payloadAsyncOperationService.extractSchema(operationData, method); - - SchemaObject headerSchema = AsyncAnnotationUtil.getAsyncHeaders(operationData, resolver); - String headerSchemaName = this.componentsService.registerSchema(headerSchema); - - Map messageBinding = - AsyncAnnotationUtil.processMessageBindingFromAnnotation(method, messageBindingProcessors); - - var messagePayload = MessagePayload.of( - MultiFormatSchema.builder().schema(payloadSchema.payload()).build()); - - String description = operationData.message().description(); - if (StringUtils.isBlank(description) && payloadSchema.payload() instanceof SchemaObject) { - String payloadDescription = ((SchemaObject) payloadSchema.payload()).getDescription(); - if (StringUtils.isNotBlank(payloadDescription)) { - description = payloadDescription; - } - } - if (StringUtils.isNotBlank(description)) { - description = this.resolver.resolveStringValue(description); - description = TextUtils.trimIndent(description); - } else { - description = null; - } - - var builder = MessageObject.builder() - .messageId(payloadSchema.name()) - .name(payloadSchema.name()) - .title(payloadSchema.title()) - .description(description) - .payload(messagePayload) - .headers(MessageHeaders.of(MessageReference.toSchema(headerSchemaName))) - .bindings(messageBinding); - - // Retrieve the Message information obtained from the @AsyncMessage annotation. These values have higher - // priority so if we find them, we need to override the default values. - AsyncAnnotationUtil.processAsyncMessageAnnotation(builder, operationData.message(), this.resolver); - - MessageObject message = builder.build(); - this.componentsService.registerMessage(message); - return message; - } - - public interface AsyncAnnotationProvider { - Class getAnnotation(); - - AsyncOperation getAsyncOperation(A annotation); - - OperationAction getOperationType(); - } - - protected record MethodAndAnnotation(Method method, A annotation) {} -} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelper.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelper.java index ccd3c37ed..70cae2199 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelper.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelper.java @@ -11,6 +11,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -23,12 +24,8 @@ public class MessageHelper { private MessageHelper() {} public static Map toMessagesMap(Set messages) { - if (messages.isEmpty()) { - throw new IllegalArgumentException("messages must not be empty"); - } - - return new ArrayList<>(messages.stream().collect(Collectors.toCollection(messageSupplier))) - .stream().collect(Collectors.toMap(MessageObject::getMessageId, MessageReference::toComponentMessage)); + Function aggregator = MessageReference::toComponentMessage; + return toMessageReferences(messages, aggregator); } public static Map toOperationsMessagesMap( @@ -37,15 +34,18 @@ public static Map toOperationsMessagesMap( throw new IllegalArgumentException("channelName must not be empty"); } + Function aggregator = (message) -> + MessageReference.toChannelMessage(ReferenceUtil.toValidId(channelName), message.getMessageId()); + return toMessageReferences(messages, aggregator); + } + + private static Map toMessageReferences( + Set messages, Function messageReferenceFunction) { if (messages.isEmpty()) { throw new IllegalArgumentException("messages must not be empty"); } return new ArrayList<>(messages.stream().collect(Collectors.toCollection(messageSupplier))) - .stream() - .collect(Collectors.toMap( - MessageObject::getMessageId, - e -> MessageReference.toChannelMessage( - ReferenceUtil.toValidId(channelName), e.getMessageId()))); + .stream().collect(Collectors.toMap(MessageObject::getMessageId, messageReferenceFunction)); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AllMethods.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AllMethods.java new file mode 100644 index 000000000..5e1c5dd19 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AllMethods.java @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.annotation; + +/** + * Internal interface to indicate that all methods of a class should be used in scanners + * instead of filtering for a specific annotation. + */ +public @interface AllMethods {} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationScannerUtil.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationScannerUtil.java new file mode 100644 index 000000000..906e69d98 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationScannerUtil.java @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.annotation; + +import io.swagger.v3.oas.annotations.Hidden; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.ReflectionUtils; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Slf4j +public class AnnotationScannerUtil { + + private AnnotationScannerUtil() {} + + /** + * Find all annotated methods on an annotated class + * + * Transform is only called if methods are found + */ + public static Stream findAnnotatedMethods( + Class clazz, + Class classAnnotationClass, + Class methodAnnotationClass, + BiFunction, Set>, Stream> transformer) { + log.debug("Scanning class \"{}\" for @\"{}\" annotation", clazz.getName(), classAnnotationClass.getName()); + Set> methods = Stream.of(clazz) + .filter(it -> AnnotationScannerUtil.isClassRelevant(it, classAnnotationClass)) + .peek(it -> log.debug("Mapping class \"{}\"", it.getName())) + .flatMap(it -> AnnotationScannerUtil.findAnnotatedMethods(it, methodAnnotationClass)) + .collect(Collectors.toSet()); + + if (methods.isEmpty()) { + return Stream.empty(); + } + + return transformer.apply(clazz, methods); + } + + static boolean isClassRelevant(Class clazz, Class annotationClass) { + return AnnotationScannerUtil.isNotHidden(clazz) + && AnnotationUtil.findFirstAnnotation(annotationClass, clazz) != null; + } + + public static Stream> findAnnotatedMethods( + Class clazz, Class methodAnnotationClass) { + log.debug( + "Scanning class \"{}\" for @\"{}\" annotated methods", + clazz.getName(), + methodAnnotationClass.getName()); + + Stream methods = Arrays.stream(ReflectionUtils.getAllDeclaredMethods(clazz)) + .filter(AnnotationScannerUtil::isMethodInSourceCode) + .filter(AnnotationScannerUtil::isNotTypicalJavaMethod) + .filter(AnnotationScannerUtil::isNotHidden); + + if (methodAnnotationClass == AllMethods.class) { + return methods.peek(method -> log.debug("Mapping method \"{}\"", method.getName())) + .map(method -> new MethodAndAnnotation<>(method, null)); + } + + return methods.filter(method -> AnnotationUtil.findFirstAnnotation(methodAnnotationClass, method) != null) + .peek(method -> log.debug("Mapping method \"{}\"", method.getName())) + .flatMap(method -> AnnotationUtil.findAnnotations(methodAnnotationClass, method).stream() + .map(annotation -> new MethodAndAnnotation<>(method, annotation))); + } + + /** + * Check that a method was written by a developer and not generated by the compiler. + */ + private static boolean isMethodInSourceCode(Method method) { + return !method.isSynthetic(); + } + + private static boolean isNotHidden(AnnotatedElement element) { + return Objects.isNull(AnnotationUtil.findFirstAnnotation(Hidden.class, element)); + } + + private static final Set typicalJavaMethods = + Set.of("clone", "equals", "finalize", "getClass", "hashCode", "notify", "notifyAll", "toString", "wait"); + + private static boolean isNotTypicalJavaMethod(Method method) { + return !typicalJavaMethods.contains(method.getName()); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AnnotationScannerUtil.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationUtil.java similarity index 56% rename from springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AnnotationScannerUtil.java rename to springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationUtil.java index 78cfc2371..904367612 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AnnotationScannerUtil.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationUtil.java @@ -1,7 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.common.utils; +package io.github.springwolf.core.asyncapi.scanners.common.annotation; -import io.swagger.v3.oas.annotations.Hidden; import jakarta.annotation.Nullable; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotationCollectors; @@ -11,23 +10,14 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Method; -import java.util.Objects; import java.util.Set; -public class AnnotationScannerUtil { +public class AnnotationUtil { + private AnnotationUtil() {} - private AnnotationScannerUtil() {} - - /** - * Check that a method was written by a developer and not generated by the compiler. - */ - public static boolean isMethodInSourceCode(Method method) { - return !method.isSynthetic(); - } - - public static T findAnnotationOrThrow(Class annotationClass, AnnotatedElement element) { - T annotation = findAnnotation(annotationClass, element); + public static T findFirstAnnotationOrThrow( + Class annotationClass, AnnotatedElement element) { + T annotation = findFirstAnnotation(annotationClass, element); if (annotation == null) { throw new IllegalArgumentException( "Method must be annotated with " + element.getClass().getName()); @@ -36,17 +26,13 @@ public static T findAnnotationOrThrow(Class annotation } @Nullable - public static T findAnnotation(Class annotationClass, AnnotatedElement element) { + public static T findFirstAnnotation(Class annotationClass, AnnotatedElement element) { Set annotations = findAnnotations(annotationClass, element); return annotations.stream().findFirst().orElse(null); } - public static boolean notHidden(AnnotatedElement element) { - return Objects.isNull(findAnnotation(Hidden.class, element)); - } - - public static Set findAnnotations(Class annotationClass, AnnotatedElement element) { + static Set findAnnotations(Class annotationClass, AnnotatedElement element) { return MergedAnnotations.from( element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY, diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtil.java similarity index 98% rename from springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java rename to springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtil.java index 3078c68f8..4317a87e8 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtil.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.common.utils; +package io.github.springwolf.core.asyncapi.scanners.common.annotation; import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; @@ -17,6 +17,7 @@ import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotUsed; +import io.github.springwolf.core.asyncapi.scanners.common.utils.TextUtils; import org.springframework.util.StringUtils; import org.springframework.util.StringValueResolver; diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/MethodAndAnnotation.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/MethodAndAnnotation.java new file mode 100644 index 000000000..807bbc034 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/MethodAndAnnotation.java @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.annotation; + +import java.lang.reflect.Method; + +public record MethodAndAnnotation(Method method, A annotation) {} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelService.java similarity index 57% rename from springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java rename to springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelService.java index e77c30dfb..62abfd31d 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelService.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.channels; +package io.github.springwolf.core.asyncapi.scanners.common.channel; import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; @@ -9,80 +9,55 @@ import io.github.springwolf.asyncapi.v3.model.server.Server; import io.github.springwolf.asyncapi.v3.model.server.ServerReference; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; -import io.github.springwolf.core.asyncapi.components.ComponentsService; -import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; -import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.bindings.operations.OperationBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; -import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AsyncAnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AsyncAnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; +import io.github.springwolf.core.asyncapi.scanners.common.message.AsyncAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.AsyncAnnotationOperationService; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.util.StringValueResolver; -import java.lang.annotation.Annotation; import java.util.List; import java.util.Map; +@RequiredArgsConstructor @Slf4j -public class AsyncAnnotationChannelsScanner extends AsyncAnnotationScanner - implements ChannelsScanner { +public class AsyncAnnotationChannelService { - private final ClassScanner classScanner; + private final AsyncAnnotationProvider asyncAnnotationProvider; + private final AsyncAnnotationOperationService asyncAnnotationOperationService; + private final AsyncAnnotationMessageService asyncAnnotationMessageService; + private final StringValueResolver resolver; private final AsyncApiDocketService asyncApiDocketService; - public AsyncAnnotationChannelsScanner( - AsyncAnnotationProvider asyncAnnotationProvider, - ClassScanner classScanner, - ComponentsService componentsService, - AsyncApiDocketService asyncApiDocketService, - PayloadAsyncOperationService payloadAsyncOperationService, - List operationBindingProcessors, - List messageBindingProcessors) { - super( - asyncAnnotationProvider, - payloadAsyncOperationService, - componentsService, - operationBindingProcessors, - messageBindingProcessors); - this.classScanner = classScanner; - this.asyncApiDocketService = asyncApiDocketService; - } - - @Override - public Map scan() { - List> channels = classScanner.scan().stream() - .flatMap(this::getAnnotatedMethods) - .map(this::buildChannel) - .toList(); - - return ChannelMerger.mergeChannels(channels); - } - - private Map.Entry buildChannel(MethodAndAnnotation methodAndAnnotation) { - ChannelObject.ChannelObjectBuilder channelBuilder = ChannelObject.builder(); - + public ChannelObject buildChannel(MethodAndAnnotation methodAndAnnotation) { AsyncOperation operationAnnotation = this.asyncAnnotationProvider.getAsyncOperation(methodAndAnnotation.annotation()); String channelName = resolver.resolveStringValue(operationAnnotation.channelName()); String channelId = ReferenceUtil.toValidId(channelName); - Operation operation = buildOperation(operationAnnotation, methodAndAnnotation.method(), channelId); - + ChannelObject.ChannelObjectBuilder channelBuilder = ChannelObject.builder(); List servers = AsyncAnnotationUtil.getServers(operationAnnotation, resolver); if (servers != null && !servers.isEmpty()) { + Operation operation = asyncAnnotationOperationService.buildOperation( + operationAnnotation, methodAndAnnotation.method(), channelId); validateServers(servers, operation.getTitle()); + channelBuilder.servers( servers.stream().map(ServerReference::fromServer).toList()); } - MessageObject message = buildMessage(operationAnnotation, methodAndAnnotation.method()); - ChannelObject channelItem = channelBuilder + MessageObject message = + asyncAnnotationMessageService.buildMessage(operationAnnotation, methodAndAnnotation.method()); + + ChannelObject channel = channelBuilder .channelId(channelId) .address(channelName) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - return Map.entry(channelItem.getChannelId(), channelItem); + return channel; } /** diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/SpringAnnotationChannelService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/SpringAnnotationChannelService.java new file mode 100644 index 000000000..bc82378cf --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/SpringAnnotationChannelService.java @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.channel; + +import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +@RequiredArgsConstructor +@Slf4j +public class SpringAnnotationChannelService { + + private final BindingFactory bindingFactory; + + public ChannelObject buildChannel(Annotation annotation, Map messages) { + Map channelBinding = bindingFactory.buildChannelBinding(annotation); + Map chBinding = channelBinding != null ? new HashMap<>(channelBinding) : null; + String channelName = bindingFactory.getChannelName(annotation); + return ChannelObject.builder() + .channelId(ReferenceUtil.toValidId(channelName)) + .address(channelName) + .messages(messages) + .bindings(chBinding) + .build(); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java new file mode 100644 index 000000000..e349c40da --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.message; + +import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.components.ComponentsService; +import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AsyncAnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; +import io.github.springwolf.core.asyncapi.scanners.common.utils.TextUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.StringValueResolver; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +@Slf4j +@RequiredArgsConstructor +public class AsyncAnnotationMessageService { + + private final PayloadAsyncOperationService payloadAsyncOperationService; + private final ComponentsService componentsService; + private final List messageBindingProcessors; + private final StringValueResolver resolver; + + public MessageObject buildMessage(AsyncOperation operationData, Method method) { + PayloadSchemaObject payloadSchema = payloadAsyncOperationService.extractSchema(operationData, method); + + SchemaObject headerSchema = AsyncAnnotationUtil.getAsyncHeaders(operationData, resolver); + String headerSchemaName = this.componentsService.registerSchema(headerSchema); + + Map messageBinding = + AsyncAnnotationUtil.processMessageBindingFromAnnotation(method, messageBindingProcessors); + + var messagePayload = MessagePayload.of( + MultiFormatSchema.builder().schema(payloadSchema.payload()).build()); + + var builder = MessageObject.builder() + .messageId(payloadSchema.name()) + .name(payloadSchema.name()) + .title(payloadSchema.title()) + .description(getDescription(operationData, payloadSchema)) + .payload(messagePayload) + .headers(MessageHeaders.of(MessageReference.toSchema(headerSchemaName))) + .bindings(messageBinding); + // Retrieve the Message information obtained from the @AsyncMessage annotation. These values have higher + // priority so if we find them, we need to override the default values. + AsyncAnnotationUtil.processAsyncMessageAnnotation(builder, operationData.message(), this.resolver); + MessageObject message = builder.build(); + + this.componentsService.registerMessage(message); + return message; + } + + private String getDescription(AsyncOperation operationData, PayloadSchemaObject payloadSchema) { + String description = operationData.message().description(); + if (StringUtils.isBlank(description) && payloadSchema.payload() instanceof SchemaObject) { + String payloadDescription = ((SchemaObject) payloadSchema.payload()).getDescription(); + if (StringUtils.isNotBlank(payloadDescription)) { + description = payloadDescription; + } + } + if (StringUtils.isNotBlank(description)) { + description = this.resolver.resolveStringValue(description); + description = TextUtils.trimIndent(description); + } else { + description = null; + } + return description; + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/SpringAnnotationMessageService.java similarity index 85% rename from springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java rename to springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/SpringAnnotationMessageService.java index 95cd1f2cc..f311e81f6 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MethodLevelAnnotationScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/SpringAnnotationMessageService.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.common; +package io.github.springwolf.core.asyncapi.scanners.common.message; import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; @@ -21,13 +21,13 @@ @RequiredArgsConstructor @Slf4j -public abstract class MethodLevelAnnotationScanner { +public class SpringAnnotationMessageService { - protected final BindingFactory bindingFactory; - protected final AsyncHeadersBuilder asyncHeadersBuilder; - protected final ComponentsService componentsService; + private final BindingFactory bindingFactory; + private final AsyncHeadersBuilder asyncHeadersBuilder; + private final ComponentsService componentsService; - protected MessageObject buildMessage( + public MessageObject buildMessage( MethodAnnotation annotation, PayloadSchemaObject payloadSchema, SchemaObject headers) { SchemaObject headerSchema = asyncHeadersBuilder.buildHeaders(payloadSchema); SchemaObject mergedHeaderSchema = HeaderSchemaObjectMerger.merge(headerSchema, headers); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/SpringAnnotationMessagesService.java similarity index 53% rename from springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java rename to springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/SpringAnnotationMessagesService.java index 25857d0c2..bee976309 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/ClassLevelAnnotationScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/SpringAnnotationMessagesService.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.common; +package io.github.springwolf.core.asyncapi.scanners.common.message; import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; @@ -15,14 +15,11 @@ import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderSchemaObjectMerger; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; -import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationClassLevelOperationsScanner; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.Arrays; import java.util.Map; import java.util.Set; @@ -32,58 +29,23 @@ @Slf4j @RequiredArgsConstructor -public abstract class ClassLevelAnnotationScanner< - ClassAnnotation extends Annotation, MethodAnnotation extends Annotation> { +public class SpringAnnotationMessagesService { - protected final Class classAnnotationClass; - protected final Class methodAnnotationClass; - protected final BindingFactory bindingFactory; - protected final AsyncHeadersBuilder asyncHeadersBuilder; - protected final PayloadMethodService payloadMethodService; - protected final HeaderClassExtractor headerClassExtractor; - protected final ComponentsService componentsService; + private final BindingFactory bindingFactory; + private final AsyncHeadersBuilder asyncHeadersBuilder; + private final PayloadMethodService payloadMethodService; + private final HeaderClassExtractor headerClassExtractor; + private final ComponentsService componentsService; - protected enum MessageType { + public enum MessageType { CHANNEL, OPERATION } - /** - * Internal interface to indicate that all methods of a class should be used in scanners - * instead of filtering for a specific annotation. - */ - public @interface AllMethods {} - protected boolean isClassAnnotated(Class component) { - return AnnotationScannerUtil.findAnnotation(classAnnotationClass, component) != null; - } - - protected Set getAnnotatedMethods(Class clazz) { - log.debug( - "Scanning class \"{}\" for @\"{}\" annotated methods", - clazz.getName(), - methodAnnotationClass.getName()); - - return Arrays.stream(clazz.getDeclaredMethods()) - .filter(this::isRelevantMethod) - .collect(toSet()); - } - - private boolean isRelevantMethod(Method method) { - return AnnotationScannerUtil.isMethodInSourceCode(method) - && (methodAnnotationClass == AllMethods.class - || AnnotationScannerUtil.findAnnotation(methodAnnotationClass, method) != null); - } - - protected Map buildMessages( - ClassAnnotation classAnnotation, - Set methods, - SpringAnnotationClassLevelOperationsScanner.MessageType messageType) { + public Map buildMessages( + ClassAnnotation classAnnotation, Set methods, MessageType messageType) { Set messages = methods.stream() - .map((Method method) -> { - PayloadSchemaObject payloadSchema = payloadMethodService.extractSchema(method); - SchemaObject headerSchema = headerClassExtractor.extractHeader(method, payloadSchema); - return buildMessage(classAnnotation, payloadSchema, headerSchema); - }) + .map(method -> buildMessage(classAnnotation, method)) .collect(toSet()); if (messageType == MessageType.OPERATION) { @@ -93,9 +55,11 @@ protected Map buildMessages( return toMessagesMap(messages); } - protected MessageObject buildMessage( - ClassAnnotation classAnnotation, PayloadSchemaObject payloadSchema, SchemaObject headers) { + private MessageObject buildMessage(ClassAnnotation classAnnotation, Method method) { + PayloadSchemaObject payloadSchema = payloadMethodService.extractSchema(method); + SchemaObject headerSchema = asyncHeadersBuilder.buildHeaders(payloadSchema); + SchemaObject headers = headerClassExtractor.extractHeader(method, payloadSchema); SchemaObject mergedHeaderSchema = HeaderSchemaObjectMerger.merge(headerSchema, headers); String headerSchemaName = componentsService.registerSchema(mergedHeaderSchema); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/AsyncAnnotationOperationService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/AsyncAnnotationOperationService.java new file mode 100644 index 000000000..294575ee8 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/AsyncAnnotationOperationService.java @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.operation; + +import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.operation.Operation; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.scanners.bindings.operations.OperationBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AsyncAnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.message.AsyncAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.utils.TextUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.StringValueResolver; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Slf4j +@RequiredArgsConstructor +public class AsyncAnnotationOperationService { + + private final AsyncAnnotationProvider asyncAnnotationProvider; + private final List operationBindingProcessors; + private final AsyncAnnotationMessageService asyncAnnotationMessageService; + private final StringValueResolver resolver; + + public Operation buildOperation(AsyncOperation asyncOperation, Method method, String channelId) { + MessageObject message = asyncAnnotationMessageService.buildMessage(asyncOperation, method); + List messages = List.of(MessageReference.toChannelMessage(channelId, message)); + + return buildOperation(asyncOperation, method, channelId, messages); + } + + public Operation buildOperation(AsyncOperation asyncOperation, Set methods, String channelId) { + Method method = methods.stream().findFirst().orElseThrow(); + List messages = methods.stream() + .map(m -> asyncAnnotationMessageService.buildMessage(asyncOperation, m)) + .map(m -> MessageReference.toChannelMessage(channelId, m)) + .collect(Collectors.toList()); + + return buildOperation(asyncOperation, method, channelId, messages); + } + + private Operation buildOperation( + AsyncOperation asyncOperation, Method method, String channelId, List messages) { + String description = this.resolver.resolveStringValue(asyncOperation.description()); + if (StringUtils.isBlank(description)) { + description = "Auto-generated description"; + } else { + description = TextUtils.trimIndent(description); + } + + String operationTitle = + StringUtils.joinWith("_", channelId, this.asyncAnnotationProvider.getOperationType().type); + + Map operationBinding = + AsyncAnnotationUtil.processOperationBindingFromAnnotation(method, operationBindingProcessors); + Map opBinding = operationBinding != null ? new HashMap<>(operationBinding) : null; + + return Operation.builder() + .channel(ChannelReference.fromChannel(channelId)) + .action(this.asyncAnnotationProvider.getOperationType()) + .description(description) + .title(operationTitle) + .messages(messages) + .bindings(opBinding) + .build(); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationService.java new file mode 100644 index 000000000..2a7fb4aac --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationService.java @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.operation; + +import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.operation.Operation; +import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; +import lombok.RequiredArgsConstructor; + +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RequiredArgsConstructor +public class SpringAnnotationOperationService { + + private final BindingFactory bindingFactory; + private final SpringAnnotationMessageService springAnnotationMessageService; + + public Operation buildOperation( + MethodAnnotation annotation, PayloadSchemaObject payloadType, SchemaObject headerSchema) { + MessageObject message = springAnnotationMessageService.buildMessage(annotation, payloadType, headerSchema); + Map operationBinding = bindingFactory.buildOperationBinding(annotation); + Map opBinding = operationBinding != null ? new HashMap<>(operationBinding) : null; + String channelId = ReferenceUtil.toValidId(bindingFactory.getChannelName(annotation)); + + return Operation.builder() + .action(OperationAction.RECEIVE) + .channel(ChannelReference.fromChannel(channelId)) + .messages(List.of(MessageReference.toChannelMessage(channelId, message))) + .bindings(opBinding) + .build(); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationsService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationsService.java new file mode 100644 index 000000000..d90feb9c7 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationsService.java @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.operation; + +import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.operation.Operation; +import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; +import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessagesService; +import lombok.RequiredArgsConstructor; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@RequiredArgsConstructor +public class SpringAnnotationOperationsService { + + private final BindingFactory bindingFactory; + private final SpringAnnotationMessagesService springAnnotationMessagesService; + + public Operation buildOperation(ClassAnnotation classAnnotation, Set methods) { + var messages = springAnnotationMessagesService.buildMessages( + classAnnotation, methods, SpringAnnotationMessagesService.MessageType.OPERATION); + return buildOperation(classAnnotation, messages); + } + + private Operation buildOperation(ClassAnnotation classAnnotation, Map messages) { + Map operationBinding = bindingFactory.buildOperationBinding(classAnnotation); + Map opBinding = operationBinding != null ? new HashMap<>(operationBinding) : null; + String channelName = bindingFactory.getChannelName(classAnnotation); + String channelId = ReferenceUtil.toValidId(channelName); + + return Operation.builder() + .action(OperationAction.RECEIVE) + .channel(ChannelReference.fromChannel(channelId)) + .messages(messages.values().stream().toList()) + .bindings(opBinding) + .build(); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/StringValueResolverProxy.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/StringValueResolverProxy.java new file mode 100644 index 000000000..83e8b1a8b --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/StringValueResolverProxy.java @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.utils; + +import org.springframework.context.EmbeddedValueResolverAware; +import org.springframework.util.StringValueResolver; + +/** + * This proxy enables autowiring of the StringValueResolver + */ +public class StringValueResolverProxy implements StringValueResolver, EmbeddedValueResolverAware { + private StringValueResolver delegate; + + @Override + public void setEmbeddedValueResolver(StringValueResolver resolver) { + this.delegate = resolver; + } + + @Override + public String resolveStringValue(String strVal) { + return delegate.resolveStringValue(strVal); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationOperationsScannerDelegator.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationsInClassScanner.java similarity index 62% rename from springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationOperationsScannerDelegator.java rename to springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationsInClassScanner.java index 7f80e67b6..fd1de7856 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationOperationsScannerDelegator.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationsInClassScanner.java @@ -1,11 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.operations.annotations; +package io.github.springwolf.core.asyncapi.scanners.operations; import io.github.springwolf.asyncapi.v3.model.operation.Operation; import java.util.Map; import java.util.stream.Stream; -public interface SpringAnnotationOperationsScannerDelegator { +public interface OperationsInClassScanner { Stream> scan(Class clazz); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/SpringAnnotationOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationsInClassScannerAdapter.java similarity index 77% rename from springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/SpringAnnotationOperationsScanner.java rename to springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationsInClassScannerAdapter.java index 67f5824d1..ee36102ab 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/SpringAnnotationOperationsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationsInClassScannerAdapter.java @@ -4,7 +4,6 @@ import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; -import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationOperationsScannerDelegator; import lombok.RequiredArgsConstructor; import java.util.List; @@ -12,11 +11,11 @@ import java.util.Set; @RequiredArgsConstructor -public class SpringAnnotationOperationsScanner implements OperationsScanner { +public class OperationsInClassScannerAdapter implements OperationsScanner { private final ClassScanner classScanner; - private final SpringAnnotationOperationsScannerDelegator classProcessor; + private final OperationsInClassScanner classProcessor; @Override public Map scan() { diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationClassLevelOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationClassLevelOperationsScanner.java new file mode 100644 index 000000000..c4787b9e4 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationClassLevelOperationsScanner.java @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.operations.annotations; + +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; +import io.github.springwolf.asyncapi.v3.model.operation.Operation; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AllMethods; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; +import io.github.springwolf.core.asyncapi.scanners.common.operation.AsyncAnnotationOperationService; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScanner; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Slf4j +@RequiredArgsConstructor +public class AsyncAnnotationClassLevelOperationsScanner + implements OperationsInClassScanner { + + private final Class classAnnotationClass; + private final AsyncAnnotationProvider asyncAnnotationProvider; + private final AsyncAnnotationOperationService asyncAnnotationOperationsService; + private final List customizers; + + @Override + public Stream> scan(Class clazz) { + Set> methodAndAnnotation = AnnotationScannerUtil.findAnnotatedMethods( + clazz, classAnnotationClass, AllMethods.class, (cl, m) -> { + ClassAnnotation classAnnotation = + AnnotationUtil.findFirstAnnotation(classAnnotationClass, clazz); + return m.stream() + .map(method -> new MethodAndAnnotation<>(method.method(), classAnnotation)); + }) + .collect(Collectors.toSet()); + if (methodAndAnnotation.isEmpty()) { + return Stream.empty(); + } + + return mapClassToOperation(clazz, methodAndAnnotation); + } + + private Stream> mapClassToOperation( + Class component, Set> annotatedMethods) { + ClassAnnotation classAnnotation = AnnotationUtil.findFirstAnnotationOrThrow(classAnnotationClass, component); + AsyncOperation asyncOperation = asyncAnnotationProvider.getAsyncOperation(classAnnotation); + + String channelName = + asyncAnnotationProvider.getAsyncOperation(classAnnotation).channelName(); + String channelId = ReferenceUtil.toValidId(channelName); + String operationId = StringUtils.joinWith( + "_", channelId, asyncAnnotationProvider.getOperationType().type, component.getSimpleName()); + + Set methods = + annotatedMethods.stream().map(MethodAndAnnotation::method).collect(Collectors.toSet()); + Operation operation = asyncAnnotationOperationsService.buildOperation(asyncOperation, methods, channelId); + annotatedMethods.forEach( + method -> customizers.forEach(customizer -> customizer.customize(operation, method.method()))); + return Stream.of(Map.entry(operationId, operation)); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScanner.java new file mode 100644 index 000000000..685922e55 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScanner.java @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.operations.annotations; + +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; +import io.github.springwolf.asyncapi.v3.model.operation.Operation; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; +import io.github.springwolf.core.asyncapi.scanners.common.operation.AsyncAnnotationOperationService; +import io.github.springwolf.core.asyncapi.scanners.common.utils.StringValueResolverProxy; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScanner; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.lang.annotation.Annotation; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +@Slf4j +@RequiredArgsConstructor +public class AsyncAnnotationMethodLevelOperationsScanner + implements OperationsInClassScanner { + + private final AsyncAnnotationProvider asyncAnnotationProvider; + private final AsyncAnnotationOperationService asyncAnnotationOperationService; + private final List customizers; + private final StringValueResolverProxy resolver; + + @Override + public Stream> scan(Class clazz) { + return AnnotationScannerUtil.findAnnotatedMethods(clazz, this.asyncAnnotationProvider.getAnnotation()) + .map(this::mapMethodToOperation); + } + + private Map.Entry mapMethodToOperation( + MethodAndAnnotation methodAndAnnotation) { + AsyncOperation operationAnnotation = + this.asyncAnnotationProvider.getAsyncOperation(methodAndAnnotation.annotation()); + + String channelName = resolver.resolveStringValue(operationAnnotation.channelName()); + String channelId = ReferenceUtil.toValidId(channelName); + // operationId should be part of the buildOperation method and part of Operation object + String operationId = StringUtils.joinWith( + "_", + channelId, + this.asyncAnnotationProvider.getOperationType().type, + methodAndAnnotation.method().getName()); + + Operation operation = asyncAnnotationOperationService.buildOperation( + operationAnnotation, methodAndAnnotation.method(), channelId); + customizers.forEach(customizer -> customizer.customize(operation, methodAndAnnotation.method())); + return Map.entry(operationId, operation); + } +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java deleted file mode 100644 index 74d29df9b..000000000 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.operations.annotations; - -import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; -import io.github.springwolf.asyncapi.v3.model.operation.Operation; -import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; -import io.github.springwolf.core.asyncapi.components.ComponentsService; -import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; -import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.bindings.operations.OperationBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; -import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; -import io.github.springwolf.core.asyncapi.scanners.operations.OperationMerger; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; - -import java.lang.annotation.Annotation; -import java.util.List; -import java.util.Map; - -@Slf4j -public class AsyncAnnotationOperationsScanner extends AsyncAnnotationScanner - implements OperationsScanner { - - private final ClassScanner classScanner; - private final List customizers; - - public AsyncAnnotationOperationsScanner( - AsyncAnnotationProvider asyncAnnotationProvider, - ClassScanner classScanner, - ComponentsService componentsService, - PayloadAsyncOperationService payloadAsyncOperationService, - List operationBindingProcessors, - List messageBindingProcessors, - List customizers) { - super( - asyncAnnotationProvider, - payloadAsyncOperationService, - componentsService, - operationBindingProcessors, - messageBindingProcessors); - this.classScanner = classScanner; - this.customizers = customizers; - } - - @Override - public Map scan() { - List> operations = classScanner.scan().stream() - .flatMap(this::getAnnotatedMethods) - .map(this::buildOperation) - .toList(); - - return OperationMerger.mergeOperations(operations); - } - - private Map.Entry buildOperation(MethodAndAnnotation methodAndAnnotation) { - AsyncOperation operationAnnotation = - this.asyncAnnotationProvider.getAsyncOperation(methodAndAnnotation.annotation()); - String channelName = resolver.resolveStringValue(operationAnnotation.channelName()); - String channelId = ReferenceUtil.toValidId(channelName); - String operationId = StringUtils.joinWith( - "_", - channelId, - this.asyncAnnotationProvider.getOperationType().type, - methodAndAnnotation.method().getName()); - - Operation operation = buildOperation(operationAnnotation, methodAndAnnotation.method(), channelId); - operation.setAction(this.asyncAnnotationProvider.getOperationType()); - customizers.forEach(customizer -> customizer.customize(operation, methodAndAnnotation.method())); - return Map.entry(operationId, operation); - } -} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/OperationCustomizer.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/OperationCustomizer.java index 56f34474a..756e8cd09 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/OperationCustomizer.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/OperationCustomizer.java @@ -7,6 +7,8 @@ /** * Allows for customization of the Operation object after it has been finalized by the scanner. + * + * Maintainer note: This interface should not be part of the annotations package */ public interface OperationCustomizer { void customize(Operation operation, Method method); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java index 59d526df1..c532b1cad 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java @@ -1,101 +1,59 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.operations.annotations; -import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; -import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; -import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import io.github.springwolf.core.asyncapi.scanners.common.ClassLevelAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersBuilder; -import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationsService; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScanner; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.Stream; @Slf4j +@RequiredArgsConstructor public class SpringAnnotationClassLevelOperationsScanner< ClassAnnotation extends Annotation, MethodAnnotation extends Annotation> - extends ClassLevelAnnotationScanner - implements SpringAnnotationOperationsScannerDelegator { + implements OperationsInClassScanner { + private final Class classAnnotationClass; + private final Class methodAnnotationClass; + private final BindingFactory bindingFactory; + private final SpringAnnotationOperationsService springAnnotationOperationsService; private final List customizers; - public SpringAnnotationClassLevelOperationsScanner( - Class classAnnotationClass, - Class methodAnnotationClass, - BindingFactory bindingFactory, - AsyncHeadersBuilder asyncHeadersBuilder, - PayloadMethodService payloadMethodService, - HeaderClassExtractor headerClassExtractor, - ComponentsService componentsService, - List customizers) { - super( - classAnnotationClass, - methodAnnotationClass, - bindingFactory, - asyncHeadersBuilder, - payloadMethodService, - headerClassExtractor, - componentsService); - this.customizers = customizers; - } - @Override public Stream> scan(Class clazz) { - log.debug( - "Scanning class \"{}\" for @\"{}\" annotated methods", clazz.getName(), classAnnotationClass.getName()); - - return Stream.of(clazz).filter(this::isClassAnnotated).flatMap(this::mapClassToOperation); + return AnnotationScannerUtil.findAnnotatedMethods( + clazz, classAnnotationClass, methodAnnotationClass, this::mapClassToOperation); } - private Stream> mapClassToOperation(Class component) { - log.debug("Mapping class \"{}\" to operations", component.getName()); - - ClassAnnotation classAnnotation = AnnotationScannerUtil.findAnnotationOrThrow(classAnnotationClass, component); - - Set annotatedMethods = getAnnotatedMethods(component); - if (annotatedMethods.isEmpty()) { - return Stream.empty(); - } + private Stream> mapClassToOperation( + Class component, Set> annotatedMethods) { + ClassAnnotation classAnnotation = AnnotationUtil.findFirstAnnotationOrThrow(classAnnotationClass, component); String channelName = bindingFactory.getChannelName(classAnnotation); - String operationId = StringUtils.joinWith( - "_", ReferenceUtil.toValidId(channelName), OperationAction.RECEIVE, component.getSimpleName()); - - Operation operation = buildOperation(classAnnotation, annotatedMethods); - annotatedMethods.forEach(method -> customizers.forEach(customizer -> customizer.customize(operation, method))); - + String channelId = ReferenceUtil.toValidId(channelName); + String operationId = + StringUtils.joinWith("_", channelId, OperationAction.RECEIVE.type, component.getSimpleName()); + + Set methods = + annotatedMethods.stream().map(MethodAndAnnotation::method).collect(Collectors.toSet()); + Operation operation = springAnnotationOperationsService.buildOperation(classAnnotation, methods); + annotatedMethods.forEach( + method -> customizers.forEach(customizer -> customizer.customize(operation, method.method()))); return Stream.of(Map.entry(operationId, operation)); } - - private Operation buildOperation(ClassAnnotation classAnnotation, Set methods) { - var messages = buildMessages(classAnnotation, methods, MessageType.OPERATION); - return buildOperation(classAnnotation, messages); - } - - private Operation buildOperation(ClassAnnotation classAnnotation, Map messages) { - Map operationBinding = bindingFactory.buildOperationBinding(classAnnotation); - Map opBinding = operationBinding != null ? new HashMap<>(operationBinding) : null; - String channelName = bindingFactory.getChannelName(classAnnotation); - - return Operation.builder() - .action(OperationAction.RECEIVE) - .channel(ChannelReference.fromChannel(ReferenceUtil.toValidId(channelName))) - .messages(messages.values().stream().toList()) - .bindings(opBinding) - .build(); - } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScanner.java index 35ae45fad..b347733ce 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScanner.java @@ -1,99 +1,59 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.operations.annotations; -import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; -import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import io.github.springwolf.core.asyncapi.scanners.common.MethodLevelAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersBuilder; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScanner; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Stream; @Slf4j +@RequiredArgsConstructor public class SpringAnnotationMethodLevelOperationsScanner - extends MethodLevelAnnotationScanner implements SpringAnnotationOperationsScannerDelegator { + implements OperationsInClassScanner { private final Class methodAnnotationClass; - private final List customizers; - private final PayloadMethodParameterService payloadMethodParameterService; + private final BindingFactory bindingFactory; private final HeaderClassExtractor headerClassExtractor; - - public SpringAnnotationMethodLevelOperationsScanner( - Class methodAnnotationClass, - BindingFactory bindingFactory, - AsyncHeadersBuilder asyncHeadersBuilder, - List customizers, - PayloadMethodParameterService payloadMethodParameterService, - HeaderClassExtractor headerClassExtractor, - ComponentsService componentsService) { - super(bindingFactory, asyncHeadersBuilder, componentsService); - this.customizers = customizers; - this.methodAnnotationClass = methodAnnotationClass; - this.payloadMethodParameterService = payloadMethodParameterService; - this.headerClassExtractor = headerClassExtractor; - } + private final PayloadMethodParameterService payloadMethodParameterService; + private final SpringAnnotationOperationService springAnnotationOperationService; + private final List customizers; @Override public Stream> scan(Class clazz) { - log.debug( - "Scanning class \"{}\" for @\"{}\" annotated methods", - clazz.getName(), - methodAnnotationClass.getName()); - - return Arrays.stream(clazz.getDeclaredMethods()) - .filter(AnnotationScannerUtil::isMethodInSourceCode) - .filter(method -> AnnotationScannerUtil.findAnnotation(methodAnnotationClass, method) != null) + return AnnotationScannerUtil.findAnnotatedMethods(clazz, methodAnnotationClass) .map(this::mapMethodToOperation); } - private Map.Entry mapMethodToOperation(Method method) { - log.debug("Mapping method \"{}\" to operations", method.getName()); - - MethodAnnotation annotation = AnnotationScannerUtil.findAnnotationOrThrow(methodAnnotationClass, method); + private Map.Entry mapMethodToOperation(MethodAndAnnotation method) { + MethodAnnotation annotation = AnnotationUtil.findFirstAnnotationOrThrow(methodAnnotationClass, method.method()); String channelName = bindingFactory.getChannelName(annotation); + String channelId = ReferenceUtil.toValidId(channelName); String operationId = StringUtils.joinWith( - "_", ReferenceUtil.toValidId(channelName), OperationAction.RECEIVE, method.getName()); + "_", channelId, OperationAction.RECEIVE.type, method.method().getName()); - PayloadSchemaObject payloadSchema = payloadMethodParameterService.extractSchema(method); - SchemaObject headerSchema = headerClassExtractor.extractHeader(method, payloadSchema); + PayloadSchemaObject payloadSchema = payloadMethodParameterService.extractSchema(method.method()); + SchemaObject headerSchema = headerClassExtractor.extractHeader(method.method(), payloadSchema); - Operation operation = buildOperation(annotation, payloadSchema, headerSchema); - customizers.forEach(customizer -> customizer.customize(operation, method)); + Operation operation = springAnnotationOperationService.buildOperation(annotation, payloadSchema, headerSchema); + customizers.forEach(customizer -> customizer.customize(operation, method.method())); return Map.entry(operationId, operation); } - - private Operation buildOperation( - MethodAnnotation annotation, PayloadSchemaObject payloadType, SchemaObject headerSchema) { - MessageObject message = buildMessage(annotation, payloadType, headerSchema); - Map operationBinding = bindingFactory.buildOperationBinding(annotation); - Map opBinding = operationBinding != null ? new HashMap<>(operationBinding) : null; - String channelId = ReferenceUtil.toValidId(bindingFactory.getChannelName(annotation)); - - return Operation.builder() - .action(OperationAction.RECEIVE) - .channel(ChannelReference.fromChannel(channelId)) - .messages(List.of(MessageReference.toChannelMessage(channelId, message))) - .bindings(opBinding) - .build(); - } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java index 50e2e8e2e..6fc86e50e 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java @@ -26,13 +26,16 @@ import io.github.springwolf.core.asyncapi.operations.OperationsService; import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; +import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.AsyncAnnotationMessageService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodReturnService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadClassExtractor; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.TypeToClassConverter; +import io.github.springwolf.core.asyncapi.scanners.common.utils.StringValueResolverProxy; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; import io.github.springwolf.core.asyncapi.schemas.converters.SchemaTitleModelConverter; @@ -225,4 +228,21 @@ public PayloadMethodParameterService payloadMethodParameterService( public PayloadMethodReturnService payloadMethodReturnService(PayloadService payloadService) { return new PayloadMethodReturnService(payloadService); } + + @Bean + @ConditionalOnMissingBean + public StringValueResolverProxy stringValueResolverProxy() { + return new StringValueResolverProxy(); + } + + @Bean + @ConditionalOnMissingBean + public AsyncAnnotationMessageService asyncAnnotationMessageService( + ComponentsService componentsService, + PayloadAsyncOperationService payloadAsyncOperationService, + List messageBindingProcessors, + StringValueResolverProxy resolver) { + return new AsyncAnnotationMessageService( + payloadAsyncOperationService, componentsService, messageBindingProcessors, resolver); + } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java index 91852a7da..d2780779e 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java @@ -5,21 +5,29 @@ import io.github.springwolf.core.asyncapi.annotations.AsyncListener; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.annotations.AsyncPublisher; -import io.github.springwolf.core.asyncapi.components.ComponentsService; +import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; import io.github.springwolf.core.asyncapi.scanners.beans.BeanMethodsScanner; import io.github.springwolf.core.asyncapi.scanners.beans.DefaultBeanMethodsScanner; -import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.OperationBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.channels.AsyncAnnotationChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.channels.ChannelPriority; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScannerAdapter; +import io.github.springwolf.core.asyncapi.scanners.channels.annotations.AsyncAnnotationClassLevelChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.channels.annotations.AsyncAnnotationMethodLevelChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.classes.SpringwolfClassScanner; import io.github.springwolf.core.asyncapi.scanners.classes.spring.ComponentClassScanner; import io.github.springwolf.core.asyncapi.scanners.classes.spring.ConfigurationClassScanner; -import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; -import io.github.springwolf.core.asyncapi.scanners.operations.annotations.AsyncAnnotationOperationsScanner; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.channel.AsyncAnnotationChannelService; +import io.github.springwolf.core.asyncapi.scanners.common.message.AsyncAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.AsyncAnnotationOperationService; +import io.github.springwolf.core.asyncapi.scanners.common.utils.StringValueResolverProxy; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScannerAdapter; +import io.github.springwolf.core.asyncapi.scanners.operations.annotations.AsyncAnnotationClassLevelOperationsScanner; +import io.github.springwolf.core.asyncapi.scanners.operations.annotations.AsyncAnnotationMethodLevelOperationsScanner; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.OperationCustomizer; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; +import lombok.val; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; @@ -70,21 +78,54 @@ public SpringwolfClassScanner springwolfClassScanner( havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.ASYNC_ANNOTATION) - public AsyncAnnotationChannelsScanner asyncListenerAnnotationChannelScanner( + public ChannelsScanner asyncListenerMethodLevelAnnotationChannelScanner( + AsyncAnnotationProvider asyncAnnotationProvider, SpringwolfClassScanner springwolfClassScanner, - ComponentsService componentsService, AsyncApiDocketService asyncApiDocketService, - PayloadAsyncOperationService payloadService, + AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, - List messageBindingProcessors) { - return new AsyncAnnotationChannelsScanner<>( - buildAsyncListenerAnnotationProvider(), - springwolfClassScanner, - componentsService, - asyncApiDocketService, - payloadService, - operationBindingProcessors, - messageBindingProcessors); + StringValueResolverProxy resolver) { + AsyncAnnotationOperationService asyncAnnotationOperationService = + new AsyncAnnotationOperationService<>( + asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + val asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( + asyncAnnotationProvider, + asyncAnnotationOperationService, + asyncAnnotationMessageService, + resolver, + asyncApiDocketService); + val strategy = + new AsyncAnnotationMethodLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); + + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); + } + + @Bean + @ConditionalOnProperty( + name = SPRINGWOLF_SCANNER_ASYNC_LISTENER_ENABLED, + havingValue = "true", + matchIfMissing = true) + @Order(value = ChannelPriority.ASYNC_ANNOTATION) + public ChannelsScanner asyncListenerClassLevelAnnotationChannelScanner( + AsyncAnnotationProvider asyncAnnotationProvider, + SpringwolfClassScanner springwolfClassScanner, + AsyncApiDocketService asyncApiDocketService, + AsyncAnnotationMessageService asyncAnnotationMessageService, + List operationBindingProcessors, + StringValueResolverProxy resolver) { + AsyncAnnotationOperationService asyncAnnotationOperationService = + new AsyncAnnotationOperationService<>( + asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + val asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( + asyncAnnotationProvider, + asyncAnnotationOperationService, + asyncAnnotationMessageService, + resolver, + asyncApiDocketService); + val strategy = + new AsyncAnnotationClassLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); + + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -93,21 +134,72 @@ public AsyncAnnotationChannelsScanner asyncListenerAnnotationChan havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.ASYNC_ANNOTATION) - public AsyncAnnotationOperationsScanner asyncListenerAnnotationOperationScanner( + public OperationsScanner asyncListenerMethodLevelAnnotationOperationScanner( + AsyncAnnotationProvider asyncAnnotationProvider, SpringwolfClassScanner springwolfClassScanner, - ComponentsService componentsService, - PayloadAsyncOperationService payloadService, + AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, - List messageBindingProcessors, + List operationCustomizers, + StringValueResolverProxy resolver) { + val asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( + asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + val strategy = new AsyncAnnotationMethodLevelOperationsScanner<>( + asyncAnnotationProvider, asyncAnnotationOperationService, operationCustomizers, resolver); + + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); + } + + @Bean + @ConditionalOnProperty( + name = SPRINGWOLF_SCANNER_ASYNC_LISTENER_ENABLED, + havingValue = "true", + matchIfMissing = true) + @Order(value = ChannelPriority.ASYNC_ANNOTATION) + public OperationsScanner asyncListenerClassLevelListenerAnnotationOperationsScanner( + AsyncAnnotationProvider asyncAnnotationProvider, + SpringwolfClassScanner springwolfClassScanner, + AsyncAnnotationMessageService asyncAnnotationMessageService, + List operationBindingProcessors, + StringValueResolverProxy resolver, List operationCustomizers) { - return new AsyncAnnotationOperationsScanner<>( - buildAsyncListenerAnnotationProvider(), - springwolfClassScanner, - componentsService, - payloadService, - operationBindingProcessors, - messageBindingProcessors, - operationCustomizers); + val asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( + asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + AsyncAnnotationClassLevelOperationsScanner strategy = + new AsyncAnnotationClassLevelOperationsScanner<>( + AsyncListener.class, + asyncAnnotationProvider, + asyncAnnotationOperationService, + operationCustomizers); + + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); + } + + @Bean + @ConditionalOnProperty( + name = SPRINGWOLF_SCANNER_ASYNC_PUBLISHER_ENABLED, + havingValue = "true", + matchIfMissing = true) + @Order(value = ChannelPriority.ASYNC_ANNOTATION) + public ChannelsScanner asyncPublisherClassLevelChannelAnnotationScanner( + AsyncAnnotationProvider asyncAnnotationProvider, + SpringwolfClassScanner springwolfClassScanner, + AsyncApiDocketService asyncApiDocketService, + AsyncAnnotationMessageService asyncAnnotationMessageService, + List operationBindingProcessors, + StringValueResolverProxy resolver) { + AsyncAnnotationOperationService asyncAnnotationOperationService = + new AsyncAnnotationOperationService<>( + asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + val asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( + asyncAnnotationProvider, + asyncAnnotationOperationService, + asyncAnnotationMessageService, + resolver, + asyncApiDocketService); + val strategy = + new AsyncAnnotationMethodLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); + + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -116,21 +208,26 @@ public AsyncAnnotationOperationsScanner asyncListenerAnnotationOp havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.ASYNC_ANNOTATION) - public AsyncAnnotationChannelsScanner asyncPublisherChannelAnnotationScanner( + public ChannelsScanner asyncPublisherClassLevelAnnotationChannelScanner( + AsyncAnnotationProvider asyncAnnotationProvider, SpringwolfClassScanner springwolfClassScanner, - ComponentsService componentsService, AsyncApiDocketService asyncApiDocketService, - PayloadAsyncOperationService payloadService, + AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, - List messageBindingProcessors) { - return new AsyncAnnotationChannelsScanner<>( - buildAsyncPublisherAnnotationProvider(), - springwolfClassScanner, - componentsService, - asyncApiDocketService, - payloadService, - operationBindingProcessors, - messageBindingProcessors); + StringValueResolverProxy resolver) { + AsyncAnnotationOperationService asyncAnnotationOperationService = + new AsyncAnnotationOperationService<>( + asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + val asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( + asyncAnnotationProvider, + asyncAnnotationOperationService, + asyncAnnotationMessageService, + resolver, + asyncApiDocketService); + val strategy = + new AsyncAnnotationClassLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); + + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -139,26 +236,50 @@ public AsyncAnnotationChannelsScanner asyncPublisherChannelAnnot havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.ASYNC_ANNOTATION) - public AsyncAnnotationOperationsScanner asyncPublisherOperationAnnotationScanner( + public OperationsScanner asyncPublisherClassLevelOperationAnnotationScanner( + AsyncAnnotationProvider asyncAnnotationProvider, SpringwolfClassScanner springwolfClassScanner, - ComponentsService componentsService, - PayloadAsyncOperationService payloadService, + AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, - List messageBindingProcessors, - List customizers) { - return new AsyncAnnotationOperationsScanner<>( - buildAsyncPublisherAnnotationProvider(), - springwolfClassScanner, - componentsService, - payloadService, - operationBindingProcessors, - messageBindingProcessors, - customizers); + List customizers, + StringValueResolverProxy resolver) { + + val asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( + asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + val strategy = new AsyncAnnotationMethodLevelOperationsScanner<>( + asyncAnnotationProvider, asyncAnnotationOperationService, customizers, resolver); + + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } - private static AsyncAnnotationScanner.AsyncAnnotationProvider - buildAsyncListenerAnnotationProvider() { - return new AsyncAnnotationScanner.AsyncAnnotationProvider<>() { + @Bean + @ConditionalOnProperty( + name = SPRINGWOLF_SCANNER_ASYNC_PUBLISHER_ENABLED, + havingValue = "true", + matchIfMissing = true) + @Order(value = ChannelPriority.ASYNC_ANNOTATION) + public OperationsScanner asyncPublisherClassLevelListenerAnnotationOperationsScanner( + AsyncAnnotationProvider asyncAnnotationProvider, + SpringwolfClassScanner springwolfClassScanner, + List operationBindingProcessors, + AsyncAnnotationMessageService asyncAnnotationMessageService, + StringValueResolverProxy resolver, + List operationCustomizers) { + val asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( + asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + AsyncAnnotationClassLevelOperationsScanner strategy = + new AsyncAnnotationClassLevelOperationsScanner<>( + AsyncPublisher.class, + asyncAnnotationProvider, + asyncAnnotationOperationService, + operationCustomizers); + + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); + } + + @Bean + public AsyncAnnotationProvider asyncListenerAnnotationProvider() { + return new AsyncAnnotationProvider<>() { @Override public Class getAnnotation() { return AsyncListener.class; @@ -176,9 +297,9 @@ public OperationAction getOperationType() { }; } - private static AsyncAnnotationScanner.AsyncAnnotationProvider - buildAsyncPublisherAnnotationProvider() { - return new AsyncAnnotationScanner.AsyncAnnotationProvider<>() { + @Bean + public AsyncAnnotationProvider asyncPublisherAnnotationProvider() { + return new AsyncAnnotationProvider<>() { @Override public Class getAnnotation() { return AsyncPublisher.class; diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/channels/DefaultChannelsServiceIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/channels/DefaultChannelsServiceIntegrationTest.java index ef3b35250..b918a4b42 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/channels/DefaultChannelsServiceIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/channels/DefaultChannelsServiceIntegrationTest.java @@ -38,22 +38,23 @@ class DefaultChannelsServiceIntegrationTest { void getChannels() { Map actualChannels = defaultChannelsService.findChannels(); - assertThat(actualChannels) - .containsAllEntriesOf(simpleChannelScanner.scan()) - .containsEntry(SameTopic.topicName, SameTopic.expectedMergedChannel); + assertThat(actualChannels).hasSize(1).containsEntry(channelId, SameTopic.expectedMergedChannel); } @Component static class SimpleChannelScanner implements ChannelsScanner { @Override public Map scan() { - return Map.of("foo", new ChannelObject()); + return Map.of( + channelId, ChannelObject.builder().channelId(channelId).build()); } } + static final String channelId = "receiveSendTopic"; + static class SameTopic { - static final String topicName = "receiveSendTopic"; static final ChannelObject expectedMergedChannel = ChannelObject.builder() + .channelId(channelId) .messages(Map.of( "receiveMessage", MessageReference.toComponentMessage("receiveMessage"), @@ -64,15 +65,16 @@ static class SameTopic { @Component static class SendChannelScanner implements ChannelsScanner { static final Operation sentOperation = Operation.builder() - .channel(ChannelReference.fromChannel(topicName)) + .channel(ChannelReference.fromChannel(channelId)) .action(OperationAction.SEND) .build(); @Override public Map scan() { return Map.of( - topicName, + channelId, ChannelObject.builder() + .channelId(channelId) .messages(Map.of("sendMessage", MessageReference.toComponentMessage("sendMessage"))) .build()); } @@ -81,15 +83,16 @@ public Map scan() { @Component static class ReceiveChannelScanner implements ChannelsScanner { static final Operation receiveOperation = Operation.builder() - .channel(ChannelReference.fromChannel(topicName)) + .channel(ChannelReference.fromChannel(channelId)) .action(OperationAction.RECEIVE) .build(); @Override public Map scan() { return Map.of( - topicName, + channelId, ChannelObject.builder() + .channelId(channelId) .messages( Map.of("receiveMessage", MessageReference.toComponentMessage("receiveMessage"))) .build()); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMergerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMergerTest.java index f0fa992d2..a69b3764e 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMergerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMergerTest.java @@ -20,12 +20,14 @@ void shouldNotMergeDifferentchannelIds() { // given String channelId1 = "channel1"; String channelId2 = "channel2"; - ChannelObject publisherChannel = ChannelObject.builder().build(); - ChannelObject subscriberChannel = ChannelObject.builder().build(); + ChannelObject publisherChannel = + ChannelObject.builder().channelId(channelId1).build(); + ChannelObject subscriberChannel = + ChannelObject.builder().channelId(channelId2).build(); // when - Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelId1, publisherChannel), Map.entry(channelId2, subscriberChannel))); + Map mergedChannels = + ChannelMerger.mergeChannels(Arrays.asList(publisherChannel, subscriberChannel)); // then assertThat(mergedChannels).hasSize(2); @@ -35,12 +37,14 @@ void shouldNotMergeDifferentchannelIds() { void shouldMergeEqualchannelIdsIntoOneChannel() { // given String channelId = "channel"; - ChannelObject publisherChannel = ChannelObject.builder().build(); - ChannelObject subscriberChannel = ChannelObject.builder().build(); + ChannelObject publisherChannel = + ChannelObject.builder().channelId(channelId).build(); + ChannelObject subscriberChannel = + ChannelObject.builder().channelId(channelId).build(); // when - Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelId, publisherChannel), Map.entry(channelId, subscriberChannel))); + Map mergedChannels = + ChannelMerger.mergeChannels(Arrays.asList(publisherChannel, subscriberChannel)); // then assertThat(mergedChannels).hasSize(1); @@ -51,13 +55,13 @@ void shouldUseFirstChannelFound() { // given String channelId = "channel"; ChannelObject publisherChannel1 = - ChannelObject.builder().title("channel1").build(); + ChannelObject.builder().channelId(channelId).title("channel1").build(); ChannelObject publisherChannel2 = - ChannelObject.builder().title("channel2").build(); + ChannelObject.builder().channelId(channelId).title("channel2").build(); // when - Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelId, publisherChannel1), Map.entry(channelId, publisherChannel2))); + Map mergedChannels = + ChannelMerger.mergeChannels(Arrays.asList(publisherChannel1, publisherChannel2)); // then assertThat(mergedChannels).hasSize(1).hasEntrySatisfying(channelId, it -> { @@ -82,20 +86,21 @@ void shouldMergeDifferentMessagesForSameChannel() { .description("This is also an integer, but in essence the same payload type") .build(); ChannelObject publisherChannel1 = ChannelObject.builder() + .channelId(channelId) .messages(Map.of(message1.getMessageId(), MessageReference.toComponentMessage(message1))) .build(); ChannelObject publisherChannel2 = ChannelObject.builder() + .channelId(channelId) .messages(Map.of(message2.getMessageId(), MessageReference.toComponentMessage(message2))) .build(); ChannelObject publisherChannel3 = ChannelObject.builder() + .channelId(channelId) .messages(Map.of(message3.getMessageId(), MessageReference.toComponentMessage(message3))) .build(); // when - Map mergedChannels = ChannelMerger.mergeChannels(Arrays.asList( - Map.entry(channelId, publisherChannel1), - Map.entry(channelId, publisherChannel2), - Map.entry(channelId, publisherChannel3))); + Map mergedChannels = + ChannelMerger.mergeChannels(Arrays.asList(publisherChannel1, publisherChannel2, publisherChannel3)); // then expectedMessage only includes message1 and message2. // Message3 is not included as it is identical in terms of payload type (Message#name) to message 2 @@ -113,14 +118,16 @@ void shouldUseOtherMessageIfFirstMessageIsMissingForChannels() { .name(String.class.getCanonicalName()) .description("This is a string") .build(); - ChannelObject publisherChannel1 = ChannelObject.builder().build(); + ChannelObject publisherChannel1 = + ChannelObject.builder().channelId(channelId).build(); ChannelObject publisherChannel2 = ChannelObject.builder() + .channelId(channelId) .messages(Map.of(message2.getName(), message2)) .build(); // when - Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelId, publisherChannel1), Map.entry(channelId, publisherChannel2))); + Map mergedChannels = + ChannelMerger.mergeChannels(Arrays.asList(publisherChannel1, publisherChannel2)); // then expectedMessage message2 var expectedMessages = Map.of(message2.getName(), message2); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScannerAdapterTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScannerAdapterTest.java new file mode 100644 index 000000000..a7ae7f67c --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelsInClassScannerAdapterTest.java @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.channels; + +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ChannelsInClassScannerAdapterTest { + + private final ClassScanner classScanner = mock(ClassScanner.class); + private final ChannelsInClassScanner channelsInClassScanner = mock(ChannelsInClassScanner.class); + + private final ChannelsInClassScannerAdapter channelsInClassScannerAdapter = + new ChannelsInClassScannerAdapter(classScanner, channelsInClassScanner); + + @Test + void noClassFoundTest() { + // when + Map channels = channelsInClassScannerAdapter.scan(); + + // then + assertThat(channels).isEmpty(); + } + + @Test + void processClassTest() { + // given + when(classScanner.scan()).thenReturn(Set.of(String.class)); + Map.Entry channel1 = Map.entry( + "channel1", ChannelObject.builder().channelId("channel1").build()); + Map.Entry channel2 = Map.entry( + "channel2", ChannelObject.builder().channelId("channel2").build()); + when(channelsInClassScanner.scan(any())).thenReturn(List.of(channel1.getValue(), channel2.getValue())); + + // when + Map channels = channelsInClassScannerAdapter.scan(); + + // then + assertThat(channels).containsExactly(channel1, channel2); + } + + @Test + void sameChannelsAreMergedTest() { + // given + when(classScanner.scan()).thenReturn(Set.of(String.class)); + Map.Entry channel1 = Map.entry( + "channel1", ChannelObject.builder().channelId("channel1").build()); + Map.Entry channel2 = Map.entry( + "channel1", ChannelObject.builder().channelId("channel1").build()); + when(channelsInClassScanner.scan(any())).thenReturn(List.of(channel1.getValue(), channel2.getValue())); + + // when + Map channels = channelsInClassScannerAdapter.scan(); + + // then + assertThat(channels) + .containsExactly(Map.entry( + "channel1", + ChannelObject.builder().channelId("channel1").build())); + } + + @Test + void processEmptyClassTest() { + // given + when(classScanner.scan()).thenReturn(Set.of(String.class)); + when(channelsInClassScanner.scan(any())).thenReturn(List.of()); + + // when + Map channels = channelsInClassScannerAdapter.scan(); + + // then + assertThat(channels).isEmpty(); + } +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/SpringAnnotationChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/SpringAnnotationChannelsScannerTest.java deleted file mode 100644 index 87c5ceee0..000000000 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/SpringAnnotationChannelsScannerTest.java +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.channels; - -import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; -import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationChannelsScannerDelegator; -import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; -import org.junit.jupiter.api.Test; - -import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class SpringAnnotationChannelsScannerTest { - - private final ClassScanner classScanner = mock(ClassScanner.class); - private final SpringAnnotationChannelsScannerDelegator springAnnotationChannelsScannerDelegator = - mock(SpringAnnotationChannelsScannerDelegator.class); - - private final SpringAnnotationChannelsScanner springAnnotationChannelsScanner = - new SpringAnnotationChannelsScanner(classScanner, springAnnotationChannelsScannerDelegator); - - @Test - void noClassFoundTest() { - // when - Map channels = springAnnotationChannelsScanner.scan(); - - // then - assertThat(channels).isEmpty(); - } - - @Test - void processClassTest() { - // given - when(classScanner.scan()).thenReturn(Set.of(String.class)); - Map.Entry channel1 = - Map.entry("channel1", ChannelObject.builder().build()); - Map.Entry channel2 = - Map.entry("channel2", ChannelObject.builder().build()); - when(springAnnotationChannelsScannerDelegator.scan(any())).thenReturn(Stream.of(channel1, channel2)); - - // when - Map channels = springAnnotationChannelsScanner.scan(); - - // then - assertThat(channels).containsExactly(channel1, channel2); - } - - @Test - void sameChannelsAreMergedTest() { - // given - when(classScanner.scan()).thenReturn(Set.of(String.class)); - Map.Entry channel1 = - Map.entry("channel1", ChannelObject.builder().build()); - Map.Entry channel2 = - Map.entry("channel1", ChannelObject.builder().build()); - when(springAnnotationChannelsScannerDelegator.scan(any())).thenReturn(Stream.of(channel1, channel2)); - - // when - Map channels = springAnnotationChannelsScanner.scan(); - - // then - assertThat(channels) - .containsExactly(Map.entry("channel1", ChannelObject.builder().build())); - } - - @Test - void processEmptyClassTest() { - // given - when(classScanner.scan()).thenReturn(Set.of(String.class)); - when(springAnnotationChannelsScannerDelegator.scan(any())).thenReturn(Stream.of()); - - // when - Map channels = springAnnotationChannelsScanner.scan(); - - // then - assertThat(channels).isEmpty(); - } -} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java deleted file mode 100644 index 02e5f888d..000000000 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java +++ /dev/null @@ -1,495 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.channels.annotations; - -import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; -import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; -import io.github.springwolf.asyncapi.v3.model.info.Info; -import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; -import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; -import io.github.springwolf.asyncapi.v3.model.server.Server; -import io.github.springwolf.asyncapi.v3.model.server.ServerReference; -import io.github.springwolf.core.asyncapi.annotations.AsyncListener; -import io.github.springwolf.core.asyncapi.annotations.AsyncMessage; -import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; -import io.github.springwolf.core.asyncapi.components.ComponentsService; -import io.github.springwolf.core.asyncapi.components.DefaultComponentsService; -import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.bindings.operations.OperationBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.bindings.processor.TestOperationBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.channels.AsyncAnnotationChannelsScanner; -import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; -import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; -import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadClassExtractor; -import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; -import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; -import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; -import io.github.springwolf.core.configuration.docket.AsyncApiDocket; -import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; -import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.springframework.util.StringValueResolver; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static java.util.Collections.EMPTY_MAP; -import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class AsyncAnnotationChannelsScannerTest { - private static final String CHANNEL = "test/channel"; - private static final String CHANNEL_ID = ReferenceUtil.toValidId(CHANNEL); - - private final AsyncAnnotationScanner.AsyncAnnotationProvider asyncAnnotationProvider = - new AsyncAnnotationScanner.AsyncAnnotationProvider<>() { - @Override - public Class getAnnotation() { - return AsyncListener.class; - } - - @Override - public AsyncOperation getAsyncOperation(AsyncListener annotation) { - return annotation.operation(); - } - - @Override - public OperationAction getOperationType() { - return OperationAction.SEND; - } - }; - private final SwaggerSchemaUtil swaggerSchemaUtil = new SwaggerSchemaUtil(); - private final SpringwolfConfigProperties properties = new SpringwolfConfigProperties(); - private final ClassScanner classScanner = mock(ClassScanner.class); - private final SwaggerSchemaService schemaService = - new SwaggerSchemaService(emptyList(), emptyList(), swaggerSchemaUtil, properties); - private final ComponentsService componentsService = new DefaultComponentsService(schemaService); - private final AsyncApiDocketService asyncApiDocketService = mock(AsyncApiDocketService.class); - private final PayloadClassExtractor payloadClassExtractor = new PayloadClassExtractor(properties); - private final PayloadService payloadService = new PayloadService(componentsService, properties); - private final PayloadAsyncOperationService payloadAsyncOperationService = - new PayloadAsyncOperationService(payloadClassExtractor, payloadService); - - private final List operationBindingProcessors = - List.of(new TestOperationBindingProcessor()); - private final List messageBindingProcessors = emptyList(); - - private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); - - private final AsyncAnnotationChannelsScanner channelScanner = new AsyncAnnotationChannelsScanner<>( - asyncAnnotationProvider, - classScanner, - componentsService, - asyncApiDocketService, - payloadAsyncOperationService, - operationBindingProcessors, - messageBindingProcessors); - - @BeforeEach - public void setup() { - when(asyncApiDocketService.getAsyncApiDocket()) - .thenReturn(AsyncApiDocket.builder() - .info(new Info()) - .server("server1", new Server()) - .server("server2", new Server()) - .build()); - - channelScanner.setEmbeddedValueResolver(stringValueResolver); - when(stringValueResolver.resolveStringValue(any())) - .thenAnswer(invocation -> switch ((String) invocation.getArgument(0)) { - case "${test.property.test-channel}" -> CHANNEL; - case "${test.property.description}" -> "description"; - case "${test.property.server1}" -> "server1"; - case "${test.property.server2}" -> "server2"; - default -> invocation.getArgument(0); - }); - } - - private void setClassToScan(Class classToScan) { - Set> classesToScan = singleton(classToScan); - when(classScanner.scan()).thenReturn(classesToScan); - } - - @Test - void scan_componentHasNoListenerMethods() { - setClassToScan(ClassWithoutListenerAnnotation.class); - - Map channels = channelScanner.scan(); - - assertThat(channels).isEmpty(); - } - - @Test - void scan_componentChannelHasListenerMethod() { - // Given a class with methods annotated with AsyncListener, where only the channel-name is set - setClassToScan(ClassWithListenerAnnotation.class); - - // When scan is called - Map actualChannels = channelScanner.scan(); - - // Then the returned collection contains the channel - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(SimpleFoo.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(SimpleFoo.class.getName()) - .name(SimpleFoo.class.getName()) - .title(SimpleFoo.class.getSimpleName()) - .description("SimpleFoo Message Description") - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .build(); - - ChannelObject expectedChannel = ChannelObject.builder() - .channelId(CHANNEL_ID) - .address(CHANNEL) - .bindings(null) - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .build(); - - assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); - } - - @Test - void scan_componentHasListenerMethodWithUnknownServer() { - // Given a class with method annotated with AsyncListener, with an unknown servername - setClassToScan(ClassWithListenerAnnotationWithInvalidServer.class); - - assertThatThrownBy(channelScanner::scan) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage( - "Operation 'test_channel_send' defines unknown server ref 'server3'. This AsyncApi defines these server(s): [server1, server2]"); - } - - @Test - void scan_componentHasListenerMethodWithAllAttributes() { - // Given a class with method annotated with AsyncListener, where all attributes are set - setClassToScan(ClassWithListenerAnnotationWithAllAttributes.class); - - // When scan is called - Map actualChannels = channelScanner.scan(); - - // Then the returned collection contains the channel - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(List.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(List.class.getName()) - .name(List.class.getName()) - .title(List.class.getSimpleName()) - .description(null) - .payload(payload) - .headers(MessageHeaders.of(MessageReference.toSchema("TestSchema"))) - .bindings(EMPTY_MAP) - .build(); - - ChannelObject expectedChannel = ChannelObject.builder() - .channelId(CHANNEL_ID) - .address(CHANNEL) - .bindings(null) - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .servers(List.of(ServerReference.fromServer("server1"), ServerReference.fromServer("server2"))) - .build(); - - assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); - } - - @Test - void scan_componentHasMultipleListenerAnnotations() { - // Given a class with methods annotated with AsyncListener, where only the channel-name is set - setClassToScan(ClassWithMultipleListenerAnnotations.class); - - // When scan is called - Map actualChannels = channelScanner.scan(); - - // Then the returned collection contains the channel - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(SimpleFoo.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(SimpleFoo.class.getName()) - .name(SimpleFoo.class.getName()) - .title(SimpleFoo.class.getSimpleName()) - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .description("SimpleFoo Message Description") - .build(); - - ChannelObject expectedChannel1 = ChannelObject.builder() - .channelId("test-channel-1") - .address("test-channel-1") - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .bindings(null) - .build(); - - ChannelObject expectedChannel2 = ChannelObject.builder() - .channelId("test-channel-2") - .address("test-channel-2") - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .bindings(null) - .build(); - - assertThat(actualChannels) - .containsExactlyInAnyOrderEntriesOf(Map.of( - "test-channel-1", expectedChannel1, - "test-channel-2", expectedChannel2)); - } - - @Test - void scan_componentHasAsyncMethodAnnotation() { - // Given a class with methods annotated with AsyncListener, where only the channel-name is set - setClassToScan(ClassWithMessageAnnotation.class); - - // When scan is called - Map actualChannels = channelScanner.scan(); - - // Then the returned collection contains the channel - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(SimpleFoo.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId("simpleFooId") - .name("SimpleFooPayLoad") - .title("Message Title") - .description("Message description") - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .build(); - - ChannelObject expectedChannel = ChannelObject.builder() - .channelId(CHANNEL_ID) - .address(CHANNEL) - .bindings(null) - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .build(); - - assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); - } - - private static class ClassWithoutListenerAnnotation { - - private void methodWithoutAnnotation() {} - } - - private static class ClassWithListenerAnnotation { - - @AsyncListener(operation = @AsyncOperation(channelName = CHANNEL)) - private void methodWithAnnotation(SimpleFoo payload) {} - - private void methodWithoutAnnotation() {} - } - - private static class ClassWithListenerAnnotationWithInvalidServer { - - @AsyncListener( - operation = - @AsyncOperation( - channelName = CHANNEL, - description = "test channel operation description", - servers = {"server3"})) - private void methodWithAnnotation(SimpleFoo payload) {} - } - - private static class ClassWithListenerAnnotationWithAllAttributes { - - @AsyncListener( - operation = - @AsyncOperation( - channelName = "${test.property.test-channel}", - description = "${test.property.description}", - payloadType = List.class, - servers = {"${test.property.server1}", "${test.property.server2}"}, - headers = - @AsyncOperation.Headers( - schemaName = "TestSchema", - values = { - @AsyncOperation.Headers.Header(name = "header", value = "value") - }))) - @TestOperationBindingProcessor.TestOperationBinding() - private void methodWithAnnotation(SimpleFoo payload) {} - - private void methodWithoutAnnotation() {} - } - - private static class ClassWithMultipleListenerAnnotations { - - @AsyncListener( - operation = @AsyncOperation(channelName = "test-channel-1", description = "test-channel-1-description")) - @AsyncListener( - operation = @AsyncOperation(channelName = "test-channel-2", description = "test-channel-2-description")) - private void methodWithMultipleAnnotation(SimpleFoo payload) {} - } - - private static class ClassWithMessageAnnotation { - - @AsyncListener( - operation = - @AsyncOperation( - channelName = CHANNEL, - description = "test channel operation description", - message = - @AsyncMessage( - description = "Message description", - messageId = "simpleFooId", - name = "SimpleFooPayLoad", - contentType = "application/json", - title = "Message Title"))) - private void methodWithAnnotation(SimpleFoo payload) {} - - private void methodWithoutAnnotation() {} - } - - @Nested - class ImplementingInterface { - @ParameterizedTest - @ValueSource(classes = {ClassImplementingInterface.class, ClassImplementingInterfaceWithAnnotation.class}) - void scan_componentHasOnlyDeclaredMethods(Class clazz) { - // Given a class with a method, which is declared in a generic interface - setClassToScan(clazz); - - // When scan is called - Map actualChannels = channelScanner.scan(); - - // Then the returned collection contains the channel with the actual method, excluding type erased methods - var messagePayload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .description(null) - .payload(messagePayload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .build(); - - ChannelObject expectedChannel = ChannelObject.builder() - .channelId(CHANNEL_ID) - .address(CHANNEL) - .bindings(null) - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .build(); - - assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); - } - - private static class ClassImplementingInterface implements ClassInterface { - - @AsyncListener( - operation = - @AsyncOperation(channelName = CHANNEL, description = "test channel operation description")) - @Override - public void methodFromInterface(String payload) {} - } - - interface ClassInterface { - void methodFromInterface(T payload); - } - - private static class ClassImplementingInterfaceWithAnnotation implements ClassInterfaceWithAnnotation { - - @Override - public void methodFromInterface(String payload) {} - } - - interface ClassInterfaceWithAnnotation { - @AsyncListener( - operation = - @AsyncOperation(channelName = CHANNEL, description = "test channel operation description")) - void methodFromInterface(T payload); - } - } - - @Nested - class MetaAnnotation { - @Test - void scan_componentHasListenerMethodWithMetaAnnotation() { - // Given a class with methods annotated with a AsyncListener meta annotation - setClassToScan(ClassWithMetaAnnotation.class); - - // When scan is called - Map actualChannels = channelScanner.scan(); - - // Then the returned collection contains the channel - var messagePayload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .description(null) - .payload(messagePayload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .build(); - - ChannelObject expectedChannel = ChannelObject.builder() - .channelId(CHANNEL_ID) - .address(CHANNEL) - .bindings(null) - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .build(); - - assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); - } - - public static class ClassWithMetaAnnotation { - @AsyncListenerMetaAnnotation - void methodFromInterface(String payload) {} - } - - @Target({ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) - @Retention(RetentionPolicy.RUNTIME) - @Inherited - @AsyncListener( - operation = @AsyncOperation(channelName = CHANNEL, description = "test channel operation description")) - public @interface AsyncListenerMetaAnnotation {} - } - - @Data - @NoArgsConstructor - @Schema(description = "SimpleFoo Message Description") - private static class SimpleFoo { - private String s; - private boolean b; - } -} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationClassLevelChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationClassLevelChannelsScannerTest.java new file mode 100644 index 000000000..c835665b2 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationClassLevelChannelsScannerTest.java @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.channels.annotations; + +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.channel.AsyncAnnotationChannelService; +import io.swagger.v3.oas.annotations.Hidden; +import org.junit.jupiter.api.Test; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class AsyncAnnotationClassLevelChannelsScannerTest { + private static final String CHANNEL = "test/channel"; + private static final String CHANNEL_ID = ReferenceUtil.toValidId(CHANNEL); + + private final AsyncAnnotationProvider asyncAnnotationProvider = new AsyncAnnotationProvider<>() { + @Override + public Class getAnnotation() { + return TestClassListener.class; + } + + @Override + public AsyncOperation getAsyncOperation(TestClassListener annotation) { + return annotation.operation(); + } + + @Override + public OperationAction getOperationType() { + return OperationAction.SEND; + } + }; + + private final AsyncAnnotationChannelService asyncAnnotationChannelService = + mock(AsyncAnnotationChannelService.class); + + AsyncAnnotationClassLevelChannelsScanner channelScanner = + new AsyncAnnotationClassLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); + + @Test + void scan() { + // given + ChannelObject channel = ChannelObject.builder().channelId(CHANNEL_ID).build(); + when(asyncAnnotationChannelService.buildChannel(any())).thenReturn(channel); + + // when + List actualChannels = channelScanner.scan(ClassWithListenerAnnotation.class); + + // then + assertThat(actualChannels).isEqualTo(List.of(channel, channel)); + + int methodsInClass = 2; + verify(asyncAnnotationChannelService, times(methodsInClass)).buildChannel(any()); + } + + @TestClassListener + private static class ClassWithListenerAnnotation { + + private void method(String payload) {} + + private void secondMethod(Integer payload) {} + + @Hidden + private void hiddenMethod() {} + } + + @Retention(RetentionPolicy.RUNTIME) + @interface TestClassListener { + AsyncOperation operation() default @AsyncOperation(channelName = ""); + } +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationMethodLevelChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationMethodLevelChannelsScannerTest.java new file mode 100644 index 000000000..8517de508 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationMethodLevelChannelsScannerTest.java @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.channels.annotations; + +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.channel.AsyncAnnotationChannelService; +import io.github.springwolf.core.asyncapi.scanners.common.message.AsyncAnnotationMessageService; +import org.junit.jupiter.api.Test; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class AsyncAnnotationMethodLevelChannelsScannerTest { + private static final String CHANNEL = "test/channel"; + private static final String CHANNEL_ID = ReferenceUtil.toValidId(CHANNEL); + + private final AsyncAnnotationProvider asyncAnnotationProvider = new AsyncAnnotationProvider<>() { + @Override + public Class getAnnotation() { + return TestListener.class; + } + + @Override + public AsyncOperation getAsyncOperation(TestListener annotation) { + return annotation.operation(); + } + + @Override + public OperationAction getOperationType() { + return OperationAction.SEND; + } + }; + private final AsyncAnnotationMessageService asyncAnnotationMessageService = + mock(AsyncAnnotationMessageService.class); + private final AsyncAnnotationChannelService asyncAnnotationChannelService = + mock(AsyncAnnotationChannelService.class); + + AsyncAnnotationMethodLevelChannelsScanner channelScanner = + new AsyncAnnotationMethodLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); + + @Test + void scan() { + MessageObject message = + MessageObject.builder().messageId(String.class.getName()).build(); + ChannelObject expectedChannelItem = ChannelObject.builder() + .channelId(CHANNEL_ID) + .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) + .build(); + + when(asyncAnnotationMessageService.buildMessage(any(), any())).thenReturn(message); + when(asyncAnnotationChannelService.buildChannel(any())).thenReturn(expectedChannelItem); + + // when + List channels = channelScanner.scan(ClassWithTestListenerAnnotation.class); + + // then + assertThat(channels).containsExactly(expectedChannelItem); + } + + private static class ClassWithTestListenerAnnotation { + + @TestListener + private void methodWithAnnotation(String payload) {} + + private void methodWithoutAnnotation() {} + } + + @Retention(RetentionPolicy.RUNTIME) + @interface TestListener { + AsyncOperation operation() default @AsyncOperation(channelName = ""); + } +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java index ae5a9d52d..0c1b80488 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java @@ -19,8 +19,10 @@ import io.github.springwolf.core.asyncapi.components.examples.walkers.DefaultSchemaWalker; import io.github.springwolf.core.asyncapi.components.examples.walkers.json.ExampleJsonValueGenerator; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessagesService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; @@ -91,11 +93,13 @@ void setUp() { scanner = new SpringAnnotationClassLevelChannelsScanner<>( TestClassListener.class, TestMethodListener.class, - this.bindingFactory, - new AsyncHeadersNotDocumented(), - payloadMethodService, - headerClassExtractor, - componentsService); + new SpringAnnotationMessagesService<>( + this.bindingFactory, + new AsyncHeadersNotDocumented(), + payloadMethodService, + headerClassExtractor, + componentsService), + new SpringAnnotationChannelService<>(this.bindingFactory)); } @Nested @@ -103,8 +107,7 @@ class NoClassListener { @Test void scan_componentHasNoClassLevelRabbitListenerAnnotation() { // when - List> channels = - scanner.scan(ClassWithoutClassListener.class).toList(); + List channels = scanner.scan(ClassWithoutClassListener.class); // then assertThat(channels).isEmpty(); @@ -122,8 +125,7 @@ class NoMethodListener { @Test void scan_componentHasNoClassLevelRabbitListenerAnnotation() { // when - List> channels = - scanner.scan(ClassWithoutMethodListener.class).toList(); + List channels = scanner.scan(ClassWithoutMethodListener.class); // then assertThat(channels).isEmpty(); @@ -141,11 +143,10 @@ class HiddenClassAnnotation { @Test void scan_componentWithHiddenAnnotationOnClassLevel() { // when - List> actualChannels = - scanner.scan(ClassWithHiddenAnnotation.class).toList(); + List channels = scanner.scan(ClassWithHiddenAnnotation.class); // then - assertThat(actualChannels).isEmpty(); + assertThat(channels).isEmpty(); } @TestClassListener @@ -164,8 +165,7 @@ class OneMethodLevelAnnotation { @Test void scan_componentWithOneMethodLevelAnnotation() { // when - List> actualChannels = - scanner.scan(ClassWithOneMethodLevelHandler.class).toList(); + List channels = scanner.scan(ClassWithOneMethodLevelHandler.class); // then MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() @@ -189,7 +189,7 @@ void scan_componentWithOneMethodLevelAnnotation() { .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannel)); + assertThat(channels).containsExactly(expectedChannel); } @TestClassListener @@ -208,8 +208,7 @@ class MultipleMethodLevelAnnotations { @Test void scan_componentWithMultipleRabbitHandlerMethods() { // when - List> actualChannels = - scanner.scan(ClassWithMultipleMethodLevelHandlers.class).toList(); + List channels = scanner.scan(ClassWithMultipleMethodLevelHandlers.class); // Then the returned collection contains the channel with message set to oneOf MessagePayload simpleFooPayload = MessagePayload.of(MultiFormatSchema.builder() @@ -249,7 +248,7 @@ void scan_componentWithMultipleRabbitHandlerMethods() { MessageReference.toComponentMessage(barMessage))) .build(); - assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannel)); + assertThat(channels).containsExactly(expectedChannel); } @TestClassListener diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java index 19f63165a..a15035018 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java @@ -1,32 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.channels.annotations; -import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; -import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; -import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPMessageBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; +import io.github.springwolf.asyncapi.v3.model.channel.message.Message; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; -import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; -import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; -import io.github.springwolf.core.asyncapi.components.ComponentsService; -import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationClassLevelChannelsScannerIntegrationTest.TestBindingFactory; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; -import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; -import io.swagger.v3.oas.annotations.Hidden; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.junit.jupiter.api.BeforeEach; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessagesService; import org.junit.jupiter.api.Test; import java.lang.annotation.Retention; @@ -36,99 +16,49 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class SpringAnnotationClassLevelChannelsScannerTest { - private final PayloadMethodService payloadMethodService = mock(); - private final HeaderClassExtractor headerClassExtractor = mock(HeaderClassExtractor.class); - private final BindingFactory bindingFactory = mock(BindingFactory.class); - private final ComponentsService componentsService = mock(ComponentsService.class); + private final SpringAnnotationMessagesService springAnnotationMessagesService = + mock(SpringAnnotationMessagesService.class); + private final SpringAnnotationChannelService springAnnotationChannelService = + mock(SpringAnnotationChannelService.class); SpringAnnotationClassLevelChannelsScanner scanner = new SpringAnnotationClassLevelChannelsScanner<>( TestClassListener.class, TestMethodListener.class, - bindingFactory, - new AsyncHeadersNotDocumented(), - payloadMethodService, - headerClassExtractor, - componentsService); - - private static final String CHANNEL = "test/channel"; - private static final Map defaultOperationBinding = - Map.of("protocol", new AMQPOperationBinding()); - private static final Map defaultMessageBinding = - Map.of("protocol", new AMQPMessageBinding()); - private static final Map defaultChannelBinding = - Map.of("protocol", new AMQPChannelBinding()); - - @BeforeEach - void setUp() { - // when - when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL); - - doReturn(defaultOperationBinding).when(bindingFactory).buildOperationBinding(any()); - doReturn(defaultChannelBinding).when(bindingFactory).buildChannelBinding(any()); - doReturn(defaultMessageBinding).when(bindingFactory).buildMessageBinding(any(), any()); - - when(payloadMethodService.extractSchema(any())) - .thenReturn(new PayloadSchemaObject( - String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); - doAnswer(invocation -> AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) - .when(componentsService) - .registerSchema(any(SchemaObject.class)); - } + springAnnotationMessagesService, + springAnnotationChannelService); @Test - void scan_componentHasHiddenAnnotation() { - // when - List> channels = - scanner.scan(ClassWithHiddenAnnotation.class).toList(); - // then - assertThat(channels).isEmpty(); - } + void scan() { + // given + MessageReference message = MessageReference.toComponentMessage("messageId"); + Map messages = Map.of("messageId", message); + + when(springAnnotationChannelService.buildChannel(any(), any())) + .thenReturn(ChannelObject.builder() + .channelId(TestBindingFactory.CHANNEL_ID) + .messages(messages) + .build()); - @Test - void scan_componentHasTestListenerMethods() { // when - List> channels = - scanner.scan(ClassWithTestListenerAnnotation.class).toList(); + List channels = scanner.scan(ClassWithTestListenerAnnotation.class); // then - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(defaultMessageBinding) - .build(); - - ChannelObject expectedChannelItem = ChannelObject.builder() - .channelId(TestBindingFactory.CHANNEL_ID) - .address(TestBindingFactory.CHANNEL) - .bindings(defaultChannelBinding) - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .build(); - - assertThat(channels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannelItem)); - } - - @TestClassListener - @Hidden - private static class ClassWithHiddenAnnotation { - @TestMethodListener - private void methodWithAnnotation(String payload) {} - - private void methodWithoutAnnotation() {} + assertThat(channels) + .isEqualTo(List.of(ChannelObject.builder() + .channelId(TestBindingFactory.CHANNEL_ID) + .messages(Map.of("messageId", message)) + .build())); + + int methodsInClass = 2; + verify(springAnnotationMessagesService) + .buildMessages(any(), argThat(list -> list.size() == methodsInClass), any()); } @TestClassListener @@ -136,14 +66,8 @@ private static class ClassWithTestListenerAnnotation { @TestMethodListener private void methodWithAnnotation(String payload) {} - private void methodWithoutAnnotation() {} - } - - @Data - @NoArgsConstructor - private static class SimpleFoo { - private String s; - private boolean b; + @TestMethodListener + private void methodWithoutAnnotation(Integer integer) {} } @Retention(RetentionPolicy.RUNTIME) diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java index 0ffe50df9..f318110bf 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java @@ -19,8 +19,10 @@ import io.github.springwolf.core.asyncapi.components.examples.walkers.DefaultSchemaWalker; import io.github.springwolf.core.asyncapi.components.examples.walkers.json.ExampleJsonValueGenerator; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; @@ -91,11 +93,11 @@ class SpringAnnotationMethodLevelChannelsScannerIntegrationTest { void setUp() { scanner = new SpringAnnotationMethodLevelChannelsScanner<>( TestChannelListener.class, - this.bindingFactory, - new AsyncHeadersNotDocumented(), payloadMethodService, headerClassExtractor, - componentsService); + new SpringAnnotationChannelService<>(bindingFactory), + new SpringAnnotationMessageService<>( + bindingFactory, new AsyncHeadersNotDocumented(), componentsService)); } @Nested @@ -103,8 +105,7 @@ class NoListener { @Test void scan_componentHasNoListenerMethods() { // when - List> channels = - scanner.scan(ClassWithoutListenerAnnotation.class).toList(); + List channels = scanner.scan(ClassWithoutListenerAnnotation.class); // then assertThat(channels).isEmpty(); @@ -120,11 +121,10 @@ class HiddenMethodAnnotation { @Test void scan_componentWithHiddenAnnotationOnMethodLevel() { // when - List> actualChannels = - scanner.scan(MethodWithHiddenAnnotation.class).toList(); + List channels = scanner.scan(MethodWithHiddenAnnotation.class); // then - assertThat(actualChannels).isEmpty(); + assertThat(channels).isEmpty(); } private static class MethodWithHiddenAnnotation { @@ -142,8 +142,7 @@ class WithListener { @Test void scan_componentHasListenerMethod() { // when - List> actualChannels = - scanner.scan(ClassWithListenerAnnotation.class).toList(); + List channels = scanner.scan(ClassWithListenerAnnotation.class); // then MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() @@ -167,7 +166,7 @@ void scan_componentHasListenerMethod() { .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannel)); + assertThat(channels).containsExactly(expectedChannel); } private static class ClassWithListenerAnnotation { @@ -184,9 +183,7 @@ class OneChannelTwoPayloads { @Test void scan_componentHasTestListenerMethods_multiplePayloads() { // when - List> channels = scanner.scan( - ClassWithTestListenerAnnotationMultiplePayloads.class) - .toList(); + List channels = scanner.scan(ClassWithTestListenerAnnotationMultiplePayloads.class); // then MessagePayload simpleFooPayload = MessagePayload.of(MultiFormatSchema.builder() @@ -230,10 +227,7 @@ void scan_componentHasTestListenerMethods_multiplePayloads() { .messages(Map.of(messageString.getMessageId(), MessageReference.toComponentMessage(messageString))) .build(); - assertThat(channels) - .containsExactlyInAnyOrder( - Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannelItem), - Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannelItem2)); + assertThat(channels).containsExactlyInAnyOrder(expectedChannelItem, expectedChannelItem2); } private static class ClassWithTestListenerAnnotationMultiplePayloads { @@ -251,8 +245,7 @@ class MetaAnnotation { @Test void scan_componentHasListenerMetaMethod() { // when - List> actualChannels = - scanner.scan(ClassWithListenerMetaAnnotation.class).toList(); + List channels = scanner.scan(ClassWithListenerMetaAnnotation.class); // then MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() @@ -276,7 +269,7 @@ void scan_componentHasListenerMetaMethod() { .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannel)); + assertThat(channels).containsExactly(expectedChannel); } private static class ClassWithListenerMetaAnnotation { diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java index ebf44ee20..17c8f3971 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java @@ -1,273 +1,69 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.channels.annotations; -import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; -import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; -import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPMessageBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding; import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; -import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; -import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; -import io.github.springwolf.core.asyncapi.components.ComponentsService; -import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; -import io.swagger.v3.oas.annotations.Hidden; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.springframework.messaging.handler.annotation.Header; -import org.springframework.messaging.handler.annotation.Payload; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class SpringAnnotationMethodLevelChannelsScannerTest { private final PayloadMethodService payloadMethodService = mock(); private final HeaderClassExtractor headerClassExtractor = mock(HeaderClassExtractor.class); - private final BindingFactory bindingFactory = mock(BindingFactory.class); - private final ComponentsService componentsService = mock(ComponentsService.class); + private final SpringAnnotationMessageService springAnnotationMessageService = + mock(SpringAnnotationMessageService.class); + private final SpringAnnotationChannelService springAnnotationChannelService = + mock(SpringAnnotationChannelService.class); SpringAnnotationMethodLevelChannelsScanner scanner = new SpringAnnotationMethodLevelChannelsScanner<>( TestListener.class, - bindingFactory, - new AsyncHeadersNotDocumented(), payloadMethodService, headerClassExtractor, - componentsService); + springAnnotationChannelService, + springAnnotationMessageService); private static final String CHANNEL = "test/channel"; private static final String CHANNEL_ID = ReferenceUtil.toValidId(CHANNEL); - private static final Map defaultOperationBinding = - Map.of("protocol", new AMQPOperationBinding()); - private static final Map defaultMessageBinding = - Map.of("protocol", new AMQPMessageBinding()); - private static final Map defaultChannelBinding = - Map.of("protocol", new AMQPChannelBinding()); - - @BeforeEach - void setUp() throws NoSuchMethodException { - // when - when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL); - - doReturn(defaultOperationBinding).when(bindingFactory).buildOperationBinding(any()); - doReturn(defaultChannelBinding).when(bindingFactory).buildChannelBinding(any()); - doReturn(defaultMessageBinding).when(bindingFactory).buildMessageBinding(any(), any()); - - when(payloadMethodService.extractSchema(any())) - .thenReturn(new PayloadSchemaObject( - String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); - doAnswer(invocation -> AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) - .when(componentsService) - .registerSchema(any(SchemaObject.class)); - - var stringMethod = - ClassWithMultipleTestListenerAnnotation.class.getDeclaredMethod("methodWithAnnotation", String.class); - when(payloadMethodService.extractSchema(stringMethod)) - .thenReturn(new PayloadSchemaObject( - String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); - var simpleFooMethod = ClassWithMultipleTestListenerAnnotation.class.getDeclaredMethod( - "anotherMethodWithAnnotation", SimpleFoo.class); - when(payloadMethodService.extractSchema(simpleFooMethod)) - .thenReturn(new PayloadSchemaObject( - SimpleFoo.class.getName(), - SimpleFoo.class.getSimpleName(), - ComponentSchema.of(new SchemaObject()))); - } - - @Test - void scan_componentHasHiddenAnnotation() { - // when - List> channels = - scanner.scan(ClassWithHiddenAnnotation.class).collect(Collectors.toList()); - - // then - assertThat(channels).isEmpty(); - } - - private static class ClassWithHiddenAnnotation { - - @TestListener - @Hidden - private void methodWithAnnotation(String payload) {} - - private void methodWithoutAnnotation() {} - } @Test - void scan_componentHasTestListenerMethods() { - // when - List> channels = - scanner.scan(ClassWithTestListenerAnnotation.class).collect(Collectors.toList()); - - // then - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(defaultMessageBinding) - .build(); - + void scan() { + MessageObject message = + MessageObject.builder().messageId(String.class.getName()).build(); ChannelObject expectedChannelItem = ChannelObject.builder() .channelId(CHANNEL_ID) - .address(CHANNEL) - .bindings(defaultChannelBinding) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(channels).containsExactly(Map.entry(CHANNEL_ID, expectedChannelItem)); - } - - private static class ClassWithTestListenerAnnotation { - - @TestListener - private void methodWithAnnotation(String payload) {} + when(springAnnotationMessageService.buildMessage(any(), any(), any())).thenReturn(message); + when(springAnnotationChannelService.buildChannel(any(), any())).thenReturn(expectedChannelItem); - private void methodWithoutAnnotation() {} - } - - @Test - void scan_componentHasMultipleTestListenerMethods() { // when - List> channels = - scanner.scan(ClassWithMultipleTestListenerAnnotation.class).toList(); + List channels = scanner.scan(ClassWithTestListenerAnnotation.class); // then - MessagePayload stringPayload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - MessagePayload simpleFooPayload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(SimpleFoo.class.getSimpleName())) - .build()); - - MessageObject stringMessage = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .payload(stringPayload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(defaultMessageBinding) - .build(); - - MessageObject simpleFooMessage = MessageObject.builder() - .messageId(SimpleFoo.class.getName()) - .name(SimpleFoo.class.getName()) - .title(SimpleFoo.class.getSimpleName()) - .payload(simpleFooPayload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(defaultMessageBinding) - .build(); - - ChannelObject methodChannel = ChannelObject.builder() - .channelId(CHANNEL_ID) - .address(CHANNEL) - .bindings(defaultChannelBinding) - .messages(Map.of(stringMessage.getMessageId(), MessageReference.toComponentMessage(stringMessage))) - .build(); - ChannelObject anotherMethodChannel = ChannelObject.builder() - .channelId(CHANNEL_ID) - .address(CHANNEL) - .bindings(defaultChannelBinding) - .messages( - Map.of(simpleFooMessage.getMessageId(), MessageReference.toComponentMessage(simpleFooMessage))) - .build(); - - assertThat(channels) - .containsExactlyInAnyOrderElementsOf( - List.of(Map.entry(CHANNEL_ID, methodChannel), Map.entry(CHANNEL_ID, anotherMethodChannel))); + assertThat(channels).containsExactly(expectedChannelItem); } - private static class ClassWithMultipleTestListenerAnnotation { + private static class ClassWithTestListenerAnnotation { @TestListener private void methodWithAnnotation(String payload) {} - @TestListener - private void anotherMethodWithAnnotation(SimpleFoo payload) {} - } - - @Nested - class HeaderAnnotation { - - @Test - void scan_componentHasHeaderAnnotation() { - // given - when(headerClassExtractor.extractHeader(any(), any())) - .thenReturn(SchemaObject.builder() - .type(SchemaType.OBJECT) - .properties(Map.of( - "header_name", - SchemaObject.builder() - .type(SchemaType.STRING) - .examples(List.of("foobar")) - .build())) - .build()); - - // when - scanner.scan(ClassWithMethodWithHeaderAnnotation.class).toList(); - - // then - verify(componentsService) - .registerSchema(eq(SchemaObject.builder() - .title("HeadersNotDocumented-934983093") - .type(SchemaType.OBJECT) - .description("There can be headers, but they are not explicitly documented.") - .properties(Map.of( - "header_name", - SchemaObject.builder() - .type(SchemaType.STRING) - .examples(List.of("foobar")) - .build())) - .build())); - } - - private static class ClassWithMethodWithHeaderAnnotation { - @TestListener - private void methodWithAnnotationAndHeader( - @Payload String payload, @Header("header_name") String headerValue) {} - } - } - - @Data - @NoArgsConstructor - private static class SimpleFoo { - private String s; - private boolean b; + private void methodWithoutAnnotation() {} } @Retention(RetentionPolicy.RUNTIME) diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationScannerUtilTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationScannerUtilTest.java new file mode 100644 index 000000000..af76eb47c --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationScannerUtilTest.java @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.annotation; + +import io.swagger.v3.oas.annotations.Hidden; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; +import java.util.List; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class AnnotationScannerUtilTest { + + @Nested + class FindAnnotatedMethodsWithClassAnnotation { + @Test + void getRelevantMethods() throws NoSuchMethodException { + List methods = AnnotationScannerUtil.findAnnotatedMethods( + ClassWithMethodAnnotation.class, + ClassAnnotation.class, + MethodAnnotation.class, + (c, m) -> m.stream().map(MethodAndAnnotation::method)) + .toList(); + + assertThat(methods) + .hasSize(1) + .contains(ClassWithMethodAnnotation.class.getDeclaredMethod("annotatedMethod")); + } + + @Test + void getAllMethods() throws NoSuchMethodException { + List methods = AnnotationScannerUtil.findAnnotatedMethods( + ClassWithMethodAnnotation.class, + ClassAnnotation.class, + AllMethods.class, + (c, m) -> m.stream().map(MethodAndAnnotation::method)) + .toList(); + + assertThat(methods) + .hasSize(2) + .contains(ClassWithMethodAnnotation.class.getDeclaredMethod("annotatedMethod")) + .contains(ClassWithMethodAnnotation.class.getDeclaredMethod("nonAnnotatedMethod")) + .doesNotContain(ClassWithMethodAnnotation.class.getDeclaredMethod("hiddenAnnotatedMethod")); + } + + @Test + void findNoRelevantMethodsOnClassWithMissingClassAnnotation() { + List methods = AnnotationScannerUtil.findAnnotatedMethods( + ClassWithoutClassAnnotation.class, + ClassAnnotation.class, + MethodAnnotation.class, + (c, m) -> m.stream().map(MethodAndAnnotation::method)) + .toList(); + + assertThat(methods).isEmpty(); + } + + @Test + void findNoAllMethodsOnClassWithMissingClassAnnotation() { + List methods = AnnotationScannerUtil.findAnnotatedMethods( + ClassWithoutClassAnnotation.class, + ClassAnnotation.class, + AllMethods.class, + (c, m) -> m.stream().map(MethodAndAnnotation::method)) + .toList(); + + assertThat(methods).isEmpty(); + } + + @ClassAnnotation + class ClassWithMethodAnnotation { + @MethodAnnotation + void annotatedMethod() {} + + void nonAnnotatedMethod() {} + + @MethodAnnotation + @Hidden + void hiddenAnnotatedMethod() {} + } + + class ClassWithoutClassAnnotation { + @MethodAnnotation + void annotatedMethod() {} + + void nonAnnotatedMethod() {} + + @MethodAnnotation + @Hidden + void hiddenAnnotatedMethod() {} + } + } + + @Nested + class IsClassRelevant { + @Test + void classWithAnnotationIsRelevant() { + assertTrue(AnnotationScannerUtil.isClassRelevant(ClassWithAnnotation.class, ClassAnnotation.class)); + } + + @Test + void classWithoutAnnotationIsNotRelevant() { + assertFalse(AnnotationScannerUtil.isClassRelevant(ClassWithoutAnnotation.class, ClassAnnotation.class)); + } + + @Test + void hiddenClassIsNotRelevant() { + assertFalse(AnnotationScannerUtil.isClassRelevant(HiddenTestClass.class, ClassAnnotation.class)); + } + + @ClassAnnotation + class ClassWithAnnotation {} + + class ClassWithoutAnnotation {} + + @ClassAnnotation + @Hidden + class HiddenTestClass {} + } + + @Nested + class FindAnnotatedMethods { + + @Test + void getRelevantMethods() throws NoSuchMethodException { + List> methods = AnnotationScannerUtil.findAnnotatedMethods( + ClassWithMethodAnnotation.class, MethodAnnotation.class) + .toList(); + + Method annotatedMethod = ClassWithMethodAnnotation.class.getDeclaredMethod("annotatedMethod"); + + assertThat(methods).hasSize(1).contains(new MethodAndAnnotation<>(annotatedMethod, (MethodAnnotation) + annotatedMethod.getAnnotations()[0])); + } + + @Test + void getAllMethods() throws NoSuchMethodException { + List> methods = AnnotationScannerUtil.findAnnotatedMethods( + ClassWithMethodAnnotation.class, AllMethods.class) + .toList(); + + assertThat(methods) + .hasSize(2) + .contains(new MethodAndAnnotation<>( + ClassWithMethodAnnotation.class.getDeclaredMethod("annotatedMethod"), null)) + .contains(new MethodAndAnnotation<>( + ClassWithMethodAnnotation.class.getDeclaredMethod("nonAnnotatedMethod"), null)) + .doesNotContain(new MethodAndAnnotation<>( + ClassWithMethodAnnotation.class.getDeclaredMethod("hiddenAnnotatedMethod"), null)); + } + + class ClassWithMethodAnnotation { + @MethodAnnotation + void annotatedMethod() {} + + void nonAnnotatedMethod() {} + + @MethodAnnotation + @Hidden + void hiddenAnnotatedMethod() {} + } + } + + @Retention(RetentionPolicy.RUNTIME) + @interface ClassAnnotation {} + + @Retention(RetentionPolicy.RUNTIME) + @interface MethodAnnotation {} +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AnnotationScannerUtilTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationUtilTest.java similarity index 62% rename from springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AnnotationScannerUtilTest.java rename to springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationUtilTest.java index 0ed17371c..fc0ed8fa3 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AnnotationScannerUtilTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AnnotationUtilTest.java @@ -1,8 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.common.utils; +package io.github.springwolf.core.asyncapi.scanners.common.annotation; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.core.annotation.AliasFor; import java.lang.annotation.ElementType; @@ -16,7 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.fail; -class AnnotationScannerUtilTest { +class AnnotationUtilTest { @Nested class FindAnnotationOrThrow { @@ -26,7 +28,7 @@ void findNoAnnotationTest() throws NoSuchMethodException { // when try { - AnnotationScannerUtil.findAnnotationOrThrow(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findFirstAnnotationOrThrow(AnnotationUtilTestAnnotation.class, method); fail(); } catch (IllegalArgumentException e) { // then @@ -40,7 +42,7 @@ void findAnnotationTest() throws NoSuchMethodException { // when AnnotationUtilTestAnnotation annotation = - AnnotationScannerUtil.findAnnotationOrThrow(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findFirstAnnotationOrThrow(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation.field()).isEqualTo("value"); @@ -52,7 +54,7 @@ void findAnnotationRepeatedTest() throws NoSuchMethodException { // when AnnotationUtilTestAnnotation annotation = - AnnotationScannerUtil.findAnnotationOrThrow(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findFirstAnnotationOrThrow(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation.field()).isEqualTo("value"); @@ -64,7 +66,7 @@ void findMetaAnnotationTest() throws NoSuchMethodException { // when AnnotationUtilTestAnnotation annotation = - AnnotationScannerUtil.findAnnotationOrThrow(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findFirstAnnotationOrThrow(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation.field()).isEqualTo("metaField"); @@ -79,7 +81,7 @@ void findNoAnnotationTest() throws NoSuchMethodException { // when AnnotationUtilTestAnnotation annotation = - AnnotationScannerUtil.findAnnotation(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findFirstAnnotation(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation).isNull(); @@ -91,7 +93,7 @@ void findAnnotationTest() throws NoSuchMethodException { // when AnnotationUtilTestAnnotation annotation = - AnnotationScannerUtil.findAnnotation(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findFirstAnnotation(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation.field()).isEqualTo("value"); @@ -103,7 +105,7 @@ void findAnnotationRepeatedTest() throws NoSuchMethodException { // when AnnotationUtilTestAnnotation annotation = - AnnotationScannerUtil.findAnnotation(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findFirstAnnotation(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation.field()).isIn("value", "value2"); @@ -115,7 +117,7 @@ void findMetaAnnotationTest() throws NoSuchMethodException { // when AnnotationUtilTestAnnotation annotation = - AnnotationScannerUtil.findAnnotation(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findFirstAnnotation(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation.field()).isEqualTo("metaField"); @@ -130,7 +132,7 @@ void findNoAnnotationTest() throws NoSuchMethodException { // when Set annotation = - AnnotationScannerUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation).isEmpty(); @@ -142,7 +144,7 @@ void findAnnotationTest() throws NoSuchMethodException { // when Set annotation = - AnnotationScannerUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation).hasSize(1); @@ -155,7 +157,7 @@ void findAnnotationRepeatedTest() throws NoSuchMethodException { // when Set annotation = - AnnotationScannerUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation).hasSize(2); @@ -169,12 +171,75 @@ void findMetaAnnotationTest() throws NoSuchMethodException { // when Set annotation = - AnnotationScannerUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); + AnnotationUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); // then assertThat(annotation).hasSize(1); assertThat(annotation.stream().findAny().get().field()).isEqualTo("metaField"); } + + @Nested + class ImplementingInterface { + @ParameterizedTest + @ValueSource(classes = {ClassImplementingInterface.class, ClassImplementingInterfaceWithAnnotation.class}) + void scan_componentHasOnlyDeclaredMethods(Class clazz) throws NoSuchMethodException { + Method method = clazz.getMethod("methodFromInterface", String.class); + + // when + Set annotation = + AnnotationUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); + + // then + assertThat(annotation).hasSize(1); + } + + private static class ClassImplementingInterface implements ClassInterface { + + @AnnotationUtilTestAnnotation + @Override + public void methodFromInterface(String payload) {} + } + + interface ClassInterface { + void methodFromInterface(T payload); + } + + private static class ClassImplementingInterfaceWithAnnotation + implements ClassInterfaceWithAnnotation { + + @Override + public void methodFromInterface(String payload) {} + } + + interface ClassInterfaceWithAnnotation { + @AnnotationUtilTestAnnotation + void methodFromInterface(T payload); + } + } + + @Nested + class AbstractClass { + @Test + void scan() throws NoSuchMethodException { + Method method = ClassExtendsFromAbstractWithListenerAnnotation.class.getMethod( + "methodWithAnnotation", String.class); + + // when + Set annotation = + AnnotationUtil.findAnnotations(AnnotationUtilTestAnnotation.class, method); + + // then + assertThat(annotation).hasSize(1); + } + + private static class ClassExtendsFromAbstractWithListenerAnnotation + extends AbstractClassWithListenerAnnotation {} + + private abstract static class AbstractClassWithListenerAnnotation { + @AnnotationUtilTestAnnotation + public void methodWithAnnotation(String payload) {} + } + } } private class TestClass { diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtilTest.java similarity index 99% rename from springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java rename to springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtilTest.java index b3a1e573f..0658c001f 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtilTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.common.utils; +package io.github.springwolf.core.asyncapi.scanners.common.annotation; import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelServiceTest.java new file mode 100644 index 000000000..48156b9f0 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelServiceTest.java @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.channel; + +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.info.Info; +import io.github.springwolf.asyncapi.v3.model.operation.Operation; +import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; +import io.github.springwolf.asyncapi.v3.model.server.ServerReference; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; +import io.github.springwolf.core.asyncapi.scanners.common.message.AsyncAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.AsyncAnnotationOperationService; +import io.github.springwolf.core.configuration.docket.AsyncApiDocket; +import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.util.StringValueResolver; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class AsyncAnnotationChannelServiceTest { + private static final String CHANNEL = "test/channel"; + private static final String CHANNEL_ID = ReferenceUtil.toValidId(CHANNEL); + + private final AsyncAnnotationProvider asyncAnnotationProvider = new AsyncAnnotationProvider<>() { + @Override + public Class getAnnotation() { + return TestListener.class; + } + + @Override + public AsyncOperation getAsyncOperation(TestListener annotation) { + return annotation.operation(); + } + + @Override + public OperationAction getOperationType() { + return OperationAction.SEND; + } + }; + private final AsyncAnnotationMessageService asyncAnnotationMessageService = + mock(AsyncAnnotationMessageService.class); + private final AsyncAnnotationOperationService asyncAnnotationOperationService = + mock(AsyncAnnotationOperationService.class); + private final StringValueResolver resolver = mock(StringValueResolver.class); + private final AsyncApiDocketService asyncApiDocketService = mock(AsyncApiDocketService.class); + + AsyncAnnotationChannelService asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( + asyncAnnotationProvider, + asyncAnnotationOperationService, + asyncAnnotationMessageService, + resolver, + asyncApiDocketService); + + @BeforeEach + void setUp() { + doAnswer(invocation -> invocation.getArgument(0)).when(resolver).resolveStringValue(any()); + } + + @Test + void scan() throws NoSuchMethodException { + // given + Method method = ClassWithListenerAnnotation.class.getDeclaredMethod("methodWithAnnotation", String.class); + MethodAndAnnotation methodAndAnnotation = + new MethodAndAnnotation<>(method, method.getAnnotation(TestListener.class)); + + MessageObject message = + MessageObject.builder().messageId(String.class.getName()).build(); + when(asyncAnnotationMessageService.buildMessage(any(), any())).thenReturn(message); + + // when + ChannelObject channel = asyncAnnotationChannelService.buildChannel(methodAndAnnotation); + + // then + assertThat(channel) + .isEqualTo(ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) + .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) + .build()); + } + + @Nested + class Server { + @Test + void scan() throws NoSuchMethodException { + // given + Method method = + ClassWithListenerAnnotationWithServer.class.getDeclaredMethod("methodWithAnnotation", String.class); + MethodAndAnnotation methodAndAnnotation = + new MethodAndAnnotation<>(method, method.getAnnotation(TestListener.class)); + + when(asyncAnnotationOperationService.buildOperation(any(), any(Method.class), any())) + .thenReturn(Operation.builder().title("operationId").build()); + AsyncApiDocket docket = AsyncApiDocket.builder() + .info(Info.builder().build()) + .server("server1", null) + .build(); + when(asyncApiDocketService.getAsyncApiDocket()).thenReturn(docket); + + MessageObject message = + MessageObject.builder().messageId(String.class.getName()).build(); + when(asyncAnnotationMessageService.buildMessage(any(), any())).thenReturn(message); + + // when + ChannelObject channel = asyncAnnotationChannelService.buildChannel(methodAndAnnotation); + + // then + assertThat(channel) + .isEqualTo(ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) + .servers(List.of(ServerReference.fromServer("server1"))) + .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) + .build()); + } + + @Test + void scanInvalid() throws NoSuchMethodException { + // given + Method method = ClassWithListenerAnnotationWithInvalidServer.class.getDeclaredMethod( + "methodWithAnnotation", String.class); + MethodAndAnnotation methodAndAnnotation = + new MethodAndAnnotation<>(method, method.getAnnotation(TestListener.class)); + + when(asyncAnnotationOperationService.buildOperation(any(), any(Method.class), any())) + .thenReturn(Operation.builder().title("operationId").build()); + AsyncApiDocket docket = AsyncApiDocket.builder() + .info(Info.builder().build()) + .server("server1", null) + .server("server2", null) + .build(); + when(asyncApiDocketService.getAsyncApiDocket()).thenReturn(docket); + + // when + assertThatThrownBy(() -> asyncAnnotationChannelService.buildChannel(methodAndAnnotation)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage( + "Operation 'operationId' defines unknown server ref 'server3'. This AsyncApi defines these server(s): [server1, server2]"); + } + + private static class ClassWithListenerAnnotationWithServer { + + @TestListener( + operation = + @AsyncOperation( + channelName = CHANNEL, + servers = {"server1"})) + private void methodWithAnnotation(String payload) {} + } + + private static class ClassWithListenerAnnotationWithInvalidServer { + + @TestListener( + operation = + @AsyncOperation( + channelName = CHANNEL, + servers = {"server3"})) + private void methodWithAnnotation(String payload) {} + } + } + + private static class ClassWithListenerAnnotation { + + @TestListener + private void methodWithAnnotation(String payload) {} + } + + @Retention(RetentionPolicy.RUNTIME) + @interface TestListener { + AsyncOperation operation() default @AsyncOperation(channelName = CHANNEL); + } +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageServiceTest.java new file mode 100644 index 000000000..da83ee902 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageServiceTest.java @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.message; + +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; +import io.github.springwolf.core.asyncapi.annotations.AsyncMessage; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.components.ComponentsService; +import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; +import io.swagger.v3.oas.annotations.media.Schema; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.util.StringValueResolver; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class AsyncAnnotationMessageServiceTest { + + private final PayloadAsyncOperationService payloadAsyncOperationService = mock(PayloadAsyncOperationService.class); + private final ComponentsService componentsService = mock(ComponentsService.class); + private final MessageBindingProcessor messageBindingProcessor = mock(MessageBindingProcessor.class); + private final StringValueResolver resolver = mock(StringValueResolver.class); + AsyncAnnotationMessageService asyncAnnotationMessageService = new AsyncAnnotationMessageService( + payloadAsyncOperationService, componentsService, List.of(messageBindingProcessor), resolver); + + private final PayloadSchemaObject payloadSchema = new PayloadSchemaObject("full.name", "name", null); + + @BeforeEach + void setUp() { + doAnswer(invocation -> invocation.getArgument(0)).when(resolver).resolveStringValue(any()); + + when(componentsService.registerSchema(any())).thenReturn("headerSchemaName"); + when(messageBindingProcessor.process(any())).thenReturn(Optional.empty()); + + when(payloadAsyncOperationService.extractSchema(any(), any())).thenReturn(payloadSchema); + } + + @Test + void buildMessage() throws NoSuchMethodException { + // given + Method method = ClassWithAnnotation.class.getDeclaredMethod("methodWithAnnotation", String.class); + AsyncOperation operationData = method.getAnnotation(TestListener.class).operation(); + + // when + MessageObject message = asyncAnnotationMessageService.buildMessage(operationData, method); + + // then + assertThat(message) + .isEqualTo(MessageObject.builder() + .title("full.name") + .name("full.name") + .title("name") + .description(null) + .headers(MessageHeaders.of(MessageReference.toSchema("headerSchemaName"))) + .payload(MessagePayload.of(MultiFormatSchema.builder() + .schema(payloadSchema.payload()) + .build())) + .bindings(Map.of()) + .build()); + } + + @Nested + class Description { + @Test + public void testAsyncOperationDescription() throws NoSuchMethodException { + // given + Method method = + ClassWithAsyncOperationDescription.class.getDeclaredMethod("methodWithAnnotation", String.class); + AsyncOperation operationData = + method.getAnnotation(TestListener.class).operation(); + + // when + MessageObject message = asyncAnnotationMessageService.buildMessage(operationData, method); + + // then + assertThat(message.getDescription()).isNull(); + } + + @Test + public void testAsyncMessageDescription() throws NoSuchMethodException { + // given + Method method = + ClassWithAsyncMessageDescription.class.getDeclaredMethod("methodWithAnnotation", String.class); + AsyncOperation operationData = + method.getAnnotation(TestListener.class).operation(); + + // when + MessageObject message = asyncAnnotationMessageService.buildMessage(operationData, method); + + // then + assertThat(message.getDescription()).isEqualTo("test-description"); + } + + @Test + public void testSchemaDescription() throws NoSuchMethodException { + // given + Method method = ClassWithSchemaDescription.class.getDeclaredMethod("methodWithAnnotation", Foo.class); + AsyncOperation operationData = + method.getAnnotation(TestListener.class).operation(); + + // when + MessageObject message = asyncAnnotationMessageService.buildMessage(operationData, method); + + // then + assertThat(message.getDescription()).isNull(); + } + + static class ClassWithAsyncOperationDescription { + @TestListener(operation = @AsyncOperation(channelName = "test-channel", description = "test-description")) + public void methodWithAnnotation(String payload) {} + } + + static class ClassWithAsyncMessageDescription { + @TestListener( + operation = + @AsyncOperation( + channelName = "test-channel", + message = @AsyncMessage(description = "test-description"))) + public void methodWithAnnotation(String payload) {} + } + + static class ClassWithSchemaDescription { + @TestListener(operation = @AsyncOperation(channelName = "test-channel")) + public void methodWithAnnotation(Foo payload) {} + } + + @Schema(description = "test-description") + static class Foo { + private String value; + } + } + + static class ClassWithAnnotation { + @TestListener + public void methodWithAnnotation(String payload) {} + } + + @Retention(RetentionPolicy.RUNTIME) + @interface TestListener { + AsyncOperation operation() default @AsyncOperation(channelName = "test-channel"); + } +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationServiceTest.java new file mode 100644 index 000000000..1e8e3b46f --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/operation/SpringAnnotationOperationServiceTest.java @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.common.operation; + +import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; +import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding; +import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; +import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.operation.Operation; +import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class SpringAnnotationOperationServiceTest { + private final BindingFactory bindingFactory = mock(BindingFactory.class); + private final SpringAnnotationMessageService springAnnotationMessageService = + mock(SpringAnnotationMessageService.class); + SpringAnnotationOperationService springAnnotationOperationService = + new SpringAnnotationOperationService<>(bindingFactory, springAnnotationMessageService); + + private static final String CHANNEL_ID = "test-channel-id"; + private static final Map defaultOperationBinding = + Map.of("protocol", new AMQPOperationBinding()); + + @BeforeEach + void setUp() { + // when + when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL_ID); + doReturn(defaultOperationBinding).when(bindingFactory).buildOperationBinding(any()); + } + + @Test + void scan_componentHasTestListenerMethods() throws NoSuchMethodException { + // given + TestMethodListener annotation = ClassWithTestListenerAnnotation.class + .getDeclaredMethod("methodWithAnnotation", String.class) + .getAnnotation(TestMethodListener.class); + PayloadSchemaObject payloadSchemaName = new PayloadSchemaObject("name", "full.name", null); + SchemaObject headerSchema = new SchemaObject(); + MessageObject messageObject = + MessageObject.builder().messageId(String.class.getName()).build(); + + when(springAnnotationMessageService.buildMessage(annotation, payloadSchemaName, headerSchema)) + .thenReturn(messageObject); + + // when + Operation operations = + springAnnotationOperationService.buildOperation(annotation, payloadSchemaName, headerSchema); + + // then + Operation expectedOperation = Operation.builder() + .action(OperationAction.RECEIVE) + .channel(ChannelReference.fromChannel(CHANNEL_ID)) + .messages(List.of(MessageReference.toChannelMessage(CHANNEL_ID, messageObject))) + .bindings(Map.of("protocol", AMQPOperationBinding.builder().build())) + .build(); + assertThat(expectedOperation).isEqualTo(operations); + } + + private static class ClassWithTestListenerAnnotation { + @TestMethodListener + private void methodWithAnnotation(String payload) {} + } + + @Retention(RetentionPolicy.RUNTIME) + @interface TestMethodListener {} +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationMergerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationMergerTest.java index 484fdf306..7354f832e 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationMergerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationMergerTest.java @@ -132,14 +132,16 @@ void shouldUseOtherMessageIfFirstMessageIsMissingForChannels() { .name(String.class.getCanonicalName()) .description("This is a string") .build(); - ChannelObject publisherChannel1 = ChannelObject.builder().build(); + ChannelObject publisherChannel1 = + ChannelObject.builder().channelId(channelId).build(); ChannelObject publisherChannel2 = ChannelObject.builder() + .channelId(channelId) .messages(Map.of(message2.getMessageId(), message2)) .build(); // when - Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelId, publisherChannel1), Map.entry(channelId, publisherChannel2))); + Map mergedChannels = + ChannelMerger.mergeChannels(Arrays.asList(publisherChannel1, publisherChannel2)); // then expectedMessage message2 var expectedMessages = Map.of(message2.getMessageId(), message2); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/SpringAnnotationOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationsInClassScannerAdapterTest.java similarity index 72% rename from springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/SpringAnnotationOperationsScannerTest.java rename to springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationsInClassScannerAdapterTest.java index 0d847397a..7ffbdf4b6 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/SpringAnnotationOperationsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationsInClassScannerAdapterTest.java @@ -3,7 +3,6 @@ import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; -import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationOperationsScannerDelegator; import org.junit.jupiter.api.Test; import java.util.Map; @@ -15,19 +14,18 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -class SpringAnnotationOperationsScannerTest { +class OperationsInClassScannerAdapterTest { private final ClassScanner classScanner = mock(ClassScanner.class); - private final SpringAnnotationOperationsScannerDelegator classProcessor = - mock(SpringAnnotationOperationsScannerDelegator.class); + private final OperationsInClassScanner classProcessor = mock(OperationsInClassScanner.class); - private final SpringAnnotationOperationsScanner springAnnotationOperationsScanner = - new SpringAnnotationOperationsScanner(classScanner, classProcessor); + private final OperationsInClassScannerAdapter operationsInClassScannerAdapter = + new OperationsInClassScannerAdapter(classScanner, classProcessor); @Test void noClassFoundTest() { // when - Map operations = springAnnotationOperationsScanner.scan(); + Map operations = operationsInClassScannerAdapter.scan(); // then assertThat(operations).isEmpty(); @@ -44,7 +42,7 @@ void processClassTest() { when(classProcessor.scan(any())).thenReturn(Stream.of(operation1, operation2)); // when - Map operations = springAnnotationOperationsScanner.scan(); + Map operations = operationsInClassScannerAdapter.scan(); // then assertThat(operations).containsExactly(operation2, operation1); @@ -61,7 +59,7 @@ void sameOperationsAreMergedTest() { when(classProcessor.scan(any())).thenReturn(Stream.of(operation1, operation2)); // when - Map operations = springAnnotationOperationsScanner.scan(); + Map operations = operationsInClassScannerAdapter.scan(); // then assertThat(operations) @@ -75,7 +73,7 @@ void processEmptyClassTest() { when(classProcessor.scan(any())).thenReturn(Stream.of()); // when - Map operations = springAnnotationOperationsScanner.scan(); + Map operations = operationsInClassScannerAdapter.scan(); // then assertThat(operations).isEmpty(); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationClassLevelOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationClassLevelOperationsScannerTest.java new file mode 100644 index 000000000..98b37e883 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationClassLevelOperationsScannerTest.java @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.operations.annotations; + +import io.github.springwolf.asyncapi.v3.model.operation.Operation; +import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.operation.AsyncAnnotationOperationService; +import org.junit.jupiter.api.Test; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anySet; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class AsyncAnnotationClassLevelOperationsScannerTest { + + private final AsyncAnnotationProvider asyncAnnotationProvider = new AsyncAnnotationProvider<>() { + @Override + public Class getAnnotation() { + return TestListener.class; + } + + @Override + public AsyncOperation getAsyncOperation(TestListener annotation) { + return annotation.operation(); + } + + @Override + public OperationAction getOperationType() { + return OperationAction.SEND; + } + }; + private final AsyncAnnotationOperationService asyncAnnotationOperationService = + mock(AsyncAnnotationOperationService.class); + private final OperationCustomizer operationCustomizer = mock(OperationCustomizer.class); + + private final AsyncAnnotationClassLevelOperationsScanner operationsScanner = + new AsyncAnnotationClassLevelOperationsScanner<>( + TestListener.class, + asyncAnnotationProvider, + asyncAnnotationOperationService, + List.of(operationCustomizer)); + + @Test + void scan() { + // given + Operation operation = Operation.builder().build(); + when(asyncAnnotationOperationService.buildOperation(any(), anySet(), any())) + .thenReturn(operation); + + // when + Map actualOperations = operationsScanner + .scan(ClassWithListenerAnnotation.class) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + // then + assertThat(actualOperations).hasSize(1); + assertThat(actualOperations) + .containsExactlyEntriesOf(Map.of("test-channel_send_ClassWithListenerAnnotation", operation)); + } + + @Test + void operationCustomizerIsCalled() { + // given + Operation operation = Operation.builder().build(); + when(asyncAnnotationOperationService.buildOperation(any(), anySet(), any())) + .thenReturn(operation); + + // when + operationsScanner.scan(ClassWithListenerAnnotation.class).toList(); + + // then + verify(operationCustomizer).customize(any(), any()); + } + + @TestListener + private static class ClassWithListenerAnnotation { + private void method(String payload) {} + } + + @Retention(RetentionPolicy.RUNTIME) + @interface TestListener { + AsyncOperation operation() default @AsyncOperation(channelName = "test-channel"); + } +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScannerTest.java new file mode 100644 index 000000000..c0dee8a11 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScannerTest.java @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.operations.annotations; + +import io.github.springwolf.asyncapi.v3.model.operation.Operation; +import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; +import io.github.springwolf.core.asyncapi.annotations.AsyncListener; +import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; +import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationProvider; +import io.github.springwolf.core.asyncapi.scanners.common.operation.AsyncAnnotationOperationService; +import io.github.springwolf.core.asyncapi.scanners.common.utils.StringValueResolverProxy; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class AsyncAnnotationMethodLevelOperationsScannerTest { + + private final AsyncAnnotationProvider asyncAnnotationProvider = new AsyncAnnotationProvider<>() { + @Override + public Class getAnnotation() { + return AsyncListener.class; + } + + @Override + public AsyncOperation getAsyncOperation(AsyncListener annotation) { + return annotation.operation(); + } + + @Override + public OperationAction getOperationType() { + return OperationAction.SEND; + } + }; + private final OperationCustomizer operationCustomizer = mock(OperationCustomizer.class); + + private final StringValueResolverProxy stringValueResolver = mock(StringValueResolverProxy.class); + private final AsyncAnnotationOperationService asyncAnnotationOperationService = + mock(AsyncAnnotationOperationService.class); + + private final AsyncAnnotationMethodLevelOperationsScanner operationsScanner = + new AsyncAnnotationMethodLevelOperationsScanner<>( + asyncAnnotationProvider, + asyncAnnotationOperationService, + List.of(operationCustomizer), + stringValueResolver); + + @BeforeEach + public void setup() { + doAnswer(invocation -> invocation.getArgument(0)) + .when(stringValueResolver) + .resolveStringValue(any()); + } + + @Test + void scan_componentOperationHasListenerMethod() { + // given + Operation operation = Operation.builder().build(); + when(asyncAnnotationOperationService.buildOperation(any(), any(Method.class), any())) + .thenReturn(operation); + + // when + Map actualOperations = operationsScanner + .scan(ClassWithListenerAnnotation.class) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + // then + assertThat(actualOperations).containsExactly(Map.entry("test-channel_send_methodWithAnnotation", operation)); + } + + @Test + void operationCustomizerIsCalled() { + // given + Operation operation = Operation.builder().build(); + when(asyncAnnotationOperationService.buildOperation(any(), any(Method.class), any())) + .thenReturn(operation); + + // when + operationsScanner + .scan(ClassWithListenerAnnotation.class) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + // then + verify(operationCustomizer).customize(any(), any()); + } + + private static class ClassWithListenerAnnotation { + + @AsyncListener( + operation = @AsyncOperation(channelName = "test-channel", description = "test-channel-1-description")) + private void methodWithAnnotation(String payload) {} + } +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScannerTest.java deleted file mode 100644 index 8622c91a5..000000000 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScannerTest.java +++ /dev/null @@ -1,586 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.core.asyncapi.scanners.operations.annotations; - -import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; -import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; -import io.github.springwolf.asyncapi.v3.model.info.Info; -import io.github.springwolf.asyncapi.v3.model.operation.Operation; -import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; -import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; -import io.github.springwolf.asyncapi.v3.model.server.Server; -import io.github.springwolf.core.asyncapi.annotations.AsyncListener; -import io.github.springwolf.core.asyncapi.annotations.AsyncMessage; -import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; -import io.github.springwolf.core.asyncapi.components.ComponentsService; -import io.github.springwolf.core.asyncapi.components.DefaultComponentsService; -import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.bindings.operations.OperationBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.bindings.processor.TestOperationBindingProcessor; -import io.github.springwolf.core.asyncapi.scanners.classes.ClassScanner; -import io.github.springwolf.core.asyncapi.scanners.common.AsyncAnnotationScanner; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; -import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadClassExtractor; -import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; -import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaService; -import io.github.springwolf.core.asyncapi.schemas.SwaggerSchemaUtil; -import io.github.springwolf.core.configuration.docket.AsyncApiDocket; -import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; -import io.github.springwolf.core.configuration.properties.SpringwolfConfigProperties; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.springframework.util.StringValueResolver; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static java.util.Collections.EMPTY_MAP; -import static java.util.Collections.emptyList; -import static java.util.Collections.singleton; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -class AsyncAnnotationOperationsScannerTest { - - private final AsyncAnnotationScanner.AsyncAnnotationProvider asyncAnnotationProvider = - new AsyncAnnotationScanner.AsyncAnnotationProvider<>() { - @Override - public Class getAnnotation() { - return AsyncListener.class; - } - - @Override - public AsyncOperation getAsyncOperation(AsyncListener annotation) { - return annotation.operation(); - } - - @Override - public OperationAction getOperationType() { - return OperationAction.SEND; - } - }; - private final SwaggerSchemaUtil swaggerSchemaUtil = new SwaggerSchemaUtil(); - private final SpringwolfConfigProperties properties = new SpringwolfConfigProperties(); - private final ClassScanner classScanner = mock(ClassScanner.class); - private final SwaggerSchemaService schemaService = - new SwaggerSchemaService(emptyList(), emptyList(), swaggerSchemaUtil, properties); - private final ComponentsService componentsService = new DefaultComponentsService(schemaService); - private final AsyncApiDocketService asyncApiDocketService = mock(AsyncApiDocketService.class); - private final PayloadClassExtractor payloadClassExtractor = new PayloadClassExtractor(properties); - private final PayloadService payloadService = new PayloadService(componentsService, properties); - private final PayloadAsyncOperationService payloadAsyncOperationService = - new PayloadAsyncOperationService(payloadClassExtractor, payloadService); - - private final List operationBindingProcessors = - List.of(new TestOperationBindingProcessor()); - private final List messageBindingProcessors = emptyList(); - private final OperationCustomizer operationCustomizer = mock(OperationCustomizer.class); - - private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); - - private final AsyncAnnotationOperationsScanner operationsScanner = - new AsyncAnnotationOperationsScanner<>( - asyncAnnotationProvider, - classScanner, - componentsService, - payloadAsyncOperationService, - operationBindingProcessors, - messageBindingProcessors, - List.of(operationCustomizer)); - - @BeforeEach - public void setup() { - when(asyncApiDocketService.getAsyncApiDocket()) - .thenReturn(AsyncApiDocket.builder() - .info(new Info()) - .server("server1", new Server()) - .server("server2", new Server()) - .build()); - - operationsScanner.setEmbeddedValueResolver(stringValueResolver); - when(stringValueResolver.resolveStringValue(any())) - .thenAnswer(invocation -> switch ((String) invocation.getArgument(0)) { - case "${test.property.test-channel}" -> "test-channel"; - case "${test.property.description}" -> "description"; - case "${test.property.server1}" -> "server1"; - case "${test.property.server2}" -> "server2"; - default -> invocation.getArgument(0); - }); - } - - private void setClassToScan(Class classToScan) { - Set> classesToScan = singleton(classToScan); - when(classScanner.scan()).thenReturn(classesToScan); - } - - @Test - void scan_componentHasNoListenerMethods() { - setClassToScan(ClassWithoutListenerAnnotation.class); - - Map channels = operationsScanner.scan(); - - assertThat(channels).isEmpty(); - } - - @Test - void scan_componentOperationHasListenerMethod() { - // Given a class with methods annotated with AsyncListener, where only the channel-name is set - setClassToScan(ClassWithListenerAnnotation.class); - - // When scan is called - Map actualOperations = operationsScanner.scan(); - - // Then the returned collection contains the channel - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(SimpleFoo.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(SimpleFoo.class.getName()) - .name(SimpleFoo.class.getName()) - .title(SimpleFoo.class.getSimpleName()) - .description("SimpleFoo Message Description") - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .build(); - - Operation expectedOperation = Operation.builder() - .title("test-channel_send") - .action(OperationAction.SEND) - .description("Auto-generated description") - .channel(ChannelReference.fromChannel("test-channel")) - .messages(List.of(MessageReference.toChannelMessage("test-channel", message))) - .bindings(EMPTY_MAP) - .build(); - - assertThat(actualOperations) - .containsExactly(Map.entry("test-channel_send_methodWithAnnotation", expectedOperation)); - } - - @Test - void scan_componentHasListenerMethodWithAllAttributes() { - // Given a class with method annotated with AsyncListener, where all attributes are set - setClassToScan(ClassWithListenerAnnotationWithAllAttributes.class); - - // When scan is called - Map actualOperations = operationsScanner.scan(); - - // Then the returned collection contains the channel - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .description(null) - .payload(payload) - .headers(MessageHeaders.of(MessageReference.toSchema("TestSchema"))) - .bindings(EMPTY_MAP) - .build(); - - Operation expectedOperation = Operation.builder() - .action(OperationAction.SEND) - .title("test-channel_send") - .channel(ChannelReference.fromChannel("test-channel")) - .description("description") - .bindings(Map.of(TestOperationBindingProcessor.TYPE, TestOperationBindingProcessor.BINDING)) - .messages(List.of(MessageReference.toChannelMessage("test-channel", message))) - .build(); - - assertThat(actualOperations) - .containsExactly(Map.entry("test-channel_send_methodWithAnnotation", expectedOperation)); - } - - @Test - void scan_componentHasMultipleListenerAnnotations() { - // Given a class with methods annotated with AsyncListener, where only the channel-name is set - setClassToScan(ClassWithMultipleListenerAnnotations.class); - - // When scan is called - Map actualOperations = operationsScanner.scan(); - - // Then the returned collection contains the channel - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(SimpleFoo.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(SimpleFoo.class.getName()) - .name(SimpleFoo.class.getName()) - .title(SimpleFoo.class.getSimpleName()) - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .description("SimpleFoo Message Description") - .build(); - - Operation expectedOperation1 = Operation.builder() - .action(OperationAction.SEND) - .channel(ChannelReference.fromChannel("test-channel-1")) - .description("test-channel-1-description") - .title("test-channel-1_send") - .bindings(EMPTY_MAP) - .messages(List.of(MessageReference.toChannelMessage("test-channel-1", message))) - .build(); - - Operation expectedOperation2 = Operation.builder() - .action(OperationAction.SEND) - .channel(ChannelReference.fromChannel("test-channel-2")) - .description("test-channel-2-description") - .title("test-channel-2_send") - .bindings(EMPTY_MAP) - .messages(List.of(MessageReference.toChannelMessage("test-channel-2", message))) - .build(); - - assertThat(actualOperations) - .containsExactlyInAnyOrderEntriesOf(Map.of( - "test-channel-1_send_methodWithMultipleAnnotation", expectedOperation1, - "test-channel-2_send_methodWithMultipleAnnotation", expectedOperation2)); - } - - @Test - void scan_componentHasAsyncMethodAnnotation() { - // Given a class with methods annotated with AsyncListener, where only the channel-name is set - setClassToScan(ClassWithMessageAnnotation.class); - - // When scan is called - Map actualOperations = operationsScanner.scan(); - - // Then the returned collection contains the channel - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(SimpleFoo.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId("simpleFoo") - .name("SimpleFooPayLoad") - .title("Message Title") - .description("Message description") - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .build(); - - Operation expectedOperation = Operation.builder() - .action(OperationAction.SEND) - .channel(ChannelReference.fromChannel("test-channel")) - .description("test channel operation description") - .title("test-channel_send") - .bindings(EMPTY_MAP) - .messages(List.of(MessageReference.toChannelMessage("test-channel", message))) - .build(); - - assertThat(actualOperations) - .containsExactly(Map.entry("test-channel_send_methodWithAnnotation", expectedOperation)); - } - - @Test - void scan_componentHasAsyncMethodAnnotationInAbstractClass() { - // Given a class with methods annotated with AsyncListener, where only the channel-name is set - setClassToScan(ClassExtendsFromAbstractWithListenerAnnotation.class); - - // When scan is called - Map actualOperations = operationsScanner.scan(); - - // Then the returned collection contains the channel - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(SimpleFoo.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId("simpleFooAbstract") - .name("SimpleFooPayLoad") - .title("Message Title") - .description("Message description") - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .build(); - - Operation expectedOperation = Operation.builder() - .action(OperationAction.SEND) - .channel(ChannelReference.fromChannel("abstract-test-channel")) - .description("test abstract channel operation description") - .title("abstract-test-channel_send") - .bindings(EMPTY_MAP) - .messages(List.of(MessageReference.toChannelMessage("abstract-test-channel", message))) - .build(); - - assertThat(actualOperations) - .containsExactly(Map.entry("abstract-test-channel_send_methodWithAnnotation", expectedOperation)); - } - - @Test - void operationCustomizerIsCalled() { - // given - setClassToScan(ClassWithListenerAnnotation.class); - - // when - operationsScanner.scan(); - - // then - verify(operationCustomizer).customize(any(), any()); - } - - private static class ClassWithoutListenerAnnotation { - - private void methodWithoutAnnotation() {} - } - - private static class ClassWithListenerAnnotation { - - @AsyncListener(operation = @AsyncOperation(channelName = "test-channel")) - private void methodWithAnnotation(SimpleFoo payload) {} - - private void methodWithoutAnnotation() {} - } - - private static class ClassWithListenerAnnotationWithInvalidServer { - - @AsyncListener( - operation = - @AsyncOperation( - channelName = "test-channel", - description = "test channel operation description", - servers = {"server3"})) - private void methodWithAnnotation(SimpleFoo payload) {} - } - - private static class ClassWithListenerAnnotationWithAllAttributes { - - @AsyncListener( - operation = - @AsyncOperation( - channelName = "${test.property.test-channel}", - description = "${test.property.description}", - payloadType = String.class, - servers = {"${test.property.server1}", "${test.property.server2}"}, - headers = - @AsyncOperation.Headers( - schemaName = "TestSchema", - values = { - @AsyncOperation.Headers.Header(name = "header", value = "value") - }))) - @TestOperationBindingProcessor.TestOperationBinding() - private void methodWithAnnotation(SimpleFoo payload) {} - - private void methodWithoutAnnotation() {} - } - - private static class ClassWithMultipleListenerAnnotations { - - @AsyncListener( - operation = @AsyncOperation(channelName = "test-channel-1", description = "test-channel-1-description")) - @AsyncListener( - operation = @AsyncOperation(channelName = "test-channel-2", description = "test-channel-2-description")) - private void methodWithMultipleAnnotation(SimpleFoo payload) {} - } - - private static class ClassWithMessageAnnotation { - - @AsyncListener( - operation = - @AsyncOperation( - channelName = "test-channel", - description = "test channel operation description", - message = - @AsyncMessage( - description = "Message description", - messageId = "simpleFoo", - name = "SimpleFooPayLoad", - contentType = "application/json", - title = "Message Title"))) - private void methodWithAnnotation(SimpleFoo payload) {} - - private void methodWithoutAnnotation() {} - } - - private static class ClassExtendsFromAbstractWithListenerAnnotation extends AbstractClassWithListenerAnnotation {} - - private abstract static class AbstractClassWithListenerAnnotation { - - @AsyncListener( - operation = - @AsyncOperation( - channelName = "abstract-test-channel", - description = "test abstract channel operation description", - message = - @AsyncMessage( - description = "Message description", - messageId = "simpleFooAbstract", - name = "SimpleFooPayLoad", - contentType = "application/json", - title = "Message Title"))) - protected void methodWithAnnotation(SimpleFoo payload) {} - } - - @Nested - class ImplementingInterface { - @ParameterizedTest - @ValueSource(classes = {ClassImplementingInterface.class, ClassImplementingInterfaceWithAnnotation.class}) - void scan_componentHasOnlyDeclaredMethods(Class clazz) { - // Given a class with a method, which is declared in a generic interface - setClassToScan(clazz); - - // When scan is called - Map actualOperations = operationsScanner.scan(); - - // Then the returned collection contains the channel with the actual method, excluding type erased methods - var messagePayload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .description(null) - .payload(messagePayload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .build(); - - Operation expectedOperation = Operation.builder() - .action(OperationAction.SEND) - .channel(ChannelReference.fromChannel("test-channel")) - .description("test channel operation description") - .title("test-channel_send") - .bindings(EMPTY_MAP) - .messages(List.of(MessageReference.toChannelMessage("test-channel", message))) - .build(); - - ChannelObject expectedChannel = ChannelObject.builder() - .bindings(null) - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .build(); - - assertThat(actualOperations) - .containsExactly(Map.entry("test-channel_send_methodFromInterface", expectedOperation)); - } - - private static class ClassImplementingInterface implements ClassInterface { - - @AsyncListener( - operation = - @AsyncOperation( - channelName = "test-channel", - description = "test channel operation description")) - @Override - public void methodFromInterface(String payload) {} - } - - interface ClassInterface { - void methodFromInterface(T payload); - } - - private static class ClassImplementingInterfaceWithAnnotation implements ClassInterfaceWithAnnotation { - - @Override - public void methodFromInterface(String payload) {} - } - - interface ClassInterfaceWithAnnotation { - @AsyncListener( - operation = - @AsyncOperation( - channelName = "test-channel", - description = "test channel operation description")) - void methodFromInterface(T payload); - } - } - - @Nested - class MetaAnnotation { - @Test - void scan_componentHasListenerMethodWithMetaAnnotation() { - // Given a class with methods annotated with a AsyncListener meta annotation - setClassToScan(ClassWithMetaAnnotation.class); - - // When scan is called - Map actualOperations = operationsScanner.scan(); - - // Then the returned collection contains the channel - var messagePayload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .description(null) - .payload(messagePayload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(EMPTY_MAP) - .build(); - - Operation expectedOperation = Operation.builder() - .action(OperationAction.SEND) - .channel(ChannelReference.fromChannel("test-channel")) - .description("test channel operation description") - .title("test-channel_send") - .bindings(EMPTY_MAP) - .messages(List.of(MessageReference.toChannelMessage("test-channel", message))) - .build(); - - ChannelObject expectedChannel = ChannelObject.builder() - .bindings(null) - .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) - .build(); - - assertThat(actualOperations) - .containsExactly(Map.entry("test-channel_send_methodFromInterface", expectedOperation)); - } - - public static class ClassWithMetaAnnotation { - @AsyncListenerMetaAnnotation - void methodFromInterface(String payload) {} - } - - @Target({ElementType.TYPE, ElementType.METHOD, ElementType.ANNOTATION_TYPE}) - @Retention(RetentionPolicy.RUNTIME) - @Inherited - @AsyncListener( - operation = - @AsyncOperation( - channelName = "test-channel", - description = "test channel operation description")) - public @interface AsyncListenerMetaAnnotation {} - } - - @Data - @NoArgsConstructor - @Schema(description = "SimpleFoo Message Description") - private static class SimpleFoo { - private String s; - private boolean b; - } -} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java index d44559234..47b732253 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java @@ -1,29 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.operations.annotations; -import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; -import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelBinding; import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPMessageBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding; -import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; -import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.operation.Operation; -import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; -import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; -import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; -import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationsService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -34,88 +16,56 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; +import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class SpringAnnotationClassLevelOperationsScannerTest { - private final PayloadMethodService payloadMethodService = mock(); - private final HeaderClassExtractor headerClassExtractor = mock(HeaderClassExtractor.class); private final BindingFactory bindingFactory = mock(BindingFactory.class); - private final ComponentsService componentsService = mock(ComponentsService.class); private final OperationCustomizer operationCustomizer = mock(OperationCustomizer.class); + private final SpringAnnotationOperationsService springAnnotationOperationsService = + mock(SpringAnnotationOperationsService.class); SpringAnnotationClassLevelOperationsScanner scanner = new SpringAnnotationClassLevelOperationsScanner<>( TestClassListener.class, TestMethodListener.class, bindingFactory, - new AsyncHeadersNotDocumented(), - payloadMethodService, - headerClassExtractor, - componentsService, + springAnnotationOperationsService, List.of(operationCustomizer)); - private static final String CHANNEL_ID = "test-channel-id"; - private static final Map defaultOperationBinding = - Map.of("protocol", new AMQPOperationBinding()); + private static final String CHANNEL_NAME = "test-channel"; + private static final Map defaultMessageBinding = Map.of("protocol", new AMQPMessageBinding()); - private static final Map defaultChannelBinding = - Map.of("protocol", new AMQPChannelBinding()); @BeforeEach void setUp() { - // when - when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL_ID); - - doReturn(defaultOperationBinding).when(bindingFactory).buildOperationBinding(any()); - doReturn(defaultChannelBinding).when(bindingFactory).buildChannelBinding(any()); - doReturn(defaultMessageBinding).when(bindingFactory).buildMessageBinding(any(), any()); - - when(payloadMethodService.extractSchema(any())) - .thenReturn(new PayloadSchemaObject( - String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); - doAnswer(invocation -> AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) - .when(componentsService) - .registerSchema(any(SchemaObject.class)); + when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL_NAME); } @Test - void scan_componentHasTestListenerMethods() { + void scan() { + // given + Operation operation = Operation.builder().build(); + when(springAnnotationOperationsService.buildOperation(any(), anySet())).thenReturn(operation); + // when List> operations = scanner.scan(ClassWithTestListenerAnnotation.class).toList(); // then - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(defaultMessageBinding) - .build(); - - Operation expectedOperation = Operation.builder() - .action(OperationAction.RECEIVE) - .channel(ChannelReference.fromChannel(CHANNEL_ID)) - .messages(List.of(MessageReference.toChannelMessage(CHANNEL_ID, message))) - .bindings(Map.of("protocol", AMQPOperationBinding.builder().build())) - .build(); - String operationName = CHANNEL_ID + "_receive_ClassWithTestListenerAnnotation"; - assertThat(operations).containsExactly(Map.entry(operationName, expectedOperation)); + String operationName = CHANNEL_NAME + "_receive_ClassWithTestListenerAnnotation"; + assertThat(operations).containsExactly(Map.entry(operationName, operation)); } @Test void operationCustomizerIsCalled() { + // given + Operation operation = Operation.builder().build(); + when(springAnnotationOperationsService.buildOperation(any(), anySet())).thenReturn(operation); + // when scanner.scan(ClassWithTestListenerAnnotation.class).toList(); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScannerTest.java index a947ebb4b..9dad7c4b4 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationMethodLevelOperationsScannerTest.java @@ -1,29 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.operations.annotations; -import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; -import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; -import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPMessageBinding; -import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding; -import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; -import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; -import io.github.springwolf.asyncapi.v3.model.components.ComponentSchema; import io.github.springwolf.asyncapi.v3.model.operation.Operation; -import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; -import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; -import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; -import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; -import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadSchemaObject; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -34,8 +16,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -45,76 +25,47 @@ class SpringAnnotationMethodLevelOperationsScannerTest { private final PayloadMethodParameterService payloadMethodParameterService = mock(); private final HeaderClassExtractor headerClassExtractor = mock(HeaderClassExtractor.class); private final BindingFactory bindingFactory = mock(BindingFactory.class); - private final ComponentsService componentsService = mock(ComponentsService.class); private final OperationCustomizer operationCustomizer = mock(OperationCustomizer.class); + private final SpringAnnotationOperationService springAnnotationOperationService = + mock(SpringAnnotationOperationService.class); SpringAnnotationMethodLevelOperationsScanner scanner = new SpringAnnotationMethodLevelOperationsScanner<>( TestMethodListener.class, bindingFactory, - new AsyncHeadersNotDocumented(), - List.of(operationCustomizer), - payloadMethodParameterService, headerClassExtractor, - componentsService); + payloadMethodParameterService, + springAnnotationOperationService, + List.of(operationCustomizer)); - private static final String CHANNEL_ID = "test-channel-id"; - private static final Map defaultOperationBinding = - Map.of("protocol", new AMQPOperationBinding()); - private static final Map defaultMessageBinding = - Map.of("protocol", new AMQPMessageBinding()); - private static final Map defaultChannelBinding = - Map.of("protocol", new AMQPChannelBinding()); + private static final String CHANNEL_NAME = "test-channel"; @BeforeEach void setUp() { - // when - when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL_ID); - - doReturn(defaultOperationBinding).when(bindingFactory).buildOperationBinding(any()); - doReturn(defaultChannelBinding).when(bindingFactory).buildChannelBinding(any()); - doReturn(defaultMessageBinding).when(bindingFactory).buildMessageBinding(any(), any()); - - when(payloadMethodParameterService.extractSchema(any())) - .thenReturn(new PayloadSchemaObject( - String.class.getName(), String.class.getSimpleName(), ComponentSchema.of(new SchemaObject()))); - doAnswer(invocation -> AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()) - .when(componentsService) - .registerSchema(any(SchemaObject.class)); + when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL_NAME); } @Test void scan_componentHasTestListenerMethods() { + // given + Operation operation = Operation.builder().build(); + when(springAnnotationOperationService.buildOperation(any(), any(), any())) + .thenReturn(operation); + // when List> operations = scanner.scan(ClassWithTestListenerAnnotation.class).toList(); // then - MessagePayload payload = MessagePayload.of(MultiFormatSchema.builder() - .schema(SchemaReference.fromSchema(String.class.getSimpleName())) - .build()); - - MessageObject message = MessageObject.builder() - .messageId(String.class.getName()) - .name(String.class.getName()) - .title(String.class.getSimpleName()) - .payload(payload) - .headers(MessageHeaders.of( - MessageReference.toSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED.getTitle()))) - .bindings(defaultMessageBinding) - .build(); - - Operation expectedOperation = Operation.builder() - .action(OperationAction.RECEIVE) - .channel(ChannelReference.fromChannel(CHANNEL_ID)) - .messages(List.of(MessageReference.toChannelMessage(CHANNEL_ID, message))) - .bindings(Map.of("protocol", AMQPOperationBinding.builder().build())) - .build(); - String operationName = CHANNEL_ID + "_receive_methodWithAnnotation"; - assertThat(operations).containsExactly(Map.entry(operationName, expectedOperation)); + String operationName = CHANNEL_NAME + "_receive_methodWithAnnotation"; + assertThat(operations).containsExactly(Map.entry(operationName, operation)); } @Test - void operationCustomizerIsCalled() { + void operationCustomizerIsCalled() { // given + Operation operation = Operation.builder().build(); + when(springAnnotationOperationService.buildOperation(any(), any(), any())) + .thenReturn(operation); + // when scanner.scan(ClassWithTestListenerAnnotation.class).toList(); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java index 0efe3c7ad..826348b33 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java @@ -40,25 +40,31 @@ void asyncListenerAnnotationIsFound() { AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); assertThat(asyncAPI).isNotNull(); - assertThat(asyncAPI.getChannels()).containsOnlyKeys("listener-channel"); + assertThat(asyncAPI.getChannels().keySet()) + .containsExactlyInAnyOrder("listener-channel", "listener-class-channel"); assertThat(asyncAPI.getChannels().get("listener-channel").getMessages()) .containsOnlyKeys( "java.lang.String", "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); + assertThat(asyncAPI.getChannels().get("listener-class-channel").getMessages()) + .containsOnlyKeys("java.lang.Integer"); assertThat(asyncAPI.getOperations()) .containsOnlyKeys( "listener-channel_receive_listen", "listener-channel_receive_listen2", "listener-channel_receive_listen3", - "listener-channel_receive_listen4"); + "listener-channel_receive_listen4", + "listener-class-channel_receive_ClassListener"); assertThat(asyncAPI.getComponents().getMessages()) .containsOnlyKeys( "java.lang.String", + "java.lang.Integer", "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); assertThat(asyncAPI.getComponents().getSchemas()) .containsOnlyKeys( "HeadersNotDocumented", "java.lang.String", + "java.lang.Integer", "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Bar", "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); @@ -99,25 +105,31 @@ void asyncPublisherAnnotationIsFound() { AsyncAPI asyncAPI = asyncApiService.getAsyncAPI(); assertThat(asyncAPI).isNotNull(); - assertThat(asyncAPI.getChannels()).containsOnlyKeys("publisher-channel"); + assertThat(asyncAPI.getChannels().keySet()) + .containsExactlyInAnyOrder("publisher-channel", "publisher-class-channel"); assertThat(asyncAPI.getChannels().get("publisher-channel").getMessages()) .containsOnlyKeys( "java.lang.String", "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); + assertThat(asyncAPI.getChannels().get("publisher-class-channel").getMessages()) + .containsOnlyKeys("java.lang.Integer"); assertThat(asyncAPI.getOperations()) .containsOnlyKeys( "publisher-channel_send_publish", "publisher-channel_send_publish2", "publisher-channel_send_publish3", - "publisher-channel_send_publish4"); + "publisher-channel_send_publish4", + "publisher-class-channel_send_ClassPublisher"); assertThat(asyncAPI.getComponents().getMessages()) .containsOnlyKeys( "java.lang.String", + "java.lang.Integer", "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); assertThat(asyncAPI.getComponents().getSchemas()) .containsOnlyKeys( "HeadersNotDocumented", "java.lang.String", + "java.lang.Integer", "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Bar", "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo"); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/listener/ListenerApplication.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/listener/ListenerApplication.java index a42df2ead..d06fce028 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/listener/ListenerApplication.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/listener/ListenerApplication.java @@ -15,6 +15,11 @@ public Listener listener() { return new Listener(); } + @Bean + public ClassListener classListener() { + return new ClassListener(); + } + static class Listener { @AsyncListener(operation = @AsyncOperation(channelName = "listener-channel")) public void listen(String payload) {} @@ -32,4 +37,9 @@ public void listen4(List payload) {} public record Foo(Bar aFieldInFooRecord) {} public record Bar(String aFieldInBarRecord) {} + + @AsyncListener(operation = @AsyncOperation(channelName = "listener-class-channel")) + static class ClassListener { + public void listen(Integer payload) {} + } } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/publisher/PublisherApplication.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/publisher/PublisherApplication.java index 6eff47314..69134400b 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/publisher/PublisherApplication.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/application/publisher/PublisherApplication.java @@ -16,6 +16,11 @@ public Publisher publisher() { return new Publisher(); } + @Bean + public ClassPublisher classPublisher() { + return new ClassPublisher(); + } + static class Publisher { @AsyncPublisher(operation = @AsyncOperation(channelName = "publisher-channel")) public void publish(String payload) {} @@ -29,4 +34,9 @@ public void publish3(ListenerApplication.Foo payload) {} @AsyncPublisher(operation = @AsyncOperation(channelName = "publisher-channel")) public void publish4(List payload) {} } + + @AsyncPublisher(operation = @AsyncOperation(channelName = "publisher-class-channel")) + static class ClassPublisher { + public void publish(Integer payload) {} + } } diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/SpringContextIntegrationTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/SpringContextIntegrationTest.java index f38bccbf6..23ffa7d7e 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/SpringContextIntegrationTest.java +++ b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/springwolf/examples/amqp/SpringContextIntegrationTest.java @@ -44,7 +44,19 @@ void testContextWithApplicationProperties() { @Test void testAllChannelsAreFound() { - assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(11); + assertThat(asyncApiService.getAsyncAPI().getChannels().keySet()) + .containsExactlyInAnyOrder( + "#", + "another-queue", + "example-bindings-queue", + "example-queue", + "example-topic-exchange", + "example-topic-routing-key", + "multi-payload-queue", + "queue-create", + "queue-delete", + "queue-read", + "queue-update"); } } 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 7ad5f1287..f2d37aa5c 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,20 @@ void testContextWithApplicationProperties() { @Test void testAllChannelsAreFound() { - assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(12); + assertThat(asyncApiService.getAsyncAPI().getChannels().keySet()) + .containsExactlyInAnyOrder( + "another-topic", + "avro-topic", + "example-topic", + "integer-topic", + "multi-payload-topic", + "no-payload-used-topic", + "protobuf-topic", + "string-topic", + "topic-defined-via-asyncPublisher-annotation", + "vehicle-topic", + "xml-topic", + "yaml-topic"); } } diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java index 67f84d920..0aa1162b3 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java +++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java @@ -2,20 +2,28 @@ package io.github.springwolf.plugins.amqp.configuration; import io.github.springwolf.core.asyncapi.components.ComponentsService; +import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; import io.github.springwolf.core.asyncapi.scanners.channels.ChannelPriority; -import io.github.springwolf.core.asyncapi.scanners.channels.SpringAnnotationChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationClassLevelChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationMethodLevelChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.classes.SpringwolfClassScanner; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessagesService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationsService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; -import io.github.springwolf.core.asyncapi.scanners.operations.SpringAnnotationOperationsScanner; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.OperationCustomizer; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationClassLevelOperationsScanner; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationMethodLevelOperationsScanner; import io.github.springwolf.plugins.amqp.asyncapi.scanners.bindings.AmqpBindingFactory; import io.github.springwolf.plugins.amqp.asyncapi.scanners.channels.RabbitQueueBeanScanner; import io.github.springwolf.plugins.amqp.asyncapi.scanners.common.headers.AsyncHeadersForAmqpBuilder; +import lombok.val; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.Exchange; import org.springframework.amqp.core.Queue; @@ -60,24 +68,28 @@ public AsyncHeadersForAmqpBuilder asyncHeadersForAmqpBuilder() { havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleRabbitClassLevelListenerAnnotationChannelsScanner( + public ChannelsScanner simpleRabbitClassLevelListenerAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, AmqpBindingFactory amqpBindingFactory, AsyncHeadersForAmqpBuilder asyncHeadersForAmqpBuilder, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { + val springAnnotationMessagesService = new SpringAnnotationMessagesService<>( + amqpBindingFactory, + asyncHeadersForAmqpBuilder, + payloadMethodParameterService, + headerClassExtractor, + componentsService); + val springAnnotationChannelService = new SpringAnnotationChannelService<>(amqpBindingFactory); SpringAnnotationClassLevelChannelsScanner strategy = new SpringAnnotationClassLevelChannelsScanner<>( RabbitListener.class, RabbitHandler.class, - amqpBindingFactory, - asyncHeadersForAmqpBuilder, - payloadMethodParameterService, - headerClassExtractor, - componentsService); + springAnnotationMessagesService, + springAnnotationChannelService); - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -86,7 +98,7 @@ public SpringAnnotationChannelsScanner simpleRabbitClassLevelListenerAnnotationC havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationOperationsScanner simpleRabbitClassLevelListenerAnnotationOperationsScanner( + public OperationsScanner simpleRabbitClassLevelListenerAnnotationOperationsScanner( SpringwolfClassScanner springwolfClassScanner, AmqpBindingFactory amqpBindingFactory, AsyncHeadersForAmqpBuilder asyncHeadersForAmqpBuilder, @@ -94,18 +106,23 @@ public SpringAnnotationOperationsScanner simpleRabbitClassLevelListenerAnnotatio HeaderClassExtractor headerClassExtractor, ComponentsService componentsService, List operationCustomizers) { + val springAnnotationOperationsService = new SpringAnnotationOperationsService<>( + amqpBindingFactory, + new SpringAnnotationMessagesService<>( + amqpBindingFactory, + asyncHeadersForAmqpBuilder, + payloadMethodParameterService, + headerClassExtractor, + componentsService)); SpringAnnotationClassLevelOperationsScanner strategy = new SpringAnnotationClassLevelOperationsScanner<>( RabbitListener.class, RabbitHandler.class, amqpBindingFactory, - asyncHeadersForAmqpBuilder, - payloadMethodParameterService, - headerClassExtractor, - componentsService, + springAnnotationOperationsService, operationCustomizers); - return new SpringAnnotationOperationsScanner(springwolfClassScanner, strategy); + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -114,23 +131,25 @@ public SpringAnnotationOperationsScanner simpleRabbitClassLevelListenerAnnotatio havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleRabbitMethodLevelListenerAnnotationChannelsScanner( + public ChannelsScanner simpleRabbitMethodLevelListenerAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, AmqpBindingFactory amqpBindingFactory, AsyncHeadersForAmqpBuilder asyncHeadersForAmqpBuilder, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { + val springAnnotationChannelService = new SpringAnnotationChannelService<>(amqpBindingFactory); + val springAnnotationMessageService = + new SpringAnnotationMessageService<>(amqpBindingFactory, asyncHeadersForAmqpBuilder, componentsService); SpringAnnotationMethodLevelChannelsScanner strategy = new SpringAnnotationMethodLevelChannelsScanner<>( RabbitListener.class, - amqpBindingFactory, - asyncHeadersForAmqpBuilder, payloadMethodParameterService, headerClassExtractor, - componentsService); + springAnnotationChannelService, + springAnnotationMessageService); - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -139,7 +158,7 @@ public SpringAnnotationChannelsScanner simpleRabbitMethodLevelListenerAnnotation havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationOperationsScanner simpleRabbitMethodLevelListenerAnnotationOperationsScanner( + public OperationsScanner simpleRabbitMethodLevelListenerAnnotationOperationsScanner( SpringwolfClassScanner springwolfClassScanner, AmqpBindingFactory amqpBindingFactory, AsyncHeadersForAmqpBuilder asyncHeadersForAmqpBuilder, @@ -147,17 +166,20 @@ public SpringAnnotationOperationsScanner simpleRabbitMethodLevelListenerAnnotati HeaderClassExtractor headerClassExtractor, ComponentsService componentsService, List operationCustomizers) { + val springAnnotationOperationService = new SpringAnnotationOperationService<>( + amqpBindingFactory, + new SpringAnnotationMessageService<>( + amqpBindingFactory, asyncHeadersForAmqpBuilder, componentsService)); SpringAnnotationMethodLevelOperationsScanner strategy = new SpringAnnotationMethodLevelOperationsScanner<>( RabbitListener.class, amqpBindingFactory, - asyncHeadersForAmqpBuilder, - operationCustomizers, - payloadMethodParameterService, headerClassExtractor, - componentsService); + payloadMethodParameterService, + springAnnotationOperationService, + operationCustomizers); - return new SpringAnnotationOperationsScanner(springwolfClassScanner, strategy); + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScanner.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScanner.java index 07d816aa9..2f3446d29 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScanner.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScanner.java @@ -21,9 +21,9 @@ import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.channels.ChannelMerger; import io.github.springwolf.core.asyncapi.scanners.classes.spring.ComponentClassScanner; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AsyncAnnotationUtil; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; import io.github.springwolf.core.asyncapi.scanners.common.payload.internal.PayloadService; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AsyncAnnotationUtil; import io.github.springwolf.core.configuration.docket.AsyncApiDocket; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; import io.github.springwolf.plugins.cloudstream.asyncapi.scanners.common.FunctionalChannelBeanBuilder; @@ -58,7 +58,7 @@ public Map scan() { elements.addAll(componentClassScanner.scan()); elements.addAll(beanMethodsScanner.getBeanMethods()); - List> channels = elements.stream() + List channels = elements.stream() .map(functionalChannelBeanBuilder::build) .flatMap(Set::stream) .filter(this::isChannelBean) @@ -72,14 +72,12 @@ private boolean isChannelBean(FunctionalChannelBeanData beanData) { return cloudStreamBindingsProperties.getBindings().containsKey(beanData.cloudStreamBinding()); } - private Map.Entry toChannelEntry(FunctionalChannelBeanData beanData) { + private ChannelObject toChannelEntry(FunctionalChannelBeanData beanData) { String channelName = cloudStreamBindingsProperties .getBindings() .get(beanData.cloudStreamBinding()) .getDestination(); - ChannelObject channelItem = buildChannel(beanData, channelName); - - return Map.entry(channelItem.getChannelId(), channelItem); + return buildChannel(beanData, channelName); } private ChannelObject buildChannel(FunctionalChannelBeanData beanData, String channelName) { diff --git a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsScannerConfiguration.java b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsScannerConfiguration.java index 96f71fe2c..53588e70b 100644 --- a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsScannerConfiguration.java +++ b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsScannerConfiguration.java @@ -2,17 +2,23 @@ package io.github.springwolf.plugins.jms.configuration; import io.github.springwolf.core.asyncapi.components.ComponentsService; +import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; import io.github.springwolf.core.asyncapi.scanners.channels.ChannelPriority; -import io.github.springwolf.core.asyncapi.scanners.channels.SpringAnnotationChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationMethodLevelChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.classes.SpringwolfClassScanner; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; -import io.github.springwolf.core.asyncapi.scanners.operations.SpringAnnotationOperationsScanner; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.OperationCustomizer; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationMethodLevelOperationsScanner; import io.github.springwolf.plugins.jms.asyncapi.scanners.bindings.JmsBindingFactory; +import lombok.val; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -38,44 +44,49 @@ public JmsBindingFactory jmsBindingFactory() { @Bean @ConditionalOnProperty(name = SPRINGWOLF_SCANNER_JMS_LISTENER_ENABLED, havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleJmsMethodLevelListenerAnnotationChannelsScanner( + public ChannelsScanner simpleJmsMethodLevelListenerAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, JmsBindingFactory jmsBindingFactory, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { + val springAnnotationChannelService = new SpringAnnotationChannelService<>(jmsBindingFactory); + val springAnnotationMessageService = new SpringAnnotationMessageService<>( + jmsBindingFactory, new AsyncHeadersNotDocumented(), componentsService); SpringAnnotationMethodLevelChannelsScanner strategy = new SpringAnnotationMethodLevelChannelsScanner<>( JmsListener.class, - jmsBindingFactory, - new AsyncHeadersNotDocumented(), payloadMethodParameterService, headerClassExtractor, - componentsService); + springAnnotationChannelService, + springAnnotationMessageService); - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @ConditionalOnProperty(name = SPRINGWOLF_SCANNER_JMS_LISTENER_ENABLED, havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationOperationsScanner simpleJmsMethodLevelListenerAnnotationOperationsScanner( + public OperationsScanner simpleJmsMethodLevelListenerAnnotationOperationsScanner( SpringwolfClassScanner springwolfClassScanner, JmsBindingFactory jmsBindingFactory, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService, List operationCustomizers) { + val springAnnotationOperationService = new SpringAnnotationOperationService<>( + jmsBindingFactory, + new SpringAnnotationMessageService<>( + jmsBindingFactory, new AsyncHeadersNotDocumented(), componentsService)); SpringAnnotationMethodLevelOperationsScanner strategy = new SpringAnnotationMethodLevelOperationsScanner<>( JmsListener.class, jmsBindingFactory, - new AsyncHeadersNotDocumented(), - operationCustomizers, - payloadMethodParameterService, headerClassExtractor, - componentsService); + payloadMethodParameterService, + springAnnotationOperationService, + operationCustomizers); - return new SpringAnnotationOperationsScanner(springwolfClassScanner, strategy); + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } } diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaScannerConfiguration.java b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaScannerConfiguration.java index 74e52cb5e..f0a093eba 100644 --- a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaScannerConfiguration.java +++ b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaScannerConfiguration.java @@ -2,19 +2,27 @@ package io.github.springwolf.plugins.kafka.configuration; import io.github.springwolf.core.asyncapi.components.ComponentsService; +import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; import io.github.springwolf.core.asyncapi.scanners.channels.ChannelPriority; -import io.github.springwolf.core.asyncapi.scanners.channels.SpringAnnotationChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationClassLevelChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationMethodLevelChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.classes.SpringwolfClassScanner; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessagesService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationsService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; -import io.github.springwolf.core.asyncapi.scanners.operations.SpringAnnotationOperationsScanner; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.OperationCustomizer; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationClassLevelOperationsScanner; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationMethodLevelOperationsScanner; import io.github.springwolf.plugins.kafka.asyncapi.scanners.bindings.KafkaBindingFactory; import io.github.springwolf.plugins.kafka.asyncapi.scanners.common.header.AsyncHeadersForKafkaBuilder; +import lombok.val; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -56,24 +64,28 @@ public AsyncHeadersForKafkaBuilder asyncHeadersForKafkaBuilder() { havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleKafkaClassLevelListenerAnnotationChannelsScanner( + public ChannelsScanner simpleKafkaClassLevelListenerAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, KafkaBindingFactory kafkaBindingFactory, AsyncHeadersForKafkaBuilder asyncHeadersForKafkaBuilder, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { + val springAnnotationMessagesService = new SpringAnnotationMessagesService<>( + kafkaBindingFactory, + asyncHeadersForKafkaBuilder, + payloadMethodParameterService, + headerClassExtractor, + componentsService); + val springAnnotationChannelService = new SpringAnnotationChannelService<>(kafkaBindingFactory); SpringAnnotationClassLevelChannelsScanner strategy = new SpringAnnotationClassLevelChannelsScanner<>( KafkaListener.class, KafkaHandler.class, - kafkaBindingFactory, - asyncHeadersForKafkaBuilder, - payloadMethodParameterService, - headerClassExtractor, - componentsService); + springAnnotationMessagesService, + springAnnotationChannelService); - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -82,7 +94,7 @@ public SpringAnnotationChannelsScanner simpleKafkaClassLevelListenerAnnotationCh havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationOperationsScanner simpleKafkaClassLevelListenerAnnotationOperationScanner( + public OperationsScanner simpleKafkaClassLevelListenerAnnotationOperationScanner( SpringwolfClassScanner springwolfClassScanner, KafkaBindingFactory kafkaBindingFactory, AsyncHeadersForKafkaBuilder asyncHeadersForKafkaBuilder, @@ -90,18 +102,23 @@ public SpringAnnotationOperationsScanner simpleKafkaClassLevelListenerAnnotation HeaderClassExtractor headerClassExtractor, ComponentsService componentsService, List operationCustomizers) { + val springAnnotationOperationsService = new SpringAnnotationOperationsService<>( + kafkaBindingFactory, + new SpringAnnotationMessagesService<>( + kafkaBindingFactory, + asyncHeadersForKafkaBuilder, + payloadMethodParameterService, + headerClassExtractor, + componentsService)); SpringAnnotationClassLevelOperationsScanner strategy = new SpringAnnotationClassLevelOperationsScanner<>( KafkaListener.class, KafkaHandler.class, kafkaBindingFactory, - asyncHeadersForKafkaBuilder, - payloadMethodParameterService, - headerClassExtractor, - componentsService, + springAnnotationOperationsService, operationCustomizers); - return new SpringAnnotationOperationsScanner(springwolfClassScanner, strategy); + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -110,23 +127,24 @@ public SpringAnnotationOperationsScanner simpleKafkaClassLevelListenerAnnotation havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleKafkaMethodLevelListenerAnnotationChannelsScanner( + public ChannelsScanner simpleKafkaMethodLevelListenerAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, KafkaBindingFactory kafkaBindingFactory, AsyncHeadersForKafkaBuilder asyncHeadersForKafkaBuilder, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { + val springAnnotationChannelService = new SpringAnnotationChannelService<>(kafkaBindingFactory); + val springAnnotationMessageService = new SpringAnnotationMessageService<>( + kafkaBindingFactory, asyncHeadersForKafkaBuilder, componentsService); SpringAnnotationMethodLevelChannelsScanner strategy = new SpringAnnotationMethodLevelChannelsScanner<>( KafkaListener.class, - kafkaBindingFactory, - asyncHeadersForKafkaBuilder, payloadMethodParameterService, headerClassExtractor, - componentsService); - - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + springAnnotationChannelService, + springAnnotationMessageService); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -135,7 +153,7 @@ public SpringAnnotationChannelsScanner simpleKafkaMethodLevelListenerAnnotationC havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationOperationsScanner simpleKafkaMethodLevelListenerAnnotationOperationsScanner( + public OperationsScanner simpleKafkaMethodLevelListenerAnnotationOperationsScanner( SpringwolfClassScanner springwolfClassScanner, KafkaBindingFactory kafkaBindingFactory, AsyncHeadersForKafkaBuilder asyncHeadersForKafkaBuilder, @@ -143,16 +161,19 @@ public SpringAnnotationOperationsScanner simpleKafkaMethodLevelListenerAnnotatio HeaderClassExtractor headerClassExtractor, ComponentsService componentsService, List operationCustomizers) { + val springAnnotationOperationService = new SpringAnnotationOperationService<>( + kafkaBindingFactory, + new SpringAnnotationMessageService<>( + kafkaBindingFactory, asyncHeadersForKafkaBuilder, componentsService)); SpringAnnotationMethodLevelOperationsScanner strategy = new SpringAnnotationMethodLevelOperationsScanner<>( KafkaListener.class, kafkaBindingFactory, - asyncHeadersForKafkaBuilder, - operationCustomizers, - payloadMethodParameterService, headerClassExtractor, - componentsService); + payloadMethodParameterService, + springAnnotationOperationService, + operationCustomizers); - return new SpringAnnotationOperationsScanner(springwolfClassScanner, strategy); + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } } diff --git a/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsScannerConfiguration.java b/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsScannerConfiguration.java index ca4bc8ed7..26387aa01 100644 --- a/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsScannerConfiguration.java +++ b/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsScannerConfiguration.java @@ -3,17 +3,23 @@ import io.awspring.cloud.sqs.annotation.SqsListener; import io.github.springwolf.core.asyncapi.components.ComponentsService; +import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; import io.github.springwolf.core.asyncapi.scanners.channels.ChannelPriority; -import io.github.springwolf.core.asyncapi.scanners.channels.SpringAnnotationChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationMethodLevelChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.classes.SpringwolfClassScanner; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; -import io.github.springwolf.core.asyncapi.scanners.operations.SpringAnnotationOperationsScanner; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.OperationCustomizer; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationMethodLevelOperationsScanner; import io.github.springwolf.plugins.sqs.asyncapi.scanners.bindings.SqsBindingFactory; +import lombok.val; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -38,44 +44,48 @@ public SqsBindingFactory sqsBindingFactory() { @Bean @ConditionalOnProperty(name = SPRINGWOLF_SCANNER_SQS_LISTENER_ENABLED, havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleSqsMethodLevelListenerAnnotationChannelsScanner( + public ChannelsScanner simpleSqsMethodLevelListenerAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, SqsBindingFactory sqsBindingFactory, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { + val springAnnotationChannelService = new SpringAnnotationChannelService<>(sqsBindingFactory); + val springAnnotationMessageService = new SpringAnnotationMessageService<>( + sqsBindingFactory, new AsyncHeadersNotDocumented(), componentsService); SpringAnnotationMethodLevelChannelsScanner strategy = new SpringAnnotationMethodLevelChannelsScanner<>( SqsListener.class, - sqsBindingFactory, - new AsyncHeadersNotDocumented(), payloadMethodParameterService, headerClassExtractor, - componentsService); - - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + springAnnotationChannelService, + springAnnotationMessageService); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @ConditionalOnProperty(name = SPRINGWOLF_SCANNER_SQS_LISTENER_ENABLED, havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationOperationsScanner simpleSqsMethodLevelListenerAnnotationOperationsScanner( + public OperationsScanner simpleSqsMethodLevelListenerAnnotationOperationsScanner( SpringwolfClassScanner springwolfClassScanner, SqsBindingFactory sqsBindingFactory, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService, List operationCustomizers) { + val springAnnotationOperationService = new SpringAnnotationOperationService<>( + sqsBindingFactory, + new SpringAnnotationMessageService<>( + sqsBindingFactory, new AsyncHeadersNotDocumented(), componentsService)); SpringAnnotationMethodLevelOperationsScanner strategy = new SpringAnnotationMethodLevelOperationsScanner<>( SqsListener.class, sqsBindingFactory, - new AsyncHeadersNotDocumented(), - operationCustomizers, - payloadMethodParameterService, headerClassExtractor, - componentsService); + payloadMethodParameterService, + springAnnotationOperationService, + operationCustomizers); - return new SpringAnnotationOperationsScanner(springwolfClassScanner, strategy); + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } } diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToCustomizer.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToCustomizer.java index 6ef62f48c..40b22d22e 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToCustomizer.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToCustomizer.java @@ -6,8 +6,8 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.asyncapi.v3.model.operation.OperationReply; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodReturnService; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.OperationCustomizer; import io.github.springwolf.plugins.stomp.asyncapi.scanners.bindings.StompBindingSendToFactory; import lombok.RequiredArgsConstructor; @@ -23,7 +23,7 @@ public class SendToCustomizer implements OperationCustomizer { @Override public void customize(Operation operation, Method method) { - SendTo annotation = AnnotationScannerUtil.findAnnotation(SendTo.class, method); + SendTo annotation = AnnotationUtil.findFirstAnnotation(SendTo.class, method); if (annotation != null) { String channelId = ReferenceUtil.toValidId(bindingFactory.getChannelName(annotation)); String payloadName = payloadService.extractSchema(method).name(); diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToUserCustomizer.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToUserCustomizer.java index 326ec59c8..af3e36526 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToUserCustomizer.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/operation/annotations/SendToUserCustomizer.java @@ -6,8 +6,8 @@ import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.asyncapi.v3.model.operation.OperationReply; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationUtil; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodReturnService; -import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.OperationCustomizer; import io.github.springwolf.plugins.stomp.asyncapi.scanners.bindings.StompBindingSendToUserFactory; import lombok.RequiredArgsConstructor; @@ -23,7 +23,7 @@ public class SendToUserCustomizer implements OperationCustomizer { @Override public void customize(Operation operation, Method method) { - SendToUser annotation = AnnotationScannerUtil.findAnnotation(SendToUser.class, method); + SendToUser annotation = AnnotationUtil.findFirstAnnotation(SendToUser.class, method); if (annotation != null) { String channelId = ReferenceUtil.toValidId(bindingFactory.getChannelName(annotation)); String payloadName = payloadService.extractSchema(method).name(); diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/configuration/SpringwolfStompScannerConfiguration.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/configuration/SpringwolfStompScannerConfiguration.java index 19928adab..484fe3852 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/configuration/SpringwolfStompScannerConfiguration.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/configuration/SpringwolfStompScannerConfiguration.java @@ -2,16 +2,23 @@ package io.github.springwolf.plugins.stomp.configuration; import io.github.springwolf.core.asyncapi.components.ComponentsService; +import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.OperationsScanner; import io.github.springwolf.core.asyncapi.scanners.channels.ChannelPriority; -import io.github.springwolf.core.asyncapi.scanners.channels.SpringAnnotationChannelsScanner; +import io.github.springwolf.core.asyncapi.scanners.channels.ChannelsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationClassLevelChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationMethodLevelChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.classes.SpringwolfClassScanner; -import io.github.springwolf.core.asyncapi.scanners.common.ClassLevelAnnotationScanner; +import io.github.springwolf.core.asyncapi.scanners.common.annotation.AllMethods; +import io.github.springwolf.core.asyncapi.scanners.common.channel.SpringAnnotationChannelService; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessageService; +import io.github.springwolf.core.asyncapi.scanners.common.message.SpringAnnotationMessagesService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationService; +import io.github.springwolf.core.asyncapi.scanners.common.operation.SpringAnnotationOperationsService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodParameterService; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodReturnService; -import io.github.springwolf.core.asyncapi.scanners.operations.SpringAnnotationOperationsScanner; +import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScannerAdapter; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.OperationCustomizer; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationClassLevelOperationsScanner; import io.github.springwolf.core.asyncapi.scanners.operations.annotations.SpringAnnotationMethodLevelOperationsScanner; @@ -22,6 +29,7 @@ import io.github.springwolf.plugins.stomp.asyncapi.scanners.operation.annotations.SendToCustomizer; import io.github.springwolf.plugins.stomp.asyncapi.scanners.operation.annotations.SendToUserCustomizer; import io.github.springwolf.plugins.stomp.configuration.properties.SpringwolfStompConfigProperties; +import lombok.val; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -101,24 +109,28 @@ public SendToUserCustomizer sendToUserCustomizer( havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleStompClassLevelListenerAnnotationChannelsScanner( + public ChannelsScanner simpleStompClassLevelListenerAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, StompBindingMessageMappingFactory stompBindingMessageMappingFactory, AsyncHeadersForStompBuilder asyncHeadersForStompBuilder, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { - SpringAnnotationClassLevelChannelsScanner strategy = + val springAnnotationMessagesService = new SpringAnnotationMessagesService<>( + stompBindingMessageMappingFactory, + asyncHeadersForStompBuilder, + payloadMethodParameterService, + headerClassExtractor, + componentsService); + val springAnnotationChannelService = new SpringAnnotationChannelService<>(stompBindingMessageMappingFactory); + SpringAnnotationClassLevelChannelsScanner strategy = new SpringAnnotationClassLevelChannelsScanner<>( MessageMapping.class, - ClassLevelAnnotationScanner.AllMethods.class, - stompBindingMessageMappingFactory, - asyncHeadersForStompBuilder, - payloadMethodParameterService, - headerClassExtractor, - componentsService); + AllMethods.class, + springAnnotationMessagesService, + springAnnotationChannelService); - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -127,7 +139,7 @@ public SpringAnnotationChannelsScanner simpleStompClassLevelListenerAnnotationCh havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationOperationsScanner simpleStompClassLevelListenerAnnotationOperationScanner( + public OperationsScanner simpleStompClassLevelListenerAnnotationOperationScanner( SpringwolfClassScanner springwolfClassScanner, StompBindingMessageMappingFactory stompBindingMessageMappingFactory, AsyncHeadersForStompBuilder asyncHeadersForStompBuilder, @@ -135,18 +147,23 @@ public SpringAnnotationOperationsScanner simpleStompClassLevelListenerAnnotation HeaderClassExtractor headerClassExtractor, ComponentsService componentsService, List operationCustomizers) { - SpringAnnotationClassLevelOperationsScanner strategy = - new SpringAnnotationClassLevelOperationsScanner<>( - MessageMapping.class, - ClassLevelAnnotationScanner.AllMethods.class, + val springAnnotationOperationsService = new SpringAnnotationOperationsService<>( + stompBindingMessageMappingFactory, + new SpringAnnotationMessagesService<>( stompBindingMessageMappingFactory, asyncHeadersForStompBuilder, payloadMethodParameterService, headerClassExtractor, - componentsService, + componentsService)); + SpringAnnotationClassLevelOperationsScanner strategy = + new SpringAnnotationClassLevelOperationsScanner<>( + MessageMapping.class, + AllMethods.class, + stompBindingMessageMappingFactory, + springAnnotationOperationsService, operationCustomizers); - return new SpringAnnotationOperationsScanner(springwolfClassScanner, strategy); + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -155,23 +172,24 @@ public SpringAnnotationOperationsScanner simpleStompClassLevelListenerAnnotation havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleStompMethodLevelListenerAnnotationChannelsScanner( + public ChannelsScanner simpleStompMethodLevelListenerAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, StompBindingMessageMappingFactory stompBindingMessageMappingFactory, AsyncHeadersForStompBuilder asyncHeadersForStompBuilder, PayloadMethodParameterService payloadMethodParameterService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { + val springAnnotationChannelService = new SpringAnnotationChannelService<>(stompBindingMessageMappingFactory); + val springAnnotationMessageService = new SpringAnnotationMessageService<>( + stompBindingMessageMappingFactory, asyncHeadersForStompBuilder, componentsService); SpringAnnotationMethodLevelChannelsScanner strategy = new SpringAnnotationMethodLevelChannelsScanner<>( MessageMapping.class, - stompBindingMessageMappingFactory, - asyncHeadersForStompBuilder, payloadMethodParameterService, headerClassExtractor, - componentsService); - - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + springAnnotationChannelService, + springAnnotationMessageService); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -180,7 +198,7 @@ public SpringAnnotationChannelsScanner simpleStompMethodLevelListenerAnnotationC havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationOperationsScanner simpleStompMethodLevelListenerAnnotationOperationsScanner( + public OperationsScanner simpleStompMethodLevelListenerAnnotationOperationsScanner( SpringwolfClassScanner springwolfClassScanner, StompBindingMessageMappingFactory stompBindingMessageMappingFactory, AsyncHeadersForStompBuilder asyncHeadersForStompBuilder, @@ -188,38 +206,42 @@ public SpringAnnotationOperationsScanner simpleStompMethodLevelListenerAnnotatio HeaderClassExtractor headerClassExtractor, ComponentsService componentsService, List operationCustomizers) { + val springAnnotationOperationService = new SpringAnnotationOperationService<>( + stompBindingMessageMappingFactory, + new SpringAnnotationMessageService<>( + stompBindingMessageMappingFactory, asyncHeadersForStompBuilder, componentsService)); SpringAnnotationMethodLevelOperationsScanner strategy = new SpringAnnotationMethodLevelOperationsScanner<>( MessageMapping.class, stompBindingMessageMappingFactory, - asyncHeadersForStompBuilder, - operationCustomizers, - payloadMethodParameterService, headerClassExtractor, - componentsService); + payloadMethodParameterService, + springAnnotationOperationService, + operationCustomizers); - return new SpringAnnotationOperationsScanner(springwolfClassScanner, strategy); + return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @ConditionalOnProperty(name = SPRINGWOLF_SCANNER_STOMP_SEND_TO_ENABLED, havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleStompMethodLevelListenerSendToAnnotationChannelsScanner( + public ChannelsScanner simpleStompMethodLevelListenerSendToAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, StompBindingSendToFactory stompBindingMessageMappingFactory, AsyncHeadersForStompBuilder asyncHeadersForStompBuilder, PayloadMethodReturnService payloadMethodReturnService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { + val springAnnotationChannelService = new SpringAnnotationChannelService<>(stompBindingMessageMappingFactory); + val springAnnotationMessageService = new SpringAnnotationMessageService<>( + stompBindingMessageMappingFactory, asyncHeadersForStompBuilder, componentsService); SpringAnnotationMethodLevelChannelsScanner strategy = new SpringAnnotationMethodLevelChannelsScanner<>( SendTo.class, - stompBindingMessageMappingFactory, - asyncHeadersForStompBuilder, payloadMethodReturnService, headerClassExtractor, - componentsService); - - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + springAnnotationChannelService, + springAnnotationMessageService); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } @Bean @@ -228,22 +250,23 @@ public SpringAnnotationChannelsScanner simpleStompMethodLevelListenerSendToAnnot havingValue = "true", matchIfMissing = true) @Order(value = ChannelPriority.AUTO_DISCOVERED) - public SpringAnnotationChannelsScanner simpleStompMethodLevelListenerSendToUserAnnotationChannelsScanner( + public ChannelsScanner simpleStompMethodLevelListenerSendToUserAnnotationChannelsScanner( SpringwolfClassScanner springwolfClassScanner, StompBindingSendToUserFactory stompBindingMessageMappingFactory, AsyncHeadersForStompBuilder asyncHeadersForStompBuilder, PayloadMethodReturnService payloadMethodReturnService, HeaderClassExtractor headerClassExtractor, ComponentsService componentsService) { + val springAnnotationChannelService = new SpringAnnotationChannelService<>(stompBindingMessageMappingFactory); + val springAnnotationMessageService = new SpringAnnotationMessageService<>( + stompBindingMessageMappingFactory, asyncHeadersForStompBuilder, componentsService); SpringAnnotationMethodLevelChannelsScanner strategy = new SpringAnnotationMethodLevelChannelsScanner<>( SendToUser.class, - stompBindingMessageMappingFactory, - asyncHeadersForStompBuilder, payloadMethodReturnService, headerClassExtractor, - componentsService); - - return new SpringAnnotationChannelsScanner(springwolfClassScanner, strategy); + springAnnotationChannelService, + springAnnotationMessageService); + return new ChannelsInClassScannerAdapter(springwolfClassScanner, strategy); } } From 0bef24c0f09a6ae7986f8f9692ef39529edda1e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 17:50:32 +0200 Subject: [PATCH 13/34] chore(deps): Bump protobufJavaVersion from 4.28.0 to 4.28.1 (#974) Bumps `protobufJavaVersion` from 4.28.0 to 4.28.1. Updates `com.google.protobuf:protobuf-java` from 4.28.0 to 4.28.1 - [Release notes](https://github.com/protocolbuffers/protobuf/releases) - [Changelog](https://github.com/protocolbuffers/protobuf/blob/main/protobuf_release.bzl) - [Commits](https://github.com/protocolbuffers/protobuf/commits) Updates `com.google.protobuf:protoc` from 4.28.0 to 4.28.1 - [Release notes](https://github.com/protocolbuffers/protobuf/releases) - [Changelog](https://github.com/protocolbuffers/protobuf/blob/main/protobuf_release.bzl) - [Commits](https://github.com/protocolbuffers/protobuf/commits) --- updated-dependencies: - dependency-name: com.google.protobuf:protobuf-java dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.google.protobuf:protoc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index f908b420f..568bca3f6 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -60,7 +60,7 @@ ext { monetaVersion = '1.4.4' moneyApiVersion = '1.1' - protobufJavaVersion = '4.28.0' + protobufJavaVersion = '4.28.1' junitJupiterVersion = '5.10.3' jsonUnitAssertJVersion = '3.4.1' From 336a6c532a93261f4a6644f12b22d75d3aca9f3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 17:51:03 +0200 Subject: [PATCH 14/34] chore(deps-dev): Bump jest-preset-angular in /springwolf-ui (#975) Bumps [jest-preset-angular](https://github.com/thymikee/jest-preset-angular) from 14.2.2 to 14.2.4. - [Release notes](https://github.com/thymikee/jest-preset-angular/releases) - [Changelog](https://github.com/thymikee/jest-preset-angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/thymikee/jest-preset-angular/compare/v14.2.2...v14.2.4) --- updated-dependencies: - dependency-name: jest-preset-angular dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- springwolf-ui/package-lock.json | 8 ++++---- springwolf-ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/springwolf-ui/package-lock.json b/springwolf-ui/package-lock.json index fce1a5e89..6f8866b0e 100644 --- a/springwolf-ui/package-lock.json +++ b/springwolf-ui/package-lock.json @@ -38,7 +38,7 @@ "esbuild": "^0.23.1", "jest": "^29.7.0", "jest-junit": "^16.0.0", - "jest-preset-angular": "^14.2.2", + "jest-preset-angular": "^14.2.4", "typescript": "^5.5.4" } }, @@ -13535,9 +13535,9 @@ } }, "node_modules/jest-preset-angular": { - "version": "14.2.2", - "resolved": "https://registry.npmjs.org/jest-preset-angular/-/jest-preset-angular-14.2.2.tgz", - "integrity": "sha512-vdpv1DV4yJMMoBRbTdwRA16Es0UU+8CuOHsV2vfUL0LOy69anvq2RUawh07EyTWSVxko838jOC146jlnCkWOOw==", + "version": "14.2.4", + "resolved": "https://registry.npmjs.org/jest-preset-angular/-/jest-preset-angular-14.2.4.tgz", + "integrity": "sha512-xyhkaiBdn3keBgxxkcbqZu/my3ADU9NcDrz6DaMuGRaxz/bf6ZC1qxZ1eQuz5V1WuA3/rD64VA3Kke8P6E9qNg==", "dev": true, "dependencies": { "bs-logger": "^0.2.6", diff --git a/springwolf-ui/package.json b/springwolf-ui/package.json index 9010480ea..2bd940a3d 100644 --- a/springwolf-ui/package.json +++ b/springwolf-ui/package.json @@ -41,7 +41,7 @@ "esbuild": "^0.23.1", "jest": "^29.7.0", "jest-junit": "^16.0.0", - "jest-preset-angular": "^14.2.2", + "jest-preset-angular": "^14.2.4", "typescript": "^5.5.4" }, "jest-junit": { From 88269050c0dd3666435392be2f83022850fd5e2d Mon Sep 17 00:00:00 2001 From: Timon Back Date: Sun, 15 Sep 2024 20:36:00 +0200 Subject: [PATCH 15/34] Feat/add options to amqp annotation (#980) * feat(amqp): add userId and bcc to AmqpAsyncOperationBinding * chore(gh): update test reports configuration in pipeline * refactor: Replace EmbeddedValueResolverAware with SpringValueResolver by using the StringValueResolverProxy bean --- .github/workflows/springwolf-core.yml | 1 + .github/workflows/springwolf-plugins.yml | 4 +- .github/workflows/springwolf-ui.yml | 1 + .../springwolf-generic-binding/build.gradle | 4 +- ...ngwolfGenericBindingAutoConfiguration.java | 6 +- ...AsyncGenericOperationBindingProcessor.java | 5 + ...cGenericOperationBindingProcessorTest.java | 6 +- .../springwolf-amqp-binding/build.gradle | 4 + .../AmqpAsyncOperationBinding.java | 4 + ...pringwolfAmqpBindingAutoConfiguration.java | 5 +- .../messages/AmqpMessageBindingProcessor.java | 11 +- .../AmqpOperationBindingProcessor.java | 9 ++ .../AmqpOperationBindingProcessorTest.java | 100 ++++++++++++++---- .../build.gradle | 3 + .../GooglePubSubChannelBindingProcessor.java | 11 +- .../GooglePubSubMessageBindingProcessor.java | 10 +- .../springwolf-jms-binding/build.gradle | 4 + ...SpringwolfJmsBindingAutoConfiguration.java | 5 +- .../messages/JmsMessageBindingProcessor.java | 10 +- .../JmsOperationBindingProcessor.java | 4 + .../JmsOperationBindingProcessorTest.java | 5 +- .../springwolf-kafka-binding/build.gradle | 4 + ...ringwolfKafkaBindingAutoConfiguration.java | 9 +- .../KafkaMessageBindingProcessor.java | 14 +-- .../KafkaOperationBindingProcessor.java | 6 ++ .../KafkaMessageBindingProcessorTest.java | 5 +- .../KafkaOperationBindingProcessorTest.java | 5 +- .../springwolf-sns-binding/build.gradle | 4 + ...SpringwolfSnsBindingAutoConfiguration.java | 5 +- .../messages/SnsMessageBindingProcessor.java | 10 +- .../SnsOperationBindingProcessor.java | 5 + .../SnsOperationBindingProcessorTest.java | 5 +- .../springwolf-sqs-binding/build.gradle | 4 + ...SpringwolfSqsBindingAutoConfiguration.java | 5 +- .../messages/SqsMessageBindingProcessor.java | 10 +- .../SqsOperationBindingProcessor.java | 5 + .../SqsOperationBindingProcessorTest.java | 5 +- .../springwolf-stomp-binding/build.gradle | 4 + ...ringwolfStompBindingAutoConfiguration.java | 5 +- .../StompMessageBindingProcessor.java | 10 +- .../StompOperationBindingProcessor.java | 5 + .../StompOperationBindingProcessorTest.java | 5 +- .../AbstractOperationBindingProcessor.java | 16 ++- .../annotation/AsyncAnnotationUtil.java | 40 +++---- .../AsyncAnnotationChannelService.java | 6 +- .../AsyncAnnotationMessageService.java | 8 +- .../AsyncAnnotationOperationService.java | 4 +- .../utils/StringValueResolverProxy.java | 4 +- ...nnotationMethodLevelOperationsScanner.java | 6 +- .../SpringwolfAutoConfiguration.java | 4 +- .../SpringwolfScannerConfiguration.java | 68 ++++++++---- ...TestAbstractOperationBindingProcessor.java | 5 + .../annotation/AsyncAnnotationUtilTest.java | 37 ++++--- .../AsyncAnnotationChannelServiceTest.java | 8 +- .../AsyncAnnotationMessageServiceTest.java | 8 +- .../src/test/resources/asyncapi.json | 3 +- .../src/test/resources/asyncapi.yaml | 1 + .../scanners/bindings/AmqpBindingFactory.java | 17 ++- .../scanners/bindings/RabbitListenerUtil.java | 38 +++---- .../SpringwolfAmqpScannerConfiguration.java | 9 +- .../bindings/RabbitListenerUtilTest.java | 78 +++++++------- ...pProducerConfigurationIntegrationTest.java | 5 +- .../scanners/bindings/JmsBindingFactory.java | 14 +-- .../scanners/bindings/JmsListenerUtil.java | 8 +- .../SpringwolfJmsScannerConfiguration.java | 5 +- .../bindings/JmsListenerUtilTest.java | 15 +-- ...sProducerConfigurationIntegrationTest.java | 7 +- .../bindings/KafkaBindingFactory.java | 14 +-- .../scanners/common/KafkaListenerUtil.java | 8 +- .../SpringwolfKafkaScannerConfiguration.java | 5 +- .../common/KafkaListenerUtilTest.java | 21 ++-- ...aProducerConfigurationIntegrationTest.java | 3 + .../scanners/bindings/SqsBindingFactory.java | 14 +-- .../scanners/bindings/SqsListenerUtil.java | 8 +- .../SpringwolfSqsScannerConfiguration.java | 5 +- .../bindings/SqsListenerUtilTest.java | 15 +-- ...sProducerConfigurationIntegrationTest.java | 7 +- .../StompBindingMessageMappingFactory.java | 10 +- .../bindings/StompBindingSendToFactory.java | 10 +- .../StompBindingSendToUserFactory.java | 10 +- .../scanners/common/MessageMappingUtil.java | 6 +- .../scanners/common/SendToUserUtil.java | 6 +- .../asyncapi/scanners/common/SendToUtil.java | 7 +- .../SpringwolfStompScannerConfiguration.java | 15 +-- .../stomp/common/MessageMappingUtilTest.java | 13 +-- .../stomp/common/SendToUserUtilTest.java | 13 +-- .../plugins/stomp/common/SendToUtilTest.java | 13 +-- 87 files changed, 544 insertions(+), 415 deletions(-) diff --git a/.github/workflows/springwolf-core.yml b/.github/workflows/springwolf-core.yml index 56a937de9..996ab60c5 100644 --- a/.github/workflows/springwolf-core.yml +++ b/.github/workflows/springwolf-core.yml @@ -42,6 +42,7 @@ jobs: if: success() || failure() with: check_name: test-core + require_tests: true report_paths: '**/build/test-results/test/TEST-*.xml' - name: Publish package diff --git a/.github/workflows/springwolf-plugins.yml b/.github/workflows/springwolf-plugins.yml index 3be2fe714..40f323077 100644 --- a/.github/workflows/springwolf-plugins.yml +++ b/.github/workflows/springwolf-plugins.yml @@ -62,7 +62,7 @@ jobs: uses: mikepenz/action-junit-report@v4 if: success() || failure() with: - check_name: test-${{ matrix.plugin }}-junit + check_name: test-plugin-${{ matrix.plugin }}-junit require_tests: true report_paths: '**/build/test-results/test/TEST-*.xml' @@ -73,7 +73,7 @@ jobs: - uses: actions/upload-artifact@v4 if: always() with: - name: test-${{ matrix.plugin }}-playwright + name: test-plugin-${{ matrix.plugin }}-playwright path: springwolf-examples/e2e/playwright-report/ retention-days: 14 diff --git a/.github/workflows/springwolf-ui.yml b/.github/workflows/springwolf-ui.yml index 299111325..0ff2f4f0f 100644 --- a/.github/workflows/springwolf-ui.yml +++ b/.github/workflows/springwolf-ui.yml @@ -44,6 +44,7 @@ jobs: if: success() || failure() with: check_name: test-ui-jest + require_tests: true report_paths: '**/build/test-results/test/*.xml' - name: Build diff --git a/springwolf-add-ons/springwolf-generic-binding/build.gradle b/springwolf-add-ons/springwolf-generic-binding/build.gradle index d0fbe1ee7..e8d31e2bf 100644 --- a/springwolf-add-ons/springwolf-generic-binding/build.gradle +++ b/springwolf-add-ons/springwolf-generic-binding/build.gradle @@ -21,7 +21,9 @@ dependencies { testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation("org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}") + testImplementation "org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}" + testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" + testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/configuration/SpringwolfGenericBindingAutoConfiguration.java b/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/configuration/SpringwolfGenericBindingAutoConfiguration.java index c07b6b25c..be7c207a7 100644 --- a/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/configuration/SpringwolfGenericBindingAutoConfiguration.java +++ b/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/configuration/SpringwolfGenericBindingAutoConfiguration.java @@ -6,13 +6,15 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; +import org.springframework.util.StringValueResolver; @Configuration public class SpringwolfGenericBindingAutoConfiguration { @Bean @Order(value = BindingProcessorPriority.GENERIC_BINDING) - public AsyncGenericOperationBindingProcessor asyncGenericOperationBindingProcessor() { - return new AsyncGenericOperationBindingProcessor(); + public AsyncGenericOperationBindingProcessor asyncGenericOperationBindingProcessor( + StringValueResolver stringValueResolver) { + return new AsyncGenericOperationBindingProcessor(stringValueResolver); } } diff --git a/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessor.java b/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessor.java index 4aa1cf89a..4695b8376 100644 --- a/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessor.java +++ b/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessor.java @@ -5,6 +5,7 @@ import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.AbstractOperationBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; +import org.springframework.util.StringValueResolver; import java.util.HashMap; import java.util.Map; @@ -12,6 +13,10 @@ public class AsyncGenericOperationBindingProcessor extends AbstractOperationBindingProcessor { + public AsyncGenericOperationBindingProcessor(StringValueResolver stringValueResolver) { + super(stringValueResolver); + } + @Override protected ProcessedOperationBinding mapToOperationBinding(AsyncGenericOperationBinding bindingAnnotation) { Map bindingData = PropertiesUtil.toMap(bindingAnnotation.fields()); diff --git a/springwolf-add-ons/springwolf-generic-binding/src/test/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessorTest.java b/springwolf-add-ons/springwolf-generic-binding/src/test/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessorTest.java index cfdae8702..722bf16d6 100644 --- a/springwolf-add-ons/springwolf-generic-binding/src/test/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessorTest.java +++ b/springwolf-add-ons/springwolf-generic-binding/src/test/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessorTest.java @@ -7,16 +7,20 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.springframework.util.StringValueResolver; import java.util.Arrays; import java.util.List; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class AsyncGenericOperationBindingProcessorTest { - private final AsyncGenericOperationBindingProcessor processor = new AsyncGenericOperationBindingProcessor(); + private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); + private final AsyncGenericOperationBindingProcessor processor = + new AsyncGenericOperationBindingProcessor(stringValueResolver); @Test void testClassWithoutAnnotation() { diff --git a/springwolf-bindings/springwolf-amqp-binding/build.gradle b/springwolf-bindings/springwolf-amqp-binding/build.gradle index 4b92963bc..fbf270f6a 100644 --- a/springwolf-bindings/springwolf-amqp-binding/build.gradle +++ b/springwolf-bindings/springwolf-amqp-binding/build.gradle @@ -14,8 +14,12 @@ dependencies { implementation "org.springframework:spring-core" implementation "org.springframework.boot:spring-boot-autoconfigure" + compileOnly "org.projectlombok:lombok:${lombokVersion}" + annotationProcessor "org.projectlombok:lombok:${lombokVersion}" + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" + testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/annotations/AmqpAsyncOperationBinding.java b/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/annotations/AmqpAsyncOperationBinding.java index 5e19b2a05..8ba820a4b 100644 --- a/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/annotations/AmqpAsyncOperationBinding.java +++ b/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/annotations/AmqpAsyncOperationBinding.java @@ -23,6 +23,8 @@ int expiration() default 0; + String userId() default ""; + String[] cc() default {}; int priority() default 0; @@ -31,6 +33,8 @@ boolean mandatory() default false; + String[] bcc() default {}; + boolean timestamp() default false; boolean ack() default false; diff --git a/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/configuration/SpringwolfAmqpBindingAutoConfiguration.java b/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/configuration/SpringwolfAmqpBindingAutoConfiguration.java index 75dfd9dd8..f300490d9 100644 --- a/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/configuration/SpringwolfAmqpBindingAutoConfiguration.java +++ b/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/configuration/SpringwolfAmqpBindingAutoConfiguration.java @@ -10,6 +10,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; +import org.springframework.util.StringValueResolver; /** * Autoconfiguration for the springwolf Amqp Binding. @@ -21,8 +22,8 @@ public class SpringwolfAmqpBindingAutoConfiguration { @Bean @Order(value = BindingProcessorPriority.PROTOCOL_BINDING) @ConditionalOnMissingBean - public AmqpOperationBindingProcessor amqpOperationBindingProcessor() { - return new AmqpOperationBindingProcessor(); + public AmqpOperationBindingProcessor amqpOperationBindingProcessor(StringValueResolver stringValueResolver) { + return new AmqpOperationBindingProcessor(stringValueResolver); } @Bean diff --git a/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/scanners/messages/AmqpMessageBindingProcessor.java b/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/scanners/messages/AmqpMessageBindingProcessor.java index 08f53f5f4..687d050ec 100644 --- a/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/scanners/messages/AmqpMessageBindingProcessor.java +++ b/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/scanners/messages/AmqpMessageBindingProcessor.java @@ -5,21 +5,12 @@ import io.github.springwolf.bindings.amqp.annotations.AmqpAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.util.StringValueResolver; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.Optional; -public class AmqpMessageBindingProcessor implements MessageBindingProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } - +public class AmqpMessageBindingProcessor implements MessageBindingProcessor { @Override public Optional process(AnnotatedElement annotatedElement) { return Arrays.stream(annotatedElement.getAnnotations()) diff --git a/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/scanners/operations/AmqpOperationBindingProcessor.java b/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/scanners/operations/AmqpOperationBindingProcessor.java index 7b96e8f14..097483e3a 100644 --- a/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/scanners/operations/AmqpOperationBindingProcessor.java +++ b/springwolf-bindings/springwolf-amqp-binding/src/main/java/io/github/springwolf/bindings/amqp/scanners/operations/AmqpOperationBindingProcessor.java @@ -5,20 +5,29 @@ import io.github.springwolf.bindings.amqp.annotations.AmqpAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.AbstractOperationBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; +import org.springframework.util.StringValueResolver; import java.util.Arrays; public class AmqpOperationBindingProcessor extends AbstractOperationBindingProcessor { + public AmqpOperationBindingProcessor(StringValueResolver stringValueResolver) { + super(stringValueResolver); + } + @Override protected ProcessedOperationBinding mapToOperationBinding(AmqpAsyncOperationBinding bindingAnnotation) { AMQPOperationBinding amqpOperationBinding = AMQPOperationBinding.builder() .expiration(bindingAnnotation.expiration()) + .userId(resolveOrNull(bindingAnnotation.userId())) .cc(Arrays.stream(bindingAnnotation.cc()) .map(this::resolveOrNull) .toList()) .priority(bindingAnnotation.priority()) .deliveryMode(bindingAnnotation.deliveryMode()) .mandatory(bindingAnnotation.mandatory()) + .bcc(Arrays.stream(bindingAnnotation.bcc()) + .map(this::resolveOrNull) + .toList()) .timestamp(bindingAnnotation.timestamp()) .ack(bindingAnnotation.ack()) .build(); diff --git a/springwolf-bindings/springwolf-amqp-binding/src/test/java/io/github/springwolf/bindings/amqp/scanners/operations/AmqpOperationBindingProcessorTest.java b/springwolf-bindings/springwolf-amqp-binding/src/test/java/io/github/springwolf/bindings/amqp/scanners/operations/AmqpOperationBindingProcessorTest.java index cd9e74144..5c4f27768 100644 --- a/springwolf-bindings/springwolf-amqp-binding/src/test/java/io/github/springwolf/bindings/amqp/scanners/operations/AmqpOperationBindingProcessorTest.java +++ b/springwolf-bindings/springwolf-amqp-binding/src/test/java/io/github/springwolf/bindings/amqp/scanners/operations/AmqpOperationBindingProcessorTest.java @@ -4,35 +4,91 @@ import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding; import io.github.springwolf.bindings.amqp.annotations.AmqpAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.springframework.util.StringValueResolver; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; class AmqpOperationBindingProcessorTest { - private final AmqpOperationBindingProcessor processor = new AmqpOperationBindingProcessor(); - - @Test - void mapToOperationBindingTest() throws NoSuchMethodException { - AmqpAsyncOperationBinding annotation = AmqpOperationBindingProcessorTest.class - .getMethod("methodWithAnnotation") - .getAnnotation(AmqpAsyncOperationBinding.class); - - ProcessedOperationBinding binding = processor.mapToOperationBinding(annotation); - - assertThat(binding.getType()).isEqualTo("amqp"); - assertThat(binding.getBinding()) - .isEqualTo(AMQPOperationBinding.builder() - .cc(List.of()) - .priority(0) - .deliveryMode(1) - .mandatory(false) - .timestamp(false) - .ack(false) - .build()); + private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); + private final AmqpOperationBindingProcessor processor = new AmqpOperationBindingProcessor(stringValueResolver); + + @BeforeEach + void setUp() { + doAnswer(invocation -> invocation.getArgument(0)) + .when(stringValueResolver) + .resolveStringValue(anyString()); + } + + @Nested + class EmptyAnnotation { + @Test + void mapToOperationBindingTest() throws NoSuchMethodException { + AmqpAsyncOperationBinding annotation = EmptyAnnotation.class + .getMethod("methodWithAnnotation") + .getAnnotation(AmqpAsyncOperationBinding.class); + + ProcessedOperationBinding binding = processor.mapToOperationBinding(annotation); + + assertThat(binding.getType()).isEqualTo("amqp"); + assertThat(binding.getBinding()) + .isEqualTo(AMQPOperationBinding.builder() + .cc(List.of()) + .bcc(List.of()) + .priority(0) + .deliveryMode(1) + .mandatory(false) + .timestamp(false) + .ack(false) + .build()); + } + + @AmqpAsyncOperationBinding + public void methodWithAnnotation() {} } - @AmqpAsyncOperationBinding - public void methodWithAnnotation() {} + @Nested + class AllFieldsSetInAnnotation { + @Test + void mapToOperationBindingTest() throws NoSuchMethodException { + AmqpAsyncOperationBinding annotation = AllFieldsSetInAnnotation.class + .getMethod("methodWithAnnotation") + .getAnnotation(AmqpAsyncOperationBinding.class); + + ProcessedOperationBinding binding = processor.mapToOperationBinding(annotation); + + assertThat(binding.getType()).isEqualTo("amqp"); + assertThat(binding.getBinding()) + .isEqualTo(AMQPOperationBinding.builder() + .expiration(1) + .userId("userId") + .cc(List.of("cc1", "cc2")) + .priority(2) + .deliveryMode(3) + .mandatory(true) + .bcc(List.of("bcc1", "bcc2")) + .timestamp(true) + .ack(true) + .build()); + } + + @AmqpAsyncOperationBinding( + expiration = 1, + userId = "userId", + cc = {"cc1", "cc2"}, + priority = 2, + deliveryMode = 3, + mandatory = true, + bcc = {"bcc1", "bcc2"}, + timestamp = true, + ack = true) + public void methodWithAnnotation() {} + } } diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle b/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle index 283f7b7fb..5a0745061 100644 --- a/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle +++ b/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle @@ -16,6 +16,9 @@ dependencies { implementation "org.apache.commons:commons-lang3:${commonsLang3Version}" + compileOnly "org.projectlombok:lombok:${lombokVersion}" + annotationProcessor "org.projectlombok:lombok:${lombokVersion}" + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/channels/GooglePubSubChannelBindingProcessor.java b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/channels/GooglePubSubChannelBindingProcessor.java index 7ea24f4d9..5c5a69a30 100644 --- a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/channels/GooglePubSubChannelBindingProcessor.java +++ b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/channels/GooglePubSubChannelBindingProcessor.java @@ -8,21 +8,12 @@ import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ChannelBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ProcessedChannelBinding; import org.apache.commons.lang3.StringUtils; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.util.StringValueResolver; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.Optional; -public class GooglePubSubChannelBindingProcessor implements ChannelBindingProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } - +public class GooglePubSubChannelBindingProcessor implements ChannelBindingProcessor { @Override public Optional process(AnnotatedElement annotatedElement) { return Arrays.stream(annotatedElement.getAnnotations()) diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/messages/GooglePubSubMessageBindingProcessor.java b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/messages/GooglePubSubMessageBindingProcessor.java index 971e29912..24a058a26 100644 --- a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/messages/GooglePubSubMessageBindingProcessor.java +++ b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/messages/GooglePubSubMessageBindingProcessor.java @@ -7,20 +7,12 @@ import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding; import org.apache.commons.lang3.StringUtils; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.util.StringValueResolver; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.Optional; -public class GooglePubSubMessageBindingProcessor implements MessageBindingProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } +public class GooglePubSubMessageBindingProcessor implements MessageBindingProcessor { @Override public Optional process(AnnotatedElement annotatedElement) { diff --git a/springwolf-bindings/springwolf-jms-binding/build.gradle b/springwolf-bindings/springwolf-jms-binding/build.gradle index d3ed9398d..c7e653ab3 100644 --- a/springwolf-bindings/springwolf-jms-binding/build.gradle +++ b/springwolf-bindings/springwolf-jms-binding/build.gradle @@ -14,8 +14,12 @@ dependencies { implementation "org.springframework:spring-core" implementation "org.springframework.boot:spring-boot-autoconfigure" + compileOnly "org.projectlombok:lombok:${lombokVersion}" + annotationProcessor "org.projectlombok:lombok:${lombokVersion}" + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" + testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/configuration/SpringwolfJmsBindingAutoConfiguration.java b/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/configuration/SpringwolfJmsBindingAutoConfiguration.java index 12fcc4aa6..72cf3b43c 100644 --- a/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/configuration/SpringwolfJmsBindingAutoConfiguration.java +++ b/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/configuration/SpringwolfJmsBindingAutoConfiguration.java @@ -4,6 +4,7 @@ import io.github.springwolf.bindings.jms.scanners.messages.JmsMessageBindingProcessor; import io.github.springwolf.bindings.jms.scanners.operations.JmsOperationBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingProcessorPriority; +import io.github.springwolf.core.asyncapi.scanners.common.utils.StringValueResolverProxy; import io.github.springwolf.core.configuration.properties.SpringwolfConfigConstants; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -21,8 +22,8 @@ public class SpringwolfJmsBindingAutoConfiguration { @Bean @Order(value = BindingProcessorPriority.PROTOCOL_BINDING) @ConditionalOnMissingBean - public JmsOperationBindingProcessor jmsOperationBindingProcessor() { - return new JmsOperationBindingProcessor(); + public JmsOperationBindingProcessor jmsOperationBindingProcessor(StringValueResolverProxy stringValueResolver) { + return new JmsOperationBindingProcessor(stringValueResolver); } @Bean diff --git a/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/scanners/messages/JmsMessageBindingProcessor.java b/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/scanners/messages/JmsMessageBindingProcessor.java index 579b302bc..eff2ebccb 100644 --- a/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/scanners/messages/JmsMessageBindingProcessor.java +++ b/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/scanners/messages/JmsMessageBindingProcessor.java @@ -5,20 +5,12 @@ import io.github.springwolf.bindings.jms.annotations.JmsAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.util.StringValueResolver; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.Optional; -public class JmsMessageBindingProcessor implements MessageBindingProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } +public class JmsMessageBindingProcessor implements MessageBindingProcessor { @Override public Optional process(AnnotatedElement annotatedElement) { diff --git a/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/scanners/operations/JmsOperationBindingProcessor.java b/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/scanners/operations/JmsOperationBindingProcessor.java index 026ae3ebd..a0a7492fb 100644 --- a/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/scanners/operations/JmsOperationBindingProcessor.java +++ b/springwolf-bindings/springwolf-jms-binding/src/main/java/io/github/springwolf/bindings/jms/scanners/operations/JmsOperationBindingProcessor.java @@ -5,8 +5,12 @@ import io.github.springwolf.bindings.jms.annotations.JmsAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.AbstractOperationBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; +import org.springframework.util.StringValueResolver; public class JmsOperationBindingProcessor extends AbstractOperationBindingProcessor { + public JmsOperationBindingProcessor(StringValueResolver stringValueResolver) { + super(stringValueResolver); + } @Override protected ProcessedOperationBinding mapToOperationBinding(JmsAsyncOperationBinding bindingAnnotation) { diff --git a/springwolf-bindings/springwolf-jms-binding/src/test/java/io/github/springwolf/bindings/jms/scanners/operations/JmsOperationBindingProcessorTest.java b/springwolf-bindings/springwolf-jms-binding/src/test/java/io/github/springwolf/bindings/jms/scanners/operations/JmsOperationBindingProcessorTest.java index b4a90c703..ae4936e28 100644 --- a/springwolf-bindings/springwolf-jms-binding/src/test/java/io/github/springwolf/bindings/jms/scanners/operations/JmsOperationBindingProcessorTest.java +++ b/springwolf-bindings/springwolf-jms-binding/src/test/java/io/github/springwolf/bindings/jms/scanners/operations/JmsOperationBindingProcessorTest.java @@ -5,11 +5,14 @@ import io.github.springwolf.bindings.jms.annotations.JmsAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; import org.junit.jupiter.api.Test; +import org.springframework.util.StringValueResolver; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class JmsOperationBindingProcessorTest { - private final JmsOperationBindingProcessor processor = new JmsOperationBindingProcessor(); + private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); + private final JmsOperationBindingProcessor processor = new JmsOperationBindingProcessor(stringValueResolver); @Test void mapToOperationBindingTest() throws NoSuchMethodException { diff --git a/springwolf-bindings/springwolf-kafka-binding/build.gradle b/springwolf-bindings/springwolf-kafka-binding/build.gradle index 8e52907bb..342a18da8 100644 --- a/springwolf-bindings/springwolf-kafka-binding/build.gradle +++ b/springwolf-bindings/springwolf-kafka-binding/build.gradle @@ -16,8 +16,12 @@ dependencies { implementation "jakarta.annotation:jakarta.annotation-api:${annotationApiVersion}" + compileOnly "org.projectlombok:lombok:${lombokVersion}" + annotationProcessor "org.projectlombok:lombok:${lombokVersion}" + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" + testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/configuration/SpringwolfKafkaBindingAutoConfiguration.java b/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/configuration/SpringwolfKafkaBindingAutoConfiguration.java index 4582b7339..8543a8c68 100644 --- a/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/configuration/SpringwolfKafkaBindingAutoConfiguration.java +++ b/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/configuration/SpringwolfKafkaBindingAutoConfiguration.java @@ -10,6 +10,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; +import org.springframework.util.StringValueResolver; /** * Autoconfiguration for the springwolf Kafka Binding. @@ -21,14 +22,14 @@ public class SpringwolfKafkaBindingAutoConfiguration { @Bean @Order(value = BindingProcessorPriority.PROTOCOL_BINDING) @ConditionalOnMissingBean - public KafkaOperationBindingProcessor kafkaOperationBindingProcessor() { - return new KafkaOperationBindingProcessor(); + public KafkaOperationBindingProcessor kafkaOperationBindingProcessor(StringValueResolver stringValueResolver) { + return new KafkaOperationBindingProcessor(stringValueResolver); } @Bean @Order(value = BindingProcessorPriority.PROTOCOL_BINDING) @ConditionalOnMissingBean - public KafkaMessageBindingProcessor kafkaMessageBindingProcessor() { - return new KafkaMessageBindingProcessor(); + public KafkaMessageBindingProcessor kafkaMessageBindingProcessor(StringValueResolver stringValueResolver) { + return new KafkaMessageBindingProcessor(stringValueResolver); } } diff --git a/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/scanners/messages/KafkaMessageBindingProcessor.java b/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/scanners/messages/KafkaMessageBindingProcessor.java index 3f8e35641..9121e9ca0 100644 --- a/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/scanners/messages/KafkaMessageBindingProcessor.java +++ b/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/scanners/messages/KafkaMessageBindingProcessor.java @@ -8,7 +8,7 @@ import io.github.springwolf.bindings.kafka.annotations.KafkaAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding; -import org.springframework.context.EmbeddedValueResolverAware; +import lombok.RequiredArgsConstructor; import org.springframework.util.StringUtils; import org.springframework.util.StringValueResolver; @@ -17,13 +17,9 @@ import java.util.List; import java.util.Optional; -public class KafkaMessageBindingProcessor implements MessageBindingProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } +@RequiredArgsConstructor +public class KafkaMessageBindingProcessor implements MessageBindingProcessor { + private final StringValueResolver stringValueResolver; @Override public Optional process(AnnotatedElement annotatedElement) { @@ -50,7 +46,7 @@ private ProcessedMessageBinding mapToMessageBinding(KafkaAsyncOperationBinding b } private String resolveOrNull(String stringValue) { - return StringUtils.hasText(stringValue) ? resolver.resolveStringValue(stringValue) : null; + return StringUtils.hasText(stringValue) ? stringValueResolver.resolveStringValue(stringValue) : null; } private Schema resolveSchemaOrNull(KafkaAsyncOperationBinding.KafkaAsyncMessageBinding messageBinding) { diff --git a/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/scanners/operations/KafkaOperationBindingProcessor.java b/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/scanners/operations/KafkaOperationBindingProcessor.java index ea9bb161a..0b92a62a7 100644 --- a/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/scanners/operations/KafkaOperationBindingProcessor.java +++ b/springwolf-bindings/springwolf-kafka-binding/src/main/java/io/github/springwolf/bindings/kafka/scanners/operations/KafkaOperationBindingProcessor.java @@ -9,10 +9,16 @@ import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; import jakarta.annotation.Nullable; import org.springframework.util.StringUtils; +import org.springframework.util.StringValueResolver; import java.util.List; public class KafkaOperationBindingProcessor extends AbstractOperationBindingProcessor { + + public KafkaOperationBindingProcessor(StringValueResolver stringValueResolver) { + super(stringValueResolver); + } + @Override protected ProcessedOperationBinding mapToOperationBinding(KafkaAsyncOperationBinding bindingAnnotation) { String clientId = resolveOrNull(bindingAnnotation.clientId()); diff --git a/springwolf-bindings/springwolf-kafka-binding/src/test/java/io/github/springwolf/bindings/kafka/scanners/messages/KafkaMessageBindingProcessorTest.java b/springwolf-bindings/springwolf-kafka-binding/src/test/java/io/github/springwolf/bindings/kafka/scanners/messages/KafkaMessageBindingProcessorTest.java index cf58e65c6..e2ea6b8dd 100644 --- a/springwolf-bindings/springwolf-kafka-binding/src/test/java/io/github/springwolf/bindings/kafka/scanners/messages/KafkaMessageBindingProcessorTest.java +++ b/springwolf-bindings/springwolf-kafka-binding/src/test/java/io/github/springwolf/bindings/kafka/scanners/messages/KafkaMessageBindingProcessorTest.java @@ -5,14 +5,17 @@ import io.github.springwolf.bindings.kafka.annotations.KafkaAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding; import org.junit.jupiter.api.Test; +import org.springframework.util.StringValueResolver; import java.lang.reflect.Method; import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class KafkaMessageBindingProcessorTest { - private final KafkaMessageBindingProcessor processor = new KafkaMessageBindingProcessor(); + private final StringValueResolver stringValueResolver = mock(); + private final KafkaMessageBindingProcessor processor = new KafkaMessageBindingProcessor(stringValueResolver); @Test void processTest() throws NoSuchMethodException { diff --git a/springwolf-bindings/springwolf-kafka-binding/src/test/java/io/github/springwolf/bindings/kafka/scanners/operations/KafkaOperationBindingProcessorTest.java b/springwolf-bindings/springwolf-kafka-binding/src/test/java/io/github/springwolf/bindings/kafka/scanners/operations/KafkaOperationBindingProcessorTest.java index ea9782860..06f157abc 100644 --- a/springwolf-bindings/springwolf-kafka-binding/src/test/java/io/github/springwolf/bindings/kafka/scanners/operations/KafkaOperationBindingProcessorTest.java +++ b/springwolf-bindings/springwolf-kafka-binding/src/test/java/io/github/springwolf/bindings/kafka/scanners/operations/KafkaOperationBindingProcessorTest.java @@ -5,11 +5,14 @@ import io.github.springwolf.bindings.kafka.annotations.KafkaAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; import org.junit.jupiter.api.Test; +import org.springframework.util.StringValueResolver; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class KafkaOperationBindingProcessorTest { - private final KafkaOperationBindingProcessor processor = new KafkaOperationBindingProcessor(); + private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); + private final KafkaOperationBindingProcessor processor = new KafkaOperationBindingProcessor(stringValueResolver); @Test void mapToOperationBindingTest() throws NoSuchMethodException { diff --git a/springwolf-bindings/springwolf-sns-binding/build.gradle b/springwolf-bindings/springwolf-sns-binding/build.gradle index 827f978ed..13668bec2 100644 --- a/springwolf-bindings/springwolf-sns-binding/build.gradle +++ b/springwolf-bindings/springwolf-sns-binding/build.gradle @@ -14,8 +14,12 @@ dependencies { implementation "org.springframework:spring-core" implementation "org.springframework.boot:spring-boot-autoconfigure" + compileOnly "org.projectlombok:lombok:${lombokVersion}" + annotationProcessor "org.projectlombok:lombok:${lombokVersion}" + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" + testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/configuration/SpringwolfSnsBindingAutoConfiguration.java b/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/configuration/SpringwolfSnsBindingAutoConfiguration.java index f8ee66733..06909dc9a 100644 --- a/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/configuration/SpringwolfSnsBindingAutoConfiguration.java +++ b/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/configuration/SpringwolfSnsBindingAutoConfiguration.java @@ -10,6 +10,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; +import org.springframework.util.StringValueResolver; /** * Autoconfiguration for the springwolf SQS Binding. @@ -28,7 +29,7 @@ public SnsMessageBindingProcessor snsMessageBindingProcessor() { @Bean @Order(value = BindingProcessorPriority.PROTOCOL_BINDING) @ConditionalOnMissingBean - public SnsOperationBindingProcessor snsOperationBindingProcessor() { - return new SnsOperationBindingProcessor(); + public SnsOperationBindingProcessor snsOperationBindingProcessor(StringValueResolver stringValueResolver) { + return new SnsOperationBindingProcessor(stringValueResolver); } } diff --git a/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/scanners/messages/SnsMessageBindingProcessor.java b/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/scanners/messages/SnsMessageBindingProcessor.java index bd681955d..86105a03e 100644 --- a/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/scanners/messages/SnsMessageBindingProcessor.java +++ b/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/scanners/messages/SnsMessageBindingProcessor.java @@ -5,20 +5,12 @@ import io.github.springwolf.bindings.sns.annotations.SnsAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.util.StringValueResolver; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.Optional; -public class SnsMessageBindingProcessor implements MessageBindingProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } +public class SnsMessageBindingProcessor implements MessageBindingProcessor { @Override public Optional process(AnnotatedElement annotatedElement) { diff --git a/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/scanners/operations/SnsOperationBindingProcessor.java b/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/scanners/operations/SnsOperationBindingProcessor.java index 1ae73b83a..68b9d171f 100644 --- a/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/scanners/operations/SnsOperationBindingProcessor.java +++ b/springwolf-bindings/springwolf-sns-binding/src/main/java/io/github/springwolf/bindings/sns/scanners/operations/SnsOperationBindingProcessor.java @@ -8,11 +8,16 @@ import io.github.springwolf.bindings.sns.annotations.SnsAsyncOperationBindingIdentifier; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.AbstractOperationBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; +import org.springframework.util.StringValueResolver; import java.util.List; public class SnsOperationBindingProcessor extends AbstractOperationBindingProcessor { + public SnsOperationBindingProcessor(StringValueResolver stringValueResolver) { + super(stringValueResolver); + } + @Override protected ProcessedOperationBinding mapToOperationBinding(SnsAsyncOperationBinding bindingAnnotation) { var identifier = convertAnnotation(bindingAnnotation.endpoint()); diff --git a/springwolf-bindings/springwolf-sns-binding/src/test/java/io/github/springwolf/bindings/sns/scanners/operations/SnsOperationBindingProcessorTest.java b/springwolf-bindings/springwolf-sns-binding/src/test/java/io/github/springwolf/bindings/sns/scanners/operations/SnsOperationBindingProcessorTest.java index 86330ccdb..7b74aa7ac 100644 --- a/springwolf-bindings/springwolf-sns-binding/src/test/java/io/github/springwolf/bindings/sns/scanners/operations/SnsOperationBindingProcessorTest.java +++ b/springwolf-bindings/springwolf-sns-binding/src/test/java/io/github/springwolf/bindings/sns/scanners/operations/SnsOperationBindingProcessorTest.java @@ -8,13 +8,16 @@ import io.github.springwolf.bindings.sns.annotations.SnsAsyncOperationBindingIdentifier; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; import org.junit.jupiter.api.Test; +import org.springframework.util.StringValueResolver; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class SnsOperationBindingProcessorTest { - private final SnsOperationBindingProcessor processor = new SnsOperationBindingProcessor(); + private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); + private final SnsOperationBindingProcessor processor = new SnsOperationBindingProcessor(stringValueResolver); @Test void mapToOperationBindingTest() throws NoSuchMethodException { diff --git a/springwolf-bindings/springwolf-sqs-binding/build.gradle b/springwolf-bindings/springwolf-sqs-binding/build.gradle index 4fee390e0..2de172da2 100644 --- a/springwolf-bindings/springwolf-sqs-binding/build.gradle +++ b/springwolf-bindings/springwolf-sqs-binding/build.gradle @@ -14,8 +14,12 @@ dependencies { implementation "org.springframework:spring-core" implementation "org.springframework.boot:spring-boot-autoconfigure" + compileOnly "org.projectlombok:lombok:${lombokVersion}" + annotationProcessor "org.projectlombok:lombok:${lombokVersion}" + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" + testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/configuration/SpringwolfSqsBindingAutoConfiguration.java b/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/configuration/SpringwolfSqsBindingAutoConfiguration.java index b94a3e1b1..35a07bb9c 100644 --- a/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/configuration/SpringwolfSqsBindingAutoConfiguration.java +++ b/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/configuration/SpringwolfSqsBindingAutoConfiguration.java @@ -10,6 +10,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; +import org.springframework.util.StringValueResolver; /** * Autoconfiguration for the springwolf SQS Binding. @@ -28,7 +29,7 @@ public SqsMessageBindingProcessor sqsMessageBindingProcessor() { @Bean @Order(value = BindingProcessorPriority.PROTOCOL_BINDING) @ConditionalOnMissingBean - public SqsOperationBindingProcessor sqsOperationBindingProcessor() { - return new SqsOperationBindingProcessor(); + public SqsOperationBindingProcessor sqsOperationBindingProcessor(StringValueResolver stringValueResolver) { + return new SqsOperationBindingProcessor(stringValueResolver); } } diff --git a/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/scanners/messages/SqsMessageBindingProcessor.java b/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/scanners/messages/SqsMessageBindingProcessor.java index 3b42d98d4..f899fc2a8 100644 --- a/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/scanners/messages/SqsMessageBindingProcessor.java +++ b/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/scanners/messages/SqsMessageBindingProcessor.java @@ -5,20 +5,12 @@ import io.github.springwolf.bindings.sqs.annotations.SqsAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.util.StringValueResolver; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.Optional; -public class SqsMessageBindingProcessor implements MessageBindingProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } +public class SqsMessageBindingProcessor implements MessageBindingProcessor { @Override public Optional process(AnnotatedElement annotatedElement) { diff --git a/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/scanners/operations/SqsOperationBindingProcessor.java b/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/scanners/operations/SqsOperationBindingProcessor.java index ce59620cb..0e2ea11c8 100644 --- a/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/scanners/operations/SqsOperationBindingProcessor.java +++ b/springwolf-bindings/springwolf-sqs-binding/src/main/java/io/github/springwolf/bindings/sqs/scanners/operations/SqsOperationBindingProcessor.java @@ -7,12 +7,17 @@ import io.github.springwolf.bindings.sqs.annotations.SqsAsyncQueueBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.AbstractOperationBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; +import org.springframework.util.StringValueResolver; import java.util.ArrayList; import java.util.List; public class SqsOperationBindingProcessor extends AbstractOperationBindingProcessor { + public SqsOperationBindingProcessor(StringValueResolver stringValueResolver) { + super(stringValueResolver); + } + @Override protected ProcessedOperationBinding mapToOperationBinding(SqsAsyncOperationBinding bindingAnnotation) { List queues = new ArrayList<>(); diff --git a/springwolf-bindings/springwolf-sqs-binding/src/test/java/io/github/springwolf/bindings/sqs/scanners/operations/SqsOperationBindingProcessorTest.java b/springwolf-bindings/springwolf-sqs-binding/src/test/java/io/github/springwolf/bindings/sqs/scanners/operations/SqsOperationBindingProcessorTest.java index 4291151df..ce4ce90ba 100644 --- a/springwolf-bindings/springwolf-sqs-binding/src/test/java/io/github/springwolf/bindings/sqs/scanners/operations/SqsOperationBindingProcessorTest.java +++ b/springwolf-bindings/springwolf-sqs-binding/src/test/java/io/github/springwolf/bindings/sqs/scanners/operations/SqsOperationBindingProcessorTest.java @@ -7,13 +7,16 @@ import io.github.springwolf.bindings.sqs.annotations.SqsAsyncQueueBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; import org.junit.jupiter.api.Test; +import org.springframework.util.StringValueResolver; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class SqsOperationBindingProcessorTest { - private final SqsOperationBindingProcessor processor = new SqsOperationBindingProcessor(); + private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); + private final SqsOperationBindingProcessor processor = new SqsOperationBindingProcessor(stringValueResolver); @Test void mapToOperationBindingTest() throws NoSuchMethodException { diff --git a/springwolf-bindings/springwolf-stomp-binding/build.gradle b/springwolf-bindings/springwolf-stomp-binding/build.gradle index fd1caff2f..80b43947a 100644 --- a/springwolf-bindings/springwolf-stomp-binding/build.gradle +++ b/springwolf-bindings/springwolf-stomp-binding/build.gradle @@ -14,8 +14,12 @@ dependencies { implementation "org.springframework:spring-core" implementation "org.springframework.boot:spring-boot-autoconfigure" + compileOnly "org.projectlombok:lombok:${lombokVersion}" + annotationProcessor "org.projectlombok:lombok:${lombokVersion}" + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" + testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/configuration/SpringwolfStompBindingAutoConfiguration.java b/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/configuration/SpringwolfStompBindingAutoConfiguration.java index 11bd62a4c..07c1212f6 100644 --- a/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/configuration/SpringwolfStompBindingAutoConfiguration.java +++ b/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/configuration/SpringwolfStompBindingAutoConfiguration.java @@ -10,6 +10,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; +import org.springframework.util.StringValueResolver; /** * Autoconfiguration for the springwolf STOMP Binding. @@ -28,7 +29,7 @@ public StompMessageBindingProcessor stompMessageBindingProcessor() { @Bean @Order(value = BindingProcessorPriority.PROTOCOL_BINDING) @ConditionalOnMissingBean - public StompOperationBindingProcessor stompOperationBindingProcessor() { - return new StompOperationBindingProcessor(); + public StompOperationBindingProcessor stompOperationBindingProcessor(StringValueResolver stringValueResolver) { + return new StompOperationBindingProcessor(stringValueResolver); } } diff --git a/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/scanners/messages/StompMessageBindingProcessor.java b/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/scanners/messages/StompMessageBindingProcessor.java index 17fba2295..0aca1b46d 100644 --- a/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/scanners/messages/StompMessageBindingProcessor.java +++ b/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/scanners/messages/StompMessageBindingProcessor.java @@ -5,20 +5,12 @@ import io.github.springwolf.bindings.stomp.annotations.StompAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding; -import org.springframework.context.EmbeddedValueResolverAware; -import org.springframework.util.StringValueResolver; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.Optional; -public class StompMessageBindingProcessor implements MessageBindingProcessor, EmbeddedValueResolverAware { - private StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } +public class StompMessageBindingProcessor implements MessageBindingProcessor { @Override public Optional process(AnnotatedElement annotatedElement) { diff --git a/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/scanners/operations/StompOperationBindingProcessor.java b/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/scanners/operations/StompOperationBindingProcessor.java index 8309e850d..4ab6b8a98 100644 --- a/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/scanners/operations/StompOperationBindingProcessor.java +++ b/springwolf-bindings/springwolf-stomp-binding/src/main/java/io/github/springwolf/bindings/stomp/scanners/operations/StompOperationBindingProcessor.java @@ -5,9 +5,14 @@ import io.github.springwolf.bindings.stomp.annotations.StompAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.AbstractOperationBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; +import org.springframework.util.StringValueResolver; public class StompOperationBindingProcessor extends AbstractOperationBindingProcessor { + public StompOperationBindingProcessor(StringValueResolver stringValueResolver) { + super(stringValueResolver); + } + @Override protected ProcessedOperationBinding mapToOperationBinding(StompAsyncOperationBinding bindingAnnotation) { var operationBinding = StompOperationBinding.builder().build(); diff --git a/springwolf-bindings/springwolf-stomp-binding/src/test/java/io/github/springwolf/bindings/stomp/scanners/operations/StompOperationBindingProcessorTest.java b/springwolf-bindings/springwolf-stomp-binding/src/test/java/io/github/springwolf/bindings/stomp/scanners/operations/StompOperationBindingProcessorTest.java index 7e3694035..2760ea1b0 100644 --- a/springwolf-bindings/springwolf-stomp-binding/src/test/java/io/github/springwolf/bindings/stomp/scanners/operations/StompOperationBindingProcessorTest.java +++ b/springwolf-bindings/springwolf-stomp-binding/src/test/java/io/github/springwolf/bindings/stomp/scanners/operations/StompOperationBindingProcessorTest.java @@ -5,11 +5,14 @@ import io.github.springwolf.bindings.stomp.annotations.StompAsyncOperationBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; import org.junit.jupiter.api.Test; +import org.springframework.util.StringValueResolver; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class StompOperationBindingProcessorTest { - private final StompOperationBindingProcessor processor = new StompOperationBindingProcessor(); + private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); + private final StompOperationBindingProcessor processor = new StompOperationBindingProcessor(stringValueResolver); @Test void mapToOperationBindingTest() throws NoSuchMethodException { diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/operations/AbstractOperationBindingProcessor.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/operations/AbstractOperationBindingProcessor.java index 1ceb4615b..ec2f77ac0 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/operations/AbstractOperationBindingProcessor.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/operations/AbstractOperationBindingProcessor.java @@ -2,8 +2,8 @@ package io.github.springwolf.core.asyncapi.scanners.bindings.operations; import io.github.springwolf.core.asyncapi.annotations.AsyncOperationBinding; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.util.StringUtils; import org.springframework.util.StringValueResolver; @@ -15,17 +15,13 @@ import java.util.stream.Stream; @Slf4j -public abstract class AbstractOperationBindingProcessor - implements OperationBindingProcessor, EmbeddedValueResolverAware { +@RequiredArgsConstructor +public abstract class AbstractOperationBindingProcessor implements OperationBindingProcessor { + + private final StringValueResolver stringValueResolver; private final Class specificAnnotationClazz = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; - private StringValueResolver resolver; - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.resolver = resolver; - } @Override public Optional process(Method method) { @@ -56,6 +52,6 @@ private Stream tryCast(Annotation obj) { protected abstract ProcessedOperationBinding mapToOperationBinding(A bindingAnnotation); protected String resolveOrNull(String stringValue) { - return StringUtils.hasText(stringValue) ? resolver.resolveStringValue(stringValue) : null; + return StringUtils.hasText(stringValue) ? stringValueResolver.resolveStringValue(stringValue) : null; } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtil.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtil.java index 4317a87e8..97c1ec39f 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtil.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtil.java @@ -37,7 +37,7 @@ public class AsyncAnnotationUtil { private AsyncAnnotationUtil() {} - public static SchemaObject getAsyncHeaders(AsyncOperation op, StringValueResolver resolver) { + public static SchemaObject getAsyncHeaders(AsyncOperation op, StringValueResolver stringValueResolver) { AsyncOperation.Headers headers = op.headers(); if (headers.values().length == 0) { if (headers.notUsed()) { @@ -49,8 +49,9 @@ public static SchemaObject getAsyncHeaders(AsyncOperation op, StringValueResolve String headerSchemaTitle; headerSchemaTitle = StringUtils.hasText(headers.schemaName()) ? headers.schemaName() : generateHeaderSchemaName(headers); - String headerDescription = - StringUtils.hasText(headers.description()) ? resolver.resolveStringValue(headers.description()) : null; + String headerDescription = StringUtils.hasText(headers.description()) + ? stringValueResolver.resolveStringValue(headers.description()) + : null; SchemaObject headerSchema = new SchemaObject(); headerSchema.setType(SchemaType.OBJECT); @@ -61,13 +62,13 @@ public static SchemaObject getAsyncHeaders(AsyncOperation op, StringValueResolve Arrays.stream(headers.values()) .collect(groupingBy(AsyncOperation.Headers.Header::name)) .forEach((headerName, headersValues) -> { - String propertyName = resolver.resolveStringValue(headerName); + String propertyName = stringValueResolver.resolveStringValue(headerName); SchemaObject property = new SchemaObject(); property.setType(SchemaType.STRING); property.setTitle(propertyName); - property.setDescription(getDescription(headersValues, resolver)); - List values = getHeaderValues(headersValues, resolver); + property.setDescription(getDescription(headersValues, stringValueResolver)); + List values = getHeaderValues(headersValues, stringValueResolver); property.setExamples(new ArrayList<>(values)); property.setEnumValues(values); headerSchema.getProperties().put(propertyName, property); @@ -77,19 +78,20 @@ public static SchemaObject getAsyncHeaders(AsyncOperation op, StringValueResolve } private static List getHeaderValues( - List value, StringValueResolver resolver) { + List value, StringValueResolver stringValueResolver) { return value.stream() .map(AsyncOperation.Headers.Header::value) .filter(StringUtils::hasText) - .map(resolver::resolveStringValue) + .map(stringValueResolver::resolveStringValue) .sorted() .toList(); } - private static String getDescription(List value, StringValueResolver resolver) { + private static String getDescription( + List value, StringValueResolver stringValueResolver) { return value.stream() .map(AsyncOperation.Headers.Header::description) - .map(resolver::resolveStringValue) + .map(stringValueResolver::resolveStringValue) .filter(StringUtils::hasText) .sorted() .findFirst() @@ -119,24 +121,24 @@ public static Map processMessageBindingFromAnnotation( public static void processAsyncMessageAnnotation( MessageObject.MessageObjectBuilder messageBuilder, AsyncMessage asyncMessage, - StringValueResolver resolver) { - String annotationMessageDescription = resolver.resolveStringValue(asyncMessage.description()); + StringValueResolver stringValueResolver) { + String annotationMessageDescription = stringValueResolver.resolveStringValue(asyncMessage.description()); if (StringUtils.hasText(annotationMessageDescription)) { annotationMessageDescription = TextUtils.trimIndent(annotationMessageDescription); messageBuilder.description(annotationMessageDescription); } - String annotationMessageId = resolver.resolveStringValue(asyncMessage.messageId()); + String annotationMessageId = stringValueResolver.resolveStringValue(asyncMessage.messageId()); if (StringUtils.hasText(annotationMessageId)) { messageBuilder.messageId(annotationMessageId); } - String annotationName = resolver.resolveStringValue(asyncMessage.name()); + String annotationName = stringValueResolver.resolveStringValue(asyncMessage.name()); if (StringUtils.hasText(annotationName)) { messageBuilder.name(annotationName); } - String annotationTitle = resolver.resolveStringValue(asyncMessage.title()); + String annotationTitle = stringValueResolver.resolveStringValue(asyncMessage.title()); if (StringUtils.hasText(annotationTitle)) { messageBuilder.title(annotationTitle); } @@ -151,11 +153,13 @@ public static void processAsyncMessageAnnotation( * return a List of server names. * * @param op the given AsyncOperation - * @param resolver the StringValueResolver to resolve placeholders + * @param stringValueResolver the StringValueResolver to resolve placeholders * @return List of server names */ - public static List getServers(AsyncOperation op, StringValueResolver resolver) { - return Arrays.stream(op.servers()).map(resolver::resolveStringValue).toList(); + public static List getServers(AsyncOperation op, StringValueResolver stringValueResolver) { + return Arrays.stream(op.servers()) + .map(stringValueResolver::resolveStringValue) + .toList(); } public static Map processChannelBindingFromAnnotation( diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelService.java index 62abfd31d..4b58836a1 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelService.java @@ -29,17 +29,17 @@ public class AsyncAnnotationChannelService asyncAnnotationProvider; private final AsyncAnnotationOperationService asyncAnnotationOperationService; private final AsyncAnnotationMessageService asyncAnnotationMessageService; - private final StringValueResolver resolver; + private final StringValueResolver stringValueResolver; private final AsyncApiDocketService asyncApiDocketService; public ChannelObject buildChannel(MethodAndAnnotation methodAndAnnotation) { AsyncOperation operationAnnotation = this.asyncAnnotationProvider.getAsyncOperation(methodAndAnnotation.annotation()); - String channelName = resolver.resolveStringValue(operationAnnotation.channelName()); + String channelName = stringValueResolver.resolveStringValue(operationAnnotation.channelName()); String channelId = ReferenceUtil.toValidId(channelName); ChannelObject.ChannelObjectBuilder channelBuilder = ChannelObject.builder(); - List servers = AsyncAnnotationUtil.getServers(operationAnnotation, resolver); + List servers = AsyncAnnotationUtil.getServers(operationAnnotation, stringValueResolver); if (servers != null && !servers.isEmpty()) { Operation operation = asyncAnnotationOperationService.buildOperation( operationAnnotation, methodAndAnnotation.method(), channelId); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java index e349c40da..994441226 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageService.java @@ -31,12 +31,12 @@ public class AsyncAnnotationMessageService { private final PayloadAsyncOperationService payloadAsyncOperationService; private final ComponentsService componentsService; private final List messageBindingProcessors; - private final StringValueResolver resolver; + private final StringValueResolver stringValueResolver; public MessageObject buildMessage(AsyncOperation operationData, Method method) { PayloadSchemaObject payloadSchema = payloadAsyncOperationService.extractSchema(operationData, method); - SchemaObject headerSchema = AsyncAnnotationUtil.getAsyncHeaders(operationData, resolver); + SchemaObject headerSchema = AsyncAnnotationUtil.getAsyncHeaders(operationData, stringValueResolver); String headerSchemaName = this.componentsService.registerSchema(headerSchema); Map messageBinding = @@ -55,7 +55,7 @@ public MessageObject buildMessage(AsyncOperation operationData, Method method) { .bindings(messageBinding); // Retrieve the Message information obtained from the @AsyncMessage annotation. These values have higher // priority so if we find them, we need to override the default values. - AsyncAnnotationUtil.processAsyncMessageAnnotation(builder, operationData.message(), this.resolver); + AsyncAnnotationUtil.processAsyncMessageAnnotation(builder, operationData.message(), this.stringValueResolver); MessageObject message = builder.build(); this.componentsService.registerMessage(message); @@ -71,7 +71,7 @@ private String getDescription(AsyncOperation operationData, PayloadSchemaObject } } if (StringUtils.isNotBlank(description)) { - description = this.resolver.resolveStringValue(description); + description = this.stringValueResolver.resolveStringValue(description); description = TextUtils.trimIndent(description); } else { description = null; diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/AsyncAnnotationOperationService.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/AsyncAnnotationOperationService.java index 294575ee8..27f2d2d83 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/AsyncAnnotationOperationService.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/operation/AsyncAnnotationOperationService.java @@ -31,7 +31,7 @@ public class AsyncAnnotationOperationService asyncAnnotationProvider; private final List operationBindingProcessors; private final AsyncAnnotationMessageService asyncAnnotationMessageService; - private final StringValueResolver resolver; + private final StringValueResolver stringValueResolver; public Operation buildOperation(AsyncOperation asyncOperation, Method method, String channelId) { MessageObject message = asyncAnnotationMessageService.buildMessage(asyncOperation, method); @@ -52,7 +52,7 @@ public Operation buildOperation(AsyncOperation asyncOperation, Set metho private Operation buildOperation( AsyncOperation asyncOperation, Method method, String channelId, List messages) { - String description = this.resolver.resolveStringValue(asyncOperation.description()); + String description = this.stringValueResolver.resolveStringValue(asyncOperation.description()); if (StringUtils.isBlank(description)) { description = "Auto-generated description"; } else { diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/StringValueResolverProxy.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/StringValueResolverProxy.java index 83e8b1a8b..00cfd5335 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/StringValueResolverProxy.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/StringValueResolverProxy.java @@ -11,8 +11,8 @@ public class StringValueResolverProxy implements StringValueResolver, EmbeddedVa private StringValueResolver delegate; @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.delegate = resolver; + public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) { + this.delegate = stringValueResolver; } @Override diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScanner.java index 685922e55..8c6be6779 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationMethodLevelOperationsScanner.java @@ -8,11 +8,11 @@ import io.github.springwolf.core.asyncapi.scanners.common.annotation.AnnotationScannerUtil; import io.github.springwolf.core.asyncapi.scanners.common.annotation.MethodAndAnnotation; import io.github.springwolf.core.asyncapi.scanners.common.operation.AsyncAnnotationOperationService; -import io.github.springwolf.core.asyncapi.scanners.common.utils.StringValueResolverProxy; import io.github.springwolf.core.asyncapi.scanners.operations.OperationsInClassScanner; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.springframework.util.StringValueResolver; import java.lang.annotation.Annotation; import java.util.List; @@ -27,7 +27,7 @@ public class AsyncAnnotationMethodLevelOperationsScanner asyncAnnotationProvider; private final AsyncAnnotationOperationService asyncAnnotationOperationService; private final List customizers; - private final StringValueResolverProxy resolver; + private final StringValueResolver stringValueResolver; @Override public Stream> scan(Class clazz) { @@ -40,7 +40,7 @@ private Map.Entry mapMethodToOperation( AsyncOperation operationAnnotation = this.asyncAnnotationProvider.getAsyncOperation(methodAndAnnotation.annotation()); - String channelName = resolver.resolveStringValue(operationAnnotation.channelName()); + String channelName = stringValueResolver.resolveStringValue(operationAnnotation.channelName()); String channelId = ReferenceUtil.toValidId(channelName); // operationId should be part of the buildOperation method and part of Operation object String operationId = StringUtils.joinWith( diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java index 6fc86e50e..49bf64694 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfAutoConfiguration.java @@ -241,8 +241,8 @@ public AsyncAnnotationMessageService asyncAnnotationMessageService( ComponentsService componentsService, PayloadAsyncOperationService payloadAsyncOperationService, List messageBindingProcessors, - StringValueResolverProxy resolver) { + StringValueResolverProxy stringValueResolver) { return new AsyncAnnotationMessageService( - payloadAsyncOperationService, componentsService, messageBindingProcessors, resolver); + payloadAsyncOperationService, componentsService, messageBindingProcessors, stringValueResolver); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java index d2780779e..ebb24b04c 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/configuration/SpringwolfScannerConfiguration.java @@ -84,15 +84,18 @@ public ChannelsScanner asyncListenerMethodLevelAnnotationChannelScanner( AsyncApiDocketService asyncApiDocketService, AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, - StringValueResolverProxy resolver) { + StringValueResolverProxy stringValueResolver) { AsyncAnnotationOperationService asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( - asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + asyncAnnotationProvider, + operationBindingProcessors, + asyncAnnotationMessageService, + stringValueResolver); val asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( asyncAnnotationProvider, asyncAnnotationOperationService, asyncAnnotationMessageService, - resolver, + stringValueResolver, asyncApiDocketService); val strategy = new AsyncAnnotationMethodLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); @@ -112,15 +115,18 @@ public ChannelsScanner asyncListenerClassLevelAnnotationChannelScanner( AsyncApiDocketService asyncApiDocketService, AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, - StringValueResolverProxy resolver) { + StringValueResolverProxy stringValueResolver) { AsyncAnnotationOperationService asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( - asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + asyncAnnotationProvider, + operationBindingProcessors, + asyncAnnotationMessageService, + stringValueResolver); val asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( asyncAnnotationProvider, asyncAnnotationOperationService, asyncAnnotationMessageService, - resolver, + stringValueResolver, asyncApiDocketService); val strategy = new AsyncAnnotationClassLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); @@ -140,11 +146,14 @@ public OperationsScanner asyncListenerMethodLevelAnnotationOperationScanner( AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, List operationCustomizers, - StringValueResolverProxy resolver) { + StringValueResolverProxy stringValueResolver) { val asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( - asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + asyncAnnotationProvider, + operationBindingProcessors, + asyncAnnotationMessageService, + stringValueResolver); val strategy = new AsyncAnnotationMethodLevelOperationsScanner<>( - asyncAnnotationProvider, asyncAnnotationOperationService, operationCustomizers, resolver); + asyncAnnotationProvider, asyncAnnotationOperationService, operationCustomizers, stringValueResolver); return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } @@ -160,10 +169,13 @@ public OperationsScanner asyncListenerClassLevelListenerAnnotationOperationsScan SpringwolfClassScanner springwolfClassScanner, AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, - StringValueResolverProxy resolver, + StringValueResolverProxy stringValueResolver, List operationCustomizers) { val asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( - asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + asyncAnnotationProvider, + operationBindingProcessors, + asyncAnnotationMessageService, + stringValueResolver); AsyncAnnotationClassLevelOperationsScanner strategy = new AsyncAnnotationClassLevelOperationsScanner<>( AsyncListener.class, @@ -186,15 +198,18 @@ public ChannelsScanner asyncPublisherClassLevelChannelAnnotationScanner( AsyncApiDocketService asyncApiDocketService, AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, - StringValueResolverProxy resolver) { + StringValueResolverProxy stringValueResolver) { AsyncAnnotationOperationService asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( - asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + asyncAnnotationProvider, + operationBindingProcessors, + asyncAnnotationMessageService, + stringValueResolver); val asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( asyncAnnotationProvider, asyncAnnotationOperationService, asyncAnnotationMessageService, - resolver, + stringValueResolver, asyncApiDocketService); val strategy = new AsyncAnnotationMethodLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); @@ -214,15 +229,18 @@ public ChannelsScanner asyncPublisherClassLevelAnnotationChannelScanner( AsyncApiDocketService asyncApiDocketService, AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, - StringValueResolverProxy resolver) { + StringValueResolverProxy stringValueResolver) { AsyncAnnotationOperationService asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( - asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + asyncAnnotationProvider, + operationBindingProcessors, + asyncAnnotationMessageService, + stringValueResolver); val asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( asyncAnnotationProvider, asyncAnnotationOperationService, asyncAnnotationMessageService, - resolver, + stringValueResolver, asyncApiDocketService); val strategy = new AsyncAnnotationClassLevelChannelsScanner<>(asyncAnnotationProvider, asyncAnnotationChannelService); @@ -242,12 +260,15 @@ public OperationsScanner asyncPublisherClassLevelOperationAnnotationScanner( AsyncAnnotationMessageService asyncAnnotationMessageService, List operationBindingProcessors, List customizers, - StringValueResolverProxy resolver) { + StringValueResolverProxy stringValueResolver) { val asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( - asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + asyncAnnotationProvider, + operationBindingProcessors, + asyncAnnotationMessageService, + stringValueResolver); val strategy = new AsyncAnnotationMethodLevelOperationsScanner<>( - asyncAnnotationProvider, asyncAnnotationOperationService, customizers, resolver); + asyncAnnotationProvider, asyncAnnotationOperationService, customizers, stringValueResolver); return new OperationsInClassScannerAdapter(springwolfClassScanner, strategy); } @@ -263,10 +284,13 @@ public OperationsScanner asyncPublisherClassLevelListenerAnnotationOperationsSca SpringwolfClassScanner springwolfClassScanner, List operationBindingProcessors, AsyncAnnotationMessageService asyncAnnotationMessageService, - StringValueResolverProxy resolver, + StringValueResolverProxy stringValueResolver, List operationCustomizers) { val asyncAnnotationOperationService = new AsyncAnnotationOperationService<>( - asyncAnnotationProvider, operationBindingProcessors, asyncAnnotationMessageService, resolver); + asyncAnnotationProvider, + operationBindingProcessors, + asyncAnnotationMessageService, + stringValueResolver); AsyncAnnotationClassLevelOperationsScanner strategy = new AsyncAnnotationClassLevelOperationsScanner<>( AsyncPublisher.class, diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/bindings/processor/TestAbstractOperationBindingProcessor.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/bindings/processor/TestAbstractOperationBindingProcessor.java index b6fc03142..c2f041182 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/bindings/processor/TestAbstractOperationBindingProcessor.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/bindings/processor/TestAbstractOperationBindingProcessor.java @@ -7,6 +7,7 @@ import io.github.springwolf.core.asyncapi.scanners.bindings.operations.AbstractOperationBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; import org.springframework.core.annotation.Order; +import org.springframework.util.StringValueResolver; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -21,6 +22,10 @@ public class TestAbstractOperationBindingProcessor public static final String TYPE = "testType"; public static final OperationBinding BINDING = new AbstractOperationBindingBinding(); + public TestAbstractOperationBindingProcessor(StringValueResolver stringValueResolver) { + super(stringValueResolver); + } + @Override protected ProcessedOperationBinding mapToOperationBinding(TestOperationBinding bindingAnnotation) { return new ProcessedOperationBinding(TYPE, BINDING); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtilTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtilTest.java index 0658c001f..97b04a54f 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtilTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/annotation/AsyncAnnotationUtilTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.when; class AsyncAnnotationUtilTest { + StringValueResolver stringValueResolver = mock(StringValueResolver.class); @ParameterizedTest @ValueSource(classes = {ClassWithOperationBindingProcessor.class, ClassWithAbstractOperationBindingProcessor.class}) @@ -43,12 +44,11 @@ void getAsyncHeaders(Class classWithOperationBindingProcessor) throws NoSuchM Method m = classWithOperationBindingProcessor.getDeclaredMethod("methodWithAnnotation", String.class); AsyncOperation operation = m.getAnnotation(AsyncListener.class).operation(); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue(any())) + when(stringValueResolver.resolveStringValue(any())) .thenAnswer(invocation -> invocation.getArgument(0).toString() + "Resolved"); // when - SchemaObject headers = AsyncAnnotationUtil.getAsyncHeaders(operation, resolver); + SchemaObject headers = AsyncAnnotationUtil.getAsyncHeaders(operation, stringValueResolver); // then assertEquals("TestSchema", headers.getTitle()); @@ -78,12 +78,12 @@ void getAsyncHeadersWithEmptyHeaders() throws NoSuchMethodException { Method m = ClassWithHeaders.class.getDeclaredMethod("emptyHeaders", String.class); AsyncOperation operation = m.getAnnotation(AsyncListener.class).operation(); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue(any())) + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue(any())) .thenAnswer(invocation -> invocation.getArgument(0).toString() + "Resolved"); // when - SchemaObject headers = AsyncAnnotationUtil.getAsyncHeaders(operation, resolver); + SchemaObject headers = AsyncAnnotationUtil.getAsyncHeaders(operation, stringValueResolver); // then assertThat(headers).isEqualTo(AsyncHeadersNotDocumented.NOT_DOCUMENTED); @@ -95,12 +95,12 @@ void getAsyncHeadersWithoutSchemaName() throws NoSuchMethodException { Method m = ClassWithHeaders.class.getDeclaredMethod("withoutSchemaName", String.class); AsyncOperation operation = m.getAnnotation(AsyncListener.class).operation(); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue(any())) + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue(any())) .thenAnswer(invocation -> invocation.getArgument(0).toString() + "Resolved"); // when - SchemaObject headers = AsyncAnnotationUtil.getAsyncHeaders(operation, resolver); + SchemaObject headers = AsyncAnnotationUtil.getAsyncHeaders(operation, stringValueResolver); // then assertThat(headers) @@ -128,13 +128,13 @@ void generatedHeaderSchemaNameShouldBeUnique() throws NoSuchMethodException { Method m2 = ClassWithHeaders.class.getDeclaredMethod("differentHeadersWithoutSchemaName", String.class); AsyncOperation operation2 = m2.getAnnotation(AsyncListener.class).operation(); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue(any())) + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue(any())) .thenAnswer(invocation -> invocation.getArgument(0).toString() + "Resolved"); // when - SchemaObject headers1 = AsyncAnnotationUtil.getAsyncHeaders(operation1, resolver); - SchemaObject headers2 = AsyncAnnotationUtil.getAsyncHeaders(operation2, resolver); + SchemaObject headers1 = AsyncAnnotationUtil.getAsyncHeaders(operation1, stringValueResolver); + SchemaObject headers2 = AsyncAnnotationUtil.getAsyncHeaders(operation2, stringValueResolver); // then assertThat(headers1.getTitle()).isNotEqualTo(headers2.getTitle()); @@ -162,7 +162,10 @@ void processMultipleOperationBindingFromAnnotation() throws NoSuchMethodExceptio // when Map bindings = AsyncAnnotationUtil.processOperationBindingFromAnnotation( - m, List.of(new TestOperationBindingProcessor(), new TestAbstractOperationBindingProcessor())); + m, + List.of( + new TestOperationBindingProcessor(), + new TestAbstractOperationBindingProcessor(stringValueResolver))); // then assertEquals( @@ -256,12 +259,12 @@ void getServers() throws NoSuchMethodException { Method m = ClassWithOperationBindingProcessor.class.getDeclaredMethod("methodWithAnnotation", String.class); AsyncOperation operation = m.getAnnotation(AsyncListener.class).operation(); - StringValueResolver resolver = mock(StringValueResolver.class); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); // when - when(resolver.resolveStringValue("${test.property.server1}")).thenReturn("server1"); + when(stringValueResolver.resolveStringValue("${test.property.server1}")).thenReturn("server1"); - List servers = AsyncAnnotationUtil.getServers(operation, resolver); + List servers = AsyncAnnotationUtil.getServers(operation, stringValueResolver); assertEquals(List.of("server1"), servers); } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelServiceTest.java index 48156b9f0..88f9d7a12 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelServiceTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/channel/AsyncAnnotationChannelServiceTest.java @@ -58,19 +58,21 @@ public OperationAction getOperationType() { mock(AsyncAnnotationMessageService.class); private final AsyncAnnotationOperationService asyncAnnotationOperationService = mock(AsyncAnnotationOperationService.class); - private final StringValueResolver resolver = mock(StringValueResolver.class); + private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); private final AsyncApiDocketService asyncApiDocketService = mock(AsyncApiDocketService.class); AsyncAnnotationChannelService asyncAnnotationChannelService = new AsyncAnnotationChannelService<>( asyncAnnotationProvider, asyncAnnotationOperationService, asyncAnnotationMessageService, - resolver, + stringValueResolver, asyncApiDocketService); @BeforeEach void setUp() { - doAnswer(invocation -> invocation.getArgument(0)).when(resolver).resolveStringValue(any()); + doAnswer(invocation -> invocation.getArgument(0)) + .when(stringValueResolver) + .resolveStringValue(any()); } @Test diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageServiceTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageServiceTest.java index da83ee902..ad4a266dc 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageServiceTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/message/AsyncAnnotationMessageServiceTest.java @@ -36,15 +36,17 @@ class AsyncAnnotationMessageServiceTest { private final PayloadAsyncOperationService payloadAsyncOperationService = mock(PayloadAsyncOperationService.class); private final ComponentsService componentsService = mock(ComponentsService.class); private final MessageBindingProcessor messageBindingProcessor = mock(MessageBindingProcessor.class); - private final StringValueResolver resolver = mock(StringValueResolver.class); + private final StringValueResolver stringValueResolver = mock(StringValueResolver.class); AsyncAnnotationMessageService asyncAnnotationMessageService = new AsyncAnnotationMessageService( - payloadAsyncOperationService, componentsService, List.of(messageBindingProcessor), resolver); + payloadAsyncOperationService, componentsService, List.of(messageBindingProcessor), stringValueResolver); private final PayloadSchemaObject payloadSchema = new PayloadSchemaObject("full.name", "name", null); @BeforeEach void setUp() { - doAnswer(invocation -> invocation.getArgument(0)).when(resolver).resolveStringValue(any()); + doAnswer(invocation -> invocation.getArgument(0)) + .when(stringValueResolver) + .resolveStringValue(any()); when(componentsService.registerSchema(any())).thenReturn("headerSchemaName"); when(messageBindingProcessor.process(any())).thenReturn(Optional.empty()); 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 3603516be..d574635c5 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json @@ -581,6 +581,7 @@ "priority": 0, "deliveryMode": 1, "mandatory": false, + "bcc": [ ], "timestamp": false, "ack": false, "bindingVersion": "0.3.0" @@ -676,4 +677,4 @@ ] } } -} +} \ No newline at end of file diff --git a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml index a097dbdd7..f5f17d59a 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.yaml @@ -400,6 +400,7 @@ operations: priority: 0 deliveryMode: 1 mandatory: false + bcc: [] timestamp: false ack: false bindingVersion: 0.3.0 diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/AmqpBindingFactory.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/AmqpBindingFactory.java index 572de75a5..d06f3d691 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/AmqpBindingFactory.java +++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/AmqpBindingFactory.java @@ -10,18 +10,22 @@ import org.springframework.amqp.core.Exchange; import org.springframework.amqp.core.Queue; import org.springframework.amqp.rabbit.annotation.RabbitListener; -import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.util.StringValueResolver; import java.util.List; import java.util.Map; -public class AmqpBindingFactory implements BindingFactory, EmbeddedValueResolverAware { +public class AmqpBindingFactory implements BindingFactory { private final RabbitListenerUtil.RabbitListenerUtilContext context; - private StringValueResolver stringValueResolver; + private final StringValueResolver stringValueResolver; - public AmqpBindingFactory(List queues, List exchanges, List bindings) { + public AmqpBindingFactory( + List queues, + List exchanges, + List bindings, + StringValueResolver stringValueResolver) { this.context = RabbitListenerUtil.RabbitListenerUtilContext.create(queues, exchanges, bindings); + this.stringValueResolver = stringValueResolver; } @Override @@ -43,9 +47,4 @@ public Map buildOperationBinding(RabbitListener annota public Map buildMessageBinding(RabbitListener annotation, SchemaObject headerSchema) { return RabbitListenerUtil.buildMessageBinding(); } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.stringValueResolver = resolver; - } } diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtil.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtil.java index e5d925482..0a8ef6bca 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtil.java +++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtil.java @@ -41,14 +41,14 @@ public class RabbitListenerUtil { private static final Boolean DEFAULT_EXCLUSIVE = false; private static final String DEFAULT_EXCHANGE_TYPE = ExchangeTypes.DIRECT; - public static String getChannelName(RabbitListener annotation, StringValueResolver resolver) { + public static String getChannelName(RabbitListener annotation, StringValueResolver stringValueResolver) { Stream annotationBindingChannelNames = Arrays.stream(annotation.bindings()) .flatMap(binding -> Stream.concat( Stream.of(binding.key()), // if routing key is configured, prefer it Stream.of(binding.value().name()))); return Stream.concat(streamQueueNames(annotation), annotationBindingChannelNames) - .map(resolver::resolveStringValue) + .map(stringValueResolver::resolveStringValue) .filter(Objects::nonNull) .peek(queue -> log.debug("Resolved channel name: {}", queue)) .findFirst() @@ -57,12 +57,12 @@ public static String getChannelName(RabbitListener annotation, StringValueResolv "No channel name was found in @RabbitListener annotation (neither in queues nor bindings property)")); } - public static String getQueueName(RabbitListener annotation, StringValueResolver resolver) { + public static String getQueueName(RabbitListener annotation, StringValueResolver stringValueResolver) { Stream annotationBindingChannelNames = Arrays.stream(annotation.bindings()) .flatMap(binding -> Stream.of(binding.value().name())); return Stream.concat(streamQueueNames(annotation), annotationBindingChannelNames) - .map(resolver::resolveStringValue) + .map(stringValueResolver::resolveStringValue) .filter(Objects::nonNull) .peek(queue -> log.debug("Resolved queue name: {}", queue)) .findFirst() @@ -89,13 +89,13 @@ private static Stream streamQueueNames(RabbitListener rabbitListenerAnno } public static Map buildChannelBinding( - RabbitListener annotation, StringValueResolver resolver, RabbitListenerUtilContext context) { + RabbitListener annotation, StringValueResolver stringValueResolver, RabbitListenerUtilContext context) { AMQPChannelBinding.AMQPChannelBindingBuilder channelBinding = AMQPChannelBinding.builder(); - String exchangeName = getExchangeName(annotation, resolver, context); + String exchangeName = getExchangeName(annotation, stringValueResolver, context); if (exchangeName.isEmpty()) { channelBinding.is(AMQPChannelType.QUEUE); - channelBinding.queue(buildQueueProperties(annotation, resolver, context)); + channelBinding.queue(buildQueueProperties(annotation, stringValueResolver, context)); } else { channelBinding.is(AMQPChannelType.ROUTING_KEY); channelBinding.exchange(buildExchangeProperties(annotation, exchangeName, context)); @@ -139,8 +139,8 @@ private static AMQPChannelExchangeProperties buildExchangeProperties( } private static AMQPChannelQueueProperties buildQueueProperties( - RabbitListener annotation, StringValueResolver resolver, RabbitListenerUtilContext context) { - String queueName = getQueueName(annotation, resolver); + RabbitListener annotation, StringValueResolver stringValueResolver, RabbitListenerUtilContext context) { + String queueName = getQueueName(annotation, stringValueResolver); org.springframework.amqp.core.Queue queue = context.queueMap.get(queueName); boolean autoDelete = queue != null ? queue.isAutoDelete() : DEFAULT_AUTO_DELETE; boolean durable = queue != null ? queue.isDurable() : DEFAULT_DURABLE; @@ -151,7 +151,7 @@ private static AMQPChannelQueueProperties buildQueueProperties( if (queueOpt.isPresent()) { Queue queueAnnotation = queueOpt.get(); return AMQPChannelQueueProperties.builder() - .name(resolver.resolveStringValue(queueAnnotation.name())) + .name(stringValueResolver.resolveStringValue(queueAnnotation.name())) .autoDelete(parse(queueAnnotation.autoDelete(), autoDelete)) .durable(parse(queueAnnotation.durable(), durable)) .exclusive(parse(queueAnnotation.exclusive(), exclusive)) @@ -192,14 +192,14 @@ private static Boolean parse(String value, Boolean defaultIfEmpty) { } private static String getExchangeName( - RabbitListener annotation, StringValueResolver resolver, RabbitListenerUtilContext context) { + RabbitListener annotation, StringValueResolver stringValueResolver, RabbitListenerUtilContext context) { String exchangeName = Stream.of(annotation.bindings()) .map(binding -> binding.exchange().name()) .filter(StringUtils::hasText) .findFirst() .orElse(null); - Binding binding = context.bindingMap.get(getChannelName(annotation, resolver)); + Binding binding = context.bindingMap.get(getChannelName(annotation, stringValueResolver)); if (exchangeName == null && binding != null) { exchangeName = binding.getExchange(); } @@ -213,16 +213,16 @@ private static String getExchangeName( } public static Map buildOperationBinding( - RabbitListener annotation, StringValueResolver resolver, RabbitListenerUtilContext context) { + RabbitListener annotation, StringValueResolver stringValueResolver, RabbitListenerUtilContext context) { return Map.of( BINDING_NAME, AMQPOperationBinding.builder() - .cc(getRoutingKeys(annotation, resolver, context)) + .cc(getRoutingKeys(annotation, stringValueResolver, context)) .build()); } private static List getRoutingKeys( - RabbitListener annotation, StringValueResolver resolver, RabbitListenerUtilContext context) { + RabbitListener annotation, StringValueResolver stringValueResolver, RabbitListenerUtilContext context) { List routingKeys = Stream.of(annotation.bindings()) .map(binding -> { if (binding.key().length == 0) { @@ -232,22 +232,22 @@ private static List getRoutingKeys( } return Arrays.stream(binding.key()) - .map(resolver::resolveStringValue) + .map(stringValueResolver::resolveStringValue) .toList(); }) .findFirst() .orElse(null); - Binding binding = context.bindingMap.get(getChannelName(annotation, resolver)); + Binding binding = context.bindingMap.get(getChannelName(annotation, stringValueResolver)); if (routingKeys == null && binding != null) { routingKeys = Collections.singletonList(binding.getRoutingKey()); } // when there is no binding for the queue present at all, it uses the fact that // RabbitMQ automatically binds default exchange to a queue with queue's name as a routing key. - String exchangeName = getExchangeName(annotation, resolver, context); + String exchangeName = getExchangeName(annotation, stringValueResolver, context); if (routingKeys == null && exchangeName.isEmpty()) { - routingKeys = Collections.singletonList(getQueueName(annotation, resolver)); + routingKeys = Collections.singletonList(getQueueName(annotation, stringValueResolver)); } return routingKeys; diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java index 0aa1162b3..d4e3a8311 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java +++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpScannerConfiguration.java @@ -33,6 +33,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; +import org.springframework.util.StringValueResolver; import java.util.List; @@ -49,8 +50,12 @@ public class SpringwolfAmqpScannerConfiguration { name = SPRINGWOLF_SCANNER_RABBIT_LISTENER_ENABLED, havingValue = "true", matchIfMissing = true) - public AmqpBindingFactory amqpBindingFactory(List queues, List exchanges, List bindings) { - return new AmqpBindingFactory(queues, exchanges, bindings); + public AmqpBindingFactory amqpBindingFactory( + List queues, + List exchanges, + List bindings, + StringValueResolver stringValueResolver) { + return new AmqpBindingFactory(queues, exchanges, bindings, stringValueResolver); } @Bean diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtilTest.java b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtilTest.java index a8bd9717d..e21b7150d 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtilTest.java +++ b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/asyncapi/scanners/bindings/RabbitListenerUtilTest.java @@ -47,11 +47,11 @@ class QueuesConfiguration { void getChannelName(Class clazz) { // given RabbitListener annotation = getAnnotation(clazz); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); // when - String channelName = RabbitListenerUtil.getChannelName(annotation, resolver); + String channelName = RabbitListenerUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("queue-1", channelName); @@ -62,12 +62,12 @@ void getChannelName(Class clazz) { void buildChannelBinding(Class clazz) { // given RabbitListener annotation = getAnnotation(clazz); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); // when Map channelBinding = - RabbitListenerUtil.buildChannelBinding(annotation, resolver, emptyContext); + RabbitListenerUtil.buildChannelBinding(annotation, stringValueResolver, emptyContext); // then assertEquals(1, channelBinding.size()); @@ -91,12 +91,12 @@ void buildChannelBinding(Class clazz) { void buildOperationBinding(Class clazz) { // given RabbitListener annotation = getAnnotation(clazz); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); // when Map operationBinding = - RabbitListenerUtil.buildOperationBinding(annotation, resolver, emptyContext); + RabbitListenerUtil.buildOperationBinding(annotation, stringValueResolver, emptyContext); // then assertEquals(1, operationBinding.size()); @@ -137,11 +137,11 @@ class QueueBindingsConfiguration { void getChannelName() { // given RabbitListener annotation = getAnnotation(ClassWithBindingsConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); // when - String channelName = RabbitListenerUtil.getChannelName(annotation, resolver); + String channelName = RabbitListenerUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("queue-1", channelName); @@ -151,12 +151,12 @@ void getChannelName() { void buildChannelBinding() { // given RabbitListener annotation = getAnnotation(ClassWithBindingsConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); // when Map channelBinding = - RabbitListenerUtil.buildChannelBinding(annotation, resolver, emptyContext); + RabbitListenerUtil.buildChannelBinding(annotation, stringValueResolver, emptyContext); // then assertEquals(1, channelBinding.size()); @@ -178,12 +178,12 @@ void buildChannelBinding() { void buildOperationBinding() { // given RabbitListener annotation = getAnnotation(ClassWithBindingsConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); // when Map operationBinding = - RabbitListenerUtil.buildOperationBinding(annotation, resolver, emptyContext); + RabbitListenerUtil.buildOperationBinding(annotation, stringValueResolver, emptyContext); // then assertEquals(1, operationBinding.size()); @@ -220,11 +220,11 @@ class QueueBindingWithRoutingKeyConfiguration { void getChannelName() { // given RabbitListener annotation = getAnnotation(ClassWithBindingsAndRoutingKeyConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); // when - String channelName = RabbitListenerUtil.getChannelName(annotation, resolver); + String channelName = RabbitListenerUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("routing-key", channelName); @@ -234,12 +234,12 @@ void getChannelName() { void buildChannelBinding() { // given RabbitListener annotation = getAnnotation(ClassWithBindingsAndRoutingKeyConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); // when Map channelBinding = - RabbitListenerUtil.buildChannelBinding(annotation, resolver, emptyContext); + RabbitListenerUtil.buildChannelBinding(annotation, stringValueResolver, emptyContext); // then assertEquals(1, channelBinding.size()); @@ -261,12 +261,12 @@ void buildChannelBinding() { void buildOperationBinding() { // given RabbitListener annotation = getAnnotation(ClassWithBindingsAndRoutingKeyConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); // when Map operationBinding = - RabbitListenerUtil.buildOperationBinding(annotation, resolver, emptyContext); + RabbitListenerUtil.buildOperationBinding(annotation, stringValueResolver, emptyContext); // then assertEquals(1, operationBinding.size()); @@ -318,12 +318,12 @@ class QueueBindingsWithBeansConfiguration { void getChannelName() { // given RabbitListener annotation = getAnnotation(ClassWithBindingsConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); - when(resolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + when(stringValueResolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); // when - String channelName = RabbitListenerUtil.getChannelName(annotation, resolver); + String channelName = RabbitListenerUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("routing-key", channelName); @@ -333,13 +333,13 @@ void getChannelName() { void buildChannelBinding() { // given RabbitListener annotation = getAnnotation(ClassWithBindingsConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); - when(resolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + when(stringValueResolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); // when Map channelBinding = - RabbitListenerUtil.buildChannelBinding(annotation, resolver, context); + RabbitListenerUtil.buildChannelBinding(annotation, stringValueResolver, context); // then assertEquals(1, channelBinding.size()); @@ -361,13 +361,13 @@ void buildChannelBinding() { void buildOperationBinding() { // given RabbitListener annotation = getAnnotation(ClassWithBindingsConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); - when(resolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + when(stringValueResolver.resolveStringValue("${routing-key}")).thenReturn("routing-key"); // when Map operationBinding = - RabbitListenerUtil.buildOperationBinding(annotation, resolver, context); + RabbitListenerUtil.buildOperationBinding(annotation, stringValueResolver, context); // then assertEquals(1, operationBinding.size()); diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpProducerConfigurationIntegrationTest.java b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpProducerConfigurationIntegrationTest.java index 1f99dc1bf..9b55d0d57 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpProducerConfigurationIntegrationTest.java +++ b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/springwolf/plugins/amqp/configuration/SpringwolfAmqpProducerConfigurationIntegrationTest.java @@ -21,6 +21,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.util.StringValueResolver; import java.util.Optional; @@ -54,7 +55,8 @@ public class SpringwolfAmqpProducerConfigurationIntegrationTest { @MockBean(PayloadAsyncOperationService.class), @MockBean(PayloadMethodParameterService.class), @MockBean(HeaderClassExtractor.class), - @MockBean(AsyncApiDocketService.class) + @MockBean(AsyncApiDocketService.class), + @MockBean(StringValueResolver.class), }) @Nested class AmqpProducerWillBeCreatedIfEnabledTest { @@ -97,6 +99,7 @@ void springwolfAmqpProducerShouldBePresentInSpringContext() { @MockBean(PayloadAsyncOperationService.class), @MockBean(PayloadMethodParameterService.class), @MockBean(HeaderClassExtractor.class), + @MockBean(StringValueResolver.class), }) @Nested class AmqpProducerWillNotBeCreatedIfDisabledTest { diff --git a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsBindingFactory.java b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsBindingFactory.java index de3b338a1..8713ebeba 100644 --- a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsBindingFactory.java +++ b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsBindingFactory.java @@ -6,16 +6,15 @@ import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import lombok.NoArgsConstructor; -import org.springframework.context.EmbeddedValueResolverAware; +import lombok.RequiredArgsConstructor; import org.springframework.jms.annotation.JmsListener; import org.springframework.util.StringValueResolver; import java.util.Map; -@NoArgsConstructor -public class JmsBindingFactory implements BindingFactory, EmbeddedValueResolverAware { - private StringValueResolver stringValueResolver; +@RequiredArgsConstructor +public class JmsBindingFactory implements BindingFactory { + private final StringValueResolver stringValueResolver; @Override public String getChannelName(JmsListener annotation) { @@ -36,9 +35,4 @@ public Map buildOperationBinding(JmsListener annotatio public Map buildMessageBinding(JmsListener annotation, SchemaObject headerSchema) { return JmsListenerUtil.buildMessageBinding(); } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.stringValueResolver = resolver; - } } diff --git a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsListenerUtil.java b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsListenerUtil.java index 8ffdf69f4..ee8528055 100644 --- a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsListenerUtil.java +++ b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsListenerUtil.java @@ -16,17 +16,17 @@ @Slf4j public class JmsListenerUtil { - public static String getChannelName(JmsListener annotation, StringValueResolver resolver) { - return resolver.resolveStringValue(annotation.destination()); + public static String getChannelName(JmsListener annotation, StringValueResolver stringValueResolver) { + return stringValueResolver.resolveStringValue(annotation.destination()); } public static Map buildChannelBinding( - JmsListener annotation, StringValueResolver resolver) { + JmsListener annotation, StringValueResolver stringValueResolver) { return Map.of("jms", new JMSChannelBinding()); } public static Map buildOperationBinding( - JmsListener annotation, StringValueResolver resolver) { + JmsListener annotation, StringValueResolver stringValueResolver) { return Map.of("jms", new JMSOperationBinding()); } diff --git a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsScannerConfiguration.java b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsScannerConfiguration.java index 53588e70b..80258565a 100644 --- a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsScannerConfiguration.java +++ b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsScannerConfiguration.java @@ -24,6 +24,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.jms.annotation.JmsListener; +import org.springframework.util.StringValueResolver; import java.util.List; @@ -37,8 +38,8 @@ public class SpringwolfJmsScannerConfiguration { @Bean @ConditionalOnProperty(name = SPRINGWOLF_SCANNER_JMS_LISTENER_ENABLED, havingValue = "true", matchIfMissing = true) - public JmsBindingFactory jmsBindingFactory() { - return new JmsBindingFactory(); + public JmsBindingFactory jmsBindingFactory(StringValueResolver stringValueResolver) { + return new JmsBindingFactory(stringValueResolver); } @Bean diff --git a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsListenerUtilTest.java b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsListenerUtilTest.java index ebd850ddd..9ef29a6eb 100644 --- a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsListenerUtilTest.java +++ b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/asyncapi/scanners/bindings/JmsListenerUtilTest.java @@ -28,11 +28,11 @@ class FullConfiguration { void getChannelName() { // given JmsListener annotation = getAnnotation(ClassWithFullJmsListenerConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); // when - String channelName = JmsListenerUtil.getChannelName(annotation, resolver); + String channelName = JmsListenerUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("queue-1", channelName); @@ -42,10 +42,11 @@ void getChannelName() { void buildChannelBinding() { // given JmsListener annotation = getAnnotation(ClassWithFullJmsListenerConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); // when - Map channelBinding = JmsListenerUtil.buildChannelBinding(annotation, resolver); + Map channelBinding = + JmsListenerUtil.buildChannelBinding(annotation, stringValueResolver); // then assertEquals(1, channelBinding.size()); @@ -57,11 +58,11 @@ void buildChannelBinding() { void buildOperationBinding() { // given JmsListener annotation = getAnnotation(ClassWithFullJmsListenerConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); // when Map operationBinding = - JmsListenerUtil.buildOperationBinding(annotation, resolver); + JmsListenerUtil.buildOperationBinding(annotation, stringValueResolver); // then assertEquals(1, operationBinding.size()); diff --git a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsProducerConfigurationIntegrationTest.java b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsProducerConfigurationIntegrationTest.java index 50f97875c..3e11ab846 100644 --- a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsProducerConfigurationIntegrationTest.java +++ b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/springwolf/plugins/jms/configuration/SpringwolfJmsProducerConfigurationIntegrationTest.java @@ -18,6 +18,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.util.StringValueResolver; import java.util.Optional; @@ -48,7 +49,8 @@ public class SpringwolfJmsProducerConfigurationIntegrationTest { @MockBean(ComponentsService.class), @MockBean(PayloadMethodParameterService.class), @MockBean(HeaderClassExtractor.class), - @MockBean(JmsTemplate.class) + @MockBean(JmsTemplate.class), + @MockBean(StringValueResolver.class), }) @Nested class JmsProducerWillBeCreatedIfEnabledTest { @@ -88,7 +90,8 @@ void springwolfJmsProducerShouldBePresentInSpringContext() { @MockBean(ComponentsService.class), @MockBean(PayloadMethodParameterService.class), @MockBean(HeaderClassExtractor.class), - @MockBean(JmsTemplate.class) + @MockBean(JmsTemplate.class), + @MockBean(StringValueResolver.class), }) @Nested class JmsProducerWillNotBeCreatedIfDisabledTest { diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/bindings/KafkaBindingFactory.java b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/bindings/KafkaBindingFactory.java index 9b82b47c1..73d13b28e 100644 --- a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/bindings/KafkaBindingFactory.java +++ b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/bindings/KafkaBindingFactory.java @@ -7,16 +7,15 @@ import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; import io.github.springwolf.plugins.kafka.asyncapi.scanners.common.KafkaListenerUtil; -import lombok.NoArgsConstructor; -import org.springframework.context.EmbeddedValueResolverAware; +import lombok.RequiredArgsConstructor; import org.springframework.kafka.annotation.KafkaListener; import org.springframework.util.StringValueResolver; import java.util.Map; -@NoArgsConstructor -public class KafkaBindingFactory implements BindingFactory, EmbeddedValueResolverAware { - private StringValueResolver stringValueResolver; +@RequiredArgsConstructor +public class KafkaBindingFactory implements BindingFactory { + private final StringValueResolver stringValueResolver; @Override public String getChannelName(KafkaListener annotation) { @@ -37,9 +36,4 @@ public Map buildOperationBinding(KafkaListener annotat public Map buildMessageBinding(KafkaListener annotation, SchemaObject headerSchema) { return KafkaListenerUtil.buildMessageBinding(headerSchema); } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.stringValueResolver = resolver; - } } diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/common/KafkaListenerUtil.java b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/common/KafkaListenerUtil.java index a4da6bf25..95adf0059 100644 --- a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/common/KafkaListenerUtil.java +++ b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/common/KafkaListenerUtil.java @@ -26,12 +26,12 @@ @Slf4j public class KafkaListenerUtil { - public static String getChannelName(KafkaListener annotation, StringValueResolver resolver) { + public static String getChannelName(KafkaListener annotation, StringValueResolver stringValueResolver) { Stream topicName = Stream.concat( // the parameters topics and topicPattern are mutually exclusive Arrays.stream(annotation.topics()), Stream.of(annotation.topicPattern())); List resolvedTopics = - topicName.map(resolver::resolveStringValue).collect(toList()); + topicName.map(stringValueResolver::resolveStringValue).collect(toList()); log.debug("Found topics: {}", String.join(", ", resolvedTopics)); return resolvedTopics.get(0); @@ -42,8 +42,8 @@ public static Map buildChannelBinding() { } public static Map buildOperationBinding( - KafkaListener annotation, StringValueResolver resolver) { - String groupId = resolver.resolveStringValue(annotation.groupId()); + KafkaListener annotation, StringValueResolver stringValueResolver) { + String groupId = stringValueResolver.resolveStringValue(annotation.groupId()); Schema groupIdSchema = buildKafkaGroupIdSchema(groupId); KafkaOperationBinding binding = new KafkaOperationBinding(); diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaScannerConfiguration.java b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaScannerConfiguration.java index f0a093eba..0e1bf5867 100644 --- a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaScannerConfiguration.java +++ b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaScannerConfiguration.java @@ -29,6 +29,7 @@ import org.springframework.core.annotation.Order; import org.springframework.kafka.annotation.KafkaHandler; import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.util.StringValueResolver; import java.util.List; @@ -45,8 +46,8 @@ public class SpringwolfKafkaScannerConfiguration { name = SPRINGWOLF_SCANNER_KAFKA_LISTENER_ENABLED, havingValue = "true", matchIfMissing = true) - public KafkaBindingFactory kafkaBindingFactory() { - return new KafkaBindingFactory(); + public KafkaBindingFactory kafkaBindingFactory(StringValueResolver stringValueResolver) { + return new KafkaBindingFactory(stringValueResolver); } @Bean diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/common/KafkaListenerUtilTest.java b/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/common/KafkaListenerUtilTest.java index 329bfffa9..9f884ccc7 100644 --- a/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/common/KafkaListenerUtilTest.java +++ b/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/asyncapi/scanners/common/KafkaListenerUtilTest.java @@ -33,12 +33,12 @@ void fromTopics() { KafkaListener annotation = mock(KafkaListener.class); when(annotation.topics()).thenReturn(Arrays.array("${topic-1}", "${topic-2}")); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); - when(resolver.resolveStringValue("${topic-2}")).thenReturn("topic-2"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); + when(stringValueResolver.resolveStringValue("${topic-2}")).thenReturn("topic-2"); // when - String channelName = KafkaListenerUtil.getChannelName(annotation, resolver); + String channelName = KafkaListenerUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("topic-1", channelName); @@ -51,11 +51,11 @@ void fromTopicPattern() { when(annotation.topics()).thenReturn(Arrays.array()); when(annotation.topicPattern()).thenReturn("${topic-1}"); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); // when - String channelName = KafkaListenerUtil.getChannelName(annotation, resolver); + String channelName = KafkaListenerUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("topic-1", channelName); @@ -79,11 +79,12 @@ void buildOperationBinding() { KafkaListener annotation = mock(KafkaListener.class); when(annotation.groupId()).thenReturn("${group-id}"); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${group-id}")).thenReturn("group-id"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${group-id}")).thenReturn("group-id"); // when - Map operationBinding = KafkaListenerUtil.buildOperationBinding(annotation, resolver); + Map operationBinding = + KafkaListenerUtil.buildOperationBinding(annotation, stringValueResolver); // then assertEquals(1, operationBinding.size()); diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaProducerConfigurationIntegrationTest.java b/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaProducerConfigurationIntegrationTest.java index de93e8b2b..096726384 100644 --- a/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaProducerConfigurationIntegrationTest.java +++ b/springwolf-plugins/springwolf-kafka-plugin/src/test/java/io/github/springwolf/plugins/kafka/configuration/SpringwolfKafkaProducerConfigurationIntegrationTest.java @@ -18,6 +18,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.util.StringValueResolver; import java.util.Optional; @@ -50,6 +51,7 @@ public class SpringwolfKafkaProducerConfigurationIntegrationTest { @MockBean(PayloadAsyncOperationService.class), @MockBean(HeaderClassExtractor.class), @MockBean(PayloadMethodParameterService.class), + @MockBean(StringValueResolver.class), }) class KafkaProducerWillBeCreatedIfEnabledTest { @Autowired @@ -90,6 +92,7 @@ void springwolfKafkaTemplateShouldBePresentInSpringContext() { @MockBean(PayloadAsyncOperationService.class), @MockBean(PayloadMethodParameterService.class), @MockBean(HeaderClassExtractor.class), + @MockBean(StringValueResolver.class), }) class KafkaProducerWillNotBeCreatedIfDisabledTest { @Autowired diff --git a/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsBindingFactory.java b/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsBindingFactory.java index c3baaca30..047d191a2 100644 --- a/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsBindingFactory.java +++ b/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsBindingFactory.java @@ -7,15 +7,14 @@ import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; -import lombok.NoArgsConstructor; -import org.springframework.context.EmbeddedValueResolverAware; +import lombok.RequiredArgsConstructor; import org.springframework.util.StringValueResolver; import java.util.Map; -@NoArgsConstructor -public class SqsBindingFactory implements BindingFactory, EmbeddedValueResolverAware { - private StringValueResolver stringValueResolver; +@RequiredArgsConstructor +public class SqsBindingFactory implements BindingFactory { + private final StringValueResolver stringValueResolver; @Override public String getChannelName(SqsListener annotation) { @@ -36,9 +35,4 @@ public Map buildOperationBinding(SqsListener annotatio public Map buildMessageBinding(SqsListener annotation, SchemaObject headerSchema) { return SqsListenerUtil.buildMessageBinding(); } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.stringValueResolver = resolver; - } } diff --git a/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsListenerUtil.java b/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsListenerUtil.java index 5fc0d758b..8eccaa4ff 100644 --- a/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsListenerUtil.java +++ b/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsListenerUtil.java @@ -21,15 +21,15 @@ @Slf4j public class SqsListenerUtil { - public static String getChannelName(SqsListener annotation, StringValueResolver resolver) { + public static String getChannelName(SqsListener annotation, StringValueResolver stringValueResolver) { return Stream.concat(Arrays.stream(annotation.value()), Arrays.stream(annotation.queueNames())) .findFirst() - .map(resolver::resolveStringValue) + .map(stringValueResolver::resolveStringValue) .orElseThrow(() -> new IllegalArgumentException("No queue name was found in @SqsListener annotation")); } public static Map buildChannelBinding( - SqsListener annotation, StringValueResolver resolver) { + SqsListener annotation, StringValueResolver stringValueResolver) { var queueName = readAnnotationQueueNames(annotation)[0]; var queue = @@ -39,7 +39,7 @@ public static Map buildChannelBinding( } public static Map buildOperationBinding( - SqsListener annotation, StringValueResolver resolver) { + SqsListener annotation, StringValueResolver stringValueResolver) { List queues = new ArrayList<>(); for (String queueName : readAnnotationQueueNames(annotation)) { diff --git a/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsScannerConfiguration.java b/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsScannerConfiguration.java index 26387aa01..4360ef137 100644 --- a/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsScannerConfiguration.java +++ b/springwolf-plugins/springwolf-sqs-plugin/src/main/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsScannerConfiguration.java @@ -24,6 +24,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; +import org.springframework.util.StringValueResolver; import java.util.List; @@ -37,8 +38,8 @@ public class SpringwolfSqsScannerConfiguration { @Bean @ConditionalOnProperty(name = SPRINGWOLF_SCANNER_SQS_LISTENER_ENABLED, havingValue = "true", matchIfMissing = true) - public SqsBindingFactory sqsBindingFactory() { - return new SqsBindingFactory(); + public SqsBindingFactory sqsBindingFactory(StringValueResolver stringValueResolver) { + return new SqsBindingFactory(stringValueResolver); } @Bean diff --git a/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsListenerUtilTest.java b/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsListenerUtilTest.java index b738b9ee4..0082d4c38 100644 --- a/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsListenerUtilTest.java +++ b/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/springwolf/plugins/sqs/asyncapi/scanners/bindings/SqsListenerUtilTest.java @@ -30,11 +30,11 @@ class FullConfiguration { void getChannelName() { // given SqsListener annotation = getAnnotation(ClassWithFullSqsListenerConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${queue-1}")).thenReturn("queue-1"); // when - String channelName = SqsListenerUtil.getChannelName(annotation, resolver); + String channelName = SqsListenerUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("queue-1", channelName); @@ -44,10 +44,11 @@ void getChannelName() { void buildChannelBinding() { // given SqsListener annotation = getAnnotation(ClassWithFullSqsListenerConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); // when - Map channelBinding = SqsListenerUtil.buildChannelBinding(annotation, resolver); + Map channelBinding = + SqsListenerUtil.buildChannelBinding(annotation, stringValueResolver); // then var expectedChannel = SQSChannelBinding.builder() @@ -66,11 +67,11 @@ void buildChannelBinding() { void buildOperationBinding() { // given SqsListener annotation = getAnnotation(ClassWithFullSqsListenerConfiguration.class); - StringValueResolver resolver = mock(StringValueResolver.class); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); // when Map operationBinding = - SqsListenerUtil.buildOperationBinding(annotation, resolver); + SqsListenerUtil.buildOperationBinding(annotation, stringValueResolver); // then var expectedOperation = SQSOperationBinding.builder() diff --git a/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsProducerConfigurationIntegrationTest.java b/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsProducerConfigurationIntegrationTest.java index f755bb512..d28c3f6e7 100644 --- a/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsProducerConfigurationIntegrationTest.java +++ b/springwolf-plugins/springwolf-sqs-plugin/src/test/java/io/github/springwolf/plugins/sqs/configuration/SpringwolfSqsProducerConfigurationIntegrationTest.java @@ -18,6 +18,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.util.StringValueResolver; import java.util.Optional; @@ -49,7 +50,8 @@ public class SpringwolfSqsProducerConfigurationIntegrationTest { @MockBean(ComponentsService.class), @MockBean(PayloadMethodParameterService.class), @MockBean(HeaderClassExtractor.class), - @MockBean(SqsTemplate.class) + @MockBean(SqsTemplate.class), + @MockBean(StringValueResolver.class), }) @Nested class SqsProducerWillBeCreatedIfEnabledTest { @@ -89,7 +91,8 @@ void springwolfSqsProducerShouldBePresentInSpringContext() { @MockBean(ComponentsService.class), @MockBean(PayloadMethodParameterService.class), @MockBean(HeaderClassExtractor.class), - @MockBean(SqsTemplate.class) + @MockBean(SqsTemplate.class), + @MockBean(StringValueResolver.class), }) @Nested class SqsProducerWillNotBeCreatedIfDisabledTest { diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingMessageMappingFactory.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingMessageMappingFactory.java index 674a2027a..0c788a088 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingMessageMappingFactory.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingMessageMappingFactory.java @@ -9,16 +9,15 @@ import io.github.springwolf.plugins.stomp.asyncapi.scanners.common.MessageMappingUtil; import io.github.springwolf.plugins.stomp.configuration.properties.SpringwolfStompConfigProperties; import lombok.RequiredArgsConstructor; -import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.util.StringValueResolver; import java.util.Map; @RequiredArgsConstructor -public class StompBindingMessageMappingFactory implements BindingFactory, EmbeddedValueResolverAware { - private StringValueResolver stringValueResolver; +public class StompBindingMessageMappingFactory implements BindingFactory { private final SpringwolfStompConfigProperties properties; + private final StringValueResolver stringValueResolver; @Override public String getChannelName(MessageMapping annotation) { @@ -39,9 +38,4 @@ public Map buildOperationBinding(MessageMapping annota public Map buildMessageBinding(MessageMapping annotation, SchemaObject headerSchema) { return MessageMappingUtil.buildMessageBinding(); } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.stringValueResolver = resolver; - } } diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingSendToFactory.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingSendToFactory.java index 4bf226d85..11728d2b5 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingSendToFactory.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingSendToFactory.java @@ -9,16 +9,15 @@ import io.github.springwolf.plugins.stomp.asyncapi.scanners.common.SendToUtil; import io.github.springwolf.plugins.stomp.configuration.properties.SpringwolfStompConfigProperties; import lombok.RequiredArgsConstructor; -import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.util.StringValueResolver; import java.util.Map; @RequiredArgsConstructor -public class StompBindingSendToFactory implements BindingFactory, EmbeddedValueResolverAware { - private StringValueResolver stringValueResolver; +public class StompBindingSendToFactory implements BindingFactory { private final SpringwolfStompConfigProperties properties; + private final StringValueResolver stringValueResolver; @Override public String getChannelName(SendTo annotation) { @@ -39,9 +38,4 @@ public Map buildOperationBinding(SendTo annotation) { public Map buildMessageBinding(SendTo annotation, SchemaObject headerSchema) { return SendToUtil.buildMessageBinding(); } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.stringValueResolver = resolver; - } } diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingSendToUserFactory.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingSendToUserFactory.java index 3e8c54a26..d62c097fb 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingSendToUserFactory.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/bindings/StompBindingSendToUserFactory.java @@ -10,16 +10,15 @@ import io.github.springwolf.plugins.stomp.asyncapi.scanners.common.SendToUtil; import io.github.springwolf.plugins.stomp.configuration.properties.SpringwolfStompConfigProperties; import lombok.RequiredArgsConstructor; -import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.messaging.simp.annotation.SendToUser; import org.springframework.util.StringValueResolver; import java.util.Map; @RequiredArgsConstructor -public class StompBindingSendToUserFactory implements BindingFactory, EmbeddedValueResolverAware { - private StringValueResolver stringValueResolver; +public class StompBindingSendToUserFactory implements BindingFactory { private final SpringwolfStompConfigProperties properties; + private final StringValueResolver stringValueResolver; @Override public String getChannelName(SendToUser annotation) { @@ -40,9 +39,4 @@ public Map buildOperationBinding(SendToUser annotation public Map buildMessageBinding(SendToUser annotation, SchemaObject headerSchema) { return SendToUtil.buildMessageBinding(); } - - @Override - public void setEmbeddedValueResolver(StringValueResolver resolver) { - this.stringValueResolver = resolver; - } } diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/MessageMappingUtil.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/MessageMappingUtil.java index 9b8f6a280..5e13d262a 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/MessageMappingUtil.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/MessageMappingUtil.java @@ -21,10 +21,10 @@ @Slf4j public class MessageMappingUtil { - public static String getChannelName(MessageMapping annotation, StringValueResolver resolver) { + public static String getChannelName(MessageMapping annotation, StringValueResolver stringValueResolver) { Stream destinations = Arrays.stream(annotation.value()); List resolvedDestinations = - destinations.map(resolver::resolveStringValue).collect(toList()); + destinations.map(stringValueResolver::resolveStringValue).collect(toList()); log.debug("Found destinations: {}", String.join(", ", resolvedDestinations)); return resolvedDestinations.get(0); @@ -35,7 +35,7 @@ public static Map buildChannelBinding() { } public static Map buildOperationBinding( - MessageMapping annotation, StringValueResolver resolver) { + MessageMapping annotation, StringValueResolver stringValueResolver) { StompOperationBinding binding = new StompOperationBinding(); return Map.of("stomp", binding); } diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/SendToUserUtil.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/SendToUserUtil.java index 80fe1303f..65b187ee5 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/SendToUserUtil.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/SendToUserUtil.java @@ -21,10 +21,10 @@ @Slf4j public class SendToUserUtil { - public static String getChannelName(SendToUser annotation, StringValueResolver resolver) { + public static String getChannelName(SendToUser annotation, StringValueResolver stringValueResolver) { Stream destinations = Arrays.stream(annotation.value()); List resolvedDestinations = - destinations.map(resolver::resolveStringValue).collect(toList()); + destinations.map(stringValueResolver::resolveStringValue).collect(toList()); log.debug("Found destinations: {}", String.join(", ", resolvedDestinations)); return resolvedDestinations.get(0); @@ -35,7 +35,7 @@ public static Map buildChannelBinding() { } public static Map buildOperationBinding( - SendToUser annotation, StringValueResolver resolver) { + SendToUser annotation, StringValueResolver stringValueResolver) { StompOperationBinding binding = new StompOperationBinding(); return Map.of("stomp", binding); } diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/SendToUtil.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/SendToUtil.java index 4e5494034..2ccf3b340 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/SendToUtil.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/asyncapi/scanners/common/SendToUtil.java @@ -21,10 +21,10 @@ @Slf4j public class SendToUtil { - public static String getChannelName(SendTo annotation, StringValueResolver resolver) { + public static String getChannelName(SendTo annotation, StringValueResolver stringValueResolver) { Stream destinations = Arrays.stream(annotation.value()); List resolvedDestinations = - destinations.map(resolver::resolveStringValue).collect(toList()); + destinations.map(stringValueResolver::resolveStringValue).collect(toList()); log.debug("Found destinations: {}", String.join(", ", resolvedDestinations)); return resolvedDestinations.get(0); @@ -34,7 +34,8 @@ public static Map buildChannelBinding() { return Map.of("stomp", new StompChannelBinding()); } - public static Map buildOperationBinding(SendTo annotation, StringValueResolver resolver) { + public static Map buildOperationBinding( + SendTo annotation, StringValueResolver stringValueResolver) { StompOperationBinding binding = new StompOperationBinding(); return Map.of("stomp", binding); } diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/configuration/SpringwolfStompScannerConfiguration.java b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/configuration/SpringwolfStompScannerConfiguration.java index 484fe3852..8a7eac8ee 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/configuration/SpringwolfStompScannerConfiguration.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/main/java/io/github/springwolf/plugins/stomp/configuration/SpringwolfStompScannerConfiguration.java @@ -37,6 +37,7 @@ import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.simp.annotation.SendToUser; +import org.springframework.util.StringValueResolver; import java.util.List; @@ -56,14 +57,15 @@ public class SpringwolfStompScannerConfiguration { havingValue = "true", matchIfMissing = true) public StompBindingMessageMappingFactory stompBindingMessageMappingFactory( - SpringwolfStompConfigProperties properties) { - return new StompBindingMessageMappingFactory(properties); + SpringwolfStompConfigProperties properties, StringValueResolver stringValueResolver) { + return new StompBindingMessageMappingFactory(properties, stringValueResolver); } @Bean @ConditionalOnProperty(name = SPRINGWOLF_SCANNER_STOMP_SEND_TO_ENABLED, havingValue = "true", matchIfMissing = true) - public StompBindingSendToFactory stompBindingSendToFactory(SpringwolfStompConfigProperties properties) { - return new StompBindingSendToFactory(properties); + public StompBindingSendToFactory stompBindingSendToFactory( + SpringwolfStompConfigProperties properties, StringValueResolver stringValueResolver) { + return new StompBindingSendToFactory(properties, stringValueResolver); } @Bean @@ -71,8 +73,9 @@ public StompBindingSendToFactory stompBindingSendToFactory(SpringwolfStompConfig name = SPRINGWOLF_SCANNER_STOMP_SEND_TO_USER_ENABLED, havingValue = "true", matchIfMissing = true) - public StompBindingSendToUserFactory stompBindingSendToUserFactory(SpringwolfStompConfigProperties properties) { - return new StompBindingSendToUserFactory(properties); + public StompBindingSendToUserFactory stompBindingSendToUserFactory( + SpringwolfStompConfigProperties properties, StringValueResolver stringValueResolver) { + return new StompBindingSendToUserFactory(properties, stringValueResolver); } @Bean diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/MessageMappingUtilTest.java b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/MessageMappingUtilTest.java index f86f212bc..cb950e650 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/MessageMappingUtilTest.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/MessageMappingUtilTest.java @@ -30,12 +30,12 @@ void fromTopics() { MessageMapping annotation = mock(MessageMapping.class); when(annotation.value()).thenReturn(Arrays.array("${topic-1}", "${topic-2}")); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); - when(resolver.resolveStringValue("${topic-2}")).thenReturn("topic-2"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); + when(stringValueResolver.resolveStringValue("${topic-2}")).thenReturn("topic-2"); // when - String channelName = MessageMappingUtil.getChannelName(annotation, resolver); + String channelName = MessageMappingUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("topic-1", channelName); @@ -56,10 +56,11 @@ void buildChannelBinding() { void buildOperationBinding() { // given MessageMapping annotation = mock(MessageMapping.class); - StringValueResolver resolver = mock(StringValueResolver.class); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); // when - Map operationBinding = MessageMappingUtil.buildOperationBinding(annotation, resolver); + Map operationBinding = + MessageMappingUtil.buildOperationBinding(annotation, stringValueResolver); // then assertEquals(1, operationBinding.size()); diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/SendToUserUtilTest.java b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/SendToUserUtilTest.java index 5b3adf4cc..c1452d46e 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/SendToUserUtilTest.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/SendToUserUtilTest.java @@ -30,12 +30,12 @@ void fromTopics() { SendToUser annotation = mock(SendToUser.class); when(annotation.value()).thenReturn(Arrays.array("${topic-1}", "${topic-2}")); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); - when(resolver.resolveStringValue("${topic-2}")).thenReturn("topic-2"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); + when(stringValueResolver.resolveStringValue("${topic-2}")).thenReturn("topic-2"); // when - String channelName = SendToUserUtil.getChannelName(annotation, resolver); + String channelName = SendToUserUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("topic-1", channelName); @@ -56,10 +56,11 @@ void buildChannelBinding() { void buildOperationBinding() { // given SendToUser annotation = mock(SendToUser.class); - StringValueResolver resolver = mock(StringValueResolver.class); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); // when - Map operationBinding = SendToUserUtil.buildOperationBinding(annotation, resolver); + Map operationBinding = + SendToUserUtil.buildOperationBinding(annotation, stringValueResolver); // then assertEquals(1, operationBinding.size()); diff --git a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/SendToUtilTest.java b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/SendToUtilTest.java index 387b85da5..552f37706 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/SendToUtilTest.java +++ b/springwolf-plugins/springwolf-stomp-plugin/src/test/java/io/github/springwolf/plugins/stomp/common/SendToUtilTest.java @@ -30,12 +30,12 @@ void fromTopics() { SendTo annotation = mock(SendTo.class); when(annotation.value()).thenReturn(Arrays.array("${topic-1}", "${topic-2}")); - StringValueResolver resolver = mock(StringValueResolver.class); - when(resolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); - when(resolver.resolveStringValue("${topic-2}")).thenReturn("topic-2"); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); + when(stringValueResolver.resolveStringValue("${topic-1}")).thenReturn("topic-1"); + when(stringValueResolver.resolveStringValue("${topic-2}")).thenReturn("topic-2"); // when - String channelName = SendToUtil.getChannelName(annotation, resolver); + String channelName = SendToUtil.getChannelName(annotation, stringValueResolver); // then assertEquals("topic-1", channelName); @@ -56,10 +56,11 @@ void buildChannelBinding() { void buildOperationBinding() { // given SendTo annotation = mock(SendTo.class); - StringValueResolver resolver = mock(StringValueResolver.class); + StringValueResolver stringValueResolver = mock(StringValueResolver.class); // when - Map operationBinding = SendToUtil.buildOperationBinding(annotation, resolver); + Map operationBinding = + SendToUtil.buildOperationBinding(annotation, stringValueResolver); // then assertEquals(1, operationBinding.size()); From db7e108714b083119885f19cf4c679cf9256cb4d Mon Sep 17 00:00:00 2001 From: Timon Back Date: Mon, 16 Sep 2024 19:02:33 +0200 Subject: [PATCH 16/34] Chore/gradle 8.10.1 (#981) * chore(deps): Bump gradle to 8.10.1 * chore(gh): remove Docker from dependabot docker-compose files are not supported --- .github/dependabot.yml | 6 ------ gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43453 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 77788438d..4a689ba87 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,12 +11,6 @@ updates: schedule: interval: "weekly" - - package-ecosystem: "docker" - directory: "/" - rebase-strategy: "disabled" - schedule: - interval: "weekly" - - package-ecosystem: "gradle" directory: "/" rebase-strategy: "disabled" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..e6441136f3d4ba8a0da8d277868979cfbc8ad796 100644 GIT binary patch delta 34118 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 delta 34176 zcmX7vV`H6d(}mmEwr$(CZQE$vU^m*aZQE(=WXEZ2+l}qF_w)XN>&rEBu9;)4>7EB0 zo(HR^Mh47P)@z^^pH!4#b(O8!;$>N+S+v5K5f8RrQ+Qv0_oH#e!pI2>yt4ij>fI9l zW&-hsVAQg%dpn3NRy$kb_vbM2sr`>bZ48b35m{D=OqX;p8A${^Dp|W&J5mXvUl#_I zN!~GCBUzj~C%K?<7+UZ_q|L)EGG#_*2Zzko-&Kck)Qd2%CpS3{P1co1?$|Sj1?E;PO z7alI9$X(MDly9AIEZ-vDLhpAKd1x4U#w$OvBtaA{fW9)iD#|AkMrsSaNz(69;h1iM1#_ z?u?O_aKa>vk=j;AR&*V-p3SY`CI}Uo%eRO(Dr-Te<99WQhi>y&l%UiS%W2m(d#woD zW?alFl75!1NiUzVqgqY98fSQNjhX3uZ&orB08Y*DFD;sjIddWoJF;S_@{Lx#SQk+9 zvSQ-620z0D7cy8-u_7u?PqYt?R0m2k%PWj%V(L|MCO(@3%l&pzEy7ijNv(VXU9byn z@6=4zL|qk*7!@QWd9imT9i%y}1#6+%w=s%WmsHbw@{UVc^?nL*GsnACaLnTbr9A>B zK)H-$tB`>jt9LSwaY+4!F1q(YO!E7@?SX3X-Ug4r($QrmJnM8m#;#LN`kE>?<{vbCZbhKOrMpux zTU=02hy${;n&ikcP8PqufhT9nJU>s;dyl;&~|Cs+o{9pCu{cRF+0{iyuH~6=tIZXVd zR~pJBC3Hf-g%Y|bhTuGyd~3-sm}kaX5=T?p$V?48h4{h2;_u{b}8s~Jar{39PnL7DsXpxcX#3zx@f9K zkkrw9s2*>)&=fLY{=xeIYVICff2Id5cc*~l7ztSsU@xuXYdV1(lLGZ5)?mXyIDf1- zA7j3P{C5s?$Y-kg60&XML*y93zrir8CNq*EMx)Kw)XA(N({9t-XAdX;rjxk`OF%4-0x?ne@LlBQMJe5+$Ir{Oj`@#qe+_-z!g5qQ2SxKQy1ex_x^Huj%u+S@EfEPP-70KeL@7@PBfadCUBt%`huTknOCj{ z;v?wZ2&wsL@-iBa(iFd)7duJTY8z-q5^HR-R9d*ex2m^A-~uCvz9B-1C$2xXL#>ow z!O<5&jhbM&@m=l_aW3F>vjJyy27gY}!9PSU3kITbrbs#Gm0gD?~Tub8ZFFK$X?pdv-%EeopaGB#$rDQHELW!8bVt`%?&>0 zrZUQ0!yP(uzVK?jWJ8^n915hO$v1SLV_&$-2y(iDIg}GDFRo!JzQF#gJoWu^UW0#? z*OC-SPMEY!LYY*OO95!sv{#-t!3Z!CfomqgzFJld>~CTFKGcr^sUai5s-y^vI5K={ z)cmQthQuKS07e8nLfaIYQ5f}PJQqcmokx?%yzFH*`%k}RyXCt1Chfv5KAeMWbq^2MNft;@`hMyhWg50(!jdAn;Jyx4Yt)^^DVCSu?xRu^$*&&=O6#JVShU_N3?D)|$5pyP8A!f)`| z>t0k&S66T*es5(_cs>0F=twYJUrQMqYa2HQvy)d+XW&rai?m;8nW9tL9Ivp9qi2-` zOQM<}D*g`28wJ54H~1U!+)vQh)(cpuf^&8uteU$G{9BUhOL| zBX{5E1**;hlc0ZAi(r@)IK{Y*ro_UL8Ztf8n{Xnwn=s=qH;fxkK+uL zY)0pvf6-iHfX+{F8&6LzG;&d%^5g`_&GEEx0GU=cJM*}RecV-AqHSK@{TMir1jaFf&R{@?|ieOUnmb?lQxCN!GnAqcii9$ z{a!Y{Vfz)xD!m2VfPH=`bk5m6dG{LfgtA4ITT?Sckn<92rt@pG+sk>3UhTQx9ywF3 z=$|RgTN<=6-B4+UbYWxfQUOe8cmEDY3QL$;mOw&X2;q9x9qNz3J97)3^jb zdlzkDYLKm^5?3IV>t3fdWwNpq3qY;hsj=pk9;P!wVmjP|6Dw^ez7_&DH9X33$T=Q{>Nl zv*a*QMM1-2XQ)O=3n@X+RO~S`N13QM81^ZzljPJIFBh%x<~No?@z_&LAl)ap!AflS zb{yFXU(Uw(dw%NR_l7%eN2VVX;^Ln{I1G+yPQr1AY+0MapBnJ3k1>Zdrw^3aUig*! z?xQe8C0LW;EDY(qe_P!Z#Q^jP3u$Z3hQpy^w7?jI;~XTz0ju$DQNc4LUyX}+S5zh> zGkB%~XU+L?3pw&j!i|x6C+RyP+_XYNm9`rtHpqxvoCdV_MXg847oHhYJqO+{t!xxdbsw4Ugn($Cwkm^+36&goy$vkaFs zrH6F29eMPXyoBha7X^b+N*a!>VZ<&Gf3eeE+Bgz7PB-6X7 z_%2M~{sTwC^iQVjH9#fVa3IO6E4b*S%M;#WhHa^L+=DP%arD_`eW5G0<9Tk=Ci?P@ z6tJXhej{ZWF=idj32x7dp{zmQY;;D2*11&-(~wifGXLmD6C-XR=K3c>S^_+x!3OuB z%D&!EOk;V4Sq6eQcE{UEDsPMtED*;qgcJU^UwLwjE-Ww54d73fQ`9Sv%^H>juEKmxN+*aD=0Q+ZFH1_J(*$~9&JyUJ6!>(Nj zi3Z6zWC%Yz0ZjX>thi~rH+lqv<9nkI3?Ghn7@!u3Ef){G(0Pvwnxc&(YeC=Kg2-7z zr>a^@b_QClXs?Obplq@Lq-l5>W);Y^JbCYk^n8G`8PzCH^rnY5Zk-AN6|7Pn=oF(H zxE#8LkI;;}K7I^UK55Z)c=zn7OX_XVgFlEGSO}~H^y|wd7piw*b1$kA!0*X*DQ~O` z*vFvc5Jy7(fFMRq>XA8Tq`E>EF35{?(_;yAdbO8rrmrlb&LceV%;U3haVV}Koh9C| zTZnR0a(*yN^Hp9u*h+eAdn)d}vPCo3k?GCz1w>OOeme(Mbo*A7)*nEmmUt?eN_vA; z=~2}K_}BtDXJM-y5fn^v>QQo+%*FdZQFNz^j&rYhmZHgDA-TH47#Wjn_@iH4?6R{J z%+C8LYIy>{3~A@|y4kN8YZZp72F8F@dOZWp>N0-DyVb4UQd_t^`P)zsCoygL_>>x| z2Hyu7;n(4G&?wCB4YVUIVg0K!CALjRsb}&4aLS|}0t`C}orYqhFe7N~h9XQ_bIW*f zGlDCIE`&wwyFX1U>}g#P0xRRn2q9%FPRfm{-M7;}6cS(V6;kn@6!$y06lO>8AE_!O z{|W{HEAbI0eD$z9tQvWth7y>qpTKQ0$EDsJkQxAaV2+gE28Al8W%t`Pbh zPl#%_S@a^6Y;lH6BfUfZNRKwS#x_keQ`;Rjg@qj zZRwQXZd-rWngbYC}r6X)VCJ-=D54A+81%(L*8?+&r7(wOxDSNn!t(U}!;5|sjq zc5yF5$V!;%C#T+T3*AD+A({T)#p$H_<$nDd#M)KOLbd*KoW~9E19BBd-UwBX1<0h9 z8lNI&7Z_r4bx;`%5&;ky+y7PD9F^;Qk{`J@z!jJKyJ|s@lY^y!r9p^75D)_TJ6S*T zLA7AA*m}Y|5~)-`cyB+lUE9CS_`iB;MM&0fX**f;$n($fQ1_Zo=u>|n~r$HvkOUK(gv_L&@DE0b4#ya{HN)8bNQMl9hCva zi~j0v&plRsp?_zR zA}uI4n;^_Ko5`N-HCw_1BMLd#OAmmIY#ol4M^UjLL-UAat+xA+zxrFqKc@V5Zqan_ z+LoVX-Ub2mT7Dk_ z<+_3?XWBEM84@J_F}FDe-hl@}x@v-s1AR{_YD!_fMgagH6s9uyi6pW3gdhauG>+H? zi<5^{dp*5-9v`|m*ceT&`Hqv77oBQ+Da!=?dDO&9jo;=JkzrQKx^o$RqAgzL{ zjK@n)JW~lzxB>(o(21ibI}i|r3e;17zTjdEl5c`Cn-KAlR7EPp84M@!8~CywES-`mxKJ@Dsf6B18_!XMIq$Q3rTDeIgJ3X zB1)voa#V{iY^ju>*Cdg&UCbx?d3UMArPRHZauE}c@Fdk;z85OcA&Th>ZN%}=VU%3b9={Q(@M4QaeuGE(BbZ{U z?WPDG+sjJSz1OYFpdImKYHUa@ELn%n&PR9&I7B$<-c3e|{tPH*u@hs)Ci>Z@5$M?lP(#d#QIz}~()P7mt`<2PT4oHH}R&#dIx4uq943D8gVbaa2&FygrSk3*whGr~Jn zR4QnS@83UZ_BUGw;?@T zo5jA#potERcBv+dd8V$xTh)COur`TQ^^Yb&cdBcesjHlA3O8SBeKrVj!-D3+_p6%P zP@e{|^-G-C(}g+=bAuAy8)wcS{$XB?I=|r=&=TvbqeyXiuG43RR>R72Ry7d6RS;n^ zO5J-QIc@)sz_l6%Lg5zA8cgNK^GK_b-Z+M{RLYk5=O|6c%!1u6YMm3jJg{TfS*L%2 zA<*7$@wgJ(M*gyTzz8+7{iRP_e~(CCbGB}FN-#`&1ntct@`5gB-u6oUp3#QDxyF8v zOjxr}pS{5RpK1l7+l(bC)0>M;%7L?@6t}S&a zx0gP8^sXi(g2_g8+8-1~hKO;9Nn%_S%9djd*;nCLadHpVx(S0tixw2{Q}vOPCWvZg zjYc6LQ~nIZ*b0m_uN~l{&2df2*ZmBU8dv`#o+^5p>D5l%9@(Y-g%`|$%nQ|SSRm0c zLZV)45DS8d#v(z6gj&6|ay@MP23leodS8-GWIMH8_YCScX#Xr)mbuvXqSHo*)cY9g z#Ea+NvHIA)@`L+)T|f$Etx;-vrE3;Gk^O@IN@1{lpg&XzU5Eh3!w;6l=Q$k|%7nj^ z|HGu}c59-Ilzu^w<93il$cRf@C(4Cr2S!!E&7#)GgUH@py?O;Vl&joXrep=2A|3Vn zH+e$Ctmdy3B^fh%12D$nQk^j|v=>_3JAdKPt2YVusbNW&CL?M*?`K1mK*!&-9Ecp~>V1w{EK(429OT>DJAV21fG z=XP=%m+0vV4LdIi#(~XpaUY$~fQ=xA#5?V%xGRr_|5WWV=uoG_Z&{fae)`2~u{6-p zG>E>8j({w7njU-5Lai|2HhDPntQ(X@yB z9l?NGoKB5N98fWrkdN3g8ox7Vic|gfTF~jIfXkm|9Yuu-p>v3d{5&hC+ZD%mh|_=* zD5v*u(SuLxzX~owH!mJQi%Z=ALvdjyt9U6baVY<88B>{HApAJ~>`buHVGQd%KUu(d z5#{NEKk6Vy08_8*E(?hqZe2L?P2$>!0~26N(rVzB9KbF&JQOIaU{SumX!TsYzR%wB z<5EgJXDJ=1L_SNCNZcBWBNeN+Y`)B%R(wEA?}Wi@mp(jcw9&^1EMSM58?68gwnXF` zzT0_7>)ep%6hid-*DZ42eU)tFcFz7@bo=<~CrLXpNDM}tv*-B(ZF`(9^RiM9W4xC%@ZHv=>w(&~$Wta%)Z;d!{J;e@z zX1Gkw^XrHOfYHR#hAU=G`v43E$Iq}*gwqm@-mPac0HOZ0 zVtfu7>CQYS_F@n6n#CGcC5R%4{+P4m7uVlg3axX}B(_kf((>W?EhIO&rQ{iUO$16X zv{Abj3ZApUrcar7Ck}B1%RvnR%uocMlKsRxV9Qqe^Y_5C$xQW@9QdCcF%W#!zj;!xWc+0#VQ*}u&rJ7)zc+{vpw+nV?{tdd&Xs`NV zKUp|dV98WbWl*_MoyzM0xv8tTNJChwifP!9WM^GD|Mkc75$F;j$K%Y8K@7?uJjq-w zz*|>EH5jH&oTKlIzueAN2926Uo1OryC|CmkyoQZABt#FtHz)QmQvSX35o`f z<^*5XXxexj+Q-a#2h4(?_*|!5Pjph@?Na8Z>K%AAjNr3T!7RN;7c)1SqAJfHY|xAV z1f;p%lSdE8I}E4~tRH(l*rK?OZ>mB4C{3e%E-bUng2ymerg8?M$rXC!D?3O}_mka? zm*Y~JMu+_F7O4T;#nFv)?Ru6 z92r|old*4ZB$*6M40B;V&2w->#>4DEu0;#vHSgXdEzm{+VS48 z7U1tVn#AnQ3z#gP26$!dmS5&JsXsrR>~rWA}%qd{92+j zu+wYAqrJYOA%WC9nZ>BKH&;9vMSW_59z5LtzS4Q@o5vcrWjg+28#&$*8SMYP z!l5=|p@x6YnmNq>23sQ(^du5K)TB&K8t{P`@T4J5cEFL@qwtsCmn~p>>*b=37y!kB zn6x{#KjM{S9O_otGQub*K)iIjtE2NfiV~zD2x{4r)IUD(Y8%r`n;#)ujIrl8Sa+L{ z>ixGoZJ1K@;wTUbRRFgnltN_U*^EOJS zRo4Y+S`cP}e-zNtdl^S5#%oN#HLjmq$W^(Y6=5tM#RBK-M14RO7X(8Gliy3+&9fO; zXn{60%0sWh1_g1Z2r0MuGwSGUE;l4TI*M!$5dm&v9pO7@KlW@j_QboeDd1k9!7S)jIwBza-V#1)(7ht|sjY}a19sO!T z2VEW7nB0!zP=Sx17-6S$r=A)MZikCjlQHE)%_Ka|OY4+jgGOw=I3CM`3ui^=o0p7u z?xujpg#dRVZCg|{%!^DvoR*~;QBH8ia6%4pOh<#t+e_u!8gjuk_Aic=|*H24Yq~Wup1dTRQs0nlZOy+30f16;f7EYh*^*i9hTZ`h`015%{i|4 z?$7qC3&kt#(jI#<76Biz=bl=k=&qyaH>foM#zA7}N`Ji~)-f-t&tR4^do)-5t?Hz_Q+X~S2bZx{t+MEjwy3kGfbv(ij^@;=?H_^FIIu*HP_7mpV)NS{MY-Rr7&rvWo@Wd~{Lt!8|66rq`GdGu% z@<(<7bYcZKCt%_RmTpAjx=TNvdh+ZiLkMN+hT;=tC?%vQQGc7WrCPIYZwYTW`;x|N zrlEz1yf95FiloUU^(onr3A3>+96;;6aL?($@!JwiQ2hO|^i)b4pCJ7-y&a~B#J`#FO!3uBp{5GBvM2U@K85&o0q~6#LtppE&cVY z3Bv{xQ-;i}LN-60B2*1suMd=Fi%Y|7@52axZ|b=Wiwk^5eg{9X4}(q%4D5N5_Gm)` zg~VyFCwfkIKW(@@ZGAlTra6CO$RA_b*yz#){B82N7AYpQ9)sLQfhOAOMUV7$0|d$=_y&jl>va$3u-H z_+H*|UXBPLe%N2Ukwu1*)kt!$Y>(IH3`YbEt; znb1uB*{UgwG{pQnh>h@vyCE!6B~!k}NxEai#iY{$!_w54s5!6jG9%pr=S~3Km^EEA z)sCnnau+ZY)(}IK#(3jGGADw8V7#v~<&y5cF=5_Ypkrs3&7{}%(4KM7) zuSHVqo~g#1kzNwXc39%hL8atpa1Wd#V^uL=W^&E)fvGivt)B!M)?)Y#Ze&zU6O_I?1wj)*M;b*dE zqlcwgX#eVuZj2GKgBu@QB(#LHMd`qk<08i$hG1@g1;zD*#(9PHjVWl*5!;ER{Q#A9 zyQ%fu<$U?dOW=&_#~{nrq{RRyD8upRi}c-m!n)DZw9P>WGs>o1vefI}ujt_`O@l#Z z%xnOt4&e}LlM1-0*dd?|EvrAO-$fX8i{aTP^2wsmSDd!Xc9DxJB=x1}6|yM~QQPbl z0xrJcQNtWHgt*MdGmtj%x6SWYd?uGnrx4{m{6A9bYx`m z$*UAs@9?3s;@Jl19%$!3TxPlCkawEk12FADYJClt0N@O@Pxxhj+Kk(1jK~laR0*KGAc7%C4nI^v2NShTc4#?!p{0@p0T#HSIRndH;#Ts0YECtlSR}~{Uck+keoJq6iH)(Zc~C!fBe2~4(Wd> zR<4I1zMeW$<0xww(@09!l?;oDiq zk8qjS9Lxv$<5m#j(?4VLDgLz;8b$B%XO|9i7^1M;V{aGC#JT)c+L=BgCfO5k>CTlI zOlf~DzcopV29Dajzt*OcYvaUH{UJPaD$;spv%>{y8goE+bDD$~HQbON>W*~JD`;`- zZEcCPSdlCvANe z=?|+e{6AW$f(H;BND>uy1MvQ`pri>SafK5bK!YAE>0URAW9RS8#LWUHBOc&BNQ9T+ zJpg~Eky!u!9WBk)!$Z?!^3M~o_VPERYnk1NmzVYaGH;1h+;st==-;jzF~2LTn+x*k zvywHZg7~=aiJe=OhS@U>1fYGvT1+jsAaiaM;) zay2xsMKhO+FIeK?|K{G4SJOEt*eX?!>K8jpsZWW8c!X|JR#v(1+Ey5NM^TB1n|_40 z@Db2gH}PNT+3YEyqXP8U@)`E|Xat<{K5K;eK7O0yV72m|b!o43!e-!P>iW>7-9HN7 zmmc7)JX0^lPzF#>$#D~nU^3f!~Q zQWly&oZEb1847&czU;dg?=dS>z3lJkADL1innNtE(f?~OxM`%A_PBp?Lj;zDDomf$ z;|P=FTmqX|!sHO6uIfCmh4Fbgw@`DOn#`qAPEsYUiBvUlw zevH{)YWQu>FPXU$%1!h*2rtk_J}qNkkq+StX8Wc*KgG$yH#p-kcD&)%>)Yctb^JDB zJe>=!)5nc~?6hrE_3n^_BE<^;2{}&Z>Dr)bX>H{?kK{@R)`R5lnlO6yU&UmWy=d03 z*(jJIwU3l0HRW1PvReOb|MyZT^700rg8eFp#p<3Et%9msiCxR+jefK%x81+iN0=hG z;<`^RUVU+S)Iv-*5y^MqD@=cp{_cP4`s=z)Ti3!Bf@zCmfpZTwf|>|0t^E8R^s`ad z5~tA?0x7OM{*D;zb6bvPu|F5XpF11`U5;b*$p zNAq7E6c=aUnq>}$JAYsO&=L^`M|DdSSp5O4LA{|tO5^8%Hf1lqqo)sj=!aLNKn9(3 zvKk($N`p`f&u+8e^Z-?uc2GZ_6-HDQs@l%+pWh!|S9+y3!jrr3V%cr{FNe&U6(tYs zLto$0D+2}K_9kuxgFSeQ!EOXjJtZ$Pyl_|$mPQ9#fES=Sw8L% zO7Jij9cscU)@W+$jeGpx&vWP9ZN3fLDTp zaYM$gJD8ccf&g>n?a56X=y zec%nLN`(dVCpSl9&pJLf2BN;cR5F0Nn{(LjGe7RjFe7efp3R_2JmHOY#nWEc2TMhMSj5tBf-L zlxP3sV`!?@!mRnDTac{35I7h@WTfRjRiFw*Q*aD8)n)jdkJC@)jD-&mzAdK6Kqdct8P}~dqixq;n zjnX!pb^;5*Rr?5ycT7>AB9)RED^x+DVDmIbHKjcDv2lHK;apZOc=O@`4nJ;k|iikKk66v4{zN#lmSn$lh z_-Y3FC)iV$rFJH!#mNqWHF-DtSNbI)84+VLDWg$ph_tkKn_6+M1RZ!)EKaRhY={el zG-i@H!fvpH&4~$5Q+zHU(Ub=;Lzcrc3;4Cqqbr$O`c5M#UMtslK$3r+Cuz>xKl+xW?`t2o=q`1djXC=Q6`3C${*>dm~I{ z(aQH&Qd{{X+&+-4{epSL;q%n$)NOQ7kM}ea9bA++*F+t$2$%F!U!U}(&y7Sd0jQMV zkOhuJ$+g7^kb<`jqFiq(y1-~JjP13J&uB=hfjH5yAArMZx?VzW1~>tln~d5pt$uWR~TM!lIg+D)prR zocU0N2}_WTYpU`@Bsi1z{$le`dO{-pHFQr{M}%iEkX@0fv!AGCTcB90@e|slf#unz z*w4Cf>(^XI64l|MmWih1g!kwMJiifdt4C<5BHtaS%Ra>~3IFwjdu;_v*7BL|fPu+c zNp687`{}e@|%)5g4U*i=0zlSWXzz=YcZ*&Bg zr$r(SH0V5a%oHh*t&0y%R8&jDI=6VTWS_kJ!^WN!ET@XfEHYG-T1jJsDd`yEgh!^* z+!P62=v`R2=TBVjt=h}|JIg7N^RevZuyxyS+jsk>=iLA52Ak+7L?2$ZDUaWdi1PgB z_;*Uae_n&7o27ewV*y(wwK~8~tU<#Np6UUIx}zW6fR&dKiPq|$A{BwG_-wVfkm+EP zxHU@m`im3cD#fH63>_X`Il-HjZN_hqOVMG;(#7RmI13D-s_>41l|vDH1BglPsNJ+p zTniY{Hwoief+h%C^|@Syep#722=wmcTR7awIzimAcye?@F~f|n<$%=rM+Jkz9m>PF70$)AK@|h_^(zn?!;={;9Zo7{ zBI7O?6!J2Ixxk;XzS~ScO9{K1U9swGvR_d+SkromF040|Slk%$)M;9O_8h0@WPe4= z%iWM^ust8w$(NhO)7*8uq+9CycO$3m-l}O70sBi<4=j0CeE_&3iRUWJkDM$FIfrkR zHG2|hVh3?Nt$fdI$W?<|Qq@#hjDijk@7eUr1&JHYI>(_Q4^3$+Zz&R)Z`WqhBIvjo zX#EbA8P0Qla-yACvt)%oAVHa#kZi3Y8|(IOp_Z6J-t{)98*OXQ#8^>vTENsV@(M}^ z(>8BXw`{+)BfyZB!&85hT0!$>7$uLgp9hP9M7v=5@H`atsri1^{1VDxDqizj46-2^ z?&eA9udH#BD|QY2B7Zr$l;NJ-$L!u8G{MZoX)~bua5J=0p_JnM`$(D4S!uF}4smWq zVo%kQ~C~X?cWCH zo4s#FqJ)k|D{c_ok+sZ8`m2#-Uk8*o)io`B+WTD0PDA!G`DjtibftJXhPVjLZj~g& z=MM9nF$7}xvILx}BhM;J-Xnz0=^m1N2`Mhn6@ct+-!ijIcgi6FZ*oIPH(tGYJ2EQ0 z{;cjcc>_GkAlWEZ2zZLA_oa-(vYBp7XLPbHCBcGH$K9AK6nx}}ya%QB2=r$A;11*~ z_wfru1SkIQ0&QUqd)%eAY^FL!G;t@7-prQ|drDn#yDf%Uz8&kGtrPxKv?*TqkC(}g zUx10<;3Vhnx{gpWXM8H zKc0kkM~gIAts$E!X-?3DWG&^knj4h(q5(L;V81VWyC@_71oIpXfsb0S(^Js#N_0E} zJ%|XX&EeVPyu}? zz~(%slTw+tcY3ZMG$+diC8zed=CTN}1fB`RXD_v2;{evY z@MCG$l9Az+F()8*SqFyrg3jrN7k^x3?;A?L&>y{ZUi$T8!F7Dv8s}}4r9+Wo0h^m= zAob@CnJ;IR-{|_D;_w)? zcH@~&V^(}Ag}%A90);X2AhDj(-YB>$>GrW1F4C*1S5`u@N{T|;pYX1;E?gtBbPvS* zlv3r#rw2KCmLqX0kGT8&%#A6Sc(S>apOHtfn+UdYiN4qPawcL{Sb$>&I)Ie>Xs~ej z7)a=-92!sv-A{-7sqiG-ysG0k&beq6^nX1L!Fs$JU#fsV*CbsZqBQ|y z{)}zvtEwO%(&mIG|L?qs2Ou1rqTZHV@H+sm8Nth(+#dp0DW4VXG;;tCh`{BpY)THY z_10NNWpJuzCG%Q@#Aj>!v7Eq8eI6_JK3g2CsB2jz)2^bWiM{&U8clnV7<2?Qx5*k_ zl9B$P@LV7Sani>Xum{^yJ6uYxM4UHnw4zbPdM|PeppudXe}+OcX z!nr!xaUA|xYtA~jE|436iL&L={H3e}H`M1;2|pLG)Z~~Ug9X%_#D!DW>w}Es!D{=4 zxRPBf5UWm2{}D>Em;v43miQ~2{>%>O*`wA{7j;yh;*DV=C-bs;3p{AD;>VPcn>E;V zLgtw|Y{|Beo+_ABz`lofH+cdf33LjIf!RdcW~wWgmsE%2yCQGbst4TS_t%6nS8a+m zFEr<|9TQzQC@<(yNN9GR4S$H-SA?xiLIK2O2>*w-?cdzNPsG4D3&%$QOK{w)@Dk}W z|3_Z>U`XBu7j6Vc=es(tz}c7k4al1$cqDW4a~|xgE9zPX(C`IsN(QwNomzsBOHqjd zi{D|jYSv5 zC>6#uB~%#!!*?zXW`!yHWjbjwm!#eo3hm;>nJ!<`ZkJamE6i>>WqkoTpbm(~b%G_v z`t3Z#ERips;EoA_0c?r@WjEP|ulD+hue5r8946Sd0kuBD$A!=dxigTZn)u3>U;Y8l zX9j(R*(;;i&HrB&M|Xnitzf@><3#)aKy=bFCf5Hz@_);{nlL?J!U>%fL$Fk~Ocs3& zB@-Ek%W>h9#$QIYg07&lS_CG3d~LrygXclO!Ws-|PxMsn@n{?77wCaq?uj`dd7lllDCGd?ed&%5k{RqUhiN1u&?uz@Fq zNkv_4xmFcl?vs>;emR1R<$tg;*Ayp@rl=ik z=x2Hk zJqsM%++e|*+#camAiem6f;3-khtIgjYmNL0x|Mz|y{r{6<@_&a7^1XDyE>v*uo!qF zBq^I8PiF#w<-lFvFx9xKoi&0j)4LX~rWsK$%3hr@ebDv^($$T^4m4h#Q-(u*Mbt6F zE%y0Fvozv=WAaTj6EWZ)cX{|9=AZDvPQuq>2fUkU(!j1GmdgeYLX`B0BbGK(331ME zu3yZ3jQ@2)WW5!C#~y}=q5Av=_;+hNi!%gmY;}~~e!S&&^{4eJuNQ2kud%Olf8TRI zW-Dze987Il<^!hCO{AR5tLW{F1WLuZ>nhPjke@CSnN zzoW{m!+PSCb7byUf-1b;`{0GU^zg7b9c!7ueJF`>L;|akVzb&IzoLNNEfxp7b7xMN zKs9QG6v@t7X)yYN9}3d4>*ROMiK-Ig8(Do$3UI&E}z!vcH2t(VIk-cLyC-Y%`)~>Ce23A=dQsc<( ziy;8MmHki+5-(CR8$=lRt{(9B9W59Pz|z0^;`C!q<^PyE$KXt!KibFH*xcB9V%xTD zn;YlZ*tTukwr$(mWMka@|8CW-J8!zCXI{P1-&=wSvZf&%9SZ7m`1&2^nV#D z6T*)`Mz3wGUC69Fg0Xk!hwY}ykk!TE%mr57TLX*U4ygwvM^!#G`HYKLIN>gT;?mo% zAxGgzSnm{}vRG}K)8n(XjG#d+IyAFnozhk|uwiey(p@ zu>j#n4C|Mhtd=0G?Qn5OGh{{^MWR)V*geNY8d)py)@5a85G&_&OSCx4ASW8g&AEXa zC}^ET`eORgG*$$Q1L=9_8MCUO4Mr^1IA{^nsB$>#Bi(vN$l8+p(U^0dvN_{Cu-UUm zQyJc!8>RWp;C3*2dGp49QVW`CRR@no(t+D|@nl138lu@%c1VCy3|v4VoKZ4AwnnjF z__8f$usTzF)TQ$sQ^|#(M}-#0^3Ag%A0%5vA=KK$37I`RY({kF-z$(P50pf3_20YTr%G@w+bxE_V+Tt^YHgrlu$#wjp7igF!=o8e2rqCs|>XM9+M7~TqI&fcx z=pcX6_MQQ{TIR6a0*~xdgFvs<2!yaA1F*4IZgI!)xnzJCwsG&EElg_IpFbrT}nr)UQy}GiK;( zDlG$cksync34R3J^FqJ=={_y9x_pcd%$B*u&vr7^ItxqWFIAkJgaAQiA)pioK1JQ| zYB_6IUKc$UM*~f9{Xzw*tY$pUglV*?BDQuhsca*Fx!sm`9y`V&?lVTH%%1eJ74#D_ z7W+@8@7LAu{aq)sPys{MM~;`k>T%-wPA)E2QH7(Z4XEUrQ5YstG`Uf@w{n_Oc!wem z7=8z;k$N{T74B*zVyJI~4d60M09FYG`33;Wxh=^Ixhs69U_SG_deO~_OUO1s9K-8p z5{HmcXAaKqHrQ@(t?d@;63;Pnj2Kk<;Hx=kr>*Ko`F*l){%GVDj5nkohSU)B&5Vrc zo0u%|b%|VITSB)BXTRPQC=Bv=qplloSI#iKV#~z#t#q*jcS`3s&w-z^m--CYDI7n2 z%{LHFZ*(1u4DvhES|Dc*n%JL8%8?h7boNf|qxl8D)np@5t~VORwQn)TuSI07b-T=_ zo8qh+0yf|-6=x;Ra$w&WeVZhUO%3v6Ni*}i&sby3s_(?l5Er{K9%0_dE<`7^>8mLr zZ|~l#Bi@5}8{iZ$(d9)!`}@2~#sA~?uH|EbrJQcTw|ssG)MSJJIF96-_gf&* zy~I&$m6e0nnLz^M2;G|IeUk?s+afSZ){10*P~9W%RtYeSg{Nv5FG<2QaWpj?d`;}<4( z>V1i|wNTpH`jJtvTD0C3CTws410U9HS_%Ti2HaB~%^h6{+$@5`K9}T=eQL;dMZ?=Y zX^z?B3ZU_!E^OW%Z*-+t&B-(kLmDwikb9+F9bj;NFq-XHRB=+L)Rew{w|7p~7ph{#fRT}}K zWA)F7;kJBCk^aFILnkV^EMs=B~#qh*RG2&@F|x2$?7QTX_T6qL?i$c6J*-cNQC~E6dro zR)CGIoz;~V?=>;(NF4dihkz~Koqu}VNPE9^R{L@e6WkL{fK84H?C*uvKkO(!H-&y( zq|@B~juu*x#J_i3gBrS0*5U*%NDg+Ur9euL*5QaF^?-pxxieMM6k_xAP;S}sfKmIa zj(T6o{4RfARHz25YWzv=QaJ4P!O$LHE(L~6fB89$`6+olZR!#%y?_v+Cf+g)5#!ZM zkabT-y%v|ihYuV}Y%-B%pxL264?K%CXlbd_s<GY5BG*`kYQjao$QHiC_qPk5uE~AO+F=eOtTWJ1vm*cU(D5kvs3kity z$IYG{$L<8|&I>|WwpCWo5K3!On`)9PIx(uWAq>bSQTvSW`NqgprBIuV^V>C~?+d(w$ZXb39Vs`R=BX;4HISfN^qW!{4 z^amy@Nqw6oqqobiNlxzxU*z2>2Q;9$Cr{K;*&l!;Y??vi^)G|tefJG9utf|~4xh=r3UjmRlADyLC*i`r+m;$7?7*bL!oR4=yU<8<-3XVA z%sAb`xe&4RV(2vj+1*ktLs<&m~mGJ@RuJ)1c zLxZyjg~*PfOeAm8R>7e&#FXBsfU_?azU=uxBm=E6z7FSr7J>{XY z1qUT>dh`X(zHRML_H-7He^P_?148AkDqrb>;~1M-k+xHVy>;D7p!z=XBgxMGQX2{* z-xMCOwS33&K^~3%#k`eIjKWvNe1f3y#}U4;J+#-{;=Xne^6+eH@eGJK#i|`~dgV5S zdn%`RHBsC!=9Q=&=wNbV#pDv6rgl?k1wM03*mN`dQBT4K%uRoyoH{e=ZL5E*`~X|T zbKG9aWI}7NGTQtjc3BYDTY3LbkgBNSHG$5xVx8gc@dEuJqT~QPBD=Scf53#kZzZ6W zM^$vkvMx+-0$6R^{{hZ2qLju~e85Em>1nDcRN3-Mm7x;87W#@RSIW9G>TT6Q{4e~b z8DN%n83FvXWdpr|I_8TaMv~MCqq0TA{AXYO-(~l=ug42gpMUvOjG_pWSEdDJ2Bxqz z!em;9=7y3HW*XUtK+M^)fycd8A6Q@B<4biGAR)r%gQf>lWI%WmMbij;un)qhk$bff zQxb{&L;`-1uvaCE7Fm*83^0;!QA5-zeSvKY}WjbwE68)jqnOmj^CTBHaD zvK6}Mc$a39b~Y(AoS|$%ePoHgMjIIux?;*;=Y|3zyfo)^fM=1GBbn7NCuKSxp1J|z zC>n4!X_w*R8es1ofcPrD>%e=E*@^)7gc?+JC@mJAYsXP;10~gZv0!Egi~){3mjVzs z^PrgddFewu>Ax_G&tj-!L=TuRl0FAh#X0gtQE#~}(dSyPO=@7yd zNC6l_?zs_u5&x8O zQ|_JvKf!WHf43F0R%NQwGQi-Dy7~PGZ@KRKMp?kxlaLAV=X{UkKgaTu2!qzPi8aJ z-;n$}unR?%uzCkMHwb56T%IUV)h>qS(XiuRLh3fdlr!Cri|{fZf0x9GVYUOlsKgxLA7vHrkpQddcSsg4JfibzpB zwR!vYiL)7%u8JG7^x@^px(t-c_Xt|9Dm)C@_zGeW_3nMLZBA*9*!fLTV$Uf1a0rDt zJI@Z6pdB9J(a|&T_&AocM2WLNB;fpLnlOFtC9yE6cb39?*1@wy8UgruTtX?@=<6YW zF%82|(F7ANWQ`#HPyPqG6~ggFlhJW#R>%p@fzrpL^K)Kbwj(@#7s97r`)iJ{&-ToR z$7(mQI@~;lwY+8dSKP~0G|#sjL2lS0LQP3Oe=>#NZ|JKKYd6s6qwe#_6Xz_^L4PJ5TM_|#&~zy= zabr|kkr3Osj;bPz`B0s;c&kzzQ2C8|tC9tz;es~zr{hom8bT?t$c|t;M0t2F{xI;G z`0`ADc_nJSdT`#PYCWu4R0Rmbk#PARx(NBfdU>8wxzE(`jA}atMEsaG6zy8^^nCu| z9_tLj90r-&Xc~+p%1vyt>=q_hQsDYB&-hPj(-OGxFpesWm;A(Lh>UWy4SH9&+mB(A z2jkTQ2C&o(Q4wC_>|c()M8_kF?qKhNB+PW6__;U+?ZUoDp2GNr<|*j(CC*#v0{L2E zgVBw6|3c(~V4N*WgJsO(I3o>8)EO5;p7Xg8yU&%rZ3QSRB6Ig6MK7Wn5r+xo2V}fM z0QpfDB9^xJEi}W*Fv6>=p4%@eP`K5k%kCE0YF2Eu5L!DM1ZY7wh`kghC^NwxrL}90dRXjQx=H>8 zOWP@<+C!tcw8EL8aCt9{|4aT+x|70i6m*LP*lhp;kGr5f#OwRy`(60LK@rd=to5yk^%N z6MTSk)7)#!cGDV@pbQ>$N8i2rAD$f{8T{QM+|gaj^sBt%24UJGF4ufrG1_Ag$Rn?c zzICg9`ICT>9N_2vqvVG#_lf9IEd%G5gJ_!j)1X#d^KUJBkE9?|K03AEe zo>5Rql|WuUU=LhLRkd&0rH4#!!>sMg@4Wr=z2|}dpOa`4c;_DqN{3Pj`AgSnc;h%# z{ny1lK%7?@rwZO(ZACq#8mL)|vy8tO0d1^4l;^e?hU+zuH%-8Y^5YqM9}sRzr-XC0 zPzY1l($LC-yyy*1@eoEANoTLQAZ2lVto2r7$|?;PPQX`}rbxPDH-a$8ez@J#v0R5n z7P*qT3aHj02*cK)WzZmoXkw?e3XNu&DkElGZ0Nk~wBti%yLh+l2DYx&U1lD_NW_Yt zGN>yOF?u%ksMW?^+~2&p@NoPzk`T)8qifG_owD>@iwI3@u^Y;Mqaa!2DGUKi{?U3d z|Efe=CBc!_ZDoa~LzZr}%;J|I$dntN24m4|1(#&Tw0R}lP`a`?uT;>szf^0mDJx3u z6IJvpeOpS$OV!Xw21p>Xu~MZ(Nas5Iim-#QSLIYSNhYgx1V!AR>b zf5b7O`ITTvW5z%X8|7>&BeEs8~J1i47l;`7Y#MUMReQ4z!IL1rh8UauKNPG?7rV_;#Y zG*6Vrt^SsTMOpV7mkui}l_S8UNOBcYi+DzcMF>YKrs3*(q5fwVCr;_zO?gpGx*@%O zl`KOwYMSUs4e&}eM#FhB3(RIDJ9ZRn6NN{2Nf+ z2jcz%-u6IPq{n7N3wLH{9c+}4G(NyZa`UmDr5c-SPgj0Sy$VN#Vxxr;kF>-P;5k!w zuAdrP(H+v{Dybn78xM6^*Ym@UGxx?L)m}WY#R>6M2zXnPL_M9#h($ECz^+(4HmKN7 zA>E;`AEqouHJd7pegrq4zkk>kHh`TEb`^(_ea;v{?MW3Sr^FXegkqAQPM-h^)$#Jn z?bKbnXR@k~%*?q`TPL=sD8C+n^I#08(}d$H(@Y;3*{~nv4RLZLw`v=1M0-%j>CtT( zTp#U03GAv{RFAtj4vln4#E4eLOvt zs;=`m&{S@AJbcl1q^39VOtmN^Zm(*x(`(SUgF(=6#&^7oA8T_ojX>V5sJx@*cV|29 z)6_%P6}e}`58Sd;LY2cWv~w}fer&_c1&mlY0`YNNk9q=TRg@Khc5E$N`aYng=!afD z@ewAv^jl$`U5;q4OxFM4ab%X_Jv>V!98w$8ZN*`D-)0S7Y^6xW$pQ%g3_lEmW9Ef^ zGmFsQw`E!ATjDvy@%mdcqrD-uiKB}!)ZRwpZRmyu+x|RUXS+oQ*_jIZKAD~U=3B|t zz>9QQr91qJihg9j9rWHww{v@+SYBzCfc0kI=4Gr{ZLcC~mft^EkJ`CMl?8fZ z3G4ix71=2dQ`5QuTOYA0(}f`@`@U<#K?1TI(XO9c*()q!Hf}JUCaUmg#y?ffT9w1g zc)e=JcF-9J`hK{0##K#A>m^@ZFx!$g09WSBdc8O^IdP&JE@O{i0&G!Ztvt{L4q%x& zGE2s!RVi6ZN9)E*(c33HuMf7#X2*VPVThdmrVz-Fyqxcs&aI4DvP#bfW={h$9>K0HsBTUf z2&!G;( z^oOVIYJv~OM=-i`6=r4Z1*hC8Fcf3rI9?;a_rL*nr@zxwKNlxf(-#Kgn@C~4?BdKk zYvL?QcQeDwwR5_S(`sn&{PL6FYxwb-qSh_rUUo{Yi-GZz5rZotG4R<+!PfsGg`MVtomw z5kzOZJrh(#rMR_87KeP0Q=#^5~r_?y1*kN?3Fq% zvnzHw$r!w|Soxz8Nbx2d&{!#w$^Hua%fx!xUbc2SI-<{h>e2I;$rJL)4)hnT5cx^* zIq#+{3;Leun3Xo=C(XVjt_z)F#PIoAw%SqJ=~DMQeB zNWQ={d|1qtlDS3xFik}#j*8%DG0<^6fW~|NGL#P_weHnJ(cYEdJtI9#1-Pa8M}(r{ zwnPJB_qB?IqZw5h!hRwW2WIEb?&F<52Ruxpr77O2K>=t*3&Z@=5(c^Uy&JSph}{Q^ z0Tl|}gt=&vK;Rb9Tx{{jUvhtmF>;~k$8T7kp;EV`C!~FKW|r$n^d6=thh`)^uYgBd zydgnY9&mm$?B@pKK+_QreOm?wnl5l}-wA$RZCZukfC$slxbqv9uKq0o^QeSID96{Rm^084kZ)*`P zk))V~+<4-_7d6<~)PL%!+%JP`Dn23vUpH47h~xnA=B_a}rLy|7U-f0W+fH`{wnyh2 zD$JYdXuygeP5&OAqpl2)BZ|X){~G;E|7{liYf%AZFmXXyA@32qLA)tuuQz`n^iH1Y z=)pAzxK$jw0Xq?7`M`=kN2WeQFhz)p;QhjbKg#SB zP~_Vqo0SGbc5Q;v4Q7vm6_#iT+p9B>%{s`8H}r|hAL5I8Q|ceJAL*eruzD8~_m>fg26HvLpik&#{3Zd#|1C_>l&-RW2nBBzSO zQ3%G{nI*T}jBjr%3fjG*&G#ruH^ioDM>0 zb0vSM8ML?tPU*y%aoCq;V%x%~!W*HaebuDn9qeT*vk0%X>fq-4zrrQf{Uq5zI1rEy zjQ@V|Cp~$AoBu=VgnVl@Yiro>ZF{uB=5)~i1rZzmDTIzLBy`8Too!#Z4nE$Z{~uB( z_=o=gKuhVpy&`}-c&f%**M&(|;2iy+nZy2Su}GOAH_GT9z`!ogwn$+Bi&1ZhtPF zVS&LO5#Bq}cew$kvE7*t8W^{{7&7WaF{upy0mj*K&xbnXvSP9V$6m6cesHGC!&Us36ld9f*Pn8gbJb3`PPT|ZG zri2?uIu09i>6Y-0-8sREOU?WaGke0+rHPb^sp;*E{Z5P7kFJ@RiLZTO`cN2mRR#Nz zxjJ##Nk+Uy-2N-8K_@576L(kJ>$UhP+)|w!SQHkkz+e62*hpzyfmY4eQLZtZUhEdG zIZluDOoPDlt5#iw+2epC3vEATfok^?SDT`TzBwtgKjY z>ZImbO)i~T=IYAfw$3j2mF1Cj*_yqK(qw(U^r-!gcUKvWQrDG@E{lEyWDWOPtA9v{ z5($&mxw{nZWo_Ov??S#Bo1;+YwVfx%M23|o$24Hdf^&4hQeV=Cffa5MMYOu2NZLSC zQ4UxWvn+8%YVGDg(Y*1iHbUyT^=gP*COcE~QkU|&6_3h z-GOS6-@o9+Vd(D7x#NYt{Bvx2`P&ZuCx#^l0bR89Hr6Vm<||c3Waq(KO0eZ zH(|B;X}{FaZ8_4yyWLdK!G_q9AYZcoOY}Jlf3R;%oR5dwR(rk7NqyF%{r>F4s^>li z`R~-fh>YIAC1?%!O?mxLx!dq*=%IRCj;vXX628aZ;+^M0CDFUY0Rc<1P5e(OVX8n- z*1UOrX{J}b2N)6m5&_xw^WSN=Lp$I$T>f8K6|J_bj%ZsIYKNs1$TFt!RuCWF48;98`7D(XPVnk+~~i=U$} zR#;!ZRo4eVqlDxjDeE^3+8)bzG_o~VRwdxqvD^HNh#@o>1My$0*Y_`wfQ$y}az|Uz zM47oEaYNTH?J^w9EVNnvfmmbV+GHDe)Kf;$^@6?9DrSHnk@*{PuJ>ra|9KO!qQ-Fp zNNcZB4ZdAI>jEh@3Mt(E1Fy!^gH-Zx6&lr8%=duIgI^~gC{Q;4yoe;#F7B`w9daIe z{(I;y)=)anc;C;)#P`8H6~iAG_q-4rPJb(6rn4pjclGi6$_L79sFAj#CTv;t@94S6 zz`Id7?k!#3JItckcwOf?sj=Xr6oKvAyt1=jiWN@XBFoW6dw_+c9O9x2i4or?*~8f& zm<>yzc6Aw_E-gsGAa`6`cjK~k^TJt(^`E1^_h)5(8)1kzAsBxjd4+!hJ&&T!qklDN z`?j#za=(^wRCvEI75uE^K#IBe5!5g2XW}|lUqAmdmIQb7xJtP}G9^(=!V`ZS_7#RZ zjXq#Cekw>fE*YS-?Qea|7~H?)bbLK;G&(~%!B@H`o#LYAuu6;-c~jFfjY7GKZ|9~{ zE!`!d@@rhY_@5fDbuQ8gRI~R_vs4%fR5$?yot4hDPJ28k_Wzmc^0yzwMr#*(OXq@g zRUgQmJA?E>3GO=5N8iWIfBP{&QM%!Oa*iwTlbd0Fbm*QCX>oRb*2XfG-=Bz1Qz0$v zn#X!2C!LqE601LEMq;X7`P*5nurdKZAmmsI-zZ|rTH;AFxNDyZ_#hN2m4W(|YB64E z470#yh$;8QzsdA;6vbNvc95HLvZvyT4{C>F(fwy&izvNDuvfO1Z;`Ss#4a_c6pm*{0t|_i9z{@84^lffQa5zG4<{(+p5-S z^>lG-^GJR#V>;5f3~y%n=`U_jBp~WgB0cp;Lx5VZYPYCH&(evw#}AYRlGJ>vcoeVr z3%#-QUBgeH!GB>XLw;rT&oMI9ynP;leDwh4O2uM!oIWo&Qxk{^9#nX&^3GJ z(U~5{S9aw@yHH^yuQGso=~*JOC9Zdi6(TFP+IddkfK5Eu9q;+F9?PPNAe-O;;P_Aa zPJ{Dqa1gQb%dZ|0I{#B0(z|r(qq!A4CxlW92-LwXFjYfOzAT1DDK`9rm4AB~l&oVv zi6_{)M9L1%JP}i52y@`!T9RB~!CRel53wl?amNHqcuElq%hn)|#BPvW5_m51RVb|? zXQ&B*eAD}}QamG>o{?i~usG5X6IDa3+Xkb8w%7;C8|Cln70biA+ZH}fxkH^Wei$vZPnuqIT!Mmy26;mLfU z3Bbv4M^vvMlz-I+46=g>0^wWkmA!hlYj*I!%it^x9Kx(d{L|+L{rW?Y#hLHWJfd5X z>B=Swk8=;mRtIz}Hr3NE_garb5W*!7fnNM{+m2_>!cHZZlNEeof~7M#FBEQ+f&gJ3 z^zv*t?XV)jQi%0-Ra|ISiW-fx)DsK-> zI}Fv%uee$#-1PKJwr=lU89eh=M{>Nk7IlJ)U33U)lLW+OOU%A|9-Lf;`@c*+vX{W2 z{{?0QoP!#?8=5%yL=fP%iF+?n$0#iHz`P;1{Ra6iwr=V7v^8;NoLJ5)QxIyIx>ur?lMwV=mBo0BA?28kMow8SX=Ax5L%S~x4+EQi#Ig`(ht%)D(F#Pa!)SiHy&PvUp32=VtAsR|6|NZR@jkad zX^aEgojf9(-)rNOZ=NVA&a;6Cljkb=H-bY9m^_I)`pBHB16QW)sU27zF13ypefeATJc1Wzy39GrKF{UntHsIU59AdXp?j{eh2R)IbU&omd zk6(qzvE@hve1yM6dgkbz>5HDR&MD~yi$yymQ}?b;RfL$N-#l7(u?T^Wlu+Q;fo|jd zBe^jzGMHY(2=5l?bEIh+zgE$1TEQ&!p3fH;AW`P?W5Hkj3eJnT>dqg! zf~}A*SZU5HHDCbdywQ^l_PqssHRlrySYN=`hAv2sVrtcF!`kyEu%XeeRUTJU7vB%h zY0*)N$mLo6d=tJfe}IPIeiH~>AKwCpkn&WEfYgl?3anq5#-F$6$v-(G_j0*S9mdsn zg@ek_ut4(?+JP_9-n`YqoD(gAz+Ttm1#t za96D}oQR(o=e8wwes19_(p4g(A1vSGwPAp~Hh3hh!fc>u{1E^+^}AzwilFVf6^vbL zc&NnRs`u)N-P|Cu4()yTiuE{j_V&=K?iP!IUBf~ei2}~_KBvUAlXa;R#Wl`gOBtJ$Y5(L))@`riLB)v*r>9*8VfmQt<72?+fdwP{BA@?_qo>mN7yzICUCaeG(+>Rb~8wg~6U(P)NlDLuhQgjbC}=)HuZgC}0Z-qLX4lJ7^)8~!!*qP0=~`Y_(A z{@15*ZevZSI^s|OnpCeCwLXf#tgbq8y~R*GB5anmZ;_N!+-3>!wu@NBFCNJ$#y?{? zMI!?s*=_xA;V&aX)ROxzVW8*de+&P#2zucA|8mksdgCXBsZ*TM=%{L1Tk5LB_*^@&S?O=ot{h)1xRVSn27&Tk8>rF|6ruzYb;Nq) z;qvlmrP^SL$mhe4Ai)xpl6Wx&y;z8o!7-+6$qj;ZLXvfR71I@w(R|6lyuP6v-lP&r z@KK-TEmGQfMmk1c0^fd7!^si}T%b5a2%>T-Drh|^Cf z$}qxIv@zxbmJ#qjK6Q_aGDe{ciVT20V1lW52Xs!}x(4_j)sUXYdm4 zwYC9FOa;X*c*LxL;xE5ov?|?^7gWXyALy_D2GvDo-8%0-Y%9TkkO_Tcr2qIUg3(OC z%3wt?hyn*+e^z%(~2#!2dvMFa$mzgwk1I1X;naFMjXSbnmZ!zd%7u)=cgi z*0&@Scrl&BDfU(9Pks8#;!~v~r7~DN{G6WE&_;7i{{a*?oiCao(l%2ruxX0fAt69e2vLgL%Mf_)!*(Tz zNKW>sW@YB2vBfP>C&L|-pq)Uq^PsG_THu;8iEcqafO?0k$IQp1KyWyOoTxwmKvlc^ zO9$%Tt8;%qQxwy5;CsJ)V}a7I6}SvQ%0_H53Kcqx=m83fIzpLSGgfVe^SPdc*xPdciI5dg}#{Etv$e<)gGD=qm0v=!aN@*?$s zLhzD%4w{vf-g6FHQjG9XyC+4=bewb?Mz%!u8%oP{G9{UJFTLTcCi3R(=Nm&t&Sl(? zr>pj?=ECdDVa}-g%`LF^1EY@>7d}%VhYpKFSDPH)D(zB+gPe1m7E}W>TiW=8L0&(D&YG=0<&7G4Bu{;-#Ud;-1%Ta9V}U6fyK1YX z`Rq|i-X(loPZ)M$H%m@j7bGx>uj~y=0)!t#dc|c}+hT%~Sq>fefez0Ul|jOJHta~u zx7*mV6~Jpt(FkY(pQN91>aFk7VS%Sa^oLaq$*)W?fy`xuFJgH<2s=!Rz}_(qdmdF~ zlr2f=)q_vpi8X;Jq>5^$GweJ{iS`Khw2f)fsvKpgh;U~13a+9 zfaw}UuGiBy;q10pI^Avb#X3D=k_r(T{N;-xA)OM}2Py5L##<96NU*Sr7GQqhfrPej z?;B$Bt_sTxuSAPXfTSC{zr?@$$0iHxC@z*5F52j*PG87hh`0w3At8jPf*rjNE~_Gj z2)fjeUFJ(#l9uWuw&5#@13|AQ1;pdA?EL4YKq0JDR5T8I?aWGxI=J9}vdyH;gQ@iE z>+UnC2iwT0f80-VuE^bY!N@(}9?bOXyy%rTqSNDN4rO4Zt#(kZwcGgTp&3((F+nsd ze~B)%K6oP4WX_w1>|QImC;9q zy}4p+s%^Too2(gE>yo%+yY#F{)phtmNqsJPVQQ0lGR|H9q>aA&AtU4M+EZ%`xvQLb zbigBOc`dL}&j3er?EOI`!W)N#>+uwp_!h^5FspaEylq!e(FPY-6T3~WeNmZ<$?Y6y z-!bM1kD7ZF8xl+Pi6fiv1?)q%`aNxn#pK%)ct||L&Xnf8Gu&3g;Of{B8Pt=u`e+Mn zA(DmU#3cF#Nr7W;X0V4ksFHMcNDAf4G&D8VjLeZ^|5-f$>_|71>P3xuu)?4NJed*w z6GR_RB5HQLzT(h+`Y?-3esxeue{-Q%b+!&o>IJ!#=}#_&q+hwJga>fkt(*(WdoN5vSta z#$mMN6}YzYRpaBZ)j)EL91-oL1(|d(>%UclsTUOyXyWM&(hNqLwqtn`!E>HJM{ zh>M~xa1@*U^cwx-k5QjePr5=B6u*jpJ)C0{C?f7Yga+I^4$TleyX$x&jm9z@c!?cC z<2kY7)p^+W{AXd@l1C09_yB*TG|yzb96BYk z8Wpj81vB>zcR+qM4m~A44w1n7$fxB$-?MV}S?Fh}c_|2FXg`cZ?750i;Cdl-_nGK# zta)h)6!*AsQ-z8caSh)%5JY>_yCeJs~FpAzdY8 zF@SU_hN#~ip5I;UACFzx1v0yf{j97l&)e-=`d#1Kp6A(Kj&HC!%vK!wEdK3HFJ?|6 za;WwUczZ+&<$g!Td^48@lJtfW@doXL#jY6)dK_RDCQAZ}l&OdD+?Yl5-bqpsHZR^( zF{u_cR(x>u(c4i5f(^8!h6CV0#ZxRFhLlunWiGDLO6yoRb(wV<(P^8=fOU7Hp{AHE z;Yg%kg@6&tL3Z*IrbkDeQ$%rbalVP39D@LVrC2xSavnTp%PorXPf1DVzHyqjDsDnS zL=mv0a2s60bHKGQM)ue>npH0SCp;XtZFUzm?R-x7D*(PxMmuJ4J*K2eY&ebe0yQHe zVG&*qe{pot{PM^xQv`H_rn2FcYOrEN+I#uX^1`Id%J$;Hi2cNCU!0Hlc0TjxLzkss zHxmC;hQBu5U4J0XflWM;{uH`_47Sg)QyZ{8D&T0;bdc3{^^<=q7P?C_2E-}PQn>*= z2T5q^J|Q_2+x%Qt`i3m6=6V$)BxIx{2KAFkMb#q`iMCD|L>+}_dYVA$wBr1Zr}YOF z^MMGO@PHGGh>g|^yF`PvvtDwN@kxt?ClLcG<+murHMz1Asj!$l=b)4{d}SqOJ}>Y< zSeAyP@ZEcpx`ayIdp>{--UVLYC_cZZURh_!4u2(*#x@Tk(QJa}4BqqZ$6%LhF-HB~ zAcc?$I6KP}IxANcAteEBX$Ys?T=JB|Fnd3*UAO0mYAXCgWf~?7Z_G7G5`H4;S^QKK zG*2l75vI@DHQC*es>6&|r^#RHKRQ5rwv_l4`!(!I3%)Z$P1fnZ8N@27zyg}54ElO%SjQ_4uujX)4ta@Gz2)_>4b~vX|rhRIH-eqdD zL)xaEpW3K|a>daQRRR*_$W>rWOsW-IE4VQl3L$3}=-PFU)s@XG&9+DFivH-;2&w~$ES_nJZJH!?1mO!CnP)Jb{mW9=f`bDpo^PI6i4|YurK)Q1 z^Ys1oHRdr!$X4RuyR%kgp!a*Lz*_AAoJ$EVAdsNCoPA^VZE1pGO@D3UStACE+%vs6 z$io@E>DmB|3VV~GbOt2oc+K;t zdn3gaFvYz;vRN-+2+Qk{8|O}e86nVck)fZn3sg$j#dLVham{yGkc$I#!HF7mRS%f* z!+NdzG49K(qaO^SBlp@K@D?|^rAq;8{*@kRc4sYSNQmoy7@_RS_ksWl2T_38h2A)# ziU2WXWD03(NqS&Mu*?0-iK8X_Z3w`}c7MPv0qZ7iM|L3xdTnR{y!7{#82$}uJCiGT zqa=8<9L05hu6 z1N+2n7OzT{NEf?gS@eq7@buCDFe9mAxY%THo^b@BHckKK>jg6{@)>n z43cPs%$Qi0iwyZ+{C491>FRu5+6baJ{&XXXC@Sp+b!QE|{7_d?lm5K=B z)myKEcxjFm74+drF|JCYcxdY%ASig#YoRBRUV7An7f-%rqj%PHECbxh#5476cEq@NQL?dI6gUqvS@w zq!WmD(aR0{NxItAZCKDCVw=Zu{9WGDu^i?2g zLerPiOU*HSaXg^3CdOX^F6c9MiHINP339N%)a96`^Z-c#&EogcxMSYo0Cb4{-}q1( zRrJine`P|6WRkm8u4Ja1QRYq$AR>b7tugd#EsT-VmXN-t!TYjZy}i!uKi6$u>EJ?w zvdHZg+hp+5ree?>fdJAX)5#Wtm#2M-{~2jfX2{G`)?D6UD1MevdeeU;;HCi}AtJr( SGW6ptSs!X7{rG*o_g?|vpSEZK diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bef08edb0..6b38c38f7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 071c637652125332626d0a475a549741be23eadf Mon Sep 17 00:00:00 2001 From: Timon Back Date: Mon, 16 Sep 2024 19:04:52 +0200 Subject: [PATCH 17/34] chore(gh): allow ui pipeline to publish to gh-pages branch --- .github/workflows/springwolf-ui.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/springwolf-ui.yml b/.github/workflows/springwolf-ui.yml index 0ff2f4f0f..a7fb981bf 100644 --- a/.github/workflows/springwolf-ui.yml +++ b/.github/workflows/springwolf-ui.yml @@ -9,7 +9,7 @@ on: workflow_dispatch: permissions: - contents: read + contents: write checks: write id-token: write From 1a7d14c1b31f77fbe260fe80f87d7d085ce6f2a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 16:39:05 +0200 Subject: [PATCH 18/34] chore(deps-dev): Bump @types/jest in /springwolf-ui (#976) Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 29.5.12 to 29.5.13. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest) --- updated-dependencies: - dependency-name: "@types/jest" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- springwolf-ui/package-lock.json | 8 ++++---- springwolf-ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/springwolf-ui/package-lock.json b/springwolf-ui/package-lock.json index 6f8866b0e..f38053257 100644 --- a/springwolf-ui/package-lock.json +++ b/springwolf-ui/package-lock.json @@ -32,7 +32,7 @@ "@angular/compiler-cli": "^18.1.2", "@asyncapi/parser": "^3.2.2", "@testing-library/angular": "^17.3.1", - "@types/jest": "^29.5.12", + "@types/jest": "^29.5.13", "@types/node": "^18.19.50", "angular-in-memory-web-api": "^0.18.0", "esbuild": "^0.23.1", @@ -6731,9 +6731,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.12", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", - "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "version": "29.5.13", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz", + "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==", "dev": true, "dependencies": { "expect": "^29.0.0", diff --git a/springwolf-ui/package.json b/springwolf-ui/package.json index 2bd940a3d..75f42c09e 100644 --- a/springwolf-ui/package.json +++ b/springwolf-ui/package.json @@ -35,7 +35,7 @@ "@angular/compiler-cli": "^18.1.2", "@asyncapi/parser": "^3.2.2", "@testing-library/angular": "^17.3.1", - "@types/jest": "^29.5.12", + "@types/jest": "^29.5.13", "@types/node": "^18.19.50", "angular-in-memory-web-api": "^0.18.0", "esbuild": "^0.23.1", From ae811bf0479c826cc8cf13f41072cebcaa0d9f94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 17:12:05 +0200 Subject: [PATCH 19/34] chore(deps): Bump the npm_and_yarn group (#973) Bumps the npm_and_yarn group in /springwolf-ui with 4 updates: [body-parser](https://github.com/expressjs/body-parser), [express](https://github.com/expressjs/express), [send](https://github.com/pillarjs/send) and [serve-static](https://github.com/expressjs/serve-static). Updates `body-parser` from 1.20.2 to 1.20.3 - [Release notes](https://github.com/expressjs/body-parser/releases) - [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md) - [Commits](https://github.com/expressjs/body-parser/compare/1.20.2...1.20.3) Updates `express` from 4.19.2 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) Updates `express` from 4.19.2 to 4.21.0 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) Updates `send` from 0.18.0 to 0.19.0 - [Release notes](https://github.com/pillarjs/send/releases) - [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md) - [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0) Updates `serve-static` from 1.15.0 to 1.16.2 - [Release notes](https://github.com/expressjs/serve-static/releases) - [Changelog](https://github.com/expressjs/serve-static/blob/v1.16.2/HISTORY.md) - [Commits](https://github.com/expressjs/serve-static/compare/v1.15.0...v1.16.2) --- updated-dependencies: - dependency-name: body-parser dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: express dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: express dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: send dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: serve-static dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- springwolf-ui/package-lock.json | 94 +++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/springwolf-ui/package-lock.json b/springwolf-ui/package-lock.json index f38053257..db50456f0 100644 --- a/springwolf-ui/package-lock.json +++ b/springwolf-ui/package-lock.json @@ -7891,9 +7891,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -7904,7 +7904,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -10056,9 +10056,9 @@ } }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "engines": { "node": ">= 0.8" @@ -10578,37 +10578,37 @@ "dev": true }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -10761,13 +10761,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -15335,10 +15335,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -17230,9 +17233,9 @@ "dev": true }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", "dev": true }, "node_modules/path-type": { @@ -17700,12 +17703,12 @@ ] }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -18475,9 +18478,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "dependencies": { "debug": "2.6.9", @@ -18513,6 +18516,15 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -18607,15 +18619,15 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" From 725dccd886c1b276561f97ce9251783aec9abe3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 17:30:14 +0200 Subject: [PATCH 20/34] chore(deps): Bump junitJupiterVersion from 5.10.3 to 5.11.0 (#933) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): Bump junitJupiterVersion from 5.10.3 to 5.11.0 Bumps `junitJupiterVersion` from 5.10.3 to 5.11.0. Updates `org.junit.jupiter:junit-jupiter-api` from 5.10.3 to 5.11.0 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.3...r5.11.0) Updates `org.junit.jupiter:junit-jupiter` from 5.10.3 to 5.11.0 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.3...r5.11.0) Updates `org.junit.jupiter:junit-jupiter-params` from 5.10.3 to 5.11.0 - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.3...r5.11.0) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.junit.jupiter:junit-jupiter dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.junit.jupiter:junit-jupiter-params dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * chore: use spring dependency management mechanism to configure junitJupiterVersion instead of manually overriding them * chore(stomp-example): move stomp example to correct package * chore(stomp-example): add explicit dependencies for mockito * chore(stomp-example): remove broken ProducerIntegrationTest --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: David Müller --- dependencies.gradle | 2 +- .../build.gradle | 7 +- .../springwolf-generic-binding/build.gradle | 9 ++- .../springwolf-json-schema/build.gradle | 10 ++- .../build.gradle | 8 +- springwolf-asyncapi/build.gradle | 8 +- .../springwolf-amqp-binding/build.gradle | 7 +- .../build.gradle | 7 +- .../springwolf-jms-binding/build.gradle | 7 +- .../springwolf-kafka-binding/build.gradle | 7 +- .../springwolf-sns-binding/build.gradle | 7 +- .../springwolf-sqs-binding/build.gradle | 7 +- .../springwolf-stomp-binding/build.gradle | 7 +- springwolf-core/build.gradle | 11 +-- .../springwolf-amqp-example/build.gradle | 8 +- .../build.gradle | 8 +- .../springwolf-jms-example/build.gradle | 9 ++- .../springwolf-kafka-example/build.gradle | 9 ++- .../springwolf-sns-example/build.gradle | 9 ++- .../springwolf-sqs-example/build.gradle | 10 ++- .../springwolf-stomp-example/build.gradle | 13 ++-- .../SpringwolfStompExampleApplication.java | 2 +- .../stomp/{stomp => }/config/Constants.java | 2 +- .../config/SessionConnectedEventListener.java | 2 +- .../{stomp => }/config/WebSocketConfig.java | 12 +-- .../config/WebSocketHandshake.java | 2 +- .../consumers/ExampleConsumer.java | 18 ++--- .../{stomp => }/dtos/AnotherPayloadDto.java | 2 +- .../{stomp => }/dtos/ExamplePayloadDto.java | 2 +- .../producers/AnotherProducer.java | 6 +- .../stomp/{stomp => }/ApiIntegrationTest.java | 2 +- .../stomp/{stomp => }/ApiSystemTest.java | 2 +- ...tompExampleApplicationIntegrationTest.java | 2 +- ...lfStompExampleResponseIntegrationTest.java | 28 +++---- .../stomp/stomp/ProducerIntegrationTest.java | 78 ------------------- .../stomp/{stomp => }/util/BaseStompUtil.java | 2 +- .../src/test/resources/asyncapi.json | 56 ++++++------- .../springwolf-amqp-plugin/build.gradle | 10 ++- .../build.gradle | 8 +- .../springwolf-jms-plugin/build.gradle | 8 +- .../springwolf-kafka-plugin/build.gradle | 8 +- .../springwolf-sns-plugin/build.gradle | 7 +- .../springwolf-sqs-plugin/build.gradle | 7 +- .../springwolf-stomp-plugin/build.gradle | 8 +- 44 files changed, 218 insertions(+), 226 deletions(-) rename springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/{stomp => }/SpringwolfStompExampleApplication.java (87%) rename springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/{stomp => }/config/Constants.java (93%) rename springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/{stomp => }/config/SessionConnectedEventListener.java (95%) rename springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/{stomp => }/config/WebSocketConfig.java (73%) rename springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/{stomp => }/config/WebSocketHandshake.java (93%) rename springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/{stomp => }/consumers/ExampleConsumer.java (65%) rename springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/{stomp => }/dtos/AnotherPayloadDto.java (92%) rename springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/{stomp => }/dtos/ExamplePayloadDto.java (93%) rename springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/{stomp => }/producers/AnotherProducer.java (82%) rename springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/{stomp => }/ApiIntegrationTest.java (95%) rename springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/{stomp => }/ApiSystemTest.java (98%) rename springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/{stomp => }/SpringwolfStompExampleApplicationIntegrationTest.java (91%) rename springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/{stomp => }/SpringwolfStompExampleResponseIntegrationTest.java (72%) delete mode 100644 springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ProducerIntegrationTest.java rename springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/{stomp => }/util/BaseStompUtil.java (98%) diff --git a/dependencies.gradle b/dependencies.gradle index 568bca3f6..673a461dd 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -62,7 +62,7 @@ ext { protobufJavaVersion = '4.28.1' - junitJupiterVersion = '5.10.3' + junitJupiterVersion = '5.11.0' jsonUnitAssertJVersion = '3.4.1' lombokVersion = '1.18.34' diff --git a/springwolf-add-ons/springwolf-common-model-converters/build.gradle b/springwolf-add-ons/springwolf-common-model-converters/build.gradle index 126b00a9a..866068e6d 100644 --- a/springwolf-add-ons/springwolf-common-model-converters/build.gradle +++ b/springwolf-add-ons/springwolf-common-model-converters/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { implementation "org.springframework:spring-context" @@ -18,8 +20,9 @@ dependencies { implementation "javax.money:money-api:${moneyApiVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-add-ons/springwolf-generic-binding/build.gradle b/springwolf-add-ons/springwolf-generic-binding/build.gradle index e8d31e2bf..2861be91c 100644 --- a/springwolf-add-ons/springwolf-generic-binding/build.gradle +++ b/springwolf-add-ons/springwolf-generic-binding/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-core") api project(":springwolf-asyncapi") @@ -20,11 +22,12 @@ dependencies { compileOnly "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testImplementation 'org.junit.jupiter:junit-jupiter-params' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-add-ons/springwolf-json-schema/build.gradle b/springwolf-add-ons/springwolf-json-schema/build.gradle index 7c90344d1..ad0db0a9d 100644 --- a/springwolf-add-ons/springwolf-json-schema/build.gradle +++ b/springwolf-add-ons/springwolf-json-schema/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-core") api project(":springwolf-asyncapi") @@ -27,9 +29,11 @@ dependencies { testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testImplementation 'org.junit.jupiter:junit-jupiter-params' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" testImplementation "com.networknt:json-schema-validator:${jsonSchemaValidator}" } diff --git a/springwolf-add-ons/springwolf-kotlinx-serialization-model-converter/build.gradle b/springwolf-add-ons/springwolf-kotlinx-serialization-model-converter/build.gradle index c691a64ff..1281fc9b1 100644 --- a/springwolf-add-ons/springwolf-kotlinx-serialization-model-converter/build.gradle +++ b/springwolf-add-ons/springwolf-kotlinx-serialization-model-converter/build.gradle @@ -16,6 +16,8 @@ plugins { id 'org.jetbrains.kotlin.plugin.serialization' version "${kotlinVersion}" } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-core") @@ -30,9 +32,11 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:${kotlinxSerializationVersion}" implementation "org.jetbrains.kotlin:kotlin-reflect" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-api" + testRuntimeOnly "org.junit.jupiter:junit-jupiter" + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "net.javacrumbs.json-unit:json-unit-assertj:${jsonUnitAssertJVersion}" } diff --git a/springwolf-asyncapi/build.gradle b/springwolf-asyncapi/build.gradle index 2aa8cac02..939a918ef 100644 --- a/springwolf-asyncapi/build.gradle +++ b/springwolf-asyncapi/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { implementation "io.swagger.core.v3:swagger-core-jakarta:${swaggerVersion}" implementation "jakarta.validation:jakarta.validation-api" @@ -21,14 +23,16 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" + 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:${jsonUnitAssertJVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-bindings/springwolf-amqp-binding/build.gradle b/springwolf-bindings/springwolf-amqp-binding/build.gradle index fbf270f6a..280e0520a 100644 --- a/springwolf-bindings/springwolf-amqp-binding/build.gradle +++ b/springwolf-bindings/springwolf-amqp-binding/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -18,10 +20,11 @@ dependencies { annotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-api" + testRuntimeOnly "org.junit.jupiter:junit-jupiter" + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle b/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle index 5a0745061..6c06a4e00 100644 --- a/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle +++ b/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -20,9 +22,10 @@ dependencies { annotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-api" + testRuntimeOnly "org.junit.jupiter:junit-jupiter" + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-bindings/springwolf-jms-binding/build.gradle b/springwolf-bindings/springwolf-jms-binding/build.gradle index c7e653ab3..ee9f15a04 100644 --- a/springwolf-bindings/springwolf-jms-binding/build.gradle +++ b/springwolf-bindings/springwolf-jms-binding/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -18,10 +20,11 @@ dependencies { annotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-api" + testRuntimeOnly "org.junit.jupiter:junit-jupiter" + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-bindings/springwolf-kafka-binding/build.gradle b/springwolf-bindings/springwolf-kafka-binding/build.gradle index 342a18da8..89d2ebd46 100644 --- a/springwolf-bindings/springwolf-kafka-binding/build.gradle +++ b/springwolf-bindings/springwolf-kafka-binding/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -20,10 +22,11 @@ dependencies { annotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-api" + testRuntimeOnly "org.junit.jupiter:junit-jupiter" + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-bindings/springwolf-sns-binding/build.gradle b/springwolf-bindings/springwolf-sns-binding/build.gradle index 13668bec2..d5dba67a0 100644 --- a/springwolf-bindings/springwolf-sns-binding/build.gradle +++ b/springwolf-bindings/springwolf-sns-binding/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -18,10 +20,11 @@ dependencies { annotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-api" + testRuntimeOnly "org.junit.jupiter:junit-jupiter" + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-bindings/springwolf-sqs-binding/build.gradle b/springwolf-bindings/springwolf-sqs-binding/build.gradle index 2de172da2..536521e71 100644 --- a/springwolf-bindings/springwolf-sqs-binding/build.gradle +++ b/springwolf-bindings/springwolf-sqs-binding/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -18,10 +20,11 @@ dependencies { annotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-api" + testRuntimeOnly "org.junit.jupiter:junit-jupiter" + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-bindings/springwolf-stomp-binding/build.gradle b/springwolf-bindings/springwolf-stomp-binding/build.gradle index 80b43947a..c67054754 100644 --- a/springwolf-bindings/springwolf-stomp-binding/build.gradle +++ b/springwolf-bindings/springwolf-stomp-binding/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -18,10 +20,11 @@ dependencies { annotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-core/build.gradle b/springwolf-core/build.gradle index 84b3093f5..bf84dc3a2 100644 --- a/springwolf-core/build.gradle +++ b/springwolf-core/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") @@ -45,18 +47,17 @@ dependencies { testImplementation project(":springwolf-add-ons:springwolf-common-model-converters") permitTestUnusedDeclared project(":springwolf-add-ons:springwolf-common-model-converters") - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.awaitility:awaitility:${awaitilityVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.mockito:mockito-junit-jupiter:${mockitoJunitJupiterVersion}" testImplementation "org.springframework.boot:spring-boot-test" testImplementation "org.springframework:spring-test" - permitTestUnusedDeclared "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" - - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-api" + testImplementation "org.junit.jupiter:junit-jupiter-params" + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' + testRuntimeOnly "org.slf4j:slf4j-simple:${slf4jSimpleVersion}" } jar { diff --git a/springwolf-examples/springwolf-amqp-example/build.gradle b/springwolf-examples/springwolf-amqp-example/build.gradle index 6091a537a..837afbb43 100644 --- a/springwolf-examples/springwolf-amqp-example/build.gradle +++ b/springwolf-examples/springwolf-amqp-example/build.gradle @@ -8,6 +8,8 @@ plugins { id 'com.bmuschko.docker-spring-boot-application' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { implementation project(":springwolf-core") implementation project(":springwolf-plugins:springwolf-amqp") @@ -33,12 +35,9 @@ dependencies { implementation "org.springframework:spring-context" implementation "org.springframework:spring-messaging" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" - testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.awaitility:awaitility:${awaitilityVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.springframework.boot:spring-boot-test" testImplementation "org.springframework:spring-beans" @@ -50,6 +49,9 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testCompileOnly "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } docker { diff --git a/springwolf-examples/springwolf-cloud-stream-example/build.gradle b/springwolf-examples/springwolf-cloud-stream-example/build.gradle index 6f225d98b..a7e3c315b 100644 --- a/springwolf-examples/springwolf-cloud-stream-example/build.gradle +++ b/springwolf-examples/springwolf-cloud-stream-example/build.gradle @@ -17,6 +17,8 @@ dependencyManagement { } } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { testImplementation project(":springwolf-core") @@ -41,9 +43,6 @@ dependencies { annotationProcessor "org.projectlombok:lombok:${lombokVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" - testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.springframework.boot:spring-boot-test" testImplementation "org.springframework:spring-test" @@ -56,6 +55,9 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testCompileOnly "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } docker { diff --git a/springwolf-examples/springwolf-jms-example/build.gradle b/springwolf-examples/springwolf-jms-example/build.gradle index 643648625..499fad783 100644 --- a/springwolf-examples/springwolf-jms-example/build.gradle +++ b/springwolf-examples/springwolf-jms-example/build.gradle @@ -8,6 +8,8 @@ plugins { id 'com.bmuschko.docker-spring-boot-application' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { implementation project(":springwolf-core") implementation project(":springwolf-add-ons:springwolf-generic-binding") @@ -35,10 +37,6 @@ dependencies { runtimeOnly "org.springframework.boot:spring-boot-starter-web" runtimeOnly "org.springframework.boot:spring-boot-starter-artemis" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" - - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.springframework.boot:spring-boot-test" @@ -51,6 +49,9 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testCompileOnly "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } docker { diff --git a/springwolf-examples/springwolf-kafka-example/build.gradle b/springwolf-examples/springwolf-kafka-example/build.gradle index 7f20fb5f0..d023f1d74 100644 --- a/springwolf-examples/springwolf-kafka-example/build.gradle +++ b/springwolf-examples/springwolf-kafka-example/build.gradle @@ -12,6 +12,8 @@ plugins { id 'com.google.protobuf' version '0.9.4' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { implementation project(":springwolf-core") implementation project(":springwolf-plugins:springwolf-kafka") @@ -66,8 +68,6 @@ dependencies { implementation "javax.money:money-api:${moneyApiVersion}" implementation "org.javamoney:moneta:${monetaVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.awaitility:awaitility:${awaitilityVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" @@ -79,8 +79,6 @@ dependencies { testImplementation "org.testcontainers:testcontainers:${testcontainersVersion}" testImplementation "org.testcontainers:junit-jupiter:${testcontainersVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" - permitTestUnusedDeclared "org.apache.kafka:kafka-clients:${kafkaClientsVersion}:test@jar" testImplementation("org.springframework.boot:spring-boot-starter-actuator") @@ -88,6 +86,9 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testCompileOnly "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } docker { diff --git a/springwolf-examples/springwolf-sns-example/build.gradle b/springwolf-examples/springwolf-sns-example/build.gradle index 71435af31..2a483eeb5 100644 --- a/springwolf-examples/springwolf-sns-example/build.gradle +++ b/springwolf-examples/springwolf-sns-example/build.gradle @@ -14,6 +14,8 @@ dependencyManagement { } } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { implementation project(":springwolf-core") implementation project(":springwolf-plugins:springwolf-sns") @@ -40,10 +42,6 @@ dependencies { implementation "org.springframework:spring-context" implementation "org.springframework:spring-messaging" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" - - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.springframework.boot:spring-boot-test" testImplementation "org.springframework:spring-beans" testImplementation "org.springframework:spring-web" @@ -55,6 +53,9 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testCompileOnly "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } docker { diff --git a/springwolf-examples/springwolf-sqs-example/build.gradle b/springwolf-examples/springwolf-sqs-example/build.gradle index fb79385cc..f6f36edc7 100644 --- a/springwolf-examples/springwolf-sqs-example/build.gradle +++ b/springwolf-examples/springwolf-sqs-example/build.gradle @@ -14,6 +14,8 @@ dependencyManagement { } } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { implementation project(":springwolf-core") implementation project(":springwolf-plugins:springwolf-sqs") @@ -38,10 +40,6 @@ dependencies { implementation "org.springframework.boot:spring-boot" implementation "org.springframework:spring-context" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" - - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.springframework.boot:spring-boot-test" @@ -55,6 +53,10 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testCompileOnly "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' + } docker { diff --git a/springwolf-examples/springwolf-stomp-example/build.gradle b/springwolf-examples/springwolf-stomp-example/build.gradle index 49161b3a5..5c4fe62f5 100644 --- a/springwolf-examples/springwolf-stomp-example/build.gradle +++ b/springwolf-examples/springwolf-stomp-example/build.gradle @@ -8,6 +8,8 @@ plugins { id 'com.bmuschko.docker-spring-boot-application' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { implementation project(":springwolf-core") implementation project(":springwolf-plugins:springwolf-stomp") @@ -33,16 +35,14 @@ dependencies { implementation "org.slf4j:slf4j-api:${slf4jApiVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.springframework.boot:spring-boot-test" testImplementation "org.springframework:spring-beans" testImplementation "org.springframework:spring-core" - testImplementation "org.springframework:spring-test" - permitTestUnusedDeclared "org.springframework:spring-test" testImplementation "org.springframework:spring-web" + permitTestUnusedDeclared "org.mockito:mockito-core:${mockitoCoreVersion}" + permitTestUnusedDeclared "org.mockito:mockito-junit-jupiter:${mockitoJunitJupiterVersion}" + testImplementation "org.testcontainers:testcontainers:${testcontainersVersion}" testImplementation "org.testcontainers:junit-jupiter:${testcontainersVersion}" @@ -50,6 +50,9 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testCompileOnly "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } docker { diff --git a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/SpringwolfStompExampleApplication.java b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/SpringwolfStompExampleApplication.java similarity index 87% rename from springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/SpringwolfStompExampleApplication.java rename to springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/SpringwolfStompExampleApplication.java index acbc2f8ac..820b59856 100644 --- a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/SpringwolfStompExampleApplication.java +++ b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/SpringwolfStompExampleApplication.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp; +package io.github.springwolf.examples.stomp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/Constants.java b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/Constants.java similarity index 93% rename from springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/Constants.java rename to springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/Constants.java index 103619c7a..5b1000477 100644 --- a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/Constants.java +++ b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/Constants.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp.config; +package io.github.springwolf.examples.stomp.config; public class Constants { diff --git a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/SessionConnectedEventListener.java b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/SessionConnectedEventListener.java similarity index 95% rename from springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/SessionConnectedEventListener.java rename to springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/SessionConnectedEventListener.java index d2005a381..0c156d602 100644 --- a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/SessionConnectedEventListener.java +++ b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/SessionConnectedEventListener.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp.config; +package io.github.springwolf.examples.stomp.config; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationListener; diff --git a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/WebSocketConfig.java b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/WebSocketConfig.java similarity index 73% rename from springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/WebSocketConfig.java rename to springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/WebSocketConfig.java index e756d381f..37ba13c0e 100644 --- a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/WebSocketConfig.java +++ b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/WebSocketConfig.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp.config; +package io.github.springwolf.examples.stomp.config; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; @@ -7,11 +7,11 @@ import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.WEBSOCKET_BROKER_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.WEBSOCKET_BROKER_TOPIC; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.WEBSOCKET_ENDPOINT; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.WEBSOCKET_PREFIX_APP; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.WEBSOCKET_PREFIX_USER; +import static io.github.springwolf.examples.stomp.config.Constants.WEBSOCKET_BROKER_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.WEBSOCKET_BROKER_TOPIC; +import static io.github.springwolf.examples.stomp.config.Constants.WEBSOCKET_ENDPOINT; +import static io.github.springwolf.examples.stomp.config.Constants.WEBSOCKET_PREFIX_APP; +import static io.github.springwolf.examples.stomp.config.Constants.WEBSOCKET_PREFIX_USER; @Configuration @EnableWebSocketMessageBroker diff --git a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/WebSocketHandshake.java b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/WebSocketHandshake.java similarity index 93% rename from springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/WebSocketHandshake.java rename to springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/WebSocketHandshake.java index 44b84cd62..7e6b31c2a 100644 --- a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/config/WebSocketHandshake.java +++ b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/config/WebSocketHandshake.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp.config; +package io.github.springwolf.examples.stomp.config; import com.sun.security.auth.UserPrincipal; import lombok.val; diff --git a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/consumers/ExampleConsumer.java b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/consumers/ExampleConsumer.java similarity index 65% rename from springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/consumers/ExampleConsumer.java rename to springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/consumers/ExampleConsumer.java index 19f3f1985..e7acfe8b8 100644 --- a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/consumers/ExampleConsumer.java +++ b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/consumers/ExampleConsumer.java @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp.consumers; +package io.github.springwolf.examples.stomp.consumers; -import io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto; -import io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto; -import io.github.springwolf.examples.stomp.stomp.producers.AnotherProducer; +import io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto; +import io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto; +import io.github.springwolf.examples.stomp.producers.AnotherProducer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.handler.annotation.MessageMapping; @@ -11,11 +11,11 @@ import org.springframework.messaging.simp.annotation.SendToUser; import org.springframework.stereotype.Controller; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.EXAMPLE_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.SENDTOUSER_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.SENDTOUSER_RESPONSE_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.SENDTO_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.SENDTO_RESPONSE_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.EXAMPLE_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.SENDTOUSER_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.SENDTOUSER_RESPONSE_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.SENDTO_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.SENDTO_RESPONSE_QUEUE; @Controller @RequiredArgsConstructor diff --git a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/dtos/AnotherPayloadDto.java b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/dtos/AnotherPayloadDto.java similarity index 92% rename from springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/dtos/AnotherPayloadDto.java rename to springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/dtos/AnotherPayloadDto.java index 2ed5229a3..1e71b4a40 100644 --- a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/dtos/AnotherPayloadDto.java +++ b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/dtos/AnotherPayloadDto.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp.dtos; +package io.github.springwolf.examples.stomp.dtos; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; diff --git a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/dtos/ExamplePayloadDto.java b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/dtos/ExamplePayloadDto.java similarity index 93% rename from springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/dtos/ExamplePayloadDto.java rename to springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/dtos/ExamplePayloadDto.java index 81ac6809b..97a171046 100644 --- a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/dtos/ExamplePayloadDto.java +++ b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/dtos/ExamplePayloadDto.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp.dtos; +package io.github.springwolf.examples.stomp.dtos; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; diff --git a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/producers/AnotherProducer.java b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/producers/AnotherProducer.java similarity index 82% rename from springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/producers/AnotherProducer.java rename to springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/producers/AnotherProducer.java index dd49dc6c1..d75e8bfae 100644 --- a/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/stomp/producers/AnotherProducer.java +++ b/springwolf-examples/springwolf-stomp-example/src/main/java/io/github/springwolf/examples/stomp/producers/AnotherProducer.java @@ -1,16 +1,16 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp.producers; +package io.github.springwolf.examples.stomp.producers; import io.github.springwolf.bindings.stomp.annotations.StompAsyncOperationBinding; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.annotations.AsyncPublisher; -import io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto; +import io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.simp.SimpMessageSendingOperations; import org.springframework.stereotype.Component; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.ANOTHER_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.ANOTHER_QUEUE; @Component @RequiredArgsConstructor diff --git a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiIntegrationTest.java b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/ApiIntegrationTest.java similarity index 95% rename from springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiIntegrationTest.java rename to springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/ApiIntegrationTest.java index bdeb42e33..5035bea6a 100644 --- a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiIntegrationTest.java +++ b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/ApiIntegrationTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp; +package io.github.springwolf.examples.stomp; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiSystemTest.java b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/ApiSystemTest.java similarity index 98% rename from springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiSystemTest.java rename to springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/ApiSystemTest.java index d8a8d5723..26a8c398b 100644 --- a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ApiSystemTest.java +++ b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/ApiSystemTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp; +package io.github.springwolf.examples.stomp; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; diff --git a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/SpringwolfStompExampleApplicationIntegrationTest.java b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/SpringwolfStompExampleApplicationIntegrationTest.java similarity index 91% rename from springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/SpringwolfStompExampleApplicationIntegrationTest.java rename to springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/SpringwolfStompExampleApplicationIntegrationTest.java index 6f53b08f5..afcbb37ca 100644 --- a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/SpringwolfStompExampleApplicationIntegrationTest.java +++ b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/SpringwolfStompExampleApplicationIntegrationTest.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp; +package io.github.springwolf.examples.stomp; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/SpringwolfStompExampleResponseIntegrationTest.java b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/SpringwolfStompExampleResponseIntegrationTest.java similarity index 72% rename from springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/SpringwolfStompExampleResponseIntegrationTest.java rename to springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/SpringwolfStompExampleResponseIntegrationTest.java index d1fddb892..5129dba8e 100644 --- a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/SpringwolfStompExampleResponseIntegrationTest.java +++ b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/SpringwolfStompExampleResponseIntegrationTest.java @@ -1,9 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp; +package io.github.springwolf.examples.stomp; -import io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto; -import io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto; -import io.github.springwolf.examples.stomp.stomp.util.BaseStompUtil; +import io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto; +import io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto; +import io.github.springwolf.examples.stomp.util.BaseStompUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @@ -17,16 +17,16 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.ANOTHER_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.EXAMPLE_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.SENDTOUSER_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.SENDTOUSER_RESPONSE_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.SENDTO_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.SENDTO_RESPONSE_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.WEBSOCKET_ENDPOINT; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.WEBSOCKET_PREFIX_APP; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.WEBSOCKET_PREFIX_USER; -import static io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto.ExampleEnum.FOO1; +import static io.github.springwolf.examples.stomp.config.Constants.ANOTHER_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.EXAMPLE_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.SENDTOUSER_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.SENDTOUSER_RESPONSE_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.SENDTO_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.SENDTO_RESPONSE_QUEUE; +import static io.github.springwolf.examples.stomp.config.Constants.WEBSOCKET_ENDPOINT; +import static io.github.springwolf.examples.stomp.config.Constants.WEBSOCKET_PREFIX_APP; +import static io.github.springwolf.examples.stomp.config.Constants.WEBSOCKET_PREFIX_USER; +import static io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto.ExampleEnum.FOO1; import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) diff --git a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ProducerIntegrationTest.java b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ProducerIntegrationTest.java deleted file mode 100644 index 11ed90456..000000000 --- a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/ProducerIntegrationTest.java +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp; - -import io.github.springwolf.examples.stomp.stomp.consumers.ExampleConsumer; -import io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto; -import io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto; -import io.github.springwolf.examples.stomp.stomp.util.BaseStompUtil; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.SpyBean; -import org.springframework.boot.test.web.server.LocalServerPort; -import org.springframework.web.socket.client.standard.StandardWebSocketClient; -import org.springframework.web.socket.messaging.WebSocketStompClient; -import org.springframework.web.socket.sockjs.client.SockJsClient; -import org.springframework.web.socket.sockjs.client.WebSocketTransport; - -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - -import static io.github.springwolf.examples.stomp.stomp.config.Constants.ANOTHER_QUEUE; -import static io.github.springwolf.examples.stomp.stomp.config.Constants.WEBSOCKET_ENDPOINT; -import static io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto.ExampleEnum.FOO1; -import static org.junit.jupiter.api.Assertions.assertEquals; - -/** - * While the assertion of this test is identical to ApiIntegrationTests, - * the setup uses a full docker-compose context. - */ -@SpringBootTest( - classes = {SpringwolfStompExampleApplication.class}, - webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -// @Ignore("Uncomment this line if you have issues running this test on your local machine.") -@Disabled("SpringwolfStompProducer has not been implemented yet.") -public class ProducerIntegrationTest { - - // @Autowired - // SpringwolfStompProducer springwolfStompProducer; // TODO: - - @SpyBean - ExampleConsumer exampleConsumer; - - @LocalServerPort - private int port; - - private String wsPath; - private WebSocketStompClient webSocketStompClient; - - private final ExamplePayloadDto payload = new ExamplePayloadDto(); - - @BeforeEach - void setup() { - wsPath = String.format("ws://localhost:%d/%s", port, WEBSOCKET_ENDPOINT); - webSocketStompClient = new WebSocketStompClient( - new SockJsClient(List.of(new WebSocketTransport(new StandardWebSocketClient())))); - - payload.setSomeString("foo"); - payload.setSomeLong(5); - payload.setSomeEnum(FOO1); - } - - @Test - void producerCanUseSpringwolfConfigurationToSendMessage() - throws ExecutionException, InterruptedException, TimeoutException { - // given - BaseStompUtil stompTestUtil = - new BaseStompUtil<>(webSocketStompClient, wsPath, List.of(ANOTHER_QUEUE), AnotherPayloadDto.class); - - // when - // springwolfStompProducer.send("example-queue", payload); // TODO: - - // then - AnotherPayloadDto response = stompTestUtil.getMessage(); - assertEquals(response.getExample(), payload); - } -} diff --git a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/util/BaseStompUtil.java b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/util/BaseStompUtil.java similarity index 98% rename from springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/util/BaseStompUtil.java rename to springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/util/BaseStompUtil.java index 757268d12..187c4f422 100644 --- a/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/stomp/util/BaseStompUtil.java +++ b/springwolf-examples/springwolf-stomp-example/src/test/java/io/github/springwolf/examples/stomp/util/BaseStompUtil.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.examples.stomp.stomp.util; +package io.github.springwolf.examples.stomp.util; import jakarta.annotation.Nullable; import lombok.extern.slf4j.Slf4j; diff --git a/springwolf-examples/springwolf-stomp-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-stomp-example/src/test/resources/asyncapi.json index 15f428340..c44b99cd0 100644 --- a/springwolf-examples/springwolf-stomp-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-stomp-example/src/test/resources/asyncapi.json @@ -25,16 +25,16 @@ "_app_queue_another-queue": { "address": "/app/queue/another-queue", "messages": { - "io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto": { - "$ref": "#/components/messages/io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto" + "io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto" } } }, "_app_queue_example-queue": { "address": "/app/queue/example-queue", "messages": { - "io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto": { - "$ref": "#/components/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } }, "bindings": { @@ -44,8 +44,8 @@ "_app_queue_sendto-queue": { "address": "/app/queue/sendto-queue", "messages": { - "io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto": { - "$ref": "#/components/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } }, "bindings": { @@ -55,8 +55,8 @@ "_app_queue_sendtouser-queue": { "address": "/app/queue/sendtouser-queue", "messages": { - "io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto": { - "$ref": "#/components/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } }, "bindings": { @@ -66,8 +66,8 @@ "_app_topic_sendto-response-queue": { "address": "/app/topic/sendto-response-queue", "messages": { - "io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto": { - "$ref": "#/components/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } }, "bindings": { @@ -77,8 +77,8 @@ "_user_queue_sendtouser-response-queue": { "address": "/user/queue/sendtouser-response-queue", "messages": { - "io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto": { - "$ref": "#/components/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } }, "bindings": { @@ -105,12 +105,12 @@ { } ] }, - "io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto": { + "io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto": { "title": "AnotherPayloadDto", "type": "object", "properties": { "example": { - "$ref": "#/components/schemas/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "$ref": "#/components/schemas/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" }, "foo": { "type": "string", @@ -136,7 +136,7 @@ "example" ] }, - "io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto": { + "io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto": { "title": "ExamplePayloadDto", "type": "object", "properties": { @@ -184,33 +184,33 @@ } }, "messages": { - "io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto": { + "io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto": { "headers": { "$ref": "#/components/schemas/HeadersNotDocumented" }, "payload": { "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", "schema": { - "$ref": "#/components/schemas/io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto" + "$ref": "#/components/schemas/io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto" } }, - "name": "io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto", + "name": "io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto", "title": "AnotherPayloadDto", "bindings": { "stomp": { } } }, - "io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto": { + "io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto": { "headers": { "$ref": "#/components/schemas/SpringStompDefaultHeaders" }, "payload": { "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", "schema": { - "$ref": "#/components/schemas/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "$ref": "#/components/schemas/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } }, - "name": "io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto", + "name": "io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto", "title": "ExamplePayloadDto", "bindings": { "stomp": { } @@ -231,7 +231,7 @@ }, "messages": [ { - "$ref": "#/channels/_app_queue_another-queue/messages/io.github.springwolf.examples.stomp.stomp.dtos.AnotherPayloadDto" + "$ref": "#/channels/_app_queue_another-queue/messages/io.github.springwolf.examples.stomp.dtos.AnotherPayloadDto" } ] }, @@ -245,7 +245,7 @@ }, "messages": [ { - "$ref": "#/channels/_app_queue_example-queue/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "$ref": "#/channels/_app_queue_example-queue/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } ] }, @@ -259,7 +259,7 @@ }, "messages": [ { - "$ref": "#/channels/_app_queue_sendto-queue/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "$ref": "#/channels/_app_queue_sendto-queue/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } ], "reply": { @@ -268,7 +268,7 @@ }, "messages": [ { - "$ref": "#/channels/_app_topic_sendto-response-queue/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "$ref": "#/channels/_app_topic_sendto-response-queue/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } ] } @@ -283,7 +283,7 @@ }, "messages": [ { - "$ref": "#/channels/_app_queue_sendtouser-queue/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "$ref": "#/channels/_app_queue_sendtouser-queue/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } ], "reply": { @@ -292,10 +292,10 @@ }, "messages": [ { - "$ref": "#/channels/_user_queue_sendtouser-response-queue/messages/io.github.springwolf.examples.stomp.stomp.dtos.ExamplePayloadDto" + "$ref": "#/channels/_user_queue_sendtouser-response-queue/messages/io.github.springwolf.examples.stomp.dtos.ExamplePayloadDto" } ] } } } -} \ No newline at end of file +} diff --git a/springwolf-plugins/springwolf-amqp-plugin/build.gradle b/springwolf-plugins/springwolf-amqp-plugin/build.gradle index 57819cd88..0456765da 100644 --- a/springwolf-plugins/springwolf-amqp-plugin/build.gradle +++ b/springwolf-plugins/springwolf-amqp-plugin/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-core") api project(":springwolf-asyncapi") @@ -32,8 +34,7 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation("org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}") + testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" @@ -41,8 +42,11 @@ dependencies { testImplementation "org.springframework:spring-beans" testImplementation "org.springframework:spring-test" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testImplementation("org.junit.jupiter:junit-jupiter-params") + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } jar { diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/build.gradle b/springwolf-plugins/springwolf-cloud-stream-plugin/build.gradle index a36e98644..dce7fd588 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/build.gradle +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/build.gradle @@ -16,6 +16,8 @@ dependencyManagement { } } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -31,11 +33,8 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" - testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.apache.kafka:kafka-streams:${kafkaStreamsVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.springframework.boot:spring-boot" @@ -43,6 +42,9 @@ dependencies { testImplementation "org.springframework:spring-beans" testImplementation "org.springframework:spring-test" testImplementation "org.springframework:spring-messaging" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } jar { diff --git a/springwolf-plugins/springwolf-jms-plugin/build.gradle b/springwolf-plugins/springwolf-jms-plugin/build.gradle index 97e2dd5f5..b58753e5a 100644 --- a/springwolf-plugins/springwolf-jms-plugin/build.gradle +++ b/springwolf-plugins/springwolf-jms-plugin/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -32,15 +34,12 @@ dependencies { annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" testRuntimeOnly "org.springframework.boot:spring-boot-starter-web" testImplementation "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.springframework:spring-beans" @@ -52,6 +51,9 @@ dependencies { testImplementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testCompileOnly "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } jar { diff --git a/springwolf-plugins/springwolf-kafka-plugin/build.gradle b/springwolf-plugins/springwolf-kafka-plugin/build.gradle index c182fcdb3..008af29e9 100644 --- a/springwolf-plugins/springwolf-kafka-plugin/build.gradle +++ b/springwolf-plugins/springwolf-kafka-plugin/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -36,14 +38,11 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testCompileOnly "org.projectlombok:lombok:${lombokVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" testRuntimeOnly "org.springframework.boot:spring-boot-starter-web" testImplementation "com.fasterxml.jackson.core:jackson-annotations:${jacksonVersion}" testImplementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.mockito:mockito-junit-jupiter:${mockitoJunitJupiterVersion}" @@ -54,6 +53,9 @@ dependencies { testImplementation "org.springframework:spring-test" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } jar { diff --git a/springwolf-plugins/springwolf-sns-plugin/build.gradle b/springwolf-plugins/springwolf-sns-plugin/build.gradle index e684e9977..48b282a2c 100644 --- a/springwolf-plugins/springwolf-sns-plugin/build.gradle +++ b/springwolf-plugins/springwolf-sns-plugin/build.gradle @@ -12,6 +12,8 @@ dependencyManagement { } } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-core") api project(":springwolf-bindings:springwolf-sns-binding") @@ -38,15 +40,16 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.springframework.boot:spring-boot-test" testImplementation "org.springframework:spring-beans" testImplementation "org.springframework:spring-test" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } jar { diff --git a/springwolf-plugins/springwolf-sqs-plugin/build.gradle b/springwolf-plugins/springwolf-sqs-plugin/build.gradle index cdeebdddd..f76a19074 100644 --- a/springwolf-plugins/springwolf-sqs-plugin/build.gradle +++ b/springwolf-plugins/springwolf-sqs-plugin/build.gradle @@ -12,6 +12,8 @@ dependencyManagement { } } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -39,15 +41,16 @@ dependencies { testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.springframework.boot:spring-boot-test" testImplementation "org.springframework:spring-beans" testImplementation "org.springframework:spring-test" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } jar { diff --git a/springwolf-plugins/springwolf-stomp-plugin/build.gradle b/springwolf-plugins/springwolf-stomp-plugin/build.gradle index 7b40302cb..63dfd654f 100644 --- a/springwolf-plugins/springwolf-stomp-plugin/build.gradle +++ b/springwolf-plugins/springwolf-stomp-plugin/build.gradle @@ -6,6 +6,8 @@ plugins { id 'ca.cutterslade.analyze' } +ext['junit-jupiter.version'] = "${junitJupiterVersion}" + dependencies { api project(":springwolf-asyncapi") api project(":springwolf-core") @@ -32,14 +34,14 @@ dependencies { compileOnly "org.projectlombok:lombok:${lombokVersion}" testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" testRuntimeOnly "org.springframework.boot:spring-boot-starter-web" - testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" - testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" + + testImplementation 'org.junit.jupiter:junit-jupiter-api' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter' } jar { From 104bd3bd0514f36127a0df92c858b193873c8294 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 17:57:08 +0200 Subject: [PATCH 21/34] chore(deps): Bump the dependencies-angular group across 1 directory with 12 updates (#983) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): Bump the dependencies-angular group across 1 directory with 12 updates Bumps the dependencies-angular group with 12 updates in the /springwolf-ui directory: | Package | From | To | | --- | --- | --- | | [@angular/animations](https://github.com/angular/angular/tree/HEAD/packages/animations) | `18.1.2` | `18.2.5` | | [@angular/cdk](https://github.com/angular/components) | `18.1.2` | `18.2.5` | | [@angular/common](https://github.com/angular/angular/tree/HEAD/packages/common) | `18.1.2` | `18.2.5` | | [@angular/compiler](https://github.com/angular/angular/tree/HEAD/packages/compiler) | `18.1.2` | `18.2.5` | | [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) | `18.1.2` | `18.2.5` | | [@angular/material](https://github.com/angular/components) | `18.1.2` | `18.2.5` | | [@angular/platform-browser](https://github.com/angular/angular/tree/HEAD/packages/platform-browser) | `18.1.2` | `18.2.5` | | [@angular/platform-browser-dynamic](https://github.com/angular/angular/tree/HEAD/packages/platform-browser-dynamic) | `18.1.2` | `18.2.5` | | [@angular/router](https://github.com/angular/angular/tree/HEAD/packages/router) | `18.1.2` | `18.2.5` | | [@angular-devkit/build-angular](https://github.com/angular/angular-cli) | `18.1.2` | `18.2.5` | | [@angular/cli](https://github.com/angular/angular-cli) | `18.1.2` | `18.2.5` | | [@angular/compiler-cli](https://github.com/angular/angular/tree/HEAD/packages/compiler-cli) | `18.1.2` | `18.2.5` | Updates `@angular/animations` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/animations) Updates `@angular/cdk` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/components/releases) - [Changelog](https://github.com/angular/components/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/components/compare/18.1.2...18.2.5) Updates `@angular/common` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/common) Updates `@angular/compiler` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/compiler) Updates `@angular/core` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/core) Updates `@angular/material` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/components/releases) - [Changelog](https://github.com/angular/components/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/components/compare/18.1.2...18.2.5) Updates `@angular/platform-browser` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/platform-browser) Updates `@angular/platform-browser-dynamic` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/platform-browser-dynamic) Updates `@angular/router` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/router) Updates `@angular-devkit/build-angular` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/18.1.2...18.2.5) Updates `@angular/cli` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/18.1.2...18.2.5) Updates `@angular/compiler-cli` from 18.1.2 to 18.2.5 - [Release notes](https://github.com/angular/angular/releases) - [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular/commits/18.2.5/packages/compiler-cli) --- updated-dependencies: - dependency-name: "@angular/animations" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/cdk" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/common" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/compiler" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/core" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/material" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/platform-browser" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/platform-browser-dynamic" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/router" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular-devkit/build-angular" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/cli" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dependencies-angular - dependency-name: "@angular/compiler-cli" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dependencies-angular ... Signed-off-by: dependabot[bot] * chore(ui): bump @angular/forms from 18.1.2 to 18.2.5 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: David Müller --- springwolf-ui/package-lock.json | 2183 ++++++++++++++----------------- springwolf-ui/package.json | 26 +- 2 files changed, 985 insertions(+), 1224 deletions(-) diff --git a/springwolf-ui/package-lock.json b/springwolf-ui/package-lock.json index db50456f0..79db472dd 100644 --- a/springwolf-ui/package-lock.json +++ b/springwolf-ui/package-lock.json @@ -8,16 +8,16 @@ "name": "springwolf-ui", "version": "0.0.0", "dependencies": { - "@angular/animations": "^18.1.2", - "@angular/cdk": "^18.1.2", - "@angular/common": "^18.1.2", - "@angular/compiler": "^18.1.2", - "@angular/core": "^18.1.2", - "@angular/forms": "^18.1.2", - "@angular/material": "^18.1.2", - "@angular/platform-browser": "^18.1.2", - "@angular/platform-browser-dynamic": "^18.1.2", - "@angular/router": "^18.1.2", + "@angular/animations": "^18.2.5", + "@angular/cdk": "^18.2.5", + "@angular/common": "^18.2.5", + "@angular/compiler": "^18.2.5", + "@angular/core": "^18.2.5", + "@angular/forms": "^18.2.5", + "@angular/material": "^18.2.5", + "@angular/platform-browser": "^18.2.5", + "@angular/platform-browser-dynamic": "^18.2.5", + "@angular/router": "^18.2.5", "marked": "^12.0.2", "ngx-markdown": "^18.0.0", "prism-code-editor": "^3.4.0", @@ -27,9 +27,9 @@ "zone.js": "~0.14.10" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.1.2", - "@angular/cli": "^18.1.2", - "@angular/compiler-cli": "^18.1.2", + "@angular-devkit/build-angular": "^18.2.5", + "@angular/cli": "^18.2.5", + "@angular/compiler-cli": "^18.2.5", "@asyncapi/parser": "^3.2.2", "@testing-library/angular": "^17.3.1", "@types/jest": "^29.5.13", @@ -56,12 +56,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1801.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1801.2.tgz", - "integrity": "sha512-y2rV8wRwTnmCH/dUo632wHi6r41Gs9XucyGm/ybzB/5tN3x6dS+O3c3zajRpdqTUr8YcD6os6sT+Ay6zS31tOw==", + "version": "0.1802.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.5.tgz", + "integrity": "sha512-c7sVoW85Yqj7IYvNKxtNSGS5I7gWpORorg/xxLZX3OkHWXDrwYbb5LN/2p5/Aytxyb0aXl4o5fFOu6CUwcaLUw==", "dev": true, "dependencies": { - "@angular-devkit/core": "18.1.2", + "@angular-devkit/core": "18.2.5", "rxjs": "7.8.1" }, "engines": { @@ -71,47 +71,47 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.1.2.tgz", - "integrity": "sha512-f4X6UOOHghofMwsYK/3ZAskI3ocSyw14J2SExz7hBPIQicoJgnrzloOkYUkXBWv2q0n11m9wjOlQV+4KPGqJQw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.5.tgz", + "integrity": "sha512-dIvb0AHoRIMM6tLuG4t6lDDslSAYP77wqytodsN317UzFOuuCPernXbO8NJs+QHxj09nPsem1T5vnvpO2E/PVQ==", "dev": true, "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1801.2", - "@angular-devkit/build-webpack": "0.1801.2", - "@angular-devkit/core": "18.1.2", - "@angular/build": "18.1.2", - "@babel/core": "7.24.7", - "@babel/generator": "7.24.7", + "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/build-webpack": "0.1802.5", + "@angular-devkit/core": "18.2.5", + "@angular/build": "18.2.5", + "@babel/core": "7.25.2", + "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", - "@babel/plugin-transform-async-generator-functions": "7.24.7", + "@babel/plugin-transform-async-generator-functions": "7.25.0", "@babel/plugin-transform-async-to-generator": "7.24.7", "@babel/plugin-transform-runtime": "7.24.7", - "@babel/preset-env": "7.24.7", - "@babel/runtime": "7.24.7", - "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "18.1.2", + "@babel/preset-env": "7.25.3", + "@babel/runtime": "7.25.0", + "@discoveryjs/json-ext": "0.6.1", + "@ngtools/webpack": "18.2.5", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", - "autoprefixer": "10.4.19", + "autoprefixer": "10.4.20", "babel-loader": "9.1.3", "browserslist": "^4.21.5", "copy-webpack-plugin": "12.0.2", "critters": "0.0.24", "css-loader": "7.1.2", - "esbuild-wasm": "0.21.5", + "esbuild-wasm": "0.23.0", "fast-glob": "3.3.2", "http-proxy-middleware": "3.0.0", "https-proxy-agent": "7.0.5", - "istanbul-lib-instrument": "6.0.2", + "istanbul-lib-instrument": "6.0.3", "jsonc-parser": "3.3.1", "karma-source-map-support": "1.4.0", "less": "4.2.0", "less-loader": "12.2.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.3.1", - "magic-string": "0.30.10", + "magic-string": "0.30.11", "mini-css-extract-plugin": "2.9.0", "mrmime": "2.0.0", "open": "10.1.0", @@ -119,25 +119,24 @@ "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", "piscina": "4.6.1", - "postcss": "8.4.38", + "postcss": "8.4.41", "postcss-loader": "8.1.1", "resolve-url-loader": "5.0.0", "rxjs": "7.8.1", "sass": "1.77.6", - "sass-loader": "14.2.1", - "semver": "7.6.2", + "sass-loader": "16.0.0", + "semver": "7.6.3", "source-map-loader": "5.0.0", "source-map-support": "0.5.21", - "terser": "5.29.2", + "terser": "5.31.6", "tree-kill": "1.2.2", "tslib": "2.6.3", - "undici": "6.19.2", - "vite": "5.3.2", + "vite": "5.4.6", "watchpack": "2.4.1", - "webpack": "5.92.1", - "webpack-dev-middleware": "7.2.1", + "webpack": "5.94.0", + "webpack-dev-middleware": "7.4.2", "webpack-dev-server": "5.0.4", - "webpack-merge": "5.10.0", + "webpack-merge": "6.0.1", "webpack-subresource-integrity": "5.1.0" }, "engines": { @@ -146,7 +145,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.21.5" + "esbuild": "0.23.0" }, "peerDependencies": { "@angular/compiler-cli": "^18.0.0", @@ -200,9 +199,9 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", + "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", "cpu": [ "ppc64" ], @@ -212,13 +211,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", + "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", "cpu": [ "arm" ], @@ -228,13 +227,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", + "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", "cpu": [ "arm64" ], @@ -244,13 +243,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", + "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", "cpu": [ "x64" ], @@ -260,13 +259,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", "cpu": [ "arm64" ], @@ -276,13 +275,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", "cpu": [ "x64" ], @@ -292,13 +291,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", + "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", "cpu": [ "arm64" ], @@ -308,13 +307,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", + "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", "cpu": [ "x64" ], @@ -324,13 +323,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", + "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", "cpu": [ "arm" ], @@ -340,13 +339,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", "cpu": [ "arm64" ], @@ -356,13 +355,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", + "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", "cpu": [ "ia32" ], @@ -372,13 +371,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", + "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", "cpu": [ "loong64" ], @@ -388,13 +387,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", + "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", "cpu": [ "mips64el" ], @@ -404,13 +403,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", + "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", "cpu": [ "ppc64" ], @@ -420,13 +419,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", + "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", "cpu": [ "riscv64" ], @@ -436,13 +435,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", + "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", "cpu": [ "s390x" ], @@ -452,13 +451,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", "cpu": [ "x64" ], @@ -468,13 +467,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", + "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", "cpu": [ "x64" ], @@ -484,13 +483,29 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", + "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", + "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", "cpu": [ "x64" ], @@ -500,13 +515,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", + "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", "cpu": [ "x64" ], @@ -516,13 +531,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", "cpu": [ "arm64" ], @@ -532,13 +547,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", + "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", "cpu": [ "ia32" ], @@ -548,13 +563,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", "cpu": [ "x64" ], @@ -564,13 +579,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular-devkit/build-angular/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, "optional": true, @@ -578,32 +593,61 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/postcss": { + "version": "8.4.41", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz", + "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.1", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" } }, "node_modules/@angular-devkit/build-angular/node_modules/tslib": { @@ -613,12 +657,12 @@ "dev": true }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1801.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1801.2.tgz", - "integrity": "sha512-S960l/BPfEAgiYs35PpqXKwg+vJbdnOAXD6MCLTMz+T/h3go/D+FtQWLLV4kP6222BMFJHl3/sd4Q6cvpEo0eg==", + "version": "0.1802.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.5.tgz", + "integrity": "sha512-6qkcrWBdkxojCVHGWcdJaz4G+7QTjFvmc+3g8xvLc9sYvJq1I059gfXhDnC0FxiA0MT4cY/26ECYWUHTD5CJLQ==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1801.2", + "@angular-devkit/architect": "0.1802.5", "rxjs": "7.8.1" }, "engines": { @@ -632,12 +676,12 @@ } }, "node_modules/@angular-devkit/core": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.1.2.tgz", - "integrity": "sha512-WYkdKT/Ime5seBX7S7S4aWQbgCG5U3otCvAg/XiMn6scexTo3EZe2jrJl8nxGGFHNWrePoD86LvJOxhnCkEKEA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.5.tgz", + "integrity": "sha512-r9TumPlJ8PvA2+yz4sp+bUHgtznaVKzhvXTN5qL1k4YP8LJ7iZWMR2FOP+HjukHZOTsenzmV9pszbogabqwoZQ==", "dev": true, "dependencies": { - "ajv": "8.16.0", + "ajv": "8.17.1", "ajv-formats": "3.0.1", "jsonc-parser": "3.3.1", "picomatch": "4.0.2", @@ -659,14 +703,14 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.1.2.tgz", - "integrity": "sha512-v8aCJ1tPPzXsdiCoZxkc6YzLGhzJgC/6QauT03/Z6wWo8uI6DKibQQwQBawRE5FN5lKDpuGlNDv40EDtVYkQSA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.5.tgz", + "integrity": "sha512-NUmz2UQ1Xl4cf4j1AgkwIfsCjBzAPgfeC3IBrD29hSOBE1Y3j6auqjBkvw50v6mbSPxESND995Xy13HpK1Xflw==", "dev": true, "dependencies": { - "@angular-devkit/core": "18.1.2", + "@angular-devkit/core": "18.2.5", "jsonc-parser": "3.3.1", - "magic-string": "0.30.10", + "magic-string": "0.30.11", "ora": "5.4.1", "rxjs": "7.8.1" }, @@ -677,9 +721,9 @@ } }, "node_modules/@angular/animations": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.1.2.tgz", - "integrity": "sha512-Gbqp3TSrkDOQgxCMK7qm+IBFxw8+IgyA//S5ZgXt2qrrhQWVDF4uQJbzusqDSUcHpdtOD05X81NFgUc8f13UFA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.2.5.tgz", + "integrity": "sha512-IlXtW/Nj48ZzjHUzH1TykZcSR64ScJx39T3IHnjV2z/bVATzZ36JGoadQHdqpJNKBodYJNgtJCGLCbgAvGWY2g==", "dependencies": { "tslib": "^2.3.0" }, @@ -687,41 +731,39 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.1.2" + "@angular/core": "18.2.5" } }, "node_modules/@angular/build": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.1.2.tgz", - "integrity": "sha512-DuXXjE4x3tDedZQTsZBRuMCkYfYSdChtnxyf2F0CywKIfcsogbhyt8bYoUyC8yJp2CLyTamdvJGcI1Gh1678Zw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.5.tgz", + "integrity": "sha512-XWkmjzgeUga0SJ0lYSYcTuYOWTyqcln2mNfBp7Ae/GZ+/7+APbedsIZEiZGZwveOIyOpTM5wguNSoe9khDl5Ig==", "dev": true, "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1801.2", - "@babel/core": "7.24.7", + "@angular-devkit/architect": "0.1802.5", + "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", "@babel/plugin-syntax-import-attributes": "7.24.7", - "@inquirer/confirm": "3.1.11", + "@inquirer/confirm": "3.1.22", "@vitejs/plugin-basic-ssl": "1.1.0", - "ansi-colors": "4.1.3", "browserslist": "^4.23.0", "critters": "0.0.24", - "esbuild": "0.21.5", + "esbuild": "0.23.0", "fast-glob": "3.3.2", "https-proxy-agent": "7.0.5", - "lmdb": "3.0.12", - "magic-string": "0.30.10", + "listr2": "8.2.4", + "lmdb": "3.0.13", + "magic-string": "0.30.11", "mrmime": "2.0.0", - "ora": "5.4.1", "parse5-html-rewriting-stream": "7.0.0", "picomatch": "4.0.2", "piscina": "4.6.1", - "rollup": "4.18.0", + "rollup": "4.20.0", "sass": "1.77.6", - "semver": "7.6.2", - "undici": "6.19.2", - "vite": "5.3.2", + "semver": "7.6.3", + "vite": "5.4.6", "watchpack": "2.4.1" }, "engines": { @@ -761,9 +803,9 @@ } }, "node_modules/@angular/build/node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", + "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", "cpu": [ "ppc64" ], @@ -773,13 +815,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", + "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", "cpu": [ "arm" ], @@ -789,13 +831,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", + "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", "cpu": [ "arm64" ], @@ -805,13 +847,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", + "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", "cpu": [ "x64" ], @@ -821,13 +863,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", "cpu": [ "arm64" ], @@ -837,13 +879,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", "cpu": [ "x64" ], @@ -853,13 +895,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", + "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", "cpu": [ "arm64" ], @@ -869,13 +911,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", + "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", "cpu": [ "x64" ], @@ -885,13 +927,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", + "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", "cpu": [ "arm" ], @@ -901,13 +943,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", "cpu": [ "arm64" ], @@ -917,13 +959,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", + "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", "cpu": [ "ia32" ], @@ -933,13 +975,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", + "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", "cpu": [ "loong64" ], @@ -949,13 +991,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", + "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", "cpu": [ "mips64el" ], @@ -965,13 +1007,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", + "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", "cpu": [ "ppc64" ], @@ -981,13 +1023,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", + "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", "cpu": [ "riscv64" ], @@ -997,13 +1039,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", + "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", "cpu": [ "s390x" ], @@ -1013,13 +1055,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", "cpu": [ "x64" ], @@ -1029,13 +1071,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", + "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", "cpu": [ "x64" ], @@ -1045,13 +1087,29 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", + "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", + "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", "cpu": [ "x64" ], @@ -1061,13 +1119,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", + "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", "cpu": [ "x64" ], @@ -1077,13 +1135,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", "cpu": [ "arm64" ], @@ -1093,13 +1151,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", + "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", "cpu": [ "ia32" ], @@ -1109,13 +1167,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", "cpu": [ "x64" ], @@ -1125,51 +1183,52 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@angular/build/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" } }, "node_modules/@angular/cdk": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.1.2.tgz", - "integrity": "sha512-yiAJ/9AMVF2zk7VLEuyJxNJwpV84xLlf0zCaXiYIs6Z8xU6m8N9KR2nqxC59gQc4nTjItmoO/Sgk7XH0X4yGOQ==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.2.5.tgz", + "integrity": "sha512-HLg5cfrIrgNIJJ+0v3kLieHeLPJLFNOBO359holXOrKUPRG+XQ3CT8EzSvREFm1XkaSEsDC0+dnG0ouNhOPFpQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -1183,26 +1242,26 @@ } }, "node_modules/@angular/cli": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.1.2.tgz", - "integrity": "sha512-5H0scWgJcDE3NSM6/j/xSwNfAQBVOhVjXuj+nZOaEkJC0Bxh6AoEdWpQdzmZ6qSlx4LMlJYI6P/sH0kiBlFfgA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.5.tgz", + "integrity": "sha512-97uNs0HsOdnMaTlNJKFjIBUXw0wz43uYvSSKmIpBt7eq1LaPLju1G/qpDIHx2YwhMClPrXXrW2H/xdvqZiIw+w==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1801.2", - "@angular-devkit/core": "18.1.2", - "@angular-devkit/schematics": "18.1.2", - "@inquirer/prompts": "5.0.7", - "@listr2/prompt-adapter-inquirer": "2.0.13", - "@schematics/angular": "18.1.2", + "@angular-devkit/architect": "0.1802.5", + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", + "@inquirer/prompts": "5.3.8", + "@listr2/prompt-adapter-inquirer": "2.0.15", + "@schematics/angular": "18.2.5", "@yarnpkg/lockfile": "1.1.0", "ini": "4.1.3", "jsonc-parser": "3.3.1", - "listr2": "8.2.3", - "npm-package-arg": "11.0.2", - "npm-pick-manifest": "9.0.1", + "listr2": "8.2.4", + "npm-package-arg": "11.0.3", + "npm-pick-manifest": "9.1.0", "pacote": "18.0.6", "resolve": "1.22.8", - "semver": "7.6.2", + "semver": "7.6.3", "symbol-observable": "4.0.0", "yargs": "17.7.2" }, @@ -1216,9 +1275,9 @@ } }, "node_modules/@angular/common": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.1.2.tgz", - "integrity": "sha512-PXzRH5fCSmjGwNvopPfwAxcMqQPFLamyIjVJa5mwTyk5FLhKNrNecSo7m6ZpsfLPsW5Ipk/ups9RJD0Mep82Hw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.2.5.tgz", + "integrity": "sha512-m+KJrtbFXTE36jP/po6UAMeUR/enQxRHpVGLCRcIcE7VWVH1ZcOvoW1yqh2A6k+KxWXeajlq/Z04nnMhcoxMRw==", "dependencies": { "tslib": "^2.3.0" }, @@ -1226,14 +1285,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.1.2", + "@angular/core": "18.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.1.2.tgz", - "integrity": "sha512-ePoSW4S899bN+QKYFCDUHX8tSvycPxncduqsG403IHzawelG8cRMjtxNAN01tJvN1KcKwR6YUYdWt8PYgipBhw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.2.5.tgz", + "integrity": "sha512-vcqe9x4dGGAnMfPhEpcZyiSVgAiqJeK80LqP1vWoAmBR+HeOqAilSv6SflcLAtuTzwgzMMAvD2T+SMCgUvaqww==", "dependencies": { "tslib": "^2.3.0" }, @@ -1241,7 +1300,7 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.1.2" + "@angular/core": "18.2.5" }, "peerDependenciesMeta": { "@angular/core": { @@ -1250,12 +1309,12 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.1.2.tgz", - "integrity": "sha512-u8VMgPFECfu+Usl8nrl6zVPDEjnXK0XH5DdQPVo4c3NDI6zStugLJbQ+OLIsHYfzJHdxxVSsF56URG5OcVTLEw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.2.5.tgz", + "integrity": "sha512-CCCtZobUTUfId/RTYtuDCw5R1oK0w65hdAUMRP1MdGmd8bb8DKJA86u1QCWwozL3rbXlIIX4ognQ6urQ43k/Gw==", "dev": true, "dependencies": { - "@babel/core": "7.24.9", + "@babel/core": "7.25.2", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", @@ -1273,74 +1332,14 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.1.2", + "@angular/compiler": "18.2.5", "typescript": ">=5.4 <5.6" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/generator": { - "version": "7.24.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", - "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.9", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@angular/core": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.1.2.tgz", - "integrity": "sha512-/wiewpA8KpEkXf3E/Q0+0H3Dgg5zCG/+vzAUVIOGP+0tYk8no0NUecHyXLjz0hRQOJ6a3zMKVtZO3wYl8WNGEg==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.5.tgz", + "integrity": "sha512-5BLVc5gXxzanQkADNS9WPsor3vNF5nQcyIHBi5VScErwM5vVZ7ATH1iZwaOg1ykDEVTFVhKDwD0X1aaqGDbhmQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -1349,13 +1348,14 @@ }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.14.0" + "zone.js": "~0.14.10" } }, "node_modules/@angular/forms": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.1.2.tgz", - "integrity": "sha512-R0drnkmiU74XHMKUnrgxJNW3WHtKKsVMualyUANR26+SH07ZZFvuvXTx7u0pbh0d1JFK3hlWvZO7X52x1bH37w==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.2.5.tgz", + "integrity": "sha512-ohKeH+EZCCIyGSiFYlraWLzssGAZc13P92cuYpXB62322PkcA5u0IT72mML9JWGKRqF2zteVsw4koWHVxXM5mA==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, @@ -1363,22 +1363,22 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.2", - "@angular/core": "18.1.2", - "@angular/platform-browser": "18.1.2", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/platform-browser": "18.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/material": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.1.2.tgz", - "integrity": "sha512-B56pofk3WMqqtNww2W33KRbAu69c+aGYFdNFW45DcdIw9OKV1x/HjhyEchSrUOPOXgJFVTYw2HRhp327ONpetw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.2.5.tgz", + "integrity": "sha512-+Yz8ayKz1ALz2UvPrM33FHSUmrE0GKHn+Gg79l6NdC4eSrzAAYBVdLfQvCBWCgtdvs7IiegbCnnAJiqXVC1DDg==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "^18.0.0 || ^19.0.0", - "@angular/cdk": "18.1.2", + "@angular/cdk": "18.2.5", "@angular/common": "^18.0.0 || ^19.0.0", "@angular/core": "^18.0.0 || ^19.0.0", "@angular/forms": "^18.0.0 || ^19.0.0", @@ -1387,9 +1387,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.1.2.tgz", - "integrity": "sha512-G/9dU6J+RyJ4qfWcxgVdUsVEF/2lQKCpC24spongOwn7yCTrORkopFEmuuwftZXaFoduxE2Q1i4GCiQkqcHRwQ==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.2.5.tgz", + "integrity": "sha512-PoX9idwnOpTJBlujzZ2nFGOsmCnZzOH7uNSWIR7trdoq0b1AFXfrxlCQ36qWamk7bbhJI4H28L8YTmKew/nXDA==", "dependencies": { "tslib": "^2.3.0" }, @@ -1397,9 +1397,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.1.2", - "@angular/common": "18.1.2", - "@angular/core": "18.1.2" + "@angular/animations": "18.2.5", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5" }, "peerDependenciesMeta": { "@angular/animations": { @@ -1408,9 +1408,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.1.2.tgz", - "integrity": "sha512-97sQTZbkOOQONSgJ/WsEfkH7FEaLShqJUaHiWaT00W95h+qmOhM2M00JtxZoREUK2HmH+Hoq/Triu1DC4RrtnQ==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.2.5.tgz", + "integrity": "sha512-5u0IuAt1r5e2u2vSKhp3phnaf6hH89B/q7GErfPse1sdDfNI6wHVppxai28PAfAj9gwooJun6MjFWhJFLzS44A==", "dependencies": { "tslib": "^2.3.0" }, @@ -1418,16 +1418,16 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.2", - "@angular/compiler": "18.1.2", - "@angular/core": "18.1.2", - "@angular/platform-browser": "18.1.2" + "@angular/common": "18.2.5", + "@angular/compiler": "18.2.5", + "@angular/core": "18.2.5", + "@angular/platform-browser": "18.2.5" } }, "node_modules/@angular/router": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.1.2.tgz", - "integrity": "sha512-2+3IbCsnD+PukwrdD2oW7H69hPNs4raMzmiufD0HyTz8C75G1mYvRCzaf8qN41e9r/AsIGzwrczw30AgnCEmzw==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.2.5.tgz", + "integrity": "sha512-OjZV1PTiSwT0ytmR0ykveLYzs4uQWf0EuIclZmWqM/bb8Q4P+gJl7/sya05nGnZsj6nHGOL0e/LhSZ3N+5p6qg==", "dependencies": { "tslib": "^2.3.0" }, @@ -1435,9 +1435,9 @@ "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.1.2", - "@angular/core": "18.1.2", - "@angular/platform-browser": "18.1.2", + "@angular/common": "18.2.5", + "@angular/core": "18.2.5", + "@angular/platform-browser": "18.2.5", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -1468,22 +1468,6 @@ "node-fetch": "2.6.7" } }, - "node_modules/@asyncapi/parser/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@asyncapi/parser/node_modules/ajv-formats": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", @@ -1524,30 +1508,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", - "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -1578,12 +1562,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dev": true, "dependencies": { - "@babel/types": "^7.24.7", + "@babel/types": "^7.25.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -1618,12 +1602,12 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.8", + "@babel/compat-data": "^7.25.2", "@babel/helper-validator-option": "^7.24.8", "browserslist": "^4.23.1", "lru-cache": "^5.1.1", @@ -1643,19 +1627,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz", - "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", "@babel/helper-member-expression-to-functions": "^7.24.8", "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/traverse": "^7.25.4", "semver": "^6.3.1" }, "engines": { @@ -1675,9 +1657,9 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", @@ -1716,43 +1698,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", @@ -1780,16 +1725,15 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", - "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -1820,14 +1764,14 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1837,14 +1781,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1919,28 +1863,27 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", - "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", "dev": true, "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.8" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" }, "engines": { "node": ">=6.9.0" @@ -1962,10 +1905,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", "dev": true, + "dependencies": { + "@babel/types": "^7.25.6" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -1974,13 +1920,28 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1990,12 +1951,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2022,13 +1983,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -2125,12 +2086,12 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.6.tgz", + "integrity": "sha512-aABl0jHw9bZ2karQ/uUD6XP4u0SG22SJrOHFoL6XB1R7dTovOP4TzTlsxOYC5yQ1pdscVK2JTUnF6QL3ARoAiQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2342,15 +2303,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz", + "integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -2392,12 +2353,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2407,13 +2368,13 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", - "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.4.tgz", + "integrity": "sha512-nZeZHyCWPfjkdU5pA/uHiTaDAFUEqkpzf1YoQT2NeSynCGYq9rxfyI3XpQbfx/a0hSnFH6TGlEXvae5Vi7GD8g==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2440,18 +2401,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz", - "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", + "integrity": "sha512-oexUfaQle2pF/b6E0dwsxQtAol9TLSO88kQvym6HHBWFliV2lGdrPieX+WgMRLSJDVzdYywk7jXbLPuO2KLTLg==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", + "@babel/helper-compilation-targets": "^7.25.2", "@babel/helper-plugin-utils": "^7.24.8", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.4", "globals": "^11.1.0" }, "engines": { @@ -2523,6 +2482,22 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", @@ -2588,14 +2563,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" }, "engines": { "node": ">=6.9.0" @@ -2621,12 +2596,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -2700,15 +2675,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", "dev": true, "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -2879,13 +2854,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", - "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.4.tgz", + "integrity": "sha512-ao8BG7E2b/URaUQGqN3Tlsg+M3KlHY6rJ1O1gXAEUnZoyNQnvKyH87Kfg+FoxSeyWUB8ISZZsC91C44ZuBFytw==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.4", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -3111,13 +3086,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", - "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.4.tgz", + "integrity": "sha512-qesBxiWkgN1Q+31xUE9RcMk79eOXXDCv6tfyGMRSs4RGlioSg2WVyQAm07k726cSE56pa+Kb0y9epX2qaXzTvA==", "dev": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -3127,19 +3102,20 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.7.tgz", - "integrity": "sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz", + "integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/compat-data": "^7.25.2", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -3160,29 +3136,30 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.0", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.0", "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-dotall-regex": "^7.24.7", "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", "@babel/plugin-transform-dynamic-import": "^7.24.7", "@babel/plugin-transform-exponentiation-operator": "^7.24.7", "@babel/plugin-transform-export-namespace-from": "^7.24.7", "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-member-expression-literals": "^7.24.7", "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", "@babel/plugin-transform-modules-umd": "^7.24.7", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-new-target": "^7.24.7", @@ -3191,7 +3168,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-object-super": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", @@ -3202,7 +3179,7 @@ "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", "@babel/plugin-transform-unicode-escapes": "^7.24.7", "@babel/plugin-transform-unicode-property-regex": "^7.24.7", "@babel/plugin-transform-unicode-regex": "^7.24.7", @@ -3211,7 +3188,7 @@ "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.4", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", + "core-js-compat": "^3.37.1", "semver": "^6.3.1" }, "engines": { @@ -3251,9 +3228,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -3263,33 +3240,30 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -3298,12 +3272,12 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.24.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", - "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", "dev": true, "dependencies": { - "@babel/types": "^7.24.9", + "@babel/types": "^7.25.6", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -3313,9 +3287,9 @@ } }, "node_modules/@babel/types": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", - "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.24.8", @@ -3339,12 +3313,12 @@ "optional": true }, "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.1.tgz", + "integrity": "sha512-boghen8F0Q8D+0/Q1/1r6DUEieUJ8w2a1gIknExMSHBsJFOr2+0KUfHiVYBvucPwl3+RU5PFBK833FjFCh3BhA==", "dev": true, "engines": { - "node": ">=10.0.0" + "node": ">=14.17.0" } }, "node_modules/@esbuild/aix-ppc64": { @@ -3732,415 +3706,231 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.4.2.tgz", - "integrity": "sha512-iZRNbTlSB9xXt/+jdMFViBdxw1ILWu3365rzfM5OLwAyOScbDFFGSH7LEUwoq1uOIo48ymOEwYSqP5y8hQMlmA==", - "dev": true, - "dependencies": { - "@inquirer/core": "^9.0.5", - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/checkbox/node_modules/@inquirer/core": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.5.tgz", - "integrity": "sha512-QWG41I7vn62O9stYKg/juKXt1PEbr/4ZZCPb4KgXDQGwgA9M5NBTQ7FnOvT1ridbxkm/wTxLCNraUs7y47pIRQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-2.5.0.tgz", + "integrity": "sha512-sMgdETOfi2dUHT8r7TT1BTKOwNvdDGFDXYWtQ2J69SvlYNntk9I/gJe7r5yvMwwsuKnYbuRs3pNhx4tgNck5aA==", "dev": true, "dependencies": { + "@inquirer/core": "^9.1.0", "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", - "@types/mute-stream": "^0.0.4", - "@types/node": "^20.14.11", - "@types/wrap-ansi": "^3.0.0", + "@inquirer/type": "^1.5.3", "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/checkbox/node_modules/@types/node": { - "version": "20.14.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", - "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/@inquirer/confirm": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.11.tgz", - "integrity": "sha512-3wWw10VPxQP279FO4bzWsf8YjIAq7NdwATJ4xS2h1uwsXZu/RmtOVV95rZ7yllS1h/dzu+uLewjMAzNDEj8h2w==", + "version": "3.1.22", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.22.tgz", + "integrity": "sha512-gsAKIOWBm2Q87CDfs9fEo7wJT3fwWIJfnDGMn9Qy74gBnNFOACDNfhUzovubbJjWnKLGBln7/NcSmZwj5DuEXg==", "dev": true, "dependencies": { - "@inquirer/core": "^8.2.4", - "@inquirer/type": "^1.3.3" + "@inquirer/core": "^9.0.10", + "@inquirer/type": "^1.5.2" }, "engines": { "node": ">=18" } }, "node_modules/@inquirer/core": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-8.2.4.tgz", - "integrity": "sha512-7vsXSfxtrrbwMTirfaKwPcjqJy7pzeuF/bP62yo1NQrRJ5HjmMlrhZml/Ljm9ODc1RnbhJlTeSnCkjtFddKjwA==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.2.1.tgz", + "integrity": "sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg==", "dev": true, "dependencies": { - "@inquirer/figures": "^1.0.3", - "@inquirer/type": "^1.3.3", + "@inquirer/figures": "^1.0.6", + "@inquirer/type": "^2.0.0", "@types/mute-stream": "^0.0.4", - "@types/node": "^20.14.9", + "@types/node": "^22.5.5", "@types/wrap-ansi": "^3.0.0", "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", "cli-width": "^4.1.0", "mute-stream": "^1.0.0", - "picocolors": "^1.0.1", "signal-exit": "^4.1.0", "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/core/node_modules/@types/node": { - "version": "20.14.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", - "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@inquirer/editor": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.1.17.tgz", - "integrity": "sha512-hwx3VpFQzOY2hFWnY+XPsUGCIUVQ5kYxH6+CExv/RbMiAoN3zXtzj8DyrWBOHami0vBrrnPS8CTq3uQWc7N2BA==", + "node_modules/@inquirer/core/node_modules/@inquirer/type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-2.0.0.tgz", + "integrity": "sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag==", "dev": true, "dependencies": { - "@inquirer/core": "^9.0.5", - "@inquirer/type": "^1.5.1", - "external-editor": "^3.1.0" + "mute-stream": "^1.0.0" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/editor/node_modules/@inquirer/core": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.5.tgz", - "integrity": "sha512-QWG41I7vn62O9stYKg/juKXt1PEbr/4ZZCPb4KgXDQGwgA9M5NBTQ7FnOvT1ridbxkm/wTxLCNraUs7y47pIRQ==", + "node_modules/@inquirer/core/node_modules/@types/node": { + "version": "22.5.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", + "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", "dev": true, "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", - "@types/mute-stream": "^0.0.4", - "@types/node": "^20.14.11", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" + "undici-types": "~6.19.2" } }, - "node_modules/@inquirer/editor/node_modules/@types/node": { - "version": "20.14.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", - "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } + "node_modules/@inquirer/core/node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true }, - "node_modules/@inquirer/expand": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.1.17.tgz", - "integrity": "sha512-s4V/dC+GeE5s97xoTtZSmC440uNKePKqZgzqEf0XM63ciilnXAtKGvoAWOePFdlK+oGTz0d8bhbPKwpKGvRYfg==", + "node_modules/@inquirer/editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-2.2.0.tgz", + "integrity": "sha512-9KHOpJ+dIL5SZli8lJ6xdaYLPPzB8xB9GZItg39MBybzhxA16vxmszmQFrRwbOA918WA2rvu8xhDEg/p6LXKbw==", "dev": true, "dependencies": { - "@inquirer/core": "^9.0.5", - "@inquirer/type": "^1.5.1", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", + "external-editor": "^3.1.0" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/expand/node_modules/@inquirer/core": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.5.tgz", - "integrity": "sha512-QWG41I7vn62O9stYKg/juKXt1PEbr/4ZZCPb4KgXDQGwgA9M5NBTQ7FnOvT1ridbxkm/wTxLCNraUs7y47pIRQ==", + "node_modules/@inquirer/expand": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-2.3.0.tgz", + "integrity": "sha512-qnJsUcOGCSG1e5DTOErmv2BPQqrtT6uzqn1vI/aYGiPKq+FgslGZmtdnXbhuI7IlT7OByDoEEqdnhUnVR2hhLw==", "dev": true, "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", - "@types/mute-stream": "^0.0.4", - "@types/node": "^20.14.11", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/expand/node_modules/@types/node": { - "version": "20.14.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", - "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/@inquirer/figures": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.5.tgz", - "integrity": "sha512-79hP/VWdZ2UVc9bFGJnoQ/lQMpL74mGgzSYX1xUqCVk7/v73vJCMw1VuyWN1jGkZ9B3z7THAbySqGbCNefcjfA==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.6.tgz", + "integrity": "sha512-yfZzps3Cso2UbM7WlxKwZQh2Hs6plrbjs1QnzQDZhK2DgyCo6D8AaHps9olkNcUFlcYERMqU3uJSp1gmy3s/qQ==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@inquirer/input": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.2.4.tgz", - "integrity": "sha512-wvYnDITPQn+ltktj/O9kQjPxOvpmwcpxLWh8brAyD+jlEbihxtrx9cZdZcxqaCVQj3caw4eZa2Uq5xELo4yXkA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-2.3.0.tgz", + "integrity": "sha512-XfnpCStx2xgh1LIRqPXrTNEEByqQWoxsWYzNRSEUxJ5c6EQlhMogJ3vHKu8aXuTacebtaZzMAHwEL0kAflKOBw==", "dev": true, "dependencies": { - "@inquirer/core": "^9.0.5", - "@inquirer/type": "^1.5.1" + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/input/node_modules/@inquirer/core": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.5.tgz", - "integrity": "sha512-QWG41I7vn62O9stYKg/juKXt1PEbr/4ZZCPb4KgXDQGwgA9M5NBTQ7FnOvT1ridbxkm/wTxLCNraUs7y47pIRQ==", + "node_modules/@inquirer/number": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-1.1.0.tgz", + "integrity": "sha512-ilUnia/GZUtfSZy3YEErXLJ2Sljo/mf9fiKc08n18DdwdmDbOzRcTv65H1jjDvlsAuvdFXf4Sa/aL7iw/NanVA==", "dev": true, "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", - "@types/mute-stream": "^0.0.4", - "@types/node": "^20.14.11", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/input/node_modules/@types/node": { - "version": "20.14.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", - "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/@inquirer/password": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.1.17.tgz", - "integrity": "sha512-/u6DM/fDHXoBWyA+9aRhghkeo5smE7wO9k4E2UoJbgiRCkt3JjBEuBqLOJNrz8E16M0ez4UM1vd5cXrmICHW+A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-2.2.0.tgz", + "integrity": "sha512-5otqIpgsPYIshqhgtEwSspBQE40etouR8VIxzpJkv9i0dVHIpyhiivbkH9/dGiMLdyamT54YRdGJLfl8TFnLHg==", "dev": true, "dependencies": { - "@inquirer/core": "^9.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", "ansi-escapes": "^4.3.2" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/password/node_modules/@inquirer/core": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.5.tgz", - "integrity": "sha512-QWG41I7vn62O9stYKg/juKXt1PEbr/4ZZCPb4KgXDQGwgA9M5NBTQ7FnOvT1ridbxkm/wTxLCNraUs7y47pIRQ==", - "dev": true, - "dependencies": { - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", - "@types/mute-stream": "^0.0.4", - "@types/node": "^20.14.11", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/password/node_modules/@types/node": { - "version": "20.14.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", - "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/@inquirer/prompts": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.0.7.tgz", - "integrity": "sha512-GFcigCxJTKCH3aECzMIu4FhgLJWnFvMXzpI4CCSoELWFtkOOU2P+goYA61+OKpGrB8fPE7q6n8zAXBSlZRrHjQ==", + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-5.3.8.tgz", + "integrity": "sha512-b2BudQY/Si4Y2a0PdZZL6BeJtl8llgeZa7U2j47aaJSCeAl1e4UI7y8a9bSkO3o/ZbZrgT5muy/34JbsjfIWxA==", "dev": true, "dependencies": { - "@inquirer/checkbox": "^2.3.7", - "@inquirer/confirm": "^3.1.11", - "@inquirer/editor": "^2.1.11", - "@inquirer/expand": "^2.1.11", - "@inquirer/input": "^2.1.11", - "@inquirer/password": "^2.1.11", - "@inquirer/rawlist": "^2.1.11", - "@inquirer/select": "^2.3.7" + "@inquirer/checkbox": "^2.4.7", + "@inquirer/confirm": "^3.1.22", + "@inquirer/editor": "^2.1.22", + "@inquirer/expand": "^2.1.22", + "@inquirer/input": "^2.2.9", + "@inquirer/number": "^1.0.10", + "@inquirer/password": "^2.1.22", + "@inquirer/rawlist": "^2.2.4", + "@inquirer/search": "^1.0.7", + "@inquirer/select": "^2.4.7" }, "engines": { "node": ">=18" } }, "node_modules/@inquirer/rawlist": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.1.17.tgz", - "integrity": "sha512-RFrw34xU5aVlMA3ZJCaeKGxYjhu3j4i46O2GMmaRRGeLObCRM1yOKQOsRclSTzjd4A7+M5QleR2iuW/68J9Kwg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-2.3.0.tgz", + "integrity": "sha512-zzfNuINhFF7OLAtGHfhwOW2TlYJyli7lOUoJUXw/uyklcwalV6WRXBXtFIicN8rTRK1XTiPWB4UY+YuW8dsnLQ==", "dev": true, "dependencies": { - "@inquirer/core": "^9.0.5", - "@inquirer/type": "^1.5.1", + "@inquirer/core": "^9.1.0", + "@inquirer/type": "^1.5.3", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/rawlist/node_modules/@inquirer/core": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.5.tgz", - "integrity": "sha512-QWG41I7vn62O9stYKg/juKXt1PEbr/4ZZCPb4KgXDQGwgA9M5NBTQ7FnOvT1ridbxkm/wTxLCNraUs7y47pIRQ==", + "node_modules/@inquirer/search": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-1.1.0.tgz", + "integrity": "sha512-h+/5LSj51dx7hp5xOn4QFnUaKeARwUCLs6mIhtkJ0JYPBLmEYjdHSYh7I6GrLg9LwpJ3xeX0FZgAG1q0QdCpVQ==", "dev": true, "dependencies": { + "@inquirer/core": "^9.1.0", "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", - "@types/mute-stream": "^0.0.4", - "@types/node": "^20.14.11", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", + "@inquirer/type": "^1.5.3", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/rawlist/node_modules/@types/node": { - "version": "20.14.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", - "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/@inquirer/select": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.4.2.tgz", - "integrity": "sha512-r78JlgShqRxyAtBDeBHSDtfrOhSQwm2ecWGGaxe7kD9JwgL3UN563G1ncVRYdsWD7/tigflcskfipVeoDLhLJg==", - "dev": true, - "dependencies": { - "@inquirer/core": "^9.0.5", - "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/select/node_modules/@inquirer/core": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-9.0.5.tgz", - "integrity": "sha512-QWG41I7vn62O9stYKg/juKXt1PEbr/4ZZCPb4KgXDQGwgA9M5NBTQ7FnOvT1ridbxkm/wTxLCNraUs7y47pIRQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-2.5.0.tgz", + "integrity": "sha512-YmDobTItPP3WcEI86GvPo+T2sRHkxxOq/kXmsBjHS5BVXUgvgZ5AfJjkvQvZr03T81NnI3KrrRuMzeuYUQRFOA==", "dev": true, "dependencies": { + "@inquirer/core": "^9.1.0", "@inquirer/figures": "^1.0.5", - "@inquirer/type": "^1.5.1", - "@types/mute-stream": "^0.0.4", - "@types/node": "^20.14.11", - "@types/wrap-ansi": "^3.0.0", + "@inquirer/type": "^1.5.3", "ansi-escapes": "^4.3.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0", "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" } }, - "node_modules/@inquirer/select/node_modules/@types/node": { - "version": "20.14.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.12.tgz", - "integrity": "sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/@inquirer/type": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.1.tgz", - "integrity": "sha512-m3YgGQlKNS0BM+8AFiJkCsTqHEFCWn6s/Rqye3mYwvqY6LdfUv12eSwbsgNzrYyrLXiy7IrrjDLPysaSBwEfhw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.5.5.tgz", + "integrity": "sha512-MzICLu4yS7V8AA61sANROZ9vT1H3ooca5dSmI1FjZkzq7o/koMsRfQSzRtFo+F3Ao4Sf1C0bpLKejpKB/+j6MA==", "dev": true, "dependencies": { "mute-stream": "^1.0.0" @@ -5108,9 +4898,9 @@ } }, "node_modules/@jsonjoy.com/json-pack": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.0.4.tgz", - "integrity": "sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", + "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "dev": true, "dependencies": { "@jsonjoy.com/base64": "^1.1.1", @@ -5130,9 +4920,9 @@ } }, "node_modules/@jsonjoy.com/util": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.2.0.tgz", - "integrity": "sha512-4B8B+3vFsY4eo33DMKyJPlQ3sBMpPFUZK2dr3O3rXrOGKKbYG44J0XSFkDo1VOQiri5HFEhIeVvItjR2xcazmg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.3.0.tgz", + "integrity": "sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==", "dev": true, "engines": { "node": ">=10.0" @@ -5152,12 +4942,12 @@ "dev": true }, "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.13.tgz", - "integrity": "sha512-nAl6teTt7EWSjttNavAnv3uFR3w3vPP3OTYmHyPNHzKhAj2NoBDHmbS3MGpvvO8KXXPASnHjEGrrKrdKTMKPnQ==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-2.0.15.tgz", + "integrity": "sha512-MZrGem/Ujjd4cPTLYDfCZK2iKKeiO/8OX13S6jqxldLs0Prf2aGqVlJ77nMBqMv7fzqgXEgjrNHLXcKR8l9lOg==", "dev": true, "dependencies": { - "@inquirer/type": "^1.3.3" + "@inquirer/type": "^1.5.1" }, "engines": { "node": ">=18.0.0" @@ -5167,9 +4957,9 @@ } }, "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.0.12.tgz", - "integrity": "sha512-vgTwzNUD3Hy4aqtGhX2+nV/usI0mwy3hDRuTjs8VcK0BLiMVEpNQXgzwlWEgPmA8AAPloUgyOs2nK5clJF5oIg==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.0.13.tgz", + "integrity": "sha512-uiKPB0Fv6WEEOZjruu9a6wnW/8jrjzlZbxXscMB8kuCJ1k6kHpcBnuvaAWcqhbI7rqX5GKziwWEdD+wi2gNLfA==", "cpu": [ "arm64" ], @@ -5180,9 +4970,9 @@ ] }, "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.0.12.tgz", - "integrity": "sha512-qOt0hAhj2ZLY6aEWu85rzt5zcyCAQITMhCMEPNlo1tuYekpVAdkQNiwXxEkCjBYvwTskvXuwXOOUpjuSc+aJnA==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.0.13.tgz", + "integrity": "sha512-bEVIIfK5mSQoG1R19qA+fJOvCB+0wVGGnXHT3smchBVahYBdlPn2OsZZKzlHWfb1E+PhLBmYfqB5zQXFP7hJig==", "cpu": [ "x64" ], @@ -5193,9 +4983,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.0.12.tgz", - "integrity": "sha512-Ggd/UXpE+alMncbELCXA3OKpDj9bDBR3qVO7WRTxstloDglRAHfZmUJgTkeaNKjFO1JHqS7AKy0jba9XebZB1w==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.0.13.tgz", + "integrity": "sha512-Yml1KlMzOnXj/tnW7yX8U78iAzTk39aILYvCPbqeewAq1kSzl+w59k/fiVkTBfvDi/oW/5YRxL+Fq+Y1Fr1r2Q==", "cpu": [ "arm" ], @@ -5206,9 +4996,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.0.12.tgz", - "integrity": "sha512-Qy4cFXFe9h1wAWMsojex8x1ifvw2kqiZv686YiRTdQEzAfc3vJASHFcD/QejHUCx7YHMYdnUoCS45rG2AiGDTQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.0.13.tgz", + "integrity": "sha512-afbVrsMgZ9dUTNUchFpj5VkmJRxvht/u335jUJ7o23YTbNbnpmXif3VKQGCtnjSh+CZaqm6N3CPG8KO3zwyZ1Q==", "cpu": [ "arm64" ], @@ -5219,9 +5009,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.0.12.tgz", - "integrity": "sha512-c+noT9IofktxktFllKHFmci8ka2SYGSLN17pj/KSl1hg7mmfAiGp4xxFxEwMLTb+SX95vP1DFiR++1I3WLVxvA==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.0.13.tgz", + "integrity": "sha512-vOtxu0xC0SLdQ2WRXg8Qgd8T32ak4SPqk5zjItRszrJk2BdeXqfGxBJbP7o4aOvSPSmSSv46Lr1EP4HXU8v7Kg==", "cpu": [ "x64" ], @@ -5232,9 +5022,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.0.12.tgz", - "integrity": "sha512-CO3MFV8gUx16NU/CyyuumAKblESwvoGVA2XhQKZ976OTOxaTbb8F8D3f0iiZ4MYqsN74jIrFuCmXpPnpjbhfOQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.0.13.tgz", + "integrity": "sha512-UCrMJQY/gJnOl3XgbWRZZUvGGBuKy6i0YNSptgMzHBjs+QYDYR1Mt/RLTOPy4fzzves65O1EDmlL//OzEqoLlA==", "cpu": [ "x64" ], @@ -5323,9 +5113,9 @@ ] }, "node_modules/@ngtools/webpack": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.1.2.tgz", - "integrity": "sha512-oIpkr1oeRMO0CVdEaxiLqqZ7E8RgDR8rf3LrM5sVOBX4aXAbzVkOZf9yZejmrXaLxj7SU/Fhkljr49ErlpB20g==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.5.tgz", + "integrity": "sha512-L0n4eHObeqEOYRfSP+e4SeF/dmwxOIFy9xYvYCOUwOLrW4b3+a1+kkT30pqyfL72LFtpf0cmUwaWEFIcWl5PCg==", "dev": true, "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", @@ -5663,9 +5453,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", - "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.20.0.tgz", + "integrity": "sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==", "cpu": [ "arm" ], @@ -5676,9 +5466,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", - "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.20.0.tgz", + "integrity": "sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==", "cpu": [ "arm64" ], @@ -5689,9 +5479,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", - "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.20.0.tgz", + "integrity": "sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==", "cpu": [ "arm64" ], @@ -5702,9 +5492,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", - "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.20.0.tgz", + "integrity": "sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==", "cpu": [ "x64" ], @@ -5715,9 +5505,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", - "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.20.0.tgz", + "integrity": "sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==", "cpu": [ "arm" ], @@ -5728,9 +5518,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", - "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.20.0.tgz", + "integrity": "sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==", "cpu": [ "arm" ], @@ -5741,9 +5531,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", - "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.20.0.tgz", + "integrity": "sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==", "cpu": [ "arm64" ], @@ -5754,9 +5544,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", - "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.20.0.tgz", + "integrity": "sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==", "cpu": [ "arm64" ], @@ -5767,9 +5557,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", - "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.20.0.tgz", + "integrity": "sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==", "cpu": [ "ppc64" ], @@ -5780,9 +5570,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", - "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.20.0.tgz", + "integrity": "sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==", "cpu": [ "riscv64" ], @@ -5793,9 +5583,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", - "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.20.0.tgz", + "integrity": "sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==", "cpu": [ "s390x" ], @@ -5806,9 +5596,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", - "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.20.0.tgz", + "integrity": "sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==", "cpu": [ "x64" ], @@ -5819,9 +5609,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", - "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.20.0.tgz", + "integrity": "sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==", "cpu": [ "x64" ], @@ -5832,9 +5622,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", - "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.20.0.tgz", + "integrity": "sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==", "cpu": [ "arm64" ], @@ -5845,9 +5635,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", - "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.20.0.tgz", + "integrity": "sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==", "cpu": [ "ia32" ], @@ -5858,9 +5648,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", - "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.20.0.tgz", + "integrity": "sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==", "cpu": [ "x64" ], @@ -5871,13 +5661,13 @@ ] }, "node_modules/@schematics/angular": { - "version": "18.1.2", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.1.2.tgz", - "integrity": "sha512-lTY9twQ30vEm3hjArUKQjKiYlbDUOHqbyY7MlynY5+T8XtYreMo20KHofxv5t5xZfPwj1z6/ppcMU2xZ4WbGUA==", + "version": "18.2.5", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.5.tgz", + "integrity": "sha512-tBXhk9OGT4U6VsBNbuCNl2ITDOF3NYdGrEieIHU+lHSkpJNGZUIGxCgXCETXkmXDq1pe4wFZSKelWjeqYDfX0g==", "dev": true, "dependencies": { - "@angular-devkit/core": "18.1.2", - "@angular-devkit/schematics": "18.1.2", + "@angular-devkit/core": "18.2.5", + "@angular-devkit/schematics": "18.2.5", "jsonc-parser": "3.3.1" }, "engines": { @@ -6632,26 +6422,6 @@ "@types/node": "*" } }, - "node_modules/@types/eslint": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.0.tgz", - "integrity": "sha512-gi6WQJ7cHRgZxtkQEoyHMppPjq9Kxo5Tjn2prSKDSmZrCz8TZ3jSRCeTJm+WoM+oB0WG37bRqLzaaU3q7JypGg==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -6838,9 +6608,9 @@ } }, "node_modules/@types/qs": { - "version": "6.9.15", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", - "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "version": "6.9.16", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", + "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", "dev": true }, "node_modules/@types/range-parser": { @@ -6925,9 +6695,9 @@ "dev": true }, "node_modules/@types/ws": { - "version": "8.5.11", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", - "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", + "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, "dependencies": { "@types/node": "*" @@ -7261,15 +7031,15 @@ } }, "node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -7506,9 +7276,9 @@ "dev": true }, "node_modules/autoprefixer": { - "version": "10.4.19", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", - "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", + "version": "10.4.20", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", + "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", "dev": true, "funding": [ { @@ -7525,11 +7295,11 @@ } ], "dependencies": { - "browserslist": "^4.23.0", - "caniuse-lite": "^1.0.30001599", + "browserslist": "^4.23.3", + "caniuse-lite": "^1.0.30001646", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "postcss-value-parser": "^4.2.0" }, "bin": { @@ -7977,9 +7747,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", "dev": true, "funding": [ { @@ -7996,9 +7766,9 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", "update-browserslist-db": "^1.1.0" }, "bin": { @@ -8194,9 +7964,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001643", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", - "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", + "version": "1.0.30001662", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001662.tgz", + "integrity": "sha512-sgMUVwLmGseH8ZIrm1d51UbrhqMCH3jvS7gF/M6byuHOnKyLOBL7W8yz5V02OHwgLGA36o/AFhWzzh4uc5aqTA==", "dev": true, "funding": [ { @@ -10011,9 +9781,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.2.tgz", - "integrity": "sha512-kc4r3U3V3WLaaZqThjYz/Y6z8tJe+7K0bbjUVo3i+LWIypVdMx5nXCkwRe6SWbY6ILqLdc1rKcKmr3HoH7wjSQ==", + "version": "1.5.26", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.26.tgz", + "integrity": "sha512-Z+OMe9M/V6Ep9n/52+b7lkvYEps26z4Yz3vjWL1V61W0q+VLF1pOHhMY17sa4roz4AWmULSI8E6SAojZA5L0YQ==", "dev": true }, "node_modules/elkjs": { @@ -10353,15 +10123,15 @@ } }, "node_modules/esbuild-wasm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.21.5.tgz", - "integrity": "sha512-L/FlOPMMFtw+6qPAbuPvJXdrOYOp9yx/PEwSrIZW0qghY4vgV003evdYDwqQ/9ENMQI0B6RMod9xT4FHtto6OQ==", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.23.0.tgz", + "integrity": "sha512-6jP8UmWy6R6TUUV8bMuC3ZyZ6lZKI56x0tkxyCIqWwRRJ/DgeQKneh/Oid5EoGoPFLrGNkz47ZEtWAYuiY/u9g==", "dev": true, "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/escalade": { @@ -12229,9 +11999,9 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", - "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "dependencies": { "@babel/core": "^7.23.9", @@ -14673,9 +14443,9 @@ } }, "node_modules/launch-editor": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.8.0.tgz", - "integrity": "sha512-vJranOAJrI/llyWGRQqiDM+adrw+k83fvmmx3+nV47g3+36xM15jE+zyZ6Ffel02+xSvuM0b2GDRosXZkbb6wA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "dev": true, "dependencies": { "picocolors": "^1.0.0", @@ -14807,15 +14577,15 @@ "dev": true }, "node_modules/listr2": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.3.tgz", - "integrity": "sha512-Lllokma2mtoniUOS94CcOErHWAug5iu7HOmDrvWgpw8jyQH2fomgB+7lZS4HWZxytUuQwkGOwe49FvwVaA85Xw==", + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", + "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", - "log-update": "^6.0.0", + "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" }, @@ -14824,9 +14594,9 @@ } }, "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -14886,9 +14656,9 @@ } }, "node_modules/lmdb": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.0.12.tgz", - "integrity": "sha512-JnoEulTgveoC64vlYJ9sufGLuNkk6TcxSYpKxSC9aM42I61jIv3pQH0fgb6qW7HV0+FNqA3g1WCQQYfhfawGoQ==", + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.0.13.tgz", + "integrity": "sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -14902,12 +14672,12 @@ "download-lmdb-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "3.0.12", - "@lmdb/lmdb-darwin-x64": "3.0.12", - "@lmdb/lmdb-linux-arm": "3.0.12", - "@lmdb/lmdb-linux-arm64": "3.0.12", - "@lmdb/lmdb-linux-x64": "3.0.12", - "@lmdb/lmdb-win32-x64": "3.0.12" + "@lmdb/lmdb-darwin-arm64": "3.0.13", + "@lmdb/lmdb-darwin-x64": "3.0.13", + "@lmdb/lmdb-linux-arm": "3.0.13", + "@lmdb/lmdb-linux-arm64": "3.0.13", + "@lmdb/lmdb-linux-x64": "3.0.13", + "@lmdb/lmdb-win32-x64": "3.0.13" } }, "node_modules/loader-runner": { @@ -15197,12 +14967,12 @@ } }, "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", "dev": true, "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/make-dir": { @@ -15316,13 +15086,13 @@ } }, "node_modules/memfs": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.9.4.tgz", - "integrity": "sha512-Xlj8b2rU11nM6+KU6wC7cuWcHQhVINWCUgdPS4Ar9nPxLaOya3RghqK7ALyDW2QtGebYAYs6uEdEVnwPVT942A==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.12.0.tgz", + "integrity": "sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==", "dev": true, "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", - "@jsonjoy.com/util": "^1.1.2", + "@jsonjoy.com/util": "^1.3.0", "tree-dump": "^1.0.1", "tslib": "^2.0.0" }, @@ -16427,9 +16197,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", - "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", + "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", "dev": true, "optional": true, "bin": { @@ -16619,9 +16389,9 @@ } }, "node_modules/npm-package-arg": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.2.tgz", - "integrity": "sha512-IGN0IAwmhDJwy13Wc8k+4PEbTPhpJnMtfR53ZbOyjkvmEcLS4nCwp6mvMWjS5sUjeiW3mpx6cHmuhKEu9XmcQw==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", + "integrity": "sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==", "dev": true, "dependencies": { "hosted-git-info": "^7.0.0", @@ -16646,9 +16416,9 @@ } }, "node_modules/npm-pick-manifest": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", - "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", + "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", "dev": true, "dependencies": { "npm-install-checks": "^6.0.0", @@ -17251,9 +17021,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "dev": true }, "node_modules/picomatch": { @@ -17412,9 +17182,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", "dev": true, "funding": [ { @@ -17432,8 +17202,8 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" @@ -17843,9 +17613,9 @@ "dev": true }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, "dependencies": { "regenerate": "^1.4.2" @@ -18098,9 +17868,9 @@ "dev": true }, "node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -18108,9 +17878,6 @@ "bin": { "rimraf": "dist/esm/bin.mjs" }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -18166,9 +17933,9 @@ "optional": true }, "node_modules/rollup": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", - "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", + "version": "4.20.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.20.0.tgz", + "integrity": "sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -18181,22 +17948,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.18.0", - "@rollup/rollup-android-arm64": "4.18.0", - "@rollup/rollup-darwin-arm64": "4.18.0", - "@rollup/rollup-darwin-x64": "4.18.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", - "@rollup/rollup-linux-arm-musleabihf": "4.18.0", - "@rollup/rollup-linux-arm64-gnu": "4.18.0", - "@rollup/rollup-linux-arm64-musl": "4.18.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", - "@rollup/rollup-linux-riscv64-gnu": "4.18.0", - "@rollup/rollup-linux-s390x-gnu": "4.18.0", - "@rollup/rollup-linux-x64-gnu": "4.18.0", - "@rollup/rollup-linux-x64-musl": "4.18.0", - "@rollup/rollup-win32-arm64-msvc": "4.18.0", - "@rollup/rollup-win32-ia32-msvc": "4.18.0", - "@rollup/rollup-win32-x64-msvc": "4.18.0", + "@rollup/rollup-android-arm-eabi": "4.20.0", + "@rollup/rollup-android-arm64": "4.20.0", + "@rollup/rollup-darwin-arm64": "4.20.0", + "@rollup/rollup-darwin-x64": "4.20.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.20.0", + "@rollup/rollup-linux-arm-musleabihf": "4.20.0", + "@rollup/rollup-linux-arm64-gnu": "4.20.0", + "@rollup/rollup-linux-arm64-musl": "4.20.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.20.0", + "@rollup/rollup-linux-riscv64-gnu": "4.20.0", + "@rollup/rollup-linux-s390x-gnu": "4.20.0", + "@rollup/rollup-linux-x64-gnu": "4.20.0", + "@rollup/rollup-linux-x64-musl": "4.20.0", + "@rollup/rollup-win32-arm64-msvc": "4.20.0", + "@rollup/rollup-win32-ia32-msvc": "4.20.0", + "@rollup/rollup-win32-x64-msvc": "4.20.0", "fsevents": "~2.3.2" } }, @@ -18346,9 +18113,9 @@ } }, "node_modules/sass-loader": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.2.1.tgz", - "integrity": "sha512-G0VcnMYU18a4N7VoNDegg2OuMjYtxnqzQWARVWCIVSZwJeiL9kg8QMsuIZOplsJgTzZLF6jGxI3AClj8I9nRdQ==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.0.tgz", + "integrity": "sha512-n13Z+3rU9A177dk4888czcVFiC8CL9dii4qpXWUg3YIIgZEvi9TCFKjOQcbK0kJM7DJu9VucrZFddvNfYCPwtw==", "dev": true, "dependencies": { "neo-async": "^2.6.2" @@ -18466,9 +18233,9 @@ } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -18886,9 +18653,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -19366,9 +19133,9 @@ "dev": true }, "node_modules/terser": { - "version": "5.29.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.2.tgz", - "integrity": "sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -19865,15 +19632,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/undici": { - "version": "6.19.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.2.tgz", - "integrity": "sha512-JfjKqIauur3Q6biAtHJ564e3bWa8VvT+7cSiOJHFbX4Erv6CLGDpg8z+Fmg/1OI/47RA+GI2QZaF48SSaLvyBA==", - "dev": true, - "engines": { - "node": ">=18.17" - } - }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -19881,9 +19639,9 @@ "dev": true }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "engines": { "node": ">=4" @@ -19903,9 +19661,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, "engines": { "node": ">=4" @@ -20155,14 +19913,14 @@ } }, "node_modules/vite": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.2.tgz", - "integrity": "sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", + "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", "dev": true, "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.38", - "rollup": "^4.13.0" + "postcss": "^8.4.43", + "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" @@ -20181,6 +19939,7 @@ "less": "*", "lightningcss": "^1.21.0", "sass": "*", + "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" @@ -20198,6 +19957,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -20689,12 +20451,11 @@ } }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", "dev": true, "dependencies": { - "@types/eslint-scope": "^3.7.3", "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", @@ -20703,7 +20464,7 @@ "acorn-import-attributes": "^1.9.5", "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -20736,9 +20497,9 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", - "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", + "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dev": true, "dependencies": { "colorette": "^2.0.10", @@ -20848,17 +20609,17 @@ } }, "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", - "wildcard": "^2.0.0" + "wildcard": "^2.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/webpack-sources": { diff --git a/springwolf-ui/package.json b/springwolf-ui/package.json index 75f42c09e..3422b9fda 100644 --- a/springwolf-ui/package.json +++ b/springwolf-ui/package.json @@ -11,16 +11,16 @@ }, "private": true, "dependencies": { - "@angular/animations": "^18.1.2", - "@angular/cdk": "^18.1.2", - "@angular/common": "^18.1.2", - "@angular/compiler": "^18.1.2", - "@angular/core": "^18.1.2", - "@angular/forms": "^18.1.2", - "@angular/material": "^18.1.2", - "@angular/platform-browser": "^18.1.2", - "@angular/platform-browser-dynamic": "^18.1.2", - "@angular/router": "^18.1.2", + "@angular/animations": "^18.2.5", + "@angular/cdk": "^18.2.5", + "@angular/common": "^18.2.5", + "@angular/compiler": "^18.2.5", + "@angular/core": "^18.2.5", + "@angular/forms": "^18.2.5", + "@angular/material": "^18.2.5", + "@angular/platform-browser": "^18.2.5", + "@angular/platform-browser-dynamic": "^18.2.5", + "@angular/router": "^18.2.5", "marked": "^12.0.2", "ngx-markdown": "^18.0.0", "prism-code-editor": "^3.4.0", @@ -30,9 +30,9 @@ "zone.js": "~0.14.10" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.1.2", - "@angular/cli": "^18.1.2", - "@angular/compiler-cli": "^18.1.2", + "@angular-devkit/build-angular": "^18.2.5", + "@angular/cli": "^18.2.5", + "@angular/compiler-cli": "^18.2.5", "@asyncapi/parser": "^3.2.2", "@testing-library/angular": "^17.3.1", "@types/jest": "^29.5.13", From f56ce7d844a5b83b7d37616893000de4a9fe84f0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:41:40 +0200 Subject: [PATCH 22/34] chore(deps): Bump com.networknt:json-schema-validator (#990) Bumps [com.networknt:json-schema-validator](https://github.com/networknt/json-schema-validator) from 1.5.1 to 1.5.2. - [Release notes](https://github.com/networknt/json-schema-validator/releases) - [Changelog](https://github.com/networknt/json-schema-validator/blob/master/CHANGELOG.md) - [Commits](https://github.com/networknt/json-schema-validator/compare/1.5.1...1.5.2) --- updated-dependencies: - dependency-name: com.networknt:json-schema-validator dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 673a461dd..9c6e62b13 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -52,7 +52,7 @@ ext { jakartaXmlBindApiVersion = '4.0.2' - jsonSchemaValidator = '1.5.1' + jsonSchemaValidator = '1.5.2' mockitoCoreVersion = '5.13.0' mockitoJunitJupiterVersion = '5.13.0' From 6e4f861770da328b23ffed70c8945db0c8056298 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:41:49 +0200 Subject: [PATCH 23/34] chore(deps): Bump swaggerVersion from 2.2.23 to 2.2.24 (#988) Bumps `swaggerVersion` from 2.2.23 to 2.2.24. Updates `io.swagger.core.v3:swagger-core-jakarta` from 2.2.23 to 2.2.24 Updates `io.swagger.core.v3:swagger-annotations-jakarta` from 2.2.23 to 2.2.24 Updates `io.swagger.core.v3:swagger-models-jakarta` from 2.2.23 to 2.2.24 Updates `io.swagger.core.v3:swagger-annotations` from 2.2.23 to 2.2.24 --- updated-dependencies: - dependency-name: io.swagger.core.v3:swagger-core-jakarta dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.swagger.core.v3:swagger-annotations-jakarta dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.swagger.core.v3:swagger-models-jakarta dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: io.swagger.core.v3:swagger-annotations dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 9c6e62b13..4e2cab8fc 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -70,7 +70,7 @@ ext { slf4jApiVersion = '2.0.16' slf4jSimpleVersion = '2.0.16' - swaggerVersion = '2.2.23' + swaggerVersion = '2.2.24' testcontainersVersion = '1.20.1' } From e61eaa6b451285fb875d6910061a098e7fe0ea5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:42:03 +0200 Subject: [PATCH 24/34] chore(deps): Bump protobufJavaVersion from 4.28.1 to 4.28.2 (#989) Bumps `protobufJavaVersion` from 4.28.1 to 4.28.2. Updates `com.google.protobuf:protobuf-java` from 4.28.1 to 4.28.2 - [Release notes](https://github.com/protocolbuffers/protobuf/releases) - [Changelog](https://github.com/protocolbuffers/protobuf/blob/main/protobuf_release.bzl) - [Commits](https://github.com/protocolbuffers/protobuf/commits) Updates `com.google.protobuf:protoc` from 4.28.1 to 4.28.2 - [Release notes](https://github.com/protocolbuffers/protobuf/releases) - [Changelog](https://github.com/protocolbuffers/protobuf/blob/main/protobuf_release.bzl) - [Commits](https://github.com/protocolbuffers/protobuf/commits) --- updated-dependencies: - dependency-name: com.google.protobuf:protobuf-java dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: com.google.protobuf:protoc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 4e2cab8fc..de8c57434 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -60,7 +60,7 @@ ext { monetaVersion = '1.4.4' moneyApiVersion = '1.1' - protobufJavaVersion = '4.28.1' + protobufJavaVersion = '4.28.2' junitJupiterVersion = '5.11.0' jsonUnitAssertJVersion = '3.4.1' From 75b8e07c890c67858d30bae6c7dda486eb6043b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 12:42:18 +0200 Subject: [PATCH 25/34] chore(deps): Bump io.awspring.cloud:spring-cloud-aws-dependencies (#987) Bumps [io.awspring.cloud:spring-cloud-aws-dependencies](https://github.com/awspring/spring-cloud-aws) from 3.1.1 to 3.2.0. - [Release notes](https://github.com/awspring/spring-cloud-aws/releases) - [Commits](https://github.com/awspring/spring-cloud-aws/compare/v3.1.1...v3.2.0) --- updated-dependencies: - dependency-name: io.awspring.cloud:spring-cloud-aws-dependencies dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- springwolf-examples/springwolf-sns-example/build.gradle | 2 +- springwolf-examples/springwolf-sqs-example/build.gradle | 2 +- springwolf-plugins/springwolf-sns-plugin/build.gradle | 2 +- springwolf-plugins/springwolf-sqs-plugin/build.gradle | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/springwolf-examples/springwolf-sns-example/build.gradle b/springwolf-examples/springwolf-sns-example/build.gradle index 2a483eeb5..7034443fa 100644 --- a/springwolf-examples/springwolf-sns-example/build.gradle +++ b/springwolf-examples/springwolf-sns-example/build.gradle @@ -10,7 +10,7 @@ plugins { dependencyManagement { imports { - mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.1.1" + mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.2.0" } } diff --git a/springwolf-examples/springwolf-sqs-example/build.gradle b/springwolf-examples/springwolf-sqs-example/build.gradle index f6f36edc7..241d19a57 100644 --- a/springwolf-examples/springwolf-sqs-example/build.gradle +++ b/springwolf-examples/springwolf-sqs-example/build.gradle @@ -10,7 +10,7 @@ plugins { dependencyManagement { imports { - mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.1.1" + mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.2.0" } } diff --git a/springwolf-plugins/springwolf-sns-plugin/build.gradle b/springwolf-plugins/springwolf-sns-plugin/build.gradle index 48b282a2c..020424ac1 100644 --- a/springwolf-plugins/springwolf-sns-plugin/build.gradle +++ b/springwolf-plugins/springwolf-sns-plugin/build.gradle @@ -8,7 +8,7 @@ plugins { dependencyManagement { imports { - mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.1.1" + mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.2.0" } } diff --git a/springwolf-plugins/springwolf-sqs-plugin/build.gradle b/springwolf-plugins/springwolf-sqs-plugin/build.gradle index f76a19074..26554b6c6 100644 --- a/springwolf-plugins/springwolf-sqs-plugin/build.gradle +++ b/springwolf-plugins/springwolf-sqs-plugin/build.gradle @@ -8,7 +8,7 @@ plugins { dependencyManagement { imports { - mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.1.1" + mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:3.2.0" } } From 85169db996308b46673e35cf24f082c599326b35 Mon Sep 17 00:00:00 2001 From: sam0r040 <93372330+sam0r040@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:42:07 +0200 Subject: [PATCH 26/34] test(jms): increase timeout of ProducerSystemTest from 10s to 20s to fix flaky test (#992) --- .../io/github/springwolf/examples/jms/ProducerSystemTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/ProducerSystemTest.java b/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/ProducerSystemTest.java index 06bc6118b..bd22fc2be 100644 --- a/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/ProducerSystemTest.java +++ b/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/ProducerSystemTest.java @@ -65,6 +65,7 @@ void producerCanUseSpringwolfConfigurationToSendMessage() { springwolfJmsProducer.send("example-queue", Map.of(), payload); // then - verify(exampleConsumer, timeout(10000)).receiveExamplePayload(payload); + // Increased timeout once from 10s to 20s to fix flaky test in ci + verify(exampleConsumer, timeout(20000)).receiveExamplePayload(payload); } } From e584e5a5bdf5811738421d5ea32aa32af0540ea9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:42:29 +0200 Subject: [PATCH 27/34] chore(deps): Bump org.springframework.boot from 3.3.3 to 3.3.4 (#986) Bumps [org.springframework.boot](https://github.com/spring-projects/spring-boot) from 3.3.3 to 3.3.4. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.3.3...v3.3.4) --- updated-dependencies: - dependency-name: org.springframework.boot dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index c95af39a1..f0aa507e6 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ plugins { id 'io.github.gradle-nexus.publish-plugin' version '2.0.0' id 'ca.cutterslade.analyze' version '1.9.1' id 'io.spring.dependency-management' version '1.1.6' apply false - id 'org.springframework.boot' version '3.3.3' apply false + id 'org.springframework.boot' version '3.3.4' apply false id 'org.owasp.dependencycheck' version '10.0.4' id 'com.diffplug.spotless' version '6.25.0' id 'com.bmuschko.docker-spring-boot-application' version '9.4.0' apply false From f313e72b19aafd6d0d84e7cb6cb4fc052d88b22e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Fri, 27 Sep 2024 15:18:23 +0200 Subject: [PATCH 28/34] chore: start development on springwolf 1.8.0-SNAPSHOT --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 3581f41df..3abe8db96 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -SPRINGWOLF_VERSION=1.7.0-SNAPSHOT +SPRINGWOLF_VERSION=1.8.0-SNAPSHOT From 69a2e32fac8564123a4075db5a52820fc8475c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Fri, 27 Sep 2024 17:22:56 +0200 Subject: [PATCH 29/34] chore(example): Bump localstack/localstack from 3.3.0 to 3.7.2 in sqs-example --- springwolf-examples/springwolf-sqs-example/docker-compose.yml | 4 ++-- .../springwolf/examples/sqs/SqsTestContainerExtension.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/springwolf-examples/springwolf-sqs-example/docker-compose.yml b/springwolf-examples/springwolf-sqs-example/docker-compose.yml index 9ce2e76a3..e8020ab7c 100644 --- a/springwolf-examples/springwolf-sqs-example/docker-compose.yml +++ b/springwolf-examples/springwolf-sqs-example/docker-compose.yml @@ -11,7 +11,7 @@ services: - localstack localstack: - image: localstack/localstack:3.3.0 + image: localstack/localstack:3.7.2 environment: - DEBUG=${DEBUG-} - AWS_REGION=eu-central-1 @@ -23,7 +23,7 @@ services: - "${TMPDIR:-/tmp/localstack}:/var/lib/localstack" - "/var/run/docker.sock:/var/run/docker.sock" localstack_setup: - image: localstack/localstack:3.3.0 + image: localstack/localstack:3.7.2 links: - localstack depends_on: diff --git a/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/springwolf/examples/sqs/SqsTestContainerExtension.java b/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/springwolf/examples/sqs/SqsTestContainerExtension.java index a3df1427e..76284a565 100644 --- a/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/springwolf/examples/sqs/SqsTestContainerExtension.java +++ b/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/springwolf/examples/sqs/SqsTestContainerExtension.java @@ -21,7 +21,7 @@ public class SqsTestContainerExtension implements BeforeAllCallback, ExtensionCo private static volatile boolean started = false; static LocalStackContainer localStack = - new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.3.0")).withServices(SQS); + new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.7.2")).withServices(SQS); @Override public void beforeAll(ExtensionContext extensionContext) throws Exception { From 5c5fe311f5df99d2777f8aef6ea1a64ef3f293d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Fri, 27 Sep 2024 17:29:15 +0200 Subject: [PATCH 30/34] chore(example): Bump localstack/localstack from 2.2.0 to 3.7.2 in sns-example --- .../springwolf-sns-example/docker-compose.yml | 6 +++--- .../springwolf/examples/sns/SnsTestContainerExtension.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/springwolf-examples/springwolf-sns-example/docker-compose.yml b/springwolf-examples/springwolf-sns-example/docker-compose.yml index e93a38fd7..cf3737bcf 100644 --- a/springwolf-examples/springwolf-sns-example/docker-compose.yml +++ b/springwolf-examples/springwolf-sns-example/docker-compose.yml @@ -11,7 +11,7 @@ services: - localstack localstack: - image: localstack/localstack:2.2.0 + image: localstack/localstack:3.7.2 environment: - DEBUG=${DEBUG-} - AWS_REGION=eu-central-1 @@ -23,7 +23,7 @@ services: - "${TMPDIR:-/tmp/localstack}:/tmp/localstack" - "/var/run/docker.sock:/var/run/docker.sock" localstack_setup: - image: localstack/localstack:2.2.0 + image: localstack/localstack:3.7.2 links: - localstack depends_on: @@ -32,4 +32,4 @@ services: entrypoint: [ "bash", "-c", " awslocal --endpoint-url=http://localstack:4566 sns create-topic --name another-topic --region eu-central-1; awslocal --endpoint-url=http://localstack:4566 sns create-topic --name example-topic --region eu-central-1; - " ] \ No newline at end of file + " ] diff --git a/springwolf-examples/springwolf-sns-example/src/test/java/io/github/springwolf/examples/sns/SnsTestContainerExtension.java b/springwolf-examples/springwolf-sns-example/src/test/java/io/github/springwolf/examples/sns/SnsTestContainerExtension.java index c94ffd369..152050ddf 100644 --- a/springwolf-examples/springwolf-sns-example/src/test/java/io/github/springwolf/examples/sns/SnsTestContainerExtension.java +++ b/springwolf-examples/springwolf-sns-example/src/test/java/io/github/springwolf/examples/sns/SnsTestContainerExtension.java @@ -21,7 +21,7 @@ public class SnsTestContainerExtension implements BeforeAllCallback, ExtensionCo private static volatile boolean started = false; static LocalStackContainer localStack = - new LocalStackContainer(DockerImageName.parse("localstack/localstack:2.2.0")).withServices(SNS); + new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.7.2")).withServices(SNS); @Override public void beforeAll(ExtensionContext extensionContext) throws Exception { From c992b28e6d66ba17db153212d69c508f2da497a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Fri, 27 Sep 2024 17:34:28 +0200 Subject: [PATCH 31/34] chore(example): Bump confluentinc/cp-kafka from 7.4.6 to 7.7.1 in kafka-example --- springwolf-examples/springwolf-kafka-example/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/springwolf-examples/springwolf-kafka-example/docker-compose.yml b/springwolf-examples/springwolf-kafka-example/docker-compose.yml index f9f6c7a33..ab82b6066 100644 --- a/springwolf-examples/springwolf-kafka-example/docker-compose.yml +++ b/springwolf-examples/springwolf-kafka-example/docker-compose.yml @@ -13,7 +13,7 @@ services: - kafka kafka: - image: confluentinc/cp-kafka:7.4.6 + image: confluentinc/cp-kafka:7.7.1 ports: - "9092:9092" # plaintext - no authentication - "9093:9093" # sasl From 9880386d71a67c487fec9090493534c802903193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Fri, 27 Sep 2024 17:39:55 +0200 Subject: [PATCH 32/34] chore(example): Bump apache/activemq-artemis from 2.34.0/2.31.2 to 2.37.0-alpine in jms-example --- .../springwolf-jms-example/docker-compose.yml | 2 +- .../springwolf/examples/jms/JmsTestContainerExtension.java | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/springwolf-examples/springwolf-jms-example/docker-compose.yml b/springwolf-examples/springwolf-jms-example/docker-compose.yml index 7d9cec476..1457e8391 100644 --- a/springwolf-examples/springwolf-jms-example/docker-compose.yml +++ b/springwolf-examples/springwolf-jms-example/docker-compose.yml @@ -11,7 +11,7 @@ services: - activemq activemq: - image: apache/activemq-artemis:2.34.0 + image: apache/activemq-artemis:2.37.0-alpine environment: EXTRA_ARGS: --http-host 0.0.0.0 --relax-jolokia --nio ARTEMIS_USER: artemis diff --git a/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/JmsTestContainerExtension.java b/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/JmsTestContainerExtension.java index aef3139d4..34783c997 100644 --- a/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/JmsTestContainerExtension.java +++ b/springwolf-examples/springwolf-jms-example/src/test/java/io/github/springwolf/examples/jms/JmsTestContainerExtension.java @@ -16,8 +16,9 @@ public class JmsTestContainerExtension implements BeforeAllCallback, ExtensionCo private static volatile boolean started = false; - static GenericContainer activeMq = - new GenericContainer<>(DockerImageName.parse("apache/activemq-artemis:2.31.2")).withExposedPorts(61616); + static GenericContainer activeMq = new GenericContainer<>( + DockerImageName.parse("apache/activemq-artemis:2.37.0-alpine")) + .withExposedPorts(61616); @Override public void beforeAll(ExtensionContext extensionContext) { From 0f7402d4ecf1bda94be15c0150015d3f9fdd70b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Fri, 27 Sep 2024 17:42:46 +0200 Subject: [PATCH 33/34] chore(example): Bump confluentinc/cp-kafka from 7.4.6 to 7.7.1 in cloud-stream-example --- .../springwolf-cloud-stream-example/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/springwolf-examples/springwolf-cloud-stream-example/docker-compose.yml b/springwolf-examples/springwolf-cloud-stream-example/docker-compose.yml index 77116a728..95e7c1061 100644 --- a/springwolf-examples/springwolf-cloud-stream-example/docker-compose.yml +++ b/springwolf-examples/springwolf-cloud-stream-example/docker-compose.yml @@ -11,7 +11,7 @@ services: - kafka kafka: - image: confluentinc/cp-kafka:7.4.6 + image: confluentinc/cp-kafka:7.7.1 ports: - "9095:9095" # plaintext - no authentication (port 9095 avoids conflict with kafka plugin) volumes: From d460c8a7c338e0d32cf6c9d141c04d13983470f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller?= Date: Fri, 27 Sep 2024 17:47:08 +0200 Subject: [PATCH 34/34] chore(example): Bump rabbitmq from 3.9-management-alpine to rabbitmq:4.0-management-alpine in amqp-example --- springwolf-examples/springwolf-amqp-example/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/springwolf-examples/springwolf-amqp-example/docker-compose.yml b/springwolf-examples/springwolf-amqp-example/docker-compose.yml index 7ef3d9143..30114e09c 100644 --- a/springwolf-examples/springwolf-amqp-example/docker-compose.yml +++ b/springwolf-examples/springwolf-amqp-example/docker-compose.yml @@ -11,7 +11,7 @@ services: - amqp amqp: - image: rabbitmq:3.9-management-alpine + image: rabbitmq:4.0-management-alpine ports: # AMQP protocol port - '5672:5672'