actual = properties.getPayload().getExtractableClasses();
+
+ assertThat(actual).hasSize(4);
+ // default values
+ assertThat(actual).containsEntry("org.apache.kafka.streams.kstream.KStream", 1);
+ assertThat(actual).containsEntry("org.springframework.messaging.Message", 0);
+ assertThat(actual).containsEntry("java.util.function.Consumer", 0);
+ assertThat(actual).containsEntry("java.util.function.Supplier", 0);
+ }
+ }
+}
diff --git a/springwolf-examples/springwolf-amqp-example/build.gradle b/springwolf-examples/springwolf-amqp-example/build.gradle
index f5cdef724..c66d1e6eb 100644
--- a/springwolf-examples/springwolf-amqp-example/build.gradle
+++ b/springwolf-examples/springwolf-amqp-example/build.gradle
@@ -20,29 +20,29 @@ dependencies {
implementation "org.springframework.amqp:spring-rabbit"
implementation "org.slf4j:slf4j-api:${slf4jApiVersion}"
implementation "io.swagger.core.v3:swagger-annotations:${swaggerVersion}"
- implementation "com.asyncapi:asyncapi-core:${asyncapiCoreVersion}"
implementation "org.springframework.amqp:spring-amqp"
implementation "org.springframework.boot:spring-boot-autoconfigure"
implementation "org.springframework.boot:spring-boot"
- implementation "org.springframework:spring-beans"
implementation "org.springframework:spring-context"
testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}"
- testImplementation "com.vaadin.external.google:android-json:${androidJsonVersion}"
-
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"
testImplementation "org.springframework:spring-web"
testImplementation "org.springframework:spring-test"
testImplementation "org.testcontainers:testcontainers:${testcontainersVersion}"
testImplementation "org.testcontainers:junit-jupiter:${testcontainersVersion}"
+
+ testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}"
+ testCompileOnly "org.projectlombok:lombok:${lombokVersion}"
}
docker {
diff --git a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/configuration/AsyncApiConfiguration.java b/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/configuration/AsyncApiConfiguration.java
deleted file mode 100644
index 4f457250a..000000000
--- a/springwolf-examples/springwolf-amqp-example/src/main/java/io/github/stavshamir/springwolf/example/amqp/configuration/AsyncApiConfiguration.java
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-package io.github.stavshamir.springwolf.example.amqp.configuration;
-
-import com.asyncapi.v2._6_0.model.info.Contact;
-import com.asyncapi.v2._6_0.model.info.Info;
-import com.asyncapi.v2._6_0.model.info.License;
-import com.asyncapi.v2._6_0.model.server.Server;
-import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncListener;
-import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncPublisher;
-import io.github.stavshamir.springwolf.asyncapi.types.AmqpConsumerData;
-import io.github.stavshamir.springwolf.asyncapi.types.AmqpProducerData;
-import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
-import io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-import java.util.Map;
-
-@Configuration
-public class AsyncApiConfiguration {
-
- private final String amqpHost;
- private final String amqpPort;
-
- public AsyncApiConfiguration(
- @Value("${spring.rabbitmq.host}") String amqpHost, @Value("${spring.rabbitmq.port}") int amqpPort) {
- this.amqpHost = amqpHost;
- this.amqpPort = String.valueOf(amqpPort);
- }
-
- /**
- * This bean is only required if full control on the {@link AsyncApiDocket} is needed
- *
- * By default, Springwolf uses the {@see Info} provided in the application.properties
- * Consumers are detected when the @RabbitListener or {@link AsyncListener} annotation is used
- * Producers are detected when the springwolf {@link AsyncPublisher} annotation is used
- */
- @Bean
- @ConditionalOnProperty(value = "customAsyncApiDocketBean", havingValue = "true", matchIfMissing = true)
- public AsyncApiDocket asyncApiDocket() {
- Info info = Info.builder()
- .version("1.0.0")
- .title("Springwolf example project - AMQP")
- .contact(Contact.builder()
- .name("springwolf")
- .url("https://github.com/springwolf/springwolf-core")
- .email("example@example.com")
- .build())
- .description("Springwolf example project to demonstrate springwolfs abilities")
- .license(License.builder().name("Apache License 2.0").build())
- .build();
-
- // the builder for asyncapi info, contact and license doesn't support setting/adding extensions, so
- // we add text extension explicitely
- info.setExtensionFields(Map.of("x-api-audience", "company-internal"));
- info.getContact().setExtensionFields(Map.of("x-phone", "+49 123 456789"));
- info.getLicense().setExtensionFields(Map.of("x-desc", "some description"));
-
- Server amqp = Server.builder()
- .protocol("amqp")
- .url(String.format("%s:%s", amqpHost, amqpPort))
- .build();
-
- AmqpProducerData exampleProducer = AmqpProducerData.amqpProducerDataBuilder()
- .queueName("example-producer-channel")
- .description("example-producer-channel-description")
- .exchangeName("example-topic-exchange")
- .routingKey("example-topic-routing-key")
- .payloadType(AnotherPayloadDto.class)
- .build();
-
- AmqpConsumerData exampleManuallyDefinedConsumer = AmqpConsumerData.amqpConsumerDataBuilder()
- .queueName("example-manual-consumer-channel")
- .description("example-manual-consumer-channel-description")
- .exchangeName("example-consumer-topic-exchange")
- .routingKey("example-consumer-topic-routing-key")
- .payloadType(AnotherPayloadDto.class)
- .build();
-
- return AsyncApiDocket.builder()
- .basePackage("io.github.stavshamir.springwolf.example")
- .info(info)
- .server("amqp", amqp)
- .producer(exampleProducer)
- .consumer(exampleManuallyDefinedConsumer)
- .build();
- }
-}
diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiSystemTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiSystemTest.java
index 2a9679e32..964c5ee15 100644
--- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiSystemTest.java
+++ b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiSystemTest.java
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.amqp;
-import org.json.JSONException;
+import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.web.client.RestTemplate;
import org.testcontainers.containers.DockerComposeContainer;
@@ -23,6 +23,7 @@
* While the assertion of this test is identical to ApiIntegrationTests,
* the setup uses a full docker-compose context with a real kafka instance.
*/
+@Slf4j
@Testcontainers
// @Ignore("Uncomment this line if you have issues running this test on your local machine.")
public class ApiSystemTest {
@@ -46,7 +47,8 @@ public class ApiSystemTest {
@Container
public static DockerComposeContainer> environment = new DockerComposeContainer<>(new File("docker-compose.yml"))
.withExposedService(APP_NAME, APP_PORT)
- .withEnv(ENV);
+ .withEnv(ENV)
+ .withLogConsumer(APP_NAME, l -> log.debug("APP: %s".formatted(l.getUtf8StringWithoutLineEnding())));
private String baseUrl() {
String host = environment.getServiceHost(APP_NAME, APP_PORT);
@@ -55,7 +57,7 @@ private String baseUrl() {
}
@Test
- void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException, JSONException {
+ void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException {
String url = baseUrl() + "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiWithDocketBeanIntegrationTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiWithDocketBeanIntegrationTest.java
deleted file mode 100644
index ea556874a..000000000
--- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiWithDocketBeanIntegrationTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-package io.github.stavshamir.springwolf.example.amqp;
-
-import org.springframework.test.context.TestPropertySource;
-
-/**
- * Api integrationtest based on a SpringBoot application that defines a custom Docket bean. This contains Info and
- * Server Informations as well as some explicit Producer and Consumer definitions.
- */
-@TestPropertySource(properties = {"customAsyncApiDocketBean=true"})
-public class ApiWithDocketBeanIntegrationTest extends BaseApiIntegrationTest {
-
- @Override
- protected String getExpectedApiFileName() {
- return "/asyncapi.json";
- }
-}
diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiWithDocketFromEnvironmentIntegrationTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiWithDocketFromEnvironmentIntegrationTest.java
deleted file mode 100644
index a562f65ed..000000000
--- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/ApiWithDocketFromEnvironmentIntegrationTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-package io.github.stavshamir.springwolf.example.amqp;
-
-import org.springframework.test.context.TestPropertySource;
-
-/**
- * Api integrationtest based on a SpringBoot application that defines all info and server properties via
- * spring environment (from application.properties).
- */
-@TestPropertySource(properties = {"customAsyncApiDocketBean=false"})
-public class ApiWithDocketFromEnvironmentIntegrationTest extends BaseApiIntegrationTest {
-
- @Override
- protected String getExpectedApiFileName() {
- return "/asyncapi_withdocketfromenvironment.json";
- }
-}
diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/BaseApiIntegrationTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/BaseApiIntegrationTest.java
deleted file mode 100644
index b2cfaa72d..000000000
--- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/BaseApiIntegrationTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-package io.github.stavshamir.springwolf.example.amqp;
-
-import org.json.JSONException;
-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 java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-/**
- * Api integrationtest base class defining a SpringBootTest and a test method which asserts the resulting asyncapi.
- * Subclasses can customize this test with @TestPropertySources and custom expectation file names.
- * @see ApiWithDocketBeanIntegrationTest
- * @see ApiWithDocketFromEnvironmentIntegrationTest
- */
-@SpringBootTest(
- classes = {SpringwolfAmqpExampleApplication.class},
- webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-public abstract class BaseApiIntegrationTest {
-
- @Autowired
- private TestRestTemplate restTemplate;
-
- @Value("${server.port}")
- public Integer serverPort;
-
- @Test
- void asyncApiResourceArtifactTest() throws JSONException, IOException {
- String url = "/springwolf/docs";
- String actual = restTemplate.getForObject(url, String.class);
- Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actual);
-
- String expectedApiFileName = getExpectedApiFileName();
- InputStream s = this.getClass().getResourceAsStream(expectedApiFileName);
- String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8);
-
- assertEquals(expected, actual);
- }
-
- protected abstract String getExpectedApiFileName();
-}
diff --git a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/SpringContextIntegrationTest.java b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/SpringContextIntegrationTest.java
index 623324ada..7eb8e0ddd 100644
--- a/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/SpringContextIntegrationTest.java
+++ b/springwolf-examples/springwolf-amqp-example/src/test/java/io/github/stavshamir/springwolf/example/amqp/SpringContextIntegrationTest.java
@@ -14,34 +14,10 @@
public class SpringContextIntegrationTest {
- @Nested
- @SpringBootTest(classes = SpringwolfAmqpExampleApplication.class)
- class AsyncApiDocketTest {
-
- @Autowired
- private ApplicationContext context;
-
- @Autowired
- private AsyncApiService asyncApiService;
-
- @Test
- void testContextWithAsyncApiDocketBean() {
- assertNotNull(context);
-
- assertThat(asyncApiService.getAsyncAPI()).isNotNull();
- }
-
- @Test
- void testAllChannelsAreFound() {
- assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(7);
- }
- }
-
@Nested
@SpringBootTest(classes = SpringwolfAmqpExampleApplication.class)
@TestPropertySource(
properties = {
- "customAsyncApiDocketBean=false",
"springwolf.enabled=true",
"springwolf.docket.info.title=Info title was loaded from spring properties",
"springwolf.docket.info.version=1.0.0",
@@ -66,7 +42,6 @@ void testContextWithApplicationProperties() {
@Test
void testAllChannelsAreFound() {
- // 2 channels defined in the AsyncDocket are not found (7 - 2 = 5)
assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(5);
}
}
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 1f1cdaf20..6c6d4ad90 100644
--- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json
+++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json
@@ -74,88 +74,6 @@
}
}
},
- "example-manual-consumer-channel": {
- "publish": {
- "operationId": "example-manual-consumer-channel_publish",
- "description": "example-manual-consumer-channel-description",
- "bindings": {
- "amqp": {
- "cc": [
- "example-consumer-topic-routing-key"
- ],
- "bindingVersion": "0.2.0"
- }
- },
- "message": {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto",
- "title": "AnotherPayloadDto",
- "description": "Another payload model",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/HeadersNotDocumented"
- },
- "bindings": {
- "amqp": {
- "bindingVersion": "0.2.0"
- }
- }
- }
- },
- "bindings": {
- "amqp": {
- "is": "routingKey",
- "exchange": {
- "name": "example-consumer-topic-exchange",
- "vhost": "/"
- },
- "bindingVersion": "0.2.0"
- }
- }
- },
- "example-producer-channel": {
- "subscribe": {
- "operationId": "example-producer-channel_subscribe",
- "description": "example-producer-channel-description",
- "bindings": {
- "amqp": {
- "cc": [
- "example-topic-routing-key"
- ],
- "bindingVersion": "0.2.0"
- }
- },
- "message": {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto",
- "title": "AnotherPayloadDto",
- "description": "Another payload model",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/HeadersNotDocumented"
- },
- "bindings": {
- "amqp": {
- "bindingVersion": "0.2.0"
- }
- }
- }
- },
- "bindings": {
- "amqp": {
- "is": "routingKey",
- "exchange": {
- "name": "example-topic-exchange",
- "vhost": "/"
- },
- "bindingVersion": "0.2.0"
- }
- }
- },
"example-producer-channel-publisher": {
"subscribe": {
"operationId": "example-producer-channel-publisher_subscribe",
diff --git a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi_withdocketfromenvironment.json b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi_withdocketfromenvironment.json
deleted file mode 100644
index 6c6d4ad90..000000000
--- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi_withdocketfromenvironment.json
+++ /dev/null
@@ -1,354 +0,0 @@
-{
- "asyncapi": "2.6.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"
- },
- "defaultContentType": "application/json",
- "servers": {
- "amqp": {
- "url": "amqp:5672",
- "protocol": "amqp"
- }
- },
- "channels": {
- "another-queue": {
- "publish": {
- "operationId": "another-queue_publish_receiveAnotherPayload",
- "description": "Auto-generated description",
- "bindings": {
- "amqp": {
- "cc": [
- "another-queue"
- ],
- "bindingVersion": "0.2.0"
- }
- },
- "message": {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto",
- "title": "AnotherPayloadDto",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/HeadersNotDocumented"
- },
- "bindings": {
- "amqp": {
- "bindingVersion": "0.2.0"
- }
- }
- }
- },
- "bindings": {
- "amqp": {
- "is": "queue",
- "exchange": {
- "name": "",
- "type": "direct",
- "durable": true,
- "autoDelete": false,
- "vhost": "/"
- },
- "queue": {
- "name": "another-queue",
- "durable": false,
- "exclusive": false,
- "autoDelete": false,
- "vhost": "/"
- },
- "bindingVersion": "0.2.0"
- }
- }
- },
- "example-producer-channel-publisher": {
- "subscribe": {
- "operationId": "example-producer-channel-publisher_subscribe",
- "description": "Custom, optional description defined in the AsyncPublisher annotation",
- "bindings": {
- "amqp": {
- "expiration": 0,
- "cc": [ ],
- "priority": 0,
- "deliveryMode": 0,
- "mandatory": false,
- "timestamp": false,
- "ack": false,
- "bindingVersion": "0.2.0"
- }
- },
- "message": {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto",
- "title": "AnotherPayloadDto",
- "description": "Another payload model",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/HeadersNotDocumented"
- },
- "bindings": {
- "amqp": {
- "bindingVersion": "0.2.0"
- }
- }
- }
- }
- },
- "example-queue": {
- "publish": {
- "operationId": "example-queue_publish_receiveExamplePayload",
- "description": "Auto-generated description",
- "bindings": {
- "amqp": {
- "cc": [
- "example-queue"
- ],
- "bindingVersion": "0.2.0"
- }
- },
- "message": {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto",
- "title": "ExamplePayloadDto",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/HeadersNotDocumented"
- },
- "bindings": {
- "amqp": {
- "bindingVersion": "0.2.0"
- }
- }
- }
- },
- "bindings": {
- "amqp": {
- "is": "queue",
- "exchange": {
- "name": "",
- "type": "direct",
- "durable": true,
- "autoDelete": false,
- "vhost": "/"
- },
- "queue": {
- "name": "example-queue",
- "durable": false,
- "exclusive": false,
- "autoDelete": false,
- "vhost": "/"
- },
- "bindingVersion": "0.2.0"
- }
- }
- },
- "example-topic-routing-key": {
- "publish": {
- "operationId": "example-topic-routing-key_publish_bindingsExample",
- "description": "Auto-generated description",
- "bindings": {
- "amqp": {
- "cc": [
- "example-topic-routing-key"
- ],
- "bindingVersion": "0.2.0"
- }
- },
- "message": {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto",
- "title": "AnotherPayloadDto",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/HeadersNotDocumented"
- },
- "bindings": {
- "amqp": {
- "bindingVersion": "0.2.0"
- }
- }
- }
- },
- "bindings": {
- "amqp": {
- "is": "routingKey",
- "exchange": {
- "name": "example-bindings-exchange-name",
- "type": "topic",
- "durable": true,
- "autoDelete": false,
- "vhost": "/"
- },
- "queue": {
- "name": "example-bindings-queue",
- "durable": false,
- "exclusive": true,
- "autoDelete": true,
- "vhost": "/"
- },
- "bindingVersion": "0.2.0"
- }
- }
- },
- "multi-payload-queue": {
- "publish": {
- "operationId": "multi-payload-queue_publish_bindingsBeanExample",
- "description": "Auto-generated description",
- "bindings": {
- "amqp": {
- "cc": [
- "example-topic-routing-key"
- ],
- "bindingVersion": "0.2.0"
- }
- },
- "message": {
- "oneOf": [
- {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto",
- "title": "AnotherPayloadDto",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/HeadersNotDocumented"
- },
- "bindings": {
- "amqp": {
- "bindingVersion": "0.2.0"
- }
- }
- },
- {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto",
- "title": "ExamplePayloadDto",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/HeadersNotDocumented"
- },
- "bindings": {
- "amqp": {
- "bindingVersion": "0.2.0"
- }
- }
- }
- ]
- }
- },
- "bindings": {
- "amqp": {
- "is": "routingKey",
- "exchange": {
- "name": "example-topic-exchange",
- "type": "topic",
- "durable": true,
- "autoDelete": false,
- "vhost": "/"
- },
- "queue": {
- "name": "multi-payload-queue",
- "durable": true,
- "exclusive": false,
- "autoDelete": false,
- "vhost": "/"
- },
- "bindingVersion": "0.2.0"
- }
- }
- }
- },
- "components": {
- "schemas": {
- "HeadersNotDocumented": {
- "type": "object",
- "properties": { },
- "example": { }
- },
- "io.github.stavshamir.springwolf.example.amqp.dtos.AnotherPayloadDto": {
- "required": [
- "example"
- ],
- "type": "object",
- "properties": {
- "example": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto"
- },
- "foo": {
- "type": "string",
- "description": "Foo field",
- "example": "bar"
- }
- },
- "description": "Another payload model",
- "example": {
- "example": {
- "someEnum": "FOO2",
- "someLong": 5,
- "someString": "some string value"
- },
- "foo": "bar"
- }
- },
- "io.github.stavshamir.springwolf.example.amqp.dtos.ExamplePayloadDto": {
- "required": [
- "someEnum",
- "someString"
- ],
- "type": "object",
- "properties": {
- "someEnum": {
- "type": "string",
- "description": "Some enum field",
- "example": "FOO2",
- "enum": [
- "FOO1",
- "FOO2",
- "FOO3"
- ]
- },
- "someLong": {
- "type": "integer",
- "description": "Some long field",
- "format": "int64",
- "example": 5
- },
- "someString": {
- "type": "string",
- "description": "Some string field",
- "example": "some string value"
- }
- },
- "description": "Example payload model",
- "example": {
- "someEnum": "FOO2",
- "someLong": 5,
- "someString": "some string value"
- }
- }
- }
- },
- "tags": [ ]
-}
\ No newline at end of file
diff --git a/springwolf-examples/springwolf-cloud-stream-example/build.gradle b/springwolf-examples/springwolf-cloud-stream-example/build.gradle
index 1eca634eb..b8ad253e5 100644
--- a/springwolf-examples/springwolf-cloud-stream-example/build.gradle
+++ b/springwolf-examples/springwolf-cloud-stream-example/build.gradle
@@ -18,7 +18,7 @@ dependencyManagement {
}
dependencies {
- implementation project(":springwolf-core")
+ testImplementation project(":springwolf-core")
runtimeOnly project(":springwolf-plugins:springwolf-cloud-stream")
annotationProcessor project(":springwolf-plugins:springwolf-cloud-stream")
@@ -27,28 +27,33 @@ dependencies {
runtimeOnly "org.springframework.boot:spring-boot-starter-web"
runtimeOnly "org.springframework.boot:spring-boot-starter-actuator"
- implementation "com.asyncapi:asyncapi-core:${asyncapiCoreVersion}"
implementation "org.apache.kafka:kafka-streams:${kafkaStreamsVersion}"
implementation "org.slf4j:slf4j-api:${slf4jApiVersion}"
implementation "io.swagger.core.v3:swagger-annotations:${swaggerVersion}"
implementation "org.springframework.boot:spring-boot-autoconfigure"
implementation "org.springframework.boot:spring-boot"
- implementation "org.springframework:spring-beans"
implementation "org.springframework:spring-context"
+ compileOnly "org.projectlombok:lombok:${lombokVersion}"
+
+ annotationProcessor "org.projectlombok:lombok:${lombokVersion}"
+
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}"
- testImplementation "com.vaadin.external.google:android-json:${androidJsonVersion}"
testImplementation "org.assertj:assertj-core:${assertjCoreVersion}"
testImplementation "org.springframework.boot:spring-boot-test"
testImplementation "org.springframework:spring-test"
+ testImplementation "org.springframework:spring-beans"
testImplementation "org.springframework:spring-web"
testImplementation "org.springframework.kafka:spring-kafka-test"
testImplementation "org.testcontainers:testcontainers:${testcontainersVersion}"
testImplementation "org.testcontainers:junit-jupiter:${testcontainersVersion}"
+
+ testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}"
+ testCompileOnly "org.projectlombok:lombok:${lombokVersion}"
}
docker {
@@ -66,8 +71,5 @@ docker {
}
test {
- minHeapSize = "128m" // initial heap size
- maxHeapSize = "1024m" // maximum heap size
-
dependsOn dockerBuildImage
}
diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/stavshamir/springwolf/example/cloudstream/configuration/AsyncApiConfiguration.java b/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/stavshamir/springwolf/example/cloudstream/configuration/AsyncApiConfiguration.java
deleted file mode 100644
index fa2fe4420..000000000
--- a/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/stavshamir/springwolf/example/cloudstream/configuration/AsyncApiConfiguration.java
+++ /dev/null
@@ -1,58 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-package io.github.stavshamir.springwolf.example.cloudstream.configuration;
-
-import com.asyncapi.v2._6_0.model.info.Contact;
-import com.asyncapi.v2._6_0.model.info.Info;
-import com.asyncapi.v2._6_0.model.info.License;
-import com.asyncapi.v2._6_0.model.server.Server;
-import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncListener;
-import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncPublisher;
-import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class AsyncApiConfiguration {
-
- private final String BOOTSTRAP_SERVERS;
-
- public AsyncApiConfiguration(@Value("${spring.kafka.bootstrap-servers}") String bootstrapServers) {
- this.BOOTSTRAP_SERVERS = bootstrapServers;
- }
-
- /**
- * This bean is only required if full control on the {@link AsyncApiDocket} is needed
- *
- * By default, Springwolf uses the {@see Info} provided in the application.properties
- * Consumers are detected when the @KafkaListener or {@link AsyncListener} annotation is used
- * Producers are detected when the springwolf {@link AsyncPublisher} annotation is used
- */
- @Bean
- @ConditionalOnProperty(value = "customAsyncApiDocketBean", havingValue = "true", matchIfMissing = true)
- public AsyncApiDocket asyncApiDocket() {
- Info info = Info.builder()
- .version("1.0.0")
- .title("Springwolf example project - CloudStream")
- .contact(Contact.builder()
- .name("springwolf")
- .url("https://github.com/springwolf/springwolf-core")
- .email("example@example.com")
- .build())
- .description("Springwolf example project")
- .license(License.builder().name("Apache License 2.0").build())
- .build();
-
- return AsyncApiDocket.builder()
- .basePackage("io.github.stavshamir.springwolf.example")
- .info(info)
- .server(
- "kafka",
- Server.builder()
- .protocol("kafka")
- .url(BOOTSTRAP_SERVERS)
- .build())
- .build();
- }
-}
diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/ApiIntegrationTest.java b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/ApiIntegrationTest.java
index 7102b2e11..7dddbeadf 100644
--- a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/ApiIntegrationTest.java
+++ b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/ApiIntegrationTest.java
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.cloudstream;
-import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -21,28 +20,26 @@
@SpringBootTest(
classes = {SpringwolfCloudstreamExampleApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@EmbeddedKafka(
- partitions = 1,
- brokerProperties = {"listeners=PLAINTEXT://localhost:29092", "port=29092"})
+@EmbeddedKafka(partitions = 1)
@DirtiesContext
public class ApiIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
- @Value("${server.port}")
- public Integer serverPort;
+ @Value("${spring.kafka.bootstrap-servers}")
+ public String bootstrapServers;
@Test
- void asyncApiResourceArtifactTest() throws JSONException, IOException {
+ void asyncApiResourceArtifactTest() throws IOException {
String url = "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actual);
InputStream s = this.getClass().getResourceAsStream("/asyncapi.json");
String expectedWithoutServersKafkaUrlPatch = new String(s.readAllBytes(), StandardCharsets.UTF_8);
- // When running with EmbeddedKafka, localhost is used as hostname
- String expected = expectedWithoutServersKafkaUrlPatch.replace("kafka:29092", "127.0.0.1:29092");
+ // When running with EmbeddedKafka, the kafka bootstrap server does run on random ports
+ String expected = expectedWithoutServersKafkaUrlPatch.replace("kafka:29092", bootstrapServers);
assertEquals(expected, actual);
}
diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/ApiSystemTest.java b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/ApiSystemTest.java
index 68b517625..5b875acdc 100644
--- a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/ApiSystemTest.java
+++ b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/ApiSystemTest.java
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.cloudstream;
-import org.json.JSONException;
+import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.web.client.RestTemplate;
import org.testcontainers.containers.DockerComposeContainer;
@@ -23,6 +23,7 @@
* While the assertion of this test is identical to ApiIntegrationTests,
* the setup uses a full docker-compose context with a real kafka instance.
*/
+@Slf4j
@Testcontainers
// @Ignore("Uncomment this line if you have issues running this test on your local machine.")
public class ApiSystemTest {
@@ -46,7 +47,8 @@ public class ApiSystemTest {
@Container
public static DockerComposeContainer> environment = new DockerComposeContainer<>(new File("docker-compose.yml"))
.withExposedService(APP_NAME, APP_PORT)
- .withEnv(ENV);
+ .withEnv(ENV)
+ .withLogConsumer(APP_NAME, l -> log.debug("APP: %s".formatted(l.getUtf8StringWithoutLineEnding())));
private String baseUrl() {
String host = environment.getServiceHost(APP_NAME, APP_PORT);
@@ -55,7 +57,7 @@ private String baseUrl() {
}
@Test
- void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException, JSONException {
+ void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException {
String url = baseUrl() + "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/SpringContextIntegrationTest.java b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/SpringContextIntegrationTest.java
index f785958ea..c15dd9716 100644
--- a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/SpringContextIntegrationTest.java
+++ b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/stavshamir/springwolf/example/cloudstream/SpringContextIntegrationTest.java
@@ -16,28 +16,6 @@
public class SpringContextIntegrationTest {
- @SpringBootTest(classes = SpringwolfCloudstreamExampleApplication.class)
- @EmbeddedKafka(
- partitions = 1,
- brokerProperties = {"listeners=PLAINTEXT://localhost:29092", "port=29092"})
- @Nested
- @DirtiesContext
- class AsyncApiDocketTest {
-
- @Autowired
- private ApplicationContext context;
-
- @Autowired
- private AsyncApiService asyncApiService;
-
- @Test
- void testContextWithAsyncApiDocketBean() {
- assertNotNull(context);
-
- assertThat(asyncApiService.getAsyncAPI()).isNotNull();
- }
- }
-
@SpringBootTest(classes = SpringwolfCloudstreamExampleApplication.class)
@EmbeddedKafka(
partitions = 1,
@@ -46,7 +24,6 @@ void testContextWithAsyncApiDocketBean() {
@DirtiesContext
@TestPropertySource(
properties = {
- "customAsyncApiDocketBean=false",
"springwolf.enabled=true",
"springwolf.docket.info.title=Info title was loaded from spring properties",
"springwolf.docket.info.version=1.0.0",
diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-cloud-stream-example/src/test/resources/asyncapi.json
index 4b93d45d0..6213321c1 100644
--- a/springwolf-examples/springwolf-cloud-stream-example/src/test/resources/asyncapi.json
+++ b/springwolf-examples/springwolf-cloud-stream-example/src/test/resources/asyncapi.json
@@ -1,9 +1,9 @@
{
"asyncapi": "2.6.0",
"info": {
- "title": "Springwolf example project - CloudStream",
+ "title": "Springwolf example project - Cloud Stream",
"version": "1.0.0",
- "description": "Springwolf example project",
+ "description": "Springwolf example project to demonstrate springwolfs abilities",
"contact": {
"name": "springwolf",
"url": "https://github.com/springwolf/springwolf-core",
diff --git a/springwolf-examples/springwolf-kafka-example/build.gradle b/springwolf-examples/springwolf-kafka-example/build.gradle
index dbb57c2b1..6b4b10e1c 100644
--- a/springwolf-examples/springwolf-kafka-example/build.gradle
+++ b/springwolf-examples/springwolf-kafka-example/build.gradle
@@ -23,7 +23,6 @@ dependencies {
implementation "org.springframework:spring-beans"
implementation "org.springframework:spring-context"
- implementation "org.springframework:spring-web"
implementation "org.springframework.boot:spring-boot"
implementation "org.springframework.boot:spring-boot-autoconfigure"
@@ -33,7 +32,6 @@ dependencies {
implementation "org.springframework.security:spring-security-config"
implementation "org.springframework.security:spring-security-web"
- implementation "com.asyncapi:asyncapi-core:${asyncapiCoreVersion}"
implementation "io.swagger.core.v3:swagger-annotations:${swaggerVersion}"
implementation "org.slf4j:slf4j-api:${slf4jApiVersion}"
@@ -42,8 +40,6 @@ dependencies {
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"
- testImplementation "com.vaadin.external.google:android-json:${androidJsonVersion}"
-
testImplementation "org.apache.kafka:kafka-clients:${kafkaClientsVersion}@jar"
testImplementation "org.assertj:assertj-core:${assertjCoreVersion}"
testImplementation "org.awaitility:awaitility:${awaitilityVersion}"
@@ -62,6 +58,9 @@ dependencies {
testImplementation("org.springframework.boot:spring-boot-starter-actuator")
permitTestUnusedDeclared("org.springframework.boot:spring-boot-starter-actuator")
+
+ testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}"
+ testCompileOnly "org.projectlombok:lombok:${lombokVersion}"
}
docker {
diff --git a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/stavshamir/springwolf/example/kafka/configuration/AsyncApiConfiguration.java b/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/stavshamir/springwolf/example/kafka/configuration/AsyncApiConfiguration.java
deleted file mode 100644
index 39c4d67c0..000000000
--- a/springwolf-examples/springwolf-kafka-example/src/main/java/io/github/stavshamir/springwolf/example/kafka/configuration/AsyncApiConfiguration.java
+++ /dev/null
@@ -1,102 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-package io.github.stavshamir.springwolf.example.kafka.configuration;
-
-import com.asyncapi.v2._6_0.model.info.Contact;
-import com.asyncapi.v2._6_0.model.info.Info;
-import com.asyncapi.v2._6_0.model.info.License;
-import com.asyncapi.v2._6_0.model.server.Server;
-import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncListener;
-import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.annotation.AsyncPublisher;
-import io.github.stavshamir.springwolf.asyncapi.types.KafkaConsumerData;
-import io.github.stavshamir.springwolf.asyncapi.types.KafkaProducerData;
-import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders;
-import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeadersForCloudEventsBuilder;
-import io.github.stavshamir.springwolf.configuration.AsyncApiDocket;
-import io.github.stavshamir.springwolf.example.kafka.dtos.AnotherPayloadDto;
-import io.github.stavshamir.springwolf.example.kafka.dtos.ExamplePayloadDto;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.MediaType;
-
-import static io.github.stavshamir.springwolf.example.kafka.configuration.KafkaConfiguration.CONSUMER_TOPIC;
-import static io.github.stavshamir.springwolf.example.kafka.configuration.KafkaConfiguration.PRODUCER_TOPIC;
-
-@Configuration
-public class AsyncApiConfiguration {
-
- private final String BOOTSTRAP_SERVERS;
-
- public AsyncApiConfiguration(@Value("${spring.kafka.bootstrap-servers}") String bootstrapServers) {
- this.BOOTSTRAP_SERVERS = bootstrapServers;
- }
-
- /**
- * This bean is only required if full control on the {@link AsyncApiDocket} is needed
- *
- * By default, Springwolf uses the {@see Info} provided in the application.properties
- * Consumers are detected when the @KafkaListener or {@link AsyncListener} annotation is used
- * Producers are detected when the springwolf {@link AsyncPublisher} annotation is used
- */
- @Bean
- @ConditionalOnProperty(value = "customAsyncApiDocketBean", havingValue = "true", matchIfMissing = true)
- public AsyncApiDocket asyncApiDocket() {
- Info info = Info.builder()
- .version("1.0.0")
- .title("Springwolf example project - Kafka")
- .contact(Contact.builder()
- .name("springwolf")
- .url("https://github.com/springwolf/springwolf-core")
- .email("example@example.com")
- .build())
- .description("Springwolf example project to demonstrate springwolfs abilities")
- .license(License.builder().name("Apache License 2.0").build())
- .build();
-
- KafkaProducerData anotherProducerData = KafkaProducerData.kafkaProducerDataBuilder()
- .topicName(PRODUCER_TOPIC)
- .description("Custom, optional description for this produced to topic")
- .payloadType(AnotherPayloadDto.class)
- .headers(createCloudEventHeaders())
- .build();
-
- KafkaConsumerData manuallyConfiguredConsumer = KafkaConsumerData.kafkaConsumerDataBuilder()
- .topicName(CONSUMER_TOPIC)
- .description("Custom, optional description for this consumed topic")
- .payloadType(ExamplePayloadDto.class)
- .build();
-
- return AsyncApiDocket.builder()
- .basePackage("io.github.stavshamir.springwolf.example")
- .info(info)
- .server(
- "kafka",
- Server.builder()
- .protocol("kafka")
- .url(BOOTSTRAP_SERVERS)
- .build())
- .producer(anotherProducerData)
- .consumer(manuallyConfiguredConsumer)
- .build();
- }
-
- private static AsyncHeaders createCloudEventHeaders() {
- AsyncHeaders ceBaseHeaders = createCloudEventsBaseHeaders();
-
- return new AsyncHeadersForCloudEventsBuilder("CloudEventHeadersForAnotherPayloadDtoEndpoint", ceBaseHeaders)
- .withTypeHeader("io.github.stavshamir.springwolf.CloudEventHeadersForAnotherPayloadDtoEndpoint")
- .withSourceHeader("springwolf-kafka-example/anotherPayloadDtoEndpoint")
- .withSubjectHeader("Test Subject")
- .build();
- }
-
- private static AsyncHeaders createCloudEventsBaseHeaders() {
- return new AsyncHeadersForCloudEventsBuilder()
- .withContentTypeHeader(MediaType.APPLICATION_JSON)
- .withSpecVersionHeader("1.0")
- .withIdHeader("1234-1234-1234")
- .withTimeHeader("2015-07-20T15:49:04-07:00")
- .build();
- }
-}
diff --git a/springwolf-examples/springwolf-kafka-example/src/main/resources/application.properties b/springwolf-examples/springwolf-kafka-example/src/main/resources/application.properties
index 7f0882c0f..d69e67c8d 100644
--- a/springwolf-examples/springwolf-kafka-example/src/main/resources/application.properties
+++ b/springwolf-examples/springwolf-kafka-example/src/main/resources/application.properties
@@ -36,6 +36,7 @@ springwolf.docket.info.contact.name=springwolf
springwolf.docket.info.contact.email=example@example.com
springwolf.docket.info.contact.url=https://github.com/springwolf/springwolf-core
springwolf.docket.info.license.name=Apache License 2.0
+springwolf.payload.extractable-classes.java.util.List=0
springwolf.use-fqn=true
# Springwolf kafka configuration
diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiIntegrationTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiIntegrationTest.java
index 83df8ab7a..f11f309b0 100644
--- a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiIntegrationTest.java
+++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiIntegrationTest.java
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.kafka;
-import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@@ -21,31 +20,26 @@
@SpringBootTest(
classes = {SpringwolfKafkaExampleApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@EmbeddedKafka(
- partitions = 1,
- brokerProperties = {
- "listeners=PLAINTEXT://localhost:9092",
- "port=9092",
- })
+@EmbeddedKafka(partitions = 1)
@DirtiesContext
public class ApiIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
- @Value("${server.port}")
- public Integer serverPort;
+ @Value("${spring.kafka.bootstrap-servers}")
+ public String bootstrapServers;
@Test
- void asyncApiResourceArtifactTest() throws JSONException, IOException {
+ void asyncApiResourceArtifactTest() throws IOException {
String url = "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actual);
InputStream s = this.getClass().getResourceAsStream("/asyncapi.json");
String expectedWithoutServersKafkaUrlPatch = new String(s.readAllBytes(), StandardCharsets.UTF_8);
- // When running with EmbeddedKafka, localhost is used as hostname
- String expected = expectedWithoutServersKafkaUrlPatch.replace("kafka:29092", "127.0.0.1:9092");
+ // When running with EmbeddedKafka, the kafka bootstrap server does run on random ports
+ String expected = expectedWithoutServersKafkaUrlPatch.replace("kafka:29092", bootstrapServers);
assertEquals(expected, actual);
}
diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiIntegrationWithActuatorIntegrationTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiIntegrationWithActuatorIntegrationTest.java
index e3092aba2..0bae6f7ff 100644
--- a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiIntegrationWithActuatorIntegrationTest.java
+++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiIntegrationWithActuatorIntegrationTest.java
@@ -1,9 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.kafka;
-import org.json.JSONException;
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.boot.test.web.server.LocalServerPort;
@@ -23,12 +23,7 @@
"springwolf.endpoint.actuator.enabled=true",
"management.endpoints.web.exposure.include=springwolf"
})
-@EmbeddedKafka(
- partitions = 1,
- brokerProperties = {
- "listeners=PLAINTEXT://localhost:9092",
- "port=9092",
- })
+@EmbeddedKafka(partitions = 1)
@DirtiesContext
public class ApiIntegrationWithActuatorIntegrationTest {
@@ -38,15 +33,18 @@ public class ApiIntegrationWithActuatorIntegrationTest {
@LocalServerPort
private int managementPort;
+ @Value("${spring.kafka.bootstrap-servers}")
+ public String bootstrapServers;
+
@Test
- void asyncApiResourceArtifactTest() throws JSONException, IOException {
+ void asyncApiResourceArtifactTest() throws IOException {
String url = "http://localhost:" + managementPort + "/actuator/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
InputStream s = this.getClass().getResourceAsStream("/asyncapi.json");
String expectedWithoutServersKafkaUrlPatch = new String(s.readAllBytes(), StandardCharsets.UTF_8);
- // When running with EmbeddedKafka, localhost is used as hostname
- String expected = expectedWithoutServersKafkaUrlPatch.replace("kafka:29092", "127.0.0.1:9092");
+ // When running with EmbeddedKafka, the kafka bootstrap server does run on random ports
+ String expected = expectedWithoutServersKafkaUrlPatch.replace("kafka:29092", bootstrapServers);
assertEquals(expected, actual);
}
diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiSystemTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiSystemTest.java
index e66d10cc6..d6cd8da94 100644
--- a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiSystemTest.java
+++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ApiSystemTest.java
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.kafka;
-import org.json.JSONException;
+import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.web.client.RestTemplate;
import org.testcontainers.containers.DockerComposeContainer;
@@ -23,6 +23,7 @@
* While the assertion of this test is identical to ApiIntegrationTests,
* the setup uses a full docker-compose context with a real kafka instance.
*/
+@Slf4j
@Testcontainers
// @Ignore("Uncomment this line if you have issues running this test on your local machine.")
public class ApiSystemTest {
@@ -46,7 +47,8 @@ public class ApiSystemTest {
@Container
public static DockerComposeContainer> environment = new DockerComposeContainer<>(new File("docker-compose.yml"))
.withExposedService(APP_NAME, APP_PORT)
- .withEnv(ENV);
+ .withEnv(ENV)
+ .withLogConsumer(APP_NAME, l -> log.debug("APP: %s".formatted(l.getUtf8StringWithoutLineEnding())));
private String baseUrl() {
String host = environment.getServiceHost(APP_NAME, APP_PORT);
@@ -55,7 +57,7 @@ private String baseUrl() {
}
@Test
- void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException, JSONException {
+ void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException {
String url = baseUrl() + "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ProducerSystemTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ProducerSystemTest.java
index b7ae9ff4d..fc46ec712 100644
--- a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ProducerSystemTest.java
+++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/ProducerSystemTest.java
@@ -12,9 +12,10 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ssl.DefaultSslBundleRegistry;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
-import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.TestPropertySource;
import org.testcontainers.containers.DockerComposeContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@@ -38,7 +39,7 @@
classes = {SpringwolfKafkaExampleApplication.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
-@DirtiesContext
+@TestPropertySource(properties = {"spring.kafka.bootstrap-servers=localhost:9092"})
@TestMethodOrder(OrderAnnotation.class)
// @Ignore("Uncomment this line if you have issues running this test on your local machine.")
public class ProducerSystemTest {
@@ -60,7 +61,7 @@ public class ProducerSystemTest {
@Order(1)
void verifyKafkaIsAvailable() {
Map consumerProperties =
- properties.getPublishing().getProducer().buildProperties();
+ properties.getPublishing().getProducer().buildProperties(new DefaultSslBundleRegistry());
AdminClient adminClient = KafkaAdminClient.create(consumerProperties);
await().atMost(60, SECONDS)
.untilAsserted(
diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/SpringContextIntegrationTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/SpringContextIntegrationTest.java
index b0e4b6ba8..67f22580d 100644
--- a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/SpringContextIntegrationTest.java
+++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/stavshamir/springwolf/example/kafka/SpringContextIntegrationTest.java
@@ -16,33 +16,6 @@
public class SpringContextIntegrationTest {
- @SpringBootTest(classes = SpringwolfKafkaExampleApplication.class)
- @EmbeddedKafka(
- partitions = 1,
- brokerProperties = {"listeners=PLAINTEXT://localhost:9092", "port=9092"})
- @Nested
- @DirtiesContext
- class AsyncApiDocketTest {
-
- @Autowired
- private ApplicationContext context;
-
- @Autowired
- private AsyncApiService asyncApiService;
-
- @Test
- void testContextWithAsyncApiDocketBean() {
- assertNotNull(context);
-
- assertThat(asyncApiService.getAsyncAPI()).isNotNull();
- }
-
- @Test
- void testAllChannelsAreFound() {
- assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(6);
- }
- }
-
@SpringBootTest(classes = SpringwolfKafkaExampleApplication.class)
@EmbeddedKafka(
partitions = 1,
@@ -51,7 +24,6 @@ void testAllChannelsAreFound() {
@DirtiesContext
@TestPropertySource(
properties = {
- "customAsyncApiDocketBean=false",
"springwolf.enabled=true",
"springwolf.docket.info.title=Info title was loaded from spring properties",
"springwolf.docket.info.version=1.0.0",
@@ -76,8 +48,6 @@ void testContextWithApplicationProperties() {
@Test
void testAllChannelsAreFound() {
- // 2 channels defined in the AsyncDocket are not found,
- // however PRODUCER_TOPIC is also used in ExampleProducer (5 - 2 + 1 = 4)
assertThat(asyncApiService.getAsyncAPI().getChannels()).hasSize(4);
}
}
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 d5529f6bb..fbdc9e901 100644
--- a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json
+++ b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json
@@ -59,72 +59,6 @@
}
}
},
- "example-consumer-topic": {
- "publish": {
- "operationId": "example-consumer-topic_publish",
- "description": "Custom, optional description for this consumed topic",
- "bindings": {
- "kafka": {
- "bindingVersion": "0.4.0"
- }
- },
- "message": {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.kafka.dtos.ExamplePayloadDto",
- "title": "ExamplePayloadDto",
- "description": "Example payload model",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.kafka.dtos.ExamplePayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/HeadersNotDocumented"
- },
- "bindings": {
- "kafka": {
- "bindingVersion": "0.4.0"
- }
- }
- }
- },
- "bindings": {
- "kafka": {
- "bindingVersion": "0.4.0"
- }
- }
- },
- "example-producer-topic": {
- "subscribe": {
- "operationId": "example-producer-topic_subscribe",
- "description": "Custom, optional description for this produced to topic",
- "bindings": {
- "kafka": {
- "bindingVersion": "0.4.0"
- }
- },
- "message": {
- "schemaFormat": "application/vnd.oai.openapi+json;version=3.0.0",
- "name": "io.github.stavshamir.springwolf.example.kafka.dtos.AnotherPayloadDto",
- "title": "AnotherPayloadDto",
- "description": "Another payload model",
- "payload": {
- "$ref": "#/components/schemas/io.github.stavshamir.springwolf.example.kafka.dtos.AnotherPayloadDto"
- },
- "headers": {
- "$ref": "#/components/schemas/CloudEventHeadersForAnotherPayloadDtoEndpoint"
- },
- "bindings": {
- "kafka": {
- "bindingVersion": "0.4.0"
- }
- }
- }
- },
- "bindings": {
- "kafka": {
- "bindingVersion": "0.4.0"
- }
- }
- },
"example-topic": {
"publish": {
"operationId": "example-topic_publish_receiveExamplePayload",
@@ -279,132 +213,6 @@
},
"components": {
"schemas": {
- "CloudEventHeadersForAnotherPayloadDtoEndpoint": {
- "type": "object",
- "properties": {
- "ce_id": {
- "type": "string",
- "description": "CloudEvent Id Header",
- "example": "1234-1234-1234",
- "enum": [
- "1234-1234-1234"
- ]
- },
- "ce_source": {
- "type": "string",
- "description": "CloudEvent Source Header",
- "example": "springwolf-kafka-example/anotherPayloadDtoEndpoint",
- "enum": [
- "springwolf-kafka-example/anotherPayloadDtoEndpoint"
- ]
- },
- "ce_specversion": {
- "type": "string",
- "description": "CloudEvent Spec Version Header",
- "example": "1.0",
- "enum": [
- "1.0"
- ]
- },
- "ce_subject": {
- "type": "string",
- "description": "CloudEvent Subject Header",
- "example": "Test Subject",
- "enum": [
- "Test Subject"
- ]
- },
- "ce_time": {
- "type": "string",
- "description": "CloudEvent Time Header",
- "example": "2015-07-20T15:49:04-07:00",
- "enum": [
- "2015-07-20T15:49:04-07:00"
- ]
- },
- "ce_type": {
- "type": "string",
- "description": "CloudEvent Payload Type Header",
- "example": "io.github.stavshamir.springwolf.CloudEventHeadersForAnotherPayloadDtoEndpoint",
- "enum": [
- "io.github.stavshamir.springwolf.CloudEventHeadersForAnotherPayloadDtoEndpoint"
- ]
- },
- "content-type": {
- "type": "string",
- "description": "CloudEvent Content-Type Header",
- "example": "application/json",
- "enum": [
- "application/json"
- ]
- }
- },
- "example": {
- "ce_id": "1234-1234-1234",
- "ce_source": "springwolf-kafka-example/anotherPayloadDtoEndpoint",
- "ce_specversion": "1.0",
- "ce_subject": "Test Subject",
- "ce_time": "2015-07-20T15:49:04-07:00",
- "ce_type": "io.github.stavshamir.springwolf.CloudEventHeadersForAnotherPayloadDtoEndpoint",
- "content-type": "application/json"
- },
- "x-json-schema": {
- "$schema": "https://json-schema.org/draft-04/schema#",
- "name": "CloudEventHeadersForAnotherPayloadDtoEndpoint",
- "properties": {
- "ce_id": {
- "description": "CloudEvent Id Header",
- "enum": [
- "1234-1234-1234"
- ],
- "type": "string"
- },
- "ce_source": {
- "description": "CloudEvent Source Header",
- "enum": [
- "springwolf-kafka-example/anotherPayloadDtoEndpoint"
- ],
- "type": "string"
- },
- "ce_specversion": {
- "description": "CloudEvent Spec Version Header",
- "enum": [
- "1.0"
- ],
- "type": "string"
- },
- "ce_subject": {
- "description": "CloudEvent Subject Header",
- "enum": [
- "Test Subject"
- ],
- "type": "string"
- },
- "ce_time": {
- "description": "CloudEvent Time Header",
- "enum": [
- "2015-07-20T15:49:04-07:00"
- ],
- "type": "string"
- },
- "ce_type": {
- "description": "CloudEvent Payload Type Header",
- "enum": [
- "io.github.stavshamir.springwolf.CloudEventHeadersForAnotherPayloadDtoEndpoint"
- ],
- "type": "string"
- },
- "content-type": {
- "description": "CloudEvent Content-Type Header",
- "enum": [
- "application/json"
- ],
- "type": "string"
- }
- },
- "type": "object"
- }
- },
"HeadersNotDocumented": {
"type": "object",
"properties": { },
diff --git a/springwolf-examples/springwolf-sns-example/build.gradle b/springwolf-examples/springwolf-sns-example/build.gradle
index 9851c78f1..3098e31b9 100644
--- a/springwolf-examples/springwolf-sns-example/build.gradle
+++ b/springwolf-examples/springwolf-sns-example/build.gradle
@@ -37,8 +37,6 @@ dependencies {
testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}"
- testImplementation "com.vaadin.external.google:android-json:${androidJsonVersion}"
-
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"
testImplementation "org.springframework.boot:spring-boot-test"
@@ -70,11 +68,4 @@ docker {
test {
dependsOn dockerBuildImage
- dependsOn spotlessApply // Automatically fix code formatting if possible
-
- useJUnitPlatform()
-
- testLogging {
- exceptionFormat = 'full'
- }
}
diff --git a/springwolf-examples/springwolf-sns-example/src/test/java/io/github/stavshamir/springwolf/example/sns/ApiIntegrationTest.java b/springwolf-examples/springwolf-sns-example/src/test/java/io/github/stavshamir/springwolf/example/sns/ApiIntegrationTest.java
index b3bc3eb12..345d5e8f3 100644
--- a/springwolf-examples/springwolf-sns-example/src/test/java/io/github/stavshamir/springwolf/example/sns/ApiIntegrationTest.java
+++ b/springwolf-examples/springwolf-sns-example/src/test/java/io/github/stavshamir/springwolf/example/sns/ApiIntegrationTest.java
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.sns;
-import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,7 +36,7 @@ static void setUpTestContainers(DynamicPropertyRegistry registry) {
public Integer serverPort;
@Test
- void asyncApiResourceArtifactTest() throws JSONException, IOException {
+ void asyncApiResourceArtifactTest() throws IOException {
String url = "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actual);
diff --git a/springwolf-examples/springwolf-sns-example/src/test/java/io/github/stavshamir/springwolf/example/sns/ApiSystemTest.java b/springwolf-examples/springwolf-sns-example/src/test/java/io/github/stavshamir/springwolf/example/sns/ApiSystemTest.java
index ff7c8f5cf..364dd22af 100644
--- a/springwolf-examples/springwolf-sns-example/src/test/java/io/github/stavshamir/springwolf/example/sns/ApiSystemTest.java
+++ b/springwolf-examples/springwolf-sns-example/src/test/java/io/github/stavshamir/springwolf/example/sns/ApiSystemTest.java
@@ -2,7 +2,6 @@
package io.github.stavshamir.springwolf.example.sns;
import lombok.extern.slf4j.Slf4j;
-import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.springframework.web.client.RestTemplate;
import org.testcontainers.containers.DockerComposeContainer;
@@ -58,7 +57,7 @@ private String baseUrl() {
}
@Test
- void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException, JSONException {
+ void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException {
String url = baseUrl() + "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
diff --git a/springwolf-examples/springwolf-sqs-example/build.gradle b/springwolf-examples/springwolf-sqs-example/build.gradle
index 3a35c5999..71ee479cd 100644
--- a/springwolf-examples/springwolf-sqs-example/build.gradle
+++ b/springwolf-examples/springwolf-sqs-example/build.gradle
@@ -36,8 +36,6 @@ dependencies {
testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}"
- testImplementation "com.vaadin.external.google:android-json:${androidJsonVersion}"
-
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"
testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}"
@@ -50,6 +48,9 @@ dependencies {
testImplementation "org.testcontainers:testcontainers:${testcontainersVersion}"
testImplementation "org.testcontainers:junit-jupiter:${testcontainersVersion}"
testImplementation "org.testcontainers:localstack:${testcontainersVersion}"
+
+ testAnnotationProcessor "org.projectlombok:lombok:${lombokVersion}"
+ testCompileOnly "org.projectlombok:lombok:${lombokVersion}"
}
docker {
diff --git a/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/stavshamir/springwolf/example/sqs/ApiIntegrationTest.java b/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/stavshamir/springwolf/example/sqs/ApiIntegrationTest.java
index a0a0545ad..e8f5c253e 100644
--- a/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/stavshamir/springwolf/example/sqs/ApiIntegrationTest.java
+++ b/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/stavshamir/springwolf/example/sqs/ApiIntegrationTest.java
@@ -1,11 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.sqs;
-import org.json.JSONException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
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.DynamicPropertyRegistry;
@@ -33,11 +31,8 @@ static void setUpTestContainers(DynamicPropertyRegistry registry) {
@Autowired
private TestRestTemplate restTemplate;
- @Value("${server.port}")
- public Integer serverPort;
-
@Test
- void asyncApiResourceArtifactTest() throws JSONException, IOException {
+ void asyncApiResourceArtifactTest() throws IOException {
String url = "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actual);
diff --git a/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/stavshamir/springwolf/example/sqs/ApiSystemTest.java b/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/stavshamir/springwolf/example/sqs/ApiSystemTest.java
index 7ffa816ca..9957883a5 100644
--- a/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/stavshamir/springwolf/example/sqs/ApiSystemTest.java
+++ b/springwolf-examples/springwolf-sqs-example/src/test/java/io/github/stavshamir/springwolf/example/sqs/ApiSystemTest.java
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.example.sqs;
-import org.json.JSONException;
+import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.web.client.RestTemplate;
import org.testcontainers.containers.DockerComposeContainer;
@@ -23,6 +23,7 @@
* While the assertion of this test is identical to ApiIntegrationTests,
* the setup uses a full docker-compose context with a real sqs instance.
*/
+@Slf4j
@Testcontainers
// @Ignore("Uncomment this line if you have issues running this test on your local machine.")
public class ApiSystemTest {
@@ -46,7 +47,8 @@ public class ApiSystemTest {
@Container
public DockerComposeContainer> environment = new DockerComposeContainer<>(new File("docker-compose.yml"))
.withExposedService(APP_NAME, APP_PORT)
- .withEnv(ENV);
+ .withEnv(ENV)
+ .withLogConsumer(APP_NAME, l -> log.debug("APP: %s".formatted(l.getUtf8StringWithoutLineEnding())));
private String baseUrl() {
String host = environment.getServiceHost(APP_NAME, APP_PORT);
@@ -55,7 +57,7 @@ private String baseUrl() {
}
@Test
- void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException, JSONException {
+ void asyncapiDocsShouldReturnTheCorrectJsonResponse() throws IOException {
String url = baseUrl() + "/springwolf/docs";
String actual = restTemplate.getForObject(url, String.class);
diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/amqp/SpringwolfAmqpScannerConfiguration.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/amqp/SpringwolfAmqpScannerConfiguration.java
index eb2796b79..2eb93a76f 100644
--- a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/amqp/SpringwolfAmqpScannerConfiguration.java
+++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/amqp/SpringwolfAmqpScannerConfiguration.java
@@ -7,6 +7,7 @@
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelPriority;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.ClassLevelRabbitListenerScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.MethodLevelRabbitListenerScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import org.springframework.amqp.core.Binding;
@@ -37,10 +38,12 @@ public class SpringwolfAmqpScannerConfiguration {
public ClassLevelRabbitListenerScanner classLevelRabbitListenerScanner(
ComponentClassScanner componentClassScanner,
SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor,
List queues,
List exchanges,
List bindings) {
- return new ClassLevelRabbitListenerScanner(componentClassScanner, schemasService, queues, exchanges, bindings);
+ return new ClassLevelRabbitListenerScanner(
+ componentClassScanner, schemasService, payloadClassExtractor, queues, exchanges, bindings);
}
@Bean
@@ -52,10 +55,12 @@ public ClassLevelRabbitListenerScanner classLevelRabbitListenerScanner(
public MethodLevelRabbitListenerScanner methodLevelRabbitListenerScanner(
ComponentClassScanner componentClassScanner,
SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor,
List queues,
List exchanges,
List bindings) {
- return new MethodLevelRabbitListenerScanner(componentClassScanner, schemasService, queues, exchanges, bindings);
+ return new MethodLevelRabbitListenerScanner(
+ componentClassScanner, schemasService, payloadClassExtractor, queues, exchanges, bindings);
}
@Bean
diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelRabbitListenerScanner.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelRabbitListenerScanner.java
index c60d37f5b..dcc6dff2e 100644
--- a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelRabbitListenerScanner.java
+++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelRabbitListenerScanner.java
@@ -5,6 +5,7 @@
import com.asyncapi.v2.binding.message.MessageBinding;
import com.asyncapi.v2.binding.operation.OperationBinding;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelsScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders;
import io.github.stavshamir.springwolf.schemas.SchemasService;
@@ -31,10 +32,11 @@ public class ClassLevelRabbitListenerScanner extends AbstractClassLevelListenerS
public ClassLevelRabbitListenerScanner(
ComponentClassScanner componentClassScanner,
SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor,
List queues,
List exchanges,
List bindings) {
- super(componentClassScanner, schemasService);
+ super(componentClassScanner, schemasService, payloadClassExtractor);
context = RabbitListenerUtil.RabbitListenerUtilContext.create(queues, exchanges, bindings);
}
diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScanner.java b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScanner.java
index 0c123acf0..6de3ca335 100644
--- a/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScanner.java
+++ b/springwolf-plugins/springwolf-amqp-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScanner.java
@@ -5,6 +5,7 @@
import com.asyncapi.v2.binding.message.MessageBinding;
import com.asyncapi.v2.binding.operation.OperationBinding;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelsScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import lombok.extern.slf4j.Slf4j;
@@ -26,14 +27,18 @@ public class MethodLevelRabbitListenerScanner extends AbstractMethodLevelListene
private final RabbitListenerUtil.RabbitListenerUtilContext context;
private StringValueResolver resolver;
+ private final PayloadClassExtractor payloadClassExtractor;
+
public MethodLevelRabbitListenerScanner(
ComponentClassScanner componentClassScanner,
SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor,
List queues,
List exchanges,
List bindings) {
super(componentClassScanner, schemasService);
- context = RabbitListenerUtil.RabbitListenerUtilContext.create(queues, exchanges, bindings);
+ this.context = RabbitListenerUtil.RabbitListenerUtilContext.create(queues, exchanges, bindings);
+ this.payloadClassExtractor = payloadClassExtractor;
}
@Override
@@ -67,6 +72,6 @@ protected String getChannelName(RabbitListener annotation) {
}
protected Class> getPayloadType(Method method) {
- return SpringPayloadAnnotationTypeExtractor.getPayloadType(method);
+ return payloadClassExtractor.extractFrom(method);
}
}
diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelRabbitListenerScannerIntegrationTest.java b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelRabbitListenerScannerIntegrationTest.java
index cf4f70343..fd85985f8 100644
--- a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelRabbitListenerScannerIntegrationTest.java
+++ b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelRabbitListenerScannerIntegrationTest.java
@@ -7,6 +7,7 @@
import com.asyncapi.v2.binding.message.MessageBinding;
import com.asyncapi.v2.binding.message.amqp.AMQPMessageBinding;
import com.asyncapi.v2.binding.operation.amqp.AMQPOperationBinding;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference;
@@ -43,6 +44,7 @@
classes = {
ClassLevelRabbitListenerScanner.class,
DefaultSchemasService.class,
+ PayloadClassExtractor.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class,
})
@@ -229,10 +231,10 @@ void scan_componentWithMultipleRabbitHandlerMethods() {
}
@Test
- void scan_componentWithSingleRabbitHandlerMethod_batchPayload() {
+ void scan_componentWithSingleRabbitHandlerMethod_genericPayload() {
// Given a @RabbitListener annotated class with one method annotated with @RabbitHandler
- // - There is a payload of type List>
- setClassToScan(RabbitListenerClassWithRabbitHandlerWithBatchPayload.class);
+ // - There is a payload of type Message>
+ setClassToScan(RabbitListenerClassWithRabbitHandlerWithGenericPayload.class);
// When scan is called
Map actualChannels = classLevelRabbitListenerScanner.scan();
@@ -248,7 +250,7 @@ void scan_componentWithSingleRabbitHandlerMethod_batchPayload() {
Operation operation = Operation.builder()
.description("Auto-generated description")
- .operationId("RabbitListenerClassWithRabbitHandlerWithBatchPayload_publish")
+ .operationId("RabbitListenerClassWithRabbitHandlerWithGenericPayload_publish")
.bindings(defaultOperationBinding)
.message(message)
.build();
@@ -293,10 +295,10 @@ private void anotherMethodWithoutAnnotation(SimpleBar payload) {}
}
@RabbitListener(queues = QUEUE)
- private static class RabbitListenerClassWithRabbitHandlerWithBatchPayload {
+ private static class RabbitListenerClassWithRabbitHandlerWithGenericPayload {
@RabbitHandler
- private void methodWithAnnotation(List batchPayload) {}
+ private void methodWithAnnotation(org.springframework.messaging.Message payload) {}
}
@Data
diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScannerIntegrationTest.java b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScannerIntegrationTest.java
index 9ba91059d..0f6c9c0b3 100644
--- a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScannerIntegrationTest.java
+++ b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelRabbitListenerScannerIntegrationTest.java
@@ -9,6 +9,7 @@
import com.asyncapi.v2.binding.message.amqp.AMQPMessageBinding;
import com.asyncapi.v2.binding.operation.amqp.AMQPOperationBinding;
import io.github.stavshamir.springwolf.asyncapi.MessageHelper;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference;
@@ -53,6 +54,7 @@
classes = {
MethodLevelRabbitListenerScanner.class,
DefaultSchemasService.class,
+ PayloadClassExtractor.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class,
MethodLevelRabbitListenerScannerIntegrationTest.ClassWithRabbitListenerAnnotationsBindingBean.class
diff --git a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/configuration/SpringwolfAmqpProducerConfigurationIntegrationTest.java b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/configuration/SpringwolfAmqpProducerConfigurationIntegrationTest.java
index be3d53b0b..f733eedac 100644
--- a/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/configuration/SpringwolfAmqpProducerConfigurationIntegrationTest.java
+++ b/springwolf-plugins/springwolf-amqp-plugin/src/test/java/io/github/stavshamir/springwolf/configuration/SpringwolfAmqpProducerConfigurationIntegrationTest.java
@@ -5,6 +5,7 @@
import io.github.stavshamir.springwolf.asyncapi.amqp.SpringwolfAmqpAutoConfiguration;
import io.github.stavshamir.springwolf.asyncapi.controller.PublishingPayloadCreator;
import io.github.stavshamir.springwolf.asyncapi.controller.SpringwolfAmqpController;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.producer.SpringwolfAmqpProducer;
import io.github.stavshamir.springwolf.schemas.SchemasService;
@@ -48,6 +49,7 @@ public class SpringwolfAmqpProducerConfigurationIntegrationTest {
@MockBean(RabbitTemplate.class),
@MockBean(ComponentClassScanner.class),
@MockBean(SchemasService.class),
+ @MockBean(PayloadClassExtractor.class),
@MockBean(AsyncApiDocketService.class)
})
@Nested
@@ -87,7 +89,8 @@ void springwolfAmqpProducerShouldBePresentInSpringContext() {
@MockBean(AsyncApiService.class),
@MockBean(RabbitTemplate.class),
@MockBean(ComponentClassScanner.class),
- @MockBean(SchemasService.class)
+ @MockBean(SchemasService.class),
+ @MockBean(PayloadClassExtractor.class),
})
@Nested
class AmqpProducerWillNotBeCreatedIfDisabledTest {
diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/build.gradle b/springwolf-plugins/springwolf-cloud-stream-plugin/build.gradle
index c221165be..6745d37ef 100644
--- a/springwolf-plugins/springwolf-cloud-stream-plugin/build.gradle
+++ b/springwolf-plugins/springwolf-cloud-stream-plugin/build.gradle
@@ -41,6 +41,7 @@ dependencies {
testImplementation "org.springframework.boot:spring-boot-test"
testImplementation "org.springframework:spring-beans"
testImplementation "org.springframework:spring-test"
+ testImplementation "org.springframework:spring-messaging"
}
jar {
diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/cloudstream/SpringwolfCloudStreamAutoConfiguration.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/cloudstream/SpringwolfCloudStreamAutoConfiguration.java
index 3bcf729a4..739b38e64 100644
--- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/cloudstream/SpringwolfCloudStreamAutoConfiguration.java
+++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/cloudstream/SpringwolfCloudStreamAutoConfiguration.java
@@ -3,6 +3,8 @@
import io.github.stavshamir.springwolf.asyncapi.scanners.beans.BeanMethodsScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream.CloudStreamFunctionChannelsScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream.FunctionalChannelBeanBuilder;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigConstants;
import io.github.stavshamir.springwolf.schemas.SchemasService;
@@ -23,8 +25,18 @@ public CloudStreamFunctionChannelsScanner cloudStreamFunctionChannelsScanner(
AsyncApiDocketService asyncApiDocketService,
BeanMethodsScanner beanMethodsScanner,
SchemasService schemasService,
- BindingServiceProperties cloudstreamBindingServiceProperties) {
+ BindingServiceProperties cloudstreamBindingServiceProperties,
+ FunctionalChannelBeanBuilder functionalChannelBeanBuilder) {
return new CloudStreamFunctionChannelsScanner(
- asyncApiDocketService, beanMethodsScanner, schemasService, cloudstreamBindingServiceProperties);
+ asyncApiDocketService,
+ beanMethodsScanner,
+ schemasService,
+ cloudstreamBindingServiceProperties,
+ functionalChannelBeanBuilder);
+ }
+
+ @Bean
+ public FunctionalChannelBeanBuilder functionalChannelBeanBuilder(PayloadClassExtractor payloadClassExtractor) {
+ return new FunctionalChannelBeanBuilder(payloadClassExtractor);
}
}
diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/CloudStreamFunctionChannelsScanner.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/CloudStreamFunctionChannelsScanner.java
index 81ebc2a63..acd309513 100644
--- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/CloudStreamFunctionChannelsScanner.java
+++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/CloudStreamFunctionChannelsScanner.java
@@ -35,12 +35,13 @@ public class CloudStreamFunctionChannelsScanner implements ChannelsScanner {
private final BeanMethodsScanner beanMethodsScanner;
private final SchemasService schemasService;
private final BindingServiceProperties cloudStreamBindingsProperties;
+ private final FunctionalChannelBeanBuilder functionalChannelBeanBuilder;
@Override
public Map scan() {
Set beanMethods = beanMethodsScanner.getBeanMethods();
return ChannelMerger.merge(beanMethods.stream()
- .map(FunctionalChannelBeanData::fromMethodBean)
+ .map(functionalChannelBeanBuilder::fromMethodBean)
.flatMap(Set::stream)
.filter(this::isChannelBean)
.map(this::toChannelEntry)
@@ -48,13 +49,13 @@ public Map scan() {
}
private boolean isChannelBean(FunctionalChannelBeanData beanData) {
- return cloudStreamBindingsProperties.getBindings().containsKey(beanData.getCloudStreamBinding());
+ return cloudStreamBindingsProperties.getBindings().containsKey(beanData.cloudStreamBinding());
}
private Map.Entry toChannelEntry(FunctionalChannelBeanData beanData) {
String channelName = cloudStreamBindingsProperties
.getBindings()
- .get(beanData.getCloudStreamBinding())
+ .get(beanData.cloudStreamBinding())
.getDestination();
String operationId = buildOperationId(beanData, channelName);
@@ -64,7 +65,7 @@ private Map.Entry toChannelEntry(FunctionalChannelBeanData
}
private ChannelItem buildChannel(FunctionalChannelBeanData beanData, String operationId) {
- Class> payloadType = beanData.getPayloadType();
+ Class> payloadType = beanData.payloadType();
String modelName = schemasService.register(payloadType);
String headerModelName = schemasService.register(AsyncHeaders.NOT_DOCUMENTED);
@@ -85,7 +86,7 @@ private ChannelItem buildChannel(FunctionalChannelBeanData beanData, String oper
.build();
Map channelBinding = buildChannelBinding();
- return beanData.getBeanType() == FunctionalChannelBeanData.BeanType.CONSUMER
+ return beanData.beanType() == FunctionalChannelBeanData.BeanType.CONSUMER
? ChannelItem.builder()
.bindings(channelBinding)
.publish(operation)
@@ -128,8 +129,8 @@ private String getProtocolName() {
private String buildOperationId(FunctionalChannelBeanData beanData, String channelName) {
String operationName =
- beanData.getBeanType() == FunctionalChannelBeanData.BeanType.CONSUMER ? "publish" : "subscribe";
+ beanData.beanType() == FunctionalChannelBeanData.BeanType.CONSUMER ? "publish" : "subscribe";
- return String.format("%s_%s_%s", channelName, operationName, beanData.getBeanName());
+ return String.format("%s_%s_%s", channelName, operationName, beanData.beanName());
}
}
diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanBuilder.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanBuilder.java
new file mode 100644
index 000000000..3281bc875
--- /dev/null
+++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanBuilder.java
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: Apache-2.0
+package io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream;
+
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
+import lombok.RequiredArgsConstructor;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import static java.util.stream.Collectors.toList;
+
+@RequiredArgsConstructor
+public class FunctionalChannelBeanBuilder {
+ private final PayloadClassExtractor extractor;
+
+ public Set fromMethodBean(Method methodBean) {
+ Class> returnType = methodBean.getReturnType();
+
+ if (Consumer.class.isAssignableFrom(returnType)) {
+ Class> payloadType = getReturnTypeGenerics(methodBean).get(0);
+ return Set.of(ofConsumer(methodBean.getName(), payloadType));
+ }
+
+ if (Supplier.class.isAssignableFrom(returnType)) {
+ Class> payloadType = getReturnTypeGenerics(methodBean).get(0);
+ return Set.of(ofSupplier(methodBean.getName(), payloadType));
+ }
+
+ if (Function.class.isAssignableFrom(returnType)) {
+ Class> inputType = getReturnTypeGenerics(methodBean).get(0);
+ Class> outputType = getReturnTypeGenerics(methodBean).get(1);
+
+ return Set.of(ofConsumer(methodBean.getName(), inputType), ofSupplier(methodBean.getName(), outputType));
+ }
+
+ return Collections.emptySet();
+ }
+
+ private static FunctionalChannelBeanData ofConsumer(String name, Class> payloadType) {
+ return new FunctionalChannelBeanData(
+ name, payloadType, FunctionalChannelBeanData.BeanType.CONSUMER, name + "-in-0");
+ }
+
+ private static FunctionalChannelBeanData ofSupplier(String name, Class> payloadType) {
+ return new FunctionalChannelBeanData(
+ name, payloadType, FunctionalChannelBeanData.BeanType.SUPPLIER, name + "-out-0");
+ }
+
+ private List> getReturnTypeGenerics(Method methodBean) {
+ ParameterizedType genericReturnType = (ParameterizedType) methodBean.getGenericReturnType();
+ return Arrays.stream(genericReturnType.getActualTypeArguments())
+ .map(extractor::typeToClass)
+ .collect(toList());
+ }
+}
diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanData.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanData.java
index 747b277a9..0992af715 100644
--- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanData.java
+++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanData.java
@@ -1,91 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream;
-import lombok.Data;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-import static java.util.stream.Collectors.toList;
-
-@Data
-class FunctionalChannelBeanData {
-
- private final String beanName;
- private final Class> payloadType;
- private final BeanType beanType;
- private final String cloudStreamBinding;
-
- static Set fromMethodBean(Method methodBean) {
- Class> returnType = methodBean.getReturnType();
-
- if (Consumer.class.isAssignableFrom(returnType)) {
- Class> payloadType = getReturnTypeGenerics(methodBean).get(0);
- return Set.of(ofConsumer(methodBean.getName(), payloadType));
- }
-
- if (Supplier.class.isAssignableFrom(returnType)) {
- Class> payloadType = getReturnTypeGenerics(methodBean).get(0);
- return Set.of(ofSupplier(methodBean.getName(), payloadType));
- }
-
- if (Function.class.isAssignableFrom(returnType)) {
- return fromFunctionBean(methodBean);
- }
-
- return Collections.emptySet();
- }
-
- private static FunctionalChannelBeanData ofConsumer(String name, Class> payloadType) {
- return new FunctionalChannelBeanData(name, payloadType, BeanType.CONSUMER, name + "-in-0");
- }
-
- private static FunctionalChannelBeanData ofSupplier(String name, Class> payloadType) {
- return new FunctionalChannelBeanData(name, payloadType, BeanType.SUPPLIER, name + "-out-0");
- }
-
- private static Set fromFunctionBean(Method methodBean) {
- String name = methodBean.getName();
-
- Class> inputType = getReturnTypeGenerics(methodBean).get(0);
- Class> outputType = getReturnTypeGenerics(methodBean).get(1);
-
- return Set.of(ofConsumer(name, inputType), ofSupplier(name, outputType));
- }
-
- private static List> getReturnTypeGenerics(Method methodBean) {
- ParameterizedType genericReturnType = (ParameterizedType) methodBean.getGenericReturnType();
- return Arrays.stream(genericReturnType.getActualTypeArguments())
- .map(FunctionalChannelBeanData::toClassObject)
- .collect(toList());
- }
-
- private static Class> toClassObject(Type type) {
- if (type instanceof Class>) {
- return (Class>) type;
- }
-
- if (type instanceof ParameterizedType) {
- Type rawType = ((ParameterizedType) type).getRawType();
-
- if ("org.apache.kafka.streams.kstream.KStream".equals(rawType.getTypeName())) {
- return (Class>) ((ParameterizedType) type).getActualTypeArguments()[1];
- }
-
- return (Class>) rawType;
- }
-
- throw new IllegalArgumentException(
- "Cannot handle Type which is not Class or ParameterizedType, but was given: " + type.getClass());
- }
+record FunctionalChannelBeanData(String beanName, Class> payloadType, BeanType beanType, String cloudStreamBinding) {
enum BeanType {
CONSUMER,
diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/CloudStreamFunctionChannelsScannerIntegrationTest.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/CloudStreamFunctionChannelsScannerIntegrationTest.java
index 9935d4cb0..7f0a2b7d5 100644
--- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/CloudStreamFunctionChannelsScannerIntegrationTest.java
+++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/CloudStreamFunctionChannelsScannerIntegrationTest.java
@@ -6,6 +6,7 @@
import com.asyncapi.v2._6_0.model.info.Info;
import com.asyncapi.v2._6_0.model.server.Server;
import io.github.stavshamir.springwolf.asyncapi.scanners.beans.DefaultBeanMethodsScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ConfigurationClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.channel.bindings.EmptyChannelBinding;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.bindings.EmptyOperationBinding;
@@ -47,9 +48,11 @@
ConfigurationClassScanner.class,
DefaultBeanMethodsScanner.class,
DefaultSchemasService.class,
+ PayloadClassExtractor.class,
ExampleJsonGenerator.class,
DefaultAsyncApiDocketService.class,
CloudStreamFunctionChannelsScanner.class,
+ FunctionalChannelBeanBuilder.class,
SpringwolfConfigProperties.class
})
@Import(CloudStreamFunctionChannelsScannerIntegrationTest.Configuration.class)
diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanBuilderTest.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanBuilderTest.java
new file mode 100644
index 000000000..bdcbdd873
--- /dev/null
+++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanBuilderTest.java
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: Apache-2.0
+package io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream;
+
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
+import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
+import org.apache.kafka.streams.kstream.KStream;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.springframework.context.annotation.Bean;
+import org.springframework.messaging.Message;
+
+import java.lang.reflect.Method;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import static io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream.FunctionalChannelBeanData.BeanType.CONSUMER;
+import static io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream.FunctionalChannelBeanData.BeanType.SUPPLIER;
+import static org.assertj.core.api.Assertions.assertThat;
+
+class FunctionalChannelBeanBuilderTest {
+ private final SpringwolfConfigProperties properties = new SpringwolfConfigProperties();
+ private final FunctionalChannelBeanBuilder functionalChannelBeanBuilder =
+ new FunctionalChannelBeanBuilder(new PayloadClassExtractor(properties));
+
+ @Nested
+ class NoBean {
+ @Test
+ void testNotAFunctionalChannelBean() throws NoSuchMethodException {
+ Method method = getMethod(this.getClass(), "notAFunctionalChannelBean");
+
+ Set data = functionalChannelBeanBuilder.fromMethodBean(method);
+
+ assertThat(data).isEmpty();
+ }
+
+ @Bean
+ private String notAFunctionalChannelBean() {
+ return "foo";
+ }
+ }
+
+ @Nested
+ class consumerBean {
+ @Test
+ void testConsumerBean() throws NoSuchMethodException {
+ Method method = getMethod(this.getClass(), "consumerBean");
+
+ Set data = functionalChannelBeanBuilder.fromMethodBean(method);
+
+ assertThat(data)
+ .containsExactly(
+ new FunctionalChannelBeanData("consumerBean", String.class, CONSUMER, "consumerBean-in-0"));
+ }
+
+ @Bean
+ private Consumer consumerBean() {
+ return System.out::println;
+ }
+ }
+
+ @Nested
+ class SupplierBean {
+ @Test
+ void testSupplierBean() throws NoSuchMethodException {
+ Method method = getMethod(this.getClass(), "supplierBean");
+
+ Set data = functionalChannelBeanBuilder.fromMethodBean(method);
+
+ assertThat(data)
+ .containsExactly(new FunctionalChannelBeanData(
+ "supplierBean", String.class, SUPPLIER, "supplierBean-out-0"));
+ }
+
+ @Bean
+ private Supplier supplierBean() {
+ return () -> "foo";
+ }
+ }
+
+ @Nested
+ class FunctionBean {
+ @Test
+ void testFunctionBean() throws NoSuchMethodException {
+ Method method = getMethod(this.getClass(), "functionBean");
+
+ Set data = functionalChannelBeanBuilder.fromMethodBean(method);
+
+ assertThat(data)
+ .containsExactlyInAnyOrder(
+ new FunctionalChannelBeanData("functionBean", String.class, CONSUMER, "functionBean-in-0"),
+ new FunctionalChannelBeanData(
+ "functionBean", Integer.class, SUPPLIER, "functionBean-out-0"));
+ }
+
+ @Bean
+ private Function functionBean() {
+ return s -> 1;
+ }
+ }
+
+ @Nested
+ class ConsumerBeanWithGenericPayload {
+
+ @Test
+ void testConsumerBeanWithGenericPayload() throws NoSuchMethodException {
+ String methodName = "consumerBeanWithGenericPayload";
+ Method method = getMethod(this.getClass(), methodName);
+
+ Set data = functionalChannelBeanBuilder.fromMethodBean(method);
+
+ assertThat(data)
+ .containsExactly(
+ new FunctionalChannelBeanData(methodName, String.class, CONSUMER, methodName + "-in-0"));
+ }
+
+ @Bean
+ private Consumer> consumerBeanWithGenericPayload() {
+ return System.out::println;
+ }
+ }
+
+ @Nested
+ class KStreamBean {
+
+ @Test
+ void testKafkaStreamsConsumerBean() throws NoSuchMethodException {
+ String methodName = "kafkaStreamsConsumerBean";
+ Method method = getMethod(this.getClass(), methodName);
+
+ Set data = functionalChannelBeanBuilder.fromMethodBean(method);
+
+ assertThat(data)
+ .containsExactly(
+ new FunctionalChannelBeanData(methodName, String.class, CONSUMER, methodName + "-in-0"));
+ }
+
+ @Bean
+ private Consumer> kafkaStreamsConsumerBean() {
+ return System.out::println;
+ }
+ }
+
+ private static Method getMethod(Class> clazz, String methodName) throws NoSuchMethodException {
+ return clazz.getDeclaredMethod(methodName);
+ }
+}
diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanDataTest.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanDataTest.java
deleted file mode 100644
index a55266e17..000000000
--- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/cloudstream/FunctionalChannelBeanDataTest.java
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-package io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream;
-
-import org.apache.kafka.streams.kstream.KStream;
-import org.junit.jupiter.api.Test;
-import org.springframework.context.annotation.Bean;
-
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.Set;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-import static io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream.FunctionalChannelBeanData.BeanType.CONSUMER;
-import static io.github.stavshamir.springwolf.asyncapi.scanners.channels.cloudstream.FunctionalChannelBeanData.BeanType.SUPPLIER;
-import static org.assertj.core.api.Assertions.assertThat;
-
-class FunctionalChannelBeanDataTest {
-
- @Test
- void testNotAFunctionalChannelBean() throws NoSuchMethodException {
- Method method = getMethod("notAFunctionalChannelBean");
-
- Set data = FunctionalChannelBeanData.fromMethodBean(method);
-
- assertThat(data).isEmpty();
- }
-
- @Bean
- private String notAFunctionalChannelBean() {
- return "foo";
- }
-
- @Test
- void testConsumerBean() throws NoSuchMethodException {
- Method method = getMethod("consumerBean");
-
- Set data = FunctionalChannelBeanData.fromMethodBean(method);
-
- assertThat(data)
- .containsExactly(
- new FunctionalChannelBeanData("consumerBean", String.class, CONSUMER, "consumerBean-in-0"));
- }
-
- @Bean
- private Consumer consumerBean() {
- return System.out::println;
- }
-
- @Test
- void testSupplierBean() throws NoSuchMethodException {
- Method method = getMethod("supplierBean");
-
- Set data = FunctionalChannelBeanData.fromMethodBean(method);
-
- assertThat(data)
- .containsExactly(
- new FunctionalChannelBeanData("supplierBean", String.class, SUPPLIER, "supplierBean-out-0"));
- }
-
- @Bean
- private Supplier supplierBean() {
- return () -> "foo";
- }
-
- @Test
- void testFunctionBean() throws NoSuchMethodException {
- Method method = getMethod("functionBean");
-
- Set data = FunctionalChannelBeanData.fromMethodBean(method);
-
- assertThat(data)
- .containsExactlyInAnyOrder(
- new FunctionalChannelBeanData("functionBean", String.class, CONSUMER, "functionBean-in-0"),
- new FunctionalChannelBeanData("functionBean", Integer.class, SUPPLIER, "functionBean-out-0"));
- }
-
- @Bean
- private Function functionBean() {
- return s -> 1;
- }
-
- @Test
- void testConsumerBeanWithGenericPayload() throws NoSuchMethodException {
- String methodName = "consumerBeanWithGenericPayload";
- Method method = getMethod(methodName);
-
- Set data = FunctionalChannelBeanData.fromMethodBean(method);
-
- assertThat(data)
- .containsExactly(new FunctionalChannelBeanData(methodName, List.class, CONSUMER, methodName + "-in-0"));
- }
-
- @Bean
- private Consumer> consumerBeanWithGenericPayload() {
- return System.out::println;
- }
-
- @Test
- void testKafkaStreamsConsumerBean() throws NoSuchMethodException {
- String methodName = "kafkaStreamsConsumerBean";
- Method method = getMethod(methodName);
-
- Set data = FunctionalChannelBeanData.fromMethodBean(method);
-
- assertThat(data)
- .containsExactly(
- new FunctionalChannelBeanData(methodName, String.class, CONSUMER, methodName + "-in-0"));
- }
-
- @Bean
- private Consumer> kafkaStreamsConsumerBean() {
- return System.out::println;
- }
-
- private static Method getMethod(String methodName) throws NoSuchMethodException {
- return FunctionalChannelBeanDataTest.class.getDeclaredMethod(methodName);
- }
-}
diff --git a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/jms/SpringwolfJmsScannerConfiguration.java b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/jms/SpringwolfJmsScannerConfiguration.java
index 1767b15c8..2331b499d 100644
--- a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/jms/SpringwolfJmsScannerConfiguration.java
+++ b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/jms/SpringwolfJmsScannerConfiguration.java
@@ -6,6 +6,7 @@
import io.github.stavshamir.springwolf.asyncapi.scanners.bindings.processor.JmsOperationBindingProcessor;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelPriority;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.MethodLevelJmsListenerScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -26,8 +27,10 @@ public class SpringwolfJmsScannerConfiguration {
@Order(value = ChannelPriority.AUTO_DISCOVERED)
@ConditionalOnProperty(name = SPRINGWOLF_SCANNER_JMS_LISTENER_ENABLED, havingValue = "true", matchIfMissing = true)
public MethodLevelJmsListenerScanner methodLevelJmsListenerScanner(
- ComponentClassScanner componentClassScanner, SchemasService schemasService) {
- return new MethodLevelJmsListenerScanner(componentClassScanner, schemasService);
+ ComponentClassScanner componentClassScanner,
+ SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor) {
+ return new MethodLevelJmsListenerScanner(componentClassScanner, schemasService, payloadClassExtractor);
}
@Bean
diff --git a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelJmsListenerScanner.java b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelJmsListenerScanner.java
index 1df17d1bb..1cdc795a2 100644
--- a/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelJmsListenerScanner.java
+++ b/springwolf-plugins/springwolf-jms-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelJmsListenerScanner.java
@@ -5,6 +5,7 @@
import com.asyncapi.v2.binding.message.MessageBinding;
import com.asyncapi.v2.binding.operation.OperationBinding;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelsScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import lombok.extern.slf4j.Slf4j;
@@ -21,8 +22,15 @@ public class MethodLevelJmsListenerScanner extends AbstractMethodLevelListenerSc
private StringValueResolver resolver;
- public MethodLevelJmsListenerScanner(ComponentClassScanner componentClassScanner, SchemasService schemasService) {
+ private final PayloadClassExtractor payloadClassExtractor;
+
+ public MethodLevelJmsListenerScanner(
+ ComponentClassScanner componentClassScanner,
+ SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor) {
super(componentClassScanner, schemasService);
+
+ this.payloadClassExtractor = payloadClassExtractor;
}
@Override
@@ -56,6 +64,6 @@ protected String getChannelName(JmsListener annotation) {
}
protected Class> getPayloadType(Method method) {
- return SpringPayloadAnnotationTypeExtractor.getPayloadType(method);
+ return payloadClassExtractor.extractFrom(method);
}
}
diff --git a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/controller/SpringwolfJmsControllerIntegrationTest.java b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/controller/SpringwolfJmsControllerIntegrationTest.java
index f72a1208a..d57e4bffb 100644
--- a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/controller/SpringwolfJmsControllerIntegrationTest.java
+++ b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/controller/SpringwolfJmsControllerIntegrationTest.java
@@ -2,6 +2,7 @@
package io.github.stavshamir.springwolf.asyncapi.controller;
import com.fasterxml.jackson.annotation.JsonProperty;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfConfigProperties;
import io.github.stavshamir.springwolf.producer.SpringwolfJmsProducer;
import io.github.stavshamir.springwolf.schemas.DefaultSchemasService;
@@ -41,6 +42,7 @@
SpringwolfJmsController.class,
PublishingPayloadCreator.class,
SpringwolfJmsProducer.class,
+ PayloadClassExtractor.class,
DefaultSchemasService.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class,
diff --git a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelJmsListenerScannerIntegrationTest.java b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelJmsListenerScannerIntegrationTest.java
index e86dcdefe..6d2fdaaf0 100644
--- a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelJmsListenerScannerIntegrationTest.java
+++ b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelJmsListenerScannerIntegrationTest.java
@@ -7,6 +7,7 @@
import com.asyncapi.v2.binding.message.MessageBinding;
import com.asyncapi.v2.binding.message.jms.JMSMessageBinding;
import com.asyncapi.v2.binding.operation.jms.JMSOperationBinding;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference;
@@ -41,6 +42,7 @@
classes = {
MethodLevelJmsListenerScanner.class,
DefaultSchemasService.class,
+ PayloadClassExtractor.class,
ExampleJsonGenerator.class,
SpringwolfConfigProperties.class,
})
@@ -187,6 +189,39 @@ void scan_componentHasJmsListenerMethods_multipleParamsWithPayloadAnnotation() {
assertThat(actualChannelItems).containsExactly(Map.entry(QUEUE, expectedChannelItem));
}
+ @Test
+ void scan_componentWithSingleRabbitHandlerMethod_genericPayload() {
+ // Given a @JmsListener annotated class with one method annotated with @RabbitHandler
+ // - There is a payload of type Message>
+ setClassToScan(ClassWithJmsListenerAnnotationWithGenericPayload.class);
+
+ // When scan is called
+ Map actualChannelItems = scanner.scan();
+
+ // Then the returned collection contains the channel, and the payload is the generic type of the list
+ Message message = Message.builder()
+ .name(SimpleFoo.class.getName())
+ .title(SimpleFoo.class.getSimpleName())
+ .payload(PayloadReference.fromModelName(SimpleFoo.class.getSimpleName()))
+ .headers(HeaderReference.fromModelName(AsyncHeaders.NOT_DOCUMENTED.getSchemaName()))
+ .bindings(defaultMessageBinding)
+ .build();
+
+ Operation operation = Operation.builder()
+ .description("Auto-generated description")
+ .operationId("test-queue_publish_methodWithAnnotation")
+ .bindings(defaultOperationBinding)
+ .message(message)
+ .build();
+
+ ChannelItem expectedChannelItem = ChannelItem.builder()
+ .bindings(defaultChannelBinding)
+ .publish(operation)
+ .build();
+
+ assertThat(actualChannelItems).containsExactly(Map.entry(QUEUE, expectedChannelItem));
+ }
+
private static class ClassWithoutJmsListenerAnnotations {
private void methodWithoutAnnotation() {}
@@ -218,6 +253,12 @@ private static class ClassWithJmsListenerAnnotationMultipleParamsWithPayloadAnno
private void methodWithAnnotation(String anotherParam, @Payload SimpleFoo payload) {}
}
+ private static class ClassWithJmsListenerAnnotationWithGenericPayload {
+
+ @JmsListener(destination = QUEUE)
+ private void methodWithAnnotation(org.springframework.messaging.Message payload) {}
+ }
+
@Data
@NoArgsConstructor
private static class SimpleFoo {
diff --git a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/configuration/SpringwolfJmsProducerConfigurationIntegrationTest.java b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/configuration/SpringwolfJmsProducerConfigurationIntegrationTest.java
index 13ea12c4e..b6dfc8077 100644
--- a/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/configuration/SpringwolfJmsProducerConfigurationIntegrationTest.java
+++ b/springwolf-plugins/springwolf-jms-plugin/src/test/java/io/github/stavshamir/springwolf/configuration/SpringwolfJmsProducerConfigurationIntegrationTest.java
@@ -6,6 +6,7 @@
import io.github.stavshamir.springwolf.asyncapi.controller.PublishingPayloadCreator;
import io.github.stavshamir.springwolf.asyncapi.controller.SpringwolfJmsController;
import io.github.stavshamir.springwolf.asyncapi.jms.SpringwolfJmsAutoConfiguration;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.producer.SpringwolfJmsProducer;
import io.github.stavshamir.springwolf.schemas.SchemasService;
@@ -49,6 +50,7 @@ public class SpringwolfJmsProducerConfigurationIntegrationTest {
@MockBean(SchemasService.class),
@MockBean(AsyncApiDocketService.class),
@MockBean(AsyncApiService.class),
+ @MockBean(PayloadClassExtractor.class),
@MockBean(JmsTemplate.class)
})
@Nested
@@ -88,6 +90,7 @@ void springwolfJmsProducerShouldBePresentInSpringContext() {
@MockBean(ComponentClassScanner.class),
@MockBean(SchemasService.class),
@MockBean(ChannelsService.class),
+ @MockBean(PayloadClassExtractor.class),
@MockBean(JmsTemplate.class)
})
@Nested
diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/kafka/SpringwolfKafkaScannerConfiguration.java b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/kafka/SpringwolfKafkaScannerConfiguration.java
index a56417764..148685566 100644
--- a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/kafka/SpringwolfKafkaScannerConfiguration.java
+++ b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/kafka/SpringwolfKafkaScannerConfiguration.java
@@ -7,6 +7,7 @@
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelPriority;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.ClassLevelKafkaListenerScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.MethodLevelKafkaListenerScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -30,8 +31,10 @@ public class SpringwolfKafkaScannerConfiguration {
havingValue = "true",
matchIfMissing = true)
public ClassLevelKafkaListenerScanner classLevelKafkaListenerScanner(
- ComponentClassScanner componentClassScanner, SchemasService schemasService) {
- return new ClassLevelKafkaListenerScanner(componentClassScanner, schemasService);
+ ComponentClassScanner componentClassScanner,
+ SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor) {
+ return new ClassLevelKafkaListenerScanner(componentClassScanner, schemasService, payloadClassExtractor);
}
@Bean
@@ -41,8 +44,10 @@ public ClassLevelKafkaListenerScanner classLevelKafkaListenerScanner(
havingValue = "true",
matchIfMissing = true)
public MethodLevelKafkaListenerScanner methodLevelKafkaListenerScanner(
- ComponentClassScanner componentClassScanner, SchemasService schemasService) {
- return new MethodLevelKafkaListenerScanner(componentClassScanner, schemasService);
+ ComponentClassScanner componentClassScanner,
+ SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor) {
+ return new MethodLevelKafkaListenerScanner(componentClassScanner, schemasService, payloadClassExtractor);
}
@Bean
diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelKafkaListenerScanner.java b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelKafkaListenerScanner.java
index 82386b774..839495689 100644
--- a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelKafkaListenerScanner.java
+++ b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/ClassLevelKafkaListenerScanner.java
@@ -5,6 +5,7 @@
import com.asyncapi.v2.binding.message.MessageBinding;
import com.asyncapi.v2.binding.operation.OperationBinding;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelsScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeadersForSpringKafkaBuilder;
@@ -18,16 +19,17 @@
import java.lang.reflect.Method;
import java.util.Map;
-import static io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.SpringPayloadAnnotationTypeExtractor.getPayloadType;
-
@Slf4j
public class ClassLevelKafkaListenerScanner extends AbstractClassLevelListenerScanner
implements ChannelsScanner, EmbeddedValueResolverAware {
private StringValueResolver resolver;
- public ClassLevelKafkaListenerScanner(ComponentClassScanner componentClassScanner, SchemasService schemasService) {
- super(componentClassScanner, schemasService);
+ public ClassLevelKafkaListenerScanner(
+ ComponentClassScanner componentClassScanner,
+ SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor) {
+ super(componentClassScanner, schemasService, payloadClassExtractor);
}
@Override
@@ -69,7 +71,7 @@ protected String getChannelName(KafkaListener annotation) {
@Override
protected AsyncHeaders buildHeaders(Method method) {
- Class> payloadType = getPayloadType(method);
+ Class> payloadType = this.payloadClassExtractor.extractFrom(method);
return new AsyncHeadersForSpringKafkaBuilder("SpringKafkaDefaultHeaders-" + payloadType.getSimpleName())
.withTypeIdHeader(payloadType.getTypeName())
.build();
diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelKafkaListenerScanner.java b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelKafkaListenerScanner.java
index 7d9e0888b..8c6a1051f 100644
--- a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelKafkaListenerScanner.java
+++ b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/asyncapi/scanners/channels/annotation/MethodLevelKafkaListenerScanner.java
@@ -5,6 +5,7 @@
import com.asyncapi.v2.binding.message.MessageBinding;
import com.asyncapi.v2.binding.operation.OperationBinding;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.ChannelsScanner;
+import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import lombok.extern.slf4j.Slf4j;
@@ -21,8 +22,14 @@ public class MethodLevelKafkaListenerScanner extends AbstractMethodLevelListener
private StringValueResolver resolver;
- public MethodLevelKafkaListenerScanner(ComponentClassScanner componentClassScanner, SchemasService schemasService) {
+ private final PayloadClassExtractor payloadClassExtractor;
+
+ public MethodLevelKafkaListenerScanner(
+ ComponentClassScanner componentClassScanner,
+ SchemasService schemasService,
+ PayloadClassExtractor payloadClassExtractor) {
super(componentClassScanner, schemasService);
+ this.payloadClassExtractor = payloadClassExtractor;
}
@Override
@@ -59,6 +66,6 @@ protected String getChannelName(KafkaListener annotation) {
@Override
protected Class> getPayloadType(Method method) {
- return SpringPayloadAnnotationTypeExtractor.getPayloadType(method);
+ return payloadClassExtractor.extractFrom(method);
}
}
diff --git a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/producer/SpringwolfKafkaTemplateFactory.java b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/producer/SpringwolfKafkaTemplateFactory.java
index be700e1bc..98224d5af 100644
--- a/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/producer/SpringwolfKafkaTemplateFactory.java
+++ b/springwolf-plugins/springwolf-kafka-plugin/src/main/java/io/github/stavshamir/springwolf/producer/SpringwolfKafkaTemplateFactory.java
@@ -5,6 +5,7 @@
import io.github.stavshamir.springwolf.configuration.properties.SpringwolfKafkaConfigProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.ssl.DefaultSslBundleRegistry;
import org.springframework.kafka.core.DefaultKafkaProducerFactory;
import org.springframework.kafka.core.KafkaTemplate;
@@ -25,7 +26,7 @@ public Optional> buildKafkaTemplate() {
Map producerProperties = springWolfKafkaConfigProperties
.getPublishing()
.getProducer()
- .buildProperties();
+ .buildProperties(new DefaultSslBundleRegistry());
DefaultKafkaProducerFactory