diff --git a/.github/workflows/springwolf-bindings.yml b/.github/workflows/springwolf-bindings.yml index e250466cd..5a9b79380 100644 --- a/.github/workflows/springwolf-bindings.yml +++ b/.github/workflows/springwolf-bindings.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - binding: [ "sns", "sqs" ] + binding: [ "googlepubsub", "sns", "sqs" ] env: binding: springwolf-bindings/springwolf-${{ matrix.binding }}-binding diff --git a/settings.gradle b/settings.gradle index 9df2245df..b637d2838 100644 --- a/settings.gradle +++ b/settings.gradle @@ -17,6 +17,7 @@ include( 'springwolf-examples:springwolf-sqs-example', 'springwolf-bindings:springwolf-sns-binding', 'springwolf-bindings:springwolf-sqs-binding', + 'springwolf-bindings:springwolf-googlepubsub-binding', 'springwolf-ui', 'springwolf-add-ons:springwolf-common-model-converters', 'springwolf-add-ons:springwolf-generic-binding', @@ -29,3 +30,4 @@ project(':springwolf-plugins:springwolf-jms-plugin').name = 'springwolf-jms' project(':springwolf-plugins:springwolf-kafka-plugin').name = 'springwolf-kafka' project(':springwolf-plugins:springwolf-sns-plugin').name = 'springwolf-sns' project(':springwolf-plugins:springwolf-sqs-plugin').name = 'springwolf-sqs' + diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle b/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle new file mode 100644 index 000000000..283f7b7fb --- /dev/null +++ b/springwolf-bindings/springwolf-googlepubsub-binding/build.gradle @@ -0,0 +1,45 @@ +plugins { + id 'java-library' + + id 'org.springframework.boot' + id 'io.spring.dependency-management' + id 'ca.cutterslade.analyze' +} + +dependencies { + api project(":springwolf-asyncapi") + api project(":springwolf-core") + + implementation "org.springframework:spring-context" + implementation "org.springframework:spring-core" + implementation "org.springframework.boot:spring-boot-autoconfigure" + + implementation "org.apache.commons:commons-lang3:${commonsLang3Version}" + + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" + testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" + + testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" +} + +jar { + enabled = true + archiveClassifier = '' +} +bootJar.enabled = false + +java { + withJavadocJar() + withSourcesJar() +} + +publishing { + publications { + mavenJava(MavenPublication) { + pom { + name = 'springwolf-googlepubsub-binding' + description = 'Automated JSON API documentation for Google PubSub Bindings' + } + } + } +} diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/annotations/GooglePubSubAsyncChannelBinding.java b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/annotations/GooglePubSubAsyncChannelBinding.java new file mode 100644 index 000000000..bf7543a1f --- /dev/null +++ b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/annotations/GooglePubSubAsyncChannelBinding.java @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.bindings.googlepubsub.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * {@code @GooglePubSubAsyncChannelBinding} is a method-level annotation. + * It configures the channel binding for the Google pubsub protocol. + * @see io.github.springwolf.asyncapi.v3.bindings.googlepubsub.GooglePubSubChannelBinding + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +@Inherited +public @interface GooglePubSubAsyncChannelBinding { + String type() default "googlepubsub"; + + String messageRetentionDuration() default ""; + + GooglePubsubAsyncMessageStoragePolicy messageStoragePolicy() default @GooglePubsubAsyncMessageStoragePolicy; + + GooglePubSubAsyncSchemaSetting schemaSettings(); + + String bindingVersion() default "0.2.0"; +} diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/annotations/GooglePubSubAsyncSchemaSetting.java b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/annotations/GooglePubSubAsyncSchemaSetting.java new file mode 100644 index 000000000..a83d2a778 --- /dev/null +++ b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/annotations/GooglePubSubAsyncSchemaSetting.java @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.bindings.googlepubsub.annotations; + +import io.github.springwolf.asyncapi.v3.bindings.googlepubsub.GooglePubSubSchemaSettings; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @see GooglePubSubSchemaSettings + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD}) +@Inherited +public @interface GooglePubSubAsyncSchemaSetting { + /** + * Mapped to {@link GooglePubSubSchemaSettings#getEncoding()} + */ + String encoding() default ""; + + /** + * Mapped to {@link GooglePubSubSchemaSettings#getName()} + */ + String name() default ""; + + /** + * Mapped to {@link GooglePubSubSchemaSettings#getFirstRevisionId()} + */ + String firstRevisionId() default ""; + + /** + * Mapped to {@link GooglePubSubSchemaSettings#getLastRevisionId()} + */ + String lastRevisionId() default ""; +} diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/annotations/GooglePubsubAsyncMessageStoragePolicy.java b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/annotations/GooglePubsubAsyncMessageStoragePolicy.java new file mode 100644 index 000000000..6e2e69597 --- /dev/null +++ b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/annotations/GooglePubsubAsyncMessageStoragePolicy.java @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.bindings.googlepubsub.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) +@Inherited +public @interface GooglePubsubAsyncMessageStoragePolicy { + String[] allowedPersistenceRegions() default {}; +} diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/configuration/SpringwolfGooglePubSubBindingAutoConfiguration.java b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/configuration/SpringwolfGooglePubSubBindingAutoConfiguration.java new file mode 100644 index 000000000..ebec0c490 --- /dev/null +++ b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/configuration/SpringwolfGooglePubSubBindingAutoConfiguration.java @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.bindings.googlepubsub.configuration; + +import io.github.springwolf.bindings.googlepubsub.scanners.channels.GooglePubSubChannelBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.bindings.BindingProcessorPriority; +import io.github.springwolf.core.configuration.properties.SpringwolfConfigConstants; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.core.annotation.Order; + +/** + * Autoconfiguration for the springwolf Google PubSub Binding. + */ +@AutoConfiguration +@ConditionalOnProperty(name = SpringwolfConfigConstants.SPRINGWOLF_ENABLED, havingValue = "true", matchIfMissing = true) +public class SpringwolfGooglePubSubBindingAutoConfiguration { + + @Bean + @Order(value = BindingProcessorPriority.PROTOCOL_BINDING) + @ConditionalOnMissingBean + public GooglePubSubChannelBindingProcessor googlePubSubChannelBindingProcessor() { + return new GooglePubSubChannelBindingProcessor(); + } +} diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/channels/GooglePubSubChannelBindingProcessor.java b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/channels/GooglePubSubChannelBindingProcessor.java new file mode 100644 index 000000000..56642a571 --- /dev/null +++ b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/java/io/github/springwolf/bindings/googlepubsub/scanners/channels/GooglePubSubChannelBindingProcessor.java @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.bindings.googlepubsub.scanners.channels; + +import io.github.springwolf.asyncapi.v3.bindings.googlepubsub.GooglePubSubChannelBinding; +import io.github.springwolf.asyncapi.v3.bindings.googlepubsub.GooglePubSubMessageStoragePolicy; +import io.github.springwolf.asyncapi.v3.bindings.googlepubsub.GooglePubSubSchemaSettings; +import io.github.springwolf.bindings.googlepubsub.annotations.GooglePubSubAsyncChannelBinding; +import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ChannelBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ProcessedChannelBinding; +import org.apache.commons.lang3.StringUtils; +import org.springframework.context.EmbeddedValueResolverAware; +import org.springframework.util.StringValueResolver; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Optional; + +public class GooglePubSubChannelBindingProcessor implements ChannelBindingProcessor, EmbeddedValueResolverAware { + private StringValueResolver resolver; + + @Override + public void setEmbeddedValueResolver(StringValueResolver resolver) { + this.resolver = resolver; + } + + @Override + public Optional process(Method method) { + return Arrays.stream(method.getAnnotations()) + .filter(GooglePubSubAsyncChannelBinding.class::isInstance) + .map(GooglePubSubAsyncChannelBinding.class::cast) + .findAny() + .map(this::mapToChannelBinding); + } + + private ProcessedChannelBinding mapToChannelBinding(GooglePubSubAsyncChannelBinding bindingAnnotation) { + + GooglePubSubMessageStoragePolicy.GooglePubSubMessageStoragePolicyBuilder policyBuilder = + GooglePubSubMessageStoragePolicy.builder(); + if (bindingAnnotation.messageStoragePolicy().allowedPersistenceRegions().length > 0) { + policyBuilder.allowedPersistenceRegions( + Arrays.stream(bindingAnnotation.messageStoragePolicy().allowedPersistenceRegions()) + .toList()); + } + + GooglePubSubSchemaSettings.GooglePubSubSchemaSettingsBuilder schemaSettingsBuilder = + GooglePubSubSchemaSettings.builder(); + if (StringUtils.isNotBlank(bindingAnnotation.schemaSettings().encoding())) { + schemaSettingsBuilder.encoding(bindingAnnotation.schemaSettings().encoding()); + } + if (StringUtils.isNotBlank(bindingAnnotation.schemaSettings().firstRevisionId())) { + schemaSettingsBuilder.firstRevisionId( + bindingAnnotation.schemaSettings().firstRevisionId()); + } + if (StringUtils.isNotBlank(bindingAnnotation.schemaSettings().lastRevisionId())) { + schemaSettingsBuilder.lastRevisionId( + bindingAnnotation.schemaSettings().lastRevisionId()); + } + if (StringUtils.isNotBlank(bindingAnnotation.schemaSettings().name())) { + schemaSettingsBuilder.name(bindingAnnotation.schemaSettings().name()); + } + + GooglePubSubChannelBinding.GooglePubSubChannelBindingBuilder bindingBuilder = + GooglePubSubChannelBinding.builder() + .messageStoragePolicy(policyBuilder.build()) + .schemaSettings(schemaSettingsBuilder.build()); + if (StringUtils.isNotBlank(bindingAnnotation.messageRetentionDuration())) { + bindingBuilder.messageRetentionDuration(bindingAnnotation.messageRetentionDuration()); + } + if (StringUtils.isNotBlank(bindingAnnotation.bindingVersion())) { + bindingBuilder.bindingVersion(bindingAnnotation.bindingVersion()); + } + + return new ProcessedChannelBinding(bindingAnnotation.type(), bindingBuilder.build()); + } +} diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..0444f7ce0 --- /dev/null +++ b/springwolf-bindings/springwolf-googlepubsub-binding/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +io.github.springwolf.bindings.googlepubsub.configuration.SpringwolfGooglePubSubBindingAutoConfiguration diff --git a/springwolf-bindings/springwolf-googlepubsub-binding/src/test/java/GooglePubSubChannelBindingProcessorTest.java b/springwolf-bindings/springwolf-googlepubsub-binding/src/test/java/GooglePubSubChannelBindingProcessorTest.java new file mode 100644 index 000000000..436de699d --- /dev/null +++ b/springwolf-bindings/springwolf-googlepubsub-binding/src/test/java/GooglePubSubChannelBindingProcessorTest.java @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Apache-2.0 +import io.github.springwolf.asyncapi.v3.bindings.googlepubsub.GooglePubSubChannelBinding; +import io.github.springwolf.asyncapi.v3.bindings.googlepubsub.GooglePubSubMessageStoragePolicy; +import io.github.springwolf.asyncapi.v3.bindings.googlepubsub.GooglePubSubSchemaSettings; +import io.github.springwolf.bindings.googlepubsub.annotations.GooglePubSubAsyncChannelBinding; +import io.github.springwolf.bindings.googlepubsub.annotations.GooglePubSubAsyncSchemaSetting; +import io.github.springwolf.bindings.googlepubsub.annotations.GooglePubsubAsyncMessageStoragePolicy; +import io.github.springwolf.bindings.googlepubsub.scanners.channels.GooglePubSubChannelBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ProcessedChannelBinding; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +public class GooglePubSubChannelBindingProcessorTest { + private final GooglePubSubChannelBindingProcessor processor = new GooglePubSubChannelBindingProcessor(); + + @Test + void processTest() throws NoSuchMethodException { + // given + Method method = GooglePubSubChannelBindingProcessorTest.class.getMethod("methodWithAnnotation"); + + // when + ProcessedChannelBinding binding = processor.process(method).get(); + + // then + assertThat(binding.getType()).isEqualTo("googlepubsub"); + assertThat(binding.getBinding()) + .isEqualTo(new GooglePubSubChannelBinding( + null, + "messageRetentionDuration", + new GooglePubSubMessageStoragePolicy(List.of("region1", "region2")), + new GooglePubSubSchemaSettings("BINARY", "firstRevisionId", "lastRevisionId", "project/test"), + "0.2.0")); + } + + @Test + void processWithoutAnnotationTest() throws NoSuchMethodException { + // given + Method method = GooglePubSubChannelBindingProcessorTest.class.getMethod("methodWithoutAnnotation"); + + // when + Optional binding = processor.process(method); + + // then + assertThat(binding).isNotPresent(); + } + + @GooglePubSubAsyncChannelBinding( + messageRetentionDuration = "messageRetentionDuration", + messageStoragePolicy = + @GooglePubsubAsyncMessageStoragePolicy(allowedPersistenceRegions = {"region1", "region2"}), + schemaSettings = + @GooglePubSubAsyncSchemaSetting( + encoding = "BINARY", + firstRevisionId = "firstRevisionId", + lastRevisionId = "lastRevisionId", + name = "project/test")) + public void methodWithAnnotation() {} + + public void methodWithoutAnnotation() {} +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/channels/ChannelBindingProcessor.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/channels/ChannelBindingProcessor.java new file mode 100644 index 000000000..a79658a13 --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/channels/ChannelBindingProcessor.java @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.bindings.channels; + +import java.lang.reflect.Method; +import java.util.Optional; + +public interface ChannelBindingProcessor { + + /** + * Process the methods annotated with Channel Binding Annotation + * for protocol specific channelBinding annotations, method parameters, etc + * + * @param method The method being annotated + * @return A message binding, if found + */ + Optional process(Method method); +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/channels/ProcessedChannelBinding.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/channels/ProcessedChannelBinding.java new file mode 100644 index 000000000..7976f1edc --- /dev/null +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/bindings/channels/ProcessedChannelBinding.java @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.bindings.channels; + +import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; +import lombok.Data; + +@Data +public class ProcessedChannelBinding { + private final String type; + private final ChannelBinding binding; +} diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java index 1a99e322d..0e9782b16 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.utils; +import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; @@ -8,6 +9,8 @@ import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.components.headers.AsyncHeaderSchema; import io.github.springwolf.core.asyncapi.components.headers.AsyncHeaders; +import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ChannelBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ProcessedChannelBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding; import io.github.springwolf.core.asyncapi.scanners.bindings.operations.OperationBindingProcessor; @@ -136,4 +139,14 @@ public static void processAsyncMessageAnnotation( public static List getServers(AsyncOperation op, StringValueResolver resolver) { return Arrays.stream(op.servers()).map(resolver::resolveStringValue).toList(); } + + public static Map processChannelBindingFromAnnotation( + Method method, List channelBindingProcessors) { + return channelBindingProcessors.stream() + .map(channelBindingProcessor -> channelBindingProcessor.process(method)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toMap( + ProcessedChannelBinding::getType, ProcessedChannelBinding::getBinding, (e1, e2) -> e1)); + } } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/bindings/processor/TestChannelBindingProcessor.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/bindings/processor/TestChannelBindingProcessor.java new file mode 100644 index 000000000..c38c7f412 --- /dev/null +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/bindings/processor/TestChannelBindingProcessor.java @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.core.asyncapi.scanners.bindings.processor; + +import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; +import io.github.springwolf.asyncapi.v3.bindings.EmptyChannelBinding; +import io.github.springwolf.core.asyncapi.scanners.bindings.BindingProcessorPriority; +import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ChannelBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ProcessedChannelBinding; +import org.springframework.core.annotation.Order; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Optional; + +@Order(value = BindingProcessorPriority.MANUAL_DEFINED) +public class TestChannelBindingProcessor implements ChannelBindingProcessor { + + public static final String TYPE = "testType"; + public static final ChannelBinding BINDING = new EmptyChannelBinding(); + + @Override + public Optional process(Method method) { + return Arrays.stream(method.getAnnotations()) + .filter(annotation -> annotation instanceof TestChannelBindingProcessor.TestChannelBinding) + .map(annotation -> (TestChannelBindingProcessor.TestChannelBinding) annotation) + .findAny() + .map(this::mapToChannelBinding); + } + + private ProcessedChannelBinding mapToChannelBinding( + TestChannelBindingProcessor.TestChannelBinding bindingAnnotation) { + return new ProcessedChannelBinding(TYPE, BINDING); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) + @Inherited + public @interface TestChannelBinding {} +} diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java index 5e643a3bf..bbbb726f3 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common.utils; +import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; import io.github.springwolf.asyncapi.v3.bindings.MessageBinding; import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; @@ -9,6 +10,7 @@ import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.components.headers.AsyncHeaders; import io.github.springwolf.core.asyncapi.scanners.bindings.processor.TestAbstractOperationBindingProcessor; +import io.github.springwolf.core.asyncapi.scanners.bindings.processor.TestChannelBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.processor.TestMessageBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.bindings.processor.TestOperationBindingProcessor; import org.assertj.core.util.Maps; @@ -178,6 +180,24 @@ void getServers() throws NoSuchMethodException { assertEquals(List.of("server1"), servers); } + @Test + void processChannelBindingFromAnnotation() throws NoSuchMethodException { + // given + Method m = ClassWithChannelBindingProcessor.class.getDeclaredMethod("methodWithAnnotation", String.class); + + // when + Map bindings = AsyncAnnotationUtil.processChannelBindingFromAnnotation( + m, Collections.singletonList(new TestChannelBindingProcessor())); + + // then + assertEquals(Maps.newHashMap(TestChannelBindingProcessor.TYPE, TestChannelBindingProcessor.BINDING), bindings); + } + + private static class ClassWithChannelBindingProcessor { + @TestChannelBindingProcessor.TestChannelBinding() + private void methodWithAnnotation(String payload) {} + } + private static class ClassWithOperationBindingProcessor { @AsyncListener( operation = diff --git a/springwolf-examples/springwolf-cloud-stream-example/build.gradle b/springwolf-examples/springwolf-cloud-stream-example/build.gradle index b8ad253e5..09a9d0698 100644 --- a/springwolf-examples/springwolf-cloud-stream-example/build.gradle +++ b/springwolf-examples/springwolf-cloud-stream-example/build.gradle @@ -23,6 +23,8 @@ dependencies { runtimeOnly project(":springwolf-plugins:springwolf-cloud-stream") annotationProcessor project(":springwolf-plugins:springwolf-cloud-stream") + implementation project(":springwolf-bindings:springwolf-googlepubsub-binding") + runtimeOnly project(":springwolf-ui") runtimeOnly "org.springframework.boot:spring-boot-starter-web" runtimeOnly "org.springframework.boot:spring-boot-starter-actuator" diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/springwolf/examples/cloudstream/configuration/CloudstreamConfiguration.java b/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/springwolf/examples/cloudstream/configuration/CloudstreamConfiguration.java index bd4225402..2e8fd5c06 100644 --- a/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/springwolf/examples/cloudstream/configuration/CloudstreamConfiguration.java +++ b/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/springwolf/examples/cloudstream/configuration/CloudstreamConfiguration.java @@ -1,8 +1,11 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.examples.cloudstream.configuration; +import io.github.springwolf.bindings.googlepubsub.annotations.GooglePubSubAsyncChannelBinding; +import io.github.springwolf.bindings.googlepubsub.annotations.GooglePubSubAsyncSchemaSetting; import io.github.springwolf.examples.cloudstream.dtos.AnotherPayloadDto; import io.github.springwolf.examples.cloudstream.dtos.ExamplePayloadDto; +import io.github.springwolf.examples.cloudstream.dtos.GooglePubSubPayloadDto; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.streams.kstream.KStream; import org.springframework.context.annotation.Bean; @@ -25,4 +28,11 @@ public Function, KStream consumerMethod() { return input -> log.info("Received new message in another-topic: {}", input.toString()); } + + @GooglePubSubAsyncChannelBinding( + schemaSettings = @GooglePubSubAsyncSchemaSetting(encoding = "BINARY", name = "project/test")) + @Bean + public Consumer googlePubSubConsumerMethod() { + return input -> log.info("Received new message in google-pubsub-topic: {}", input.toString()); + } } diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/springwolf/examples/cloudstream/dtos/GooglePubSubPayloadDto.java b/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/springwolf/examples/cloudstream/dtos/GooglePubSubPayloadDto.java new file mode 100644 index 000000000..1ef31c309 --- /dev/null +++ b/springwolf-examples/springwolf-cloud-stream-example/src/main/java/io/github/springwolf/examples/cloudstream/dtos/GooglePubSubPayloadDto.java @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.examples.cloudstream.dtos; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + +@Schema(description = "Google pubsub payload model") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GooglePubSubPayloadDto { + @Schema(description = "Some string field", example = "some string value", requiredMode = REQUIRED) + private String someString; + + @Schema(description = "Some long field", example = "5") + private long someLong; +} diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/main/resources/application.properties b/springwolf-examples/springwolf-cloud-stream-example/src/main/resources/application.properties index 4b150d9ea..ca03fd0b5 100644 --- a/springwolf-examples/springwolf-cloud-stream-example/src/main/resources/application.properties +++ b/springwolf-examples/springwolf-cloud-stream-example/src/main/resources/application.properties @@ -10,6 +10,7 @@ spring.kafka.bootstrap-servers=${BOOTSTRAP_SERVER:localhost:29092} spring.cloud.stream.bindings.process-in-0.destination=example-topic spring.cloud.stream.bindings.process-out-0.destination=another-topic spring.cloud.stream.bindings.consumerMethod-in-0.destination=another-topic +spring.cloud.stream.bindings.googlePubSubConsumerMethod-in-0.destination=google-pubsub-topic ######### diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/springwolf/examples/cloudstream/ApiIntegrationTest.java b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/springwolf/examples/cloudstream/ApiIntegrationTest.java index b3e383023..397f79848 100644 --- a/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/springwolf/examples/cloudstream/ApiIntegrationTest.java +++ b/springwolf-examples/springwolf-cloud-stream-example/src/test/java/io/github/springwolf/examples/cloudstream/ApiIntegrationTest.java @@ -39,7 +39,7 @@ void asyncApiResourceArtifactTest() throws IOException { Files.writeString(Path.of("src", "test", "resources", "asyncapi.actual.json"), actualPatched); InputStream s = this.getClass().getResourceAsStream("/asyncapi.json"); - String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8); + String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim(); assertEquals(expected, actualPatched); } diff --git a/springwolf-examples/springwolf-cloud-stream-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-cloud-stream-example/src/test/resources/asyncapi.json index c81b34014..11b5fab74 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 @@ -41,6 +41,23 @@ "bindings": { "kafka": { } } + }, + "google-pubsub-topic": { + "messages": { + "io.github.springwolf.examples.cloudstream.dtos.GooglePubSubPayloadDto": { + "$ref": "#/components/messages/io.github.springwolf.examples.cloudstream.dtos.GooglePubSubPayloadDto" + } + }, + "bindings": { + "googlepubsub": { + "messageStoragePolicy": { }, + "schemaSettings": { + "encoding": "BINARY", + "name": "project/test" + }, + "bindingVersion": "0.2.0" + } + } } }, "components": { @@ -118,6 +135,36 @@ "someString" ] }, + "GooglePubSubPayloadDto": { + "type": "object", + "properties": { + "someLong": { + "type": "integer", + "description": "Some long field", + "format": "int64", + "examples": [ + 5 + ] + }, + "someString": { + "type": "string", + "description": "Some string field", + "examples": [ + "some string value" + ] + } + }, + "description": "Google pubsub payload model", + "examples": [ + { + "someLong": 5, + "someString": "some string value" + } + ], + "required": [ + "someString" + ] + }, "HeadersNotDocumented": { "type": "object", "properties": { }, @@ -158,6 +205,22 @@ "bindings": { "kafka": { } } + }, + "io.github.springwolf.examples.cloudstream.dtos.GooglePubSubPayloadDto": { + "headers": { + "$ref": "#/components/schemas/HeadersNotDocumented" + }, + "payload": { + "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0", + "schema": { + "$ref": "#/components/schemas/GooglePubSubPayloadDto" + } + }, + "name": "io.github.springwolf.examples.cloudstream.dtos.GooglePubSubPayloadDto", + "title": "GooglePubSubPayloadDto", + "bindings": { + "kafka": { } + } } } }, @@ -206,6 +269,21 @@ "$ref": "#/channels/example-topic/messages/io.github.springwolf.examples.cloudstream.dtos.ExamplePayloadDto" } ] + }, + "google-pubsub-topic_publish_googlePubSubConsumerMethod": { + "action": "receive", + "channel": { + "$ref": "#/channels/google-pubsub-topic" + }, + "description": "Auto-generated description", + "bindings": { + "kafka": { } + }, + "messages": [ + { + "$ref": "#/channels/google-pubsub-topic/messages/io.github.springwolf.examples.cloudstream.dtos.GooglePubSubPayloadDto" + } + ] } } -} \ No newline at end of file +} diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScanner.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScanner.java index 441f22bae..d2c9e7773 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScanner.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScanner.java @@ -17,7 +17,9 @@ import io.github.springwolf.core.asyncapi.components.headers.AsyncHeaders; import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; import io.github.springwolf.core.asyncapi.scanners.beans.BeanMethodsScanner; +import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ChannelBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.channels.ChannelMerger; +import io.github.springwolf.core.asyncapi.scanners.common.utils.AsyncAnnotationUtil; import io.github.springwolf.core.configuration.docket.AsyncApiDocket; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; import io.github.springwolf.plugins.cloudstream.asyncapi.scanners.common.FunctionalChannelBeanBuilder; @@ -27,6 +29,7 @@ import org.springframework.cloud.stream.config.BindingServiceProperties; import java.lang.reflect.Method; +import java.util.List; import java.util.Map; import java.util.Set; @@ -39,6 +42,7 @@ public class CloudStreamFunctionChannelsScanner implements ChannelsScanner { private final ComponentsService componentsService; private final BindingServiceProperties cloudStreamBindingsProperties; private final FunctionalChannelBeanBuilder functionalChannelBeanBuilder; + protected final List channelBindingProcessors; @Override public Map scan() { @@ -84,7 +88,7 @@ private ChannelObject buildChannel(FunctionalChannelBeanData beanData) { .build(); this.componentsService.registerMessage(message); - Map channelBinding = buildChannelBinding(); + Map channelBinding = buildChannelBinding(beanData.method()); return ChannelObject.builder() .bindings(channelBinding) .messages(Map.of(message.getName(), MessageReference.toComponentMessage(message))) @@ -92,11 +96,18 @@ private ChannelObject buildChannel(FunctionalChannelBeanData beanData) { } private Map buildMessageBinding() { + // FIXME: handle messageBindings from annotations as for the channel String protocolName = getProtocolName(); return Map.of(protocolName, new EmptyMessageBinding()); } - private Map buildChannelBinding() { + private Map buildChannelBinding(Method method) { + Map channelBindingMap = + AsyncAnnotationUtil.processChannelBindingFromAnnotation(method, channelBindingProcessors); + if (!channelBindingMap.isEmpty()) { + return channelBindingMap; + } + String protocolName = getProtocolName(); return Map.of(protocolName, new EmptyChannelBinding()); } diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanBuilder.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanBuilder.java index 0ff74871a..35c2375c1 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanBuilder.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanBuilder.java @@ -22,35 +22,34 @@ public class FunctionalChannelBeanBuilder { 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)); + return Set.of(ofConsumer(methodBean, payloadType)); } if (Supplier.class.isAssignableFrom(returnType)) { Class payloadType = getReturnTypeGenerics(methodBean).get(0); - return Set.of(ofSupplier(methodBean.getName(), payloadType)); + return Set.of(ofSupplier(methodBean, 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 Set.of(ofConsumer(methodBean, inputType), ofSupplier(methodBean, outputType)); } return Collections.emptySet(); } - private static FunctionalChannelBeanData ofConsumer(String name, Class payloadType) { + private static FunctionalChannelBeanData ofConsumer(Method method, Class payloadType) { return new FunctionalChannelBeanData( - name, payloadType, FunctionalChannelBeanData.BeanType.CONSUMER, name + "-in-0"); + method, payloadType, FunctionalChannelBeanData.BeanType.CONSUMER, method.getName() + "-in-0"); } - private static FunctionalChannelBeanData ofSupplier(String name, Class payloadType) { + private static FunctionalChannelBeanData ofSupplier(Method method, Class payloadType) { return new FunctionalChannelBeanData( - name, payloadType, FunctionalChannelBeanData.BeanType.SUPPLIER, name + "-out-0"); + method, payloadType, FunctionalChannelBeanData.BeanType.SUPPLIER, method.getName() + "-out-0"); } private List> getReturnTypeGenerics(Method methodBean) { diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanData.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanData.java index 578a3881f..4d7a42be4 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanData.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanData.java @@ -1,8 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.plugins.cloudstream.asyncapi.scanners.common; +import java.lang.reflect.Method; + public record FunctionalChannelBeanData( - String beanName, Class payloadType, BeanType beanType, String cloudStreamBinding) { + Method method, Class payloadType, BeanType beanType, String cloudStreamBinding) { public enum BeanType { CONSUMER, diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/operations/CloudStreamFunctionOperationsScanner.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/operations/CloudStreamFunctionOperationsScanner.java index a73d89672..db401c7f3 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/operations/CloudStreamFunctionOperationsScanner.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/operations/CloudStreamFunctionOperationsScanner.java @@ -96,11 +96,13 @@ private Operation buildOperation(FunctionalChannelBeanData beanData, String chan } private Map buildMessageBinding() { + // FIXME: handle messageBindings from annotations as for the channel String protocolName = getProtocolName(); return Map.of(protocolName, new EmptyMessageBinding()); } private Map buildOperationBinding() { + // FIXME: handle operationBindings from annotations as for the channel String protocolName = getProtocolName(); return Map.of(protocolName, new EmptyOperationBinding()); } @@ -124,6 +126,7 @@ private String buildOperationId(FunctionalChannelBeanData beanData, String chann String operationName = beanData.beanType() == FunctionalChannelBeanData.BeanType.CONSUMER ? "publish" : "subscribe"; - return String.format("%s_%s_%s", channelName, operationName, beanData.beanName()); + return String.format( + "%s_%s_%s", channelName, operationName, beanData.method().getName()); } } diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/configuration/SpringwolfCloudStreamAutoConfiguration.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/configuration/SpringwolfCloudStreamAutoConfiguration.java index 77ed475b8..412e368ff 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/configuration/SpringwolfCloudStreamAutoConfiguration.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/main/java/io/github/springwolf/plugins/cloudstream/configuration/SpringwolfCloudStreamAutoConfiguration.java @@ -3,6 +3,7 @@ import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.beans.BeanMethodsScanner; +import io.github.springwolf.core.asyncapi.scanners.bindings.channels.ChannelBindingProcessor; import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor; import io.github.springwolf.core.configuration.docket.AsyncApiDocketService; import io.github.springwolf.core.configuration.properties.SpringwolfConfigConstants; @@ -14,6 +15,8 @@ import org.springframework.cloud.stream.config.BindingServiceProperties; import org.springframework.context.annotation.Bean; +import java.util.List; + /** * Autoconfiguration for the springwolf cloudstream plugin. */ @@ -27,13 +30,15 @@ public CloudStreamFunctionChannelsScanner cloudStreamFunctionChannelsScanner( BeanMethodsScanner beanMethodsScanner, ComponentsService componentsService, BindingServiceProperties cloudstreamBindingServiceProperties, - FunctionalChannelBeanBuilder functionalChannelBeanBuilder) { + FunctionalChannelBeanBuilder functionalChannelBeanBuilder, + List channelBindingProcessors) { return new CloudStreamFunctionChannelsScanner( asyncApiDocketService, beanMethodsScanner, componentsService, cloudstreamBindingServiceProperties, - functionalChannelBeanBuilder); + functionalChannelBeanBuilder, + channelBindingProcessors); } @Bean diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java index e679a8275..9005d07f1 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/channels/CloudStreamFunctionChannelsScannerIntegrationTest.java @@ -431,7 +431,6 @@ void testFunctionBindingWithSameTopicName() { @TestConfiguration public static class Configuration { - @Bean public Consumer testConsumer() { return System.out::println; diff --git a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanBuilderTest.java b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanBuilderTest.java index 69eadfc97..599a2135d 100644 --- a/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanBuilderTest.java +++ b/springwolf-plugins/springwolf-cloud-stream-plugin/src/test/java/io/github/springwolf/plugins/cloudstream/asyncapi/scanners/common/FunctionalChannelBeanBuilderTest.java @@ -51,7 +51,7 @@ void testConsumerBean() throws NoSuchMethodException { Assertions.assertThat(data) .containsExactly( - new FunctionalChannelBeanData("consumerBean", String.class, CONSUMER, "consumerBean-in-0")); + new FunctionalChannelBeanData(method, String.class, CONSUMER, "consumerBean-in-0")); } @Bean @@ -69,8 +69,8 @@ void testSupplierBean() throws NoSuchMethodException { Set data = functionalChannelBeanBuilder.fromMethodBean(method); Assertions.assertThat(data) - .containsExactly(new FunctionalChannelBeanData( - "supplierBean", String.class, SUPPLIER, "supplierBean-out-0")); + .containsExactly( + new FunctionalChannelBeanData(method, String.class, SUPPLIER, "supplierBean-out-0")); } @Bean @@ -89,9 +89,8 @@ void testFunctionBean() throws NoSuchMethodException { Assertions.assertThat(data) .containsExactlyInAnyOrder( - new FunctionalChannelBeanData("functionBean", String.class, CONSUMER, "functionBean-in-0"), - new FunctionalChannelBeanData( - "functionBean", Integer.class, SUPPLIER, "functionBean-out-0")); + new FunctionalChannelBeanData(method, String.class, CONSUMER, "functionBean-in-0"), + new FunctionalChannelBeanData(method, Integer.class, SUPPLIER, "functionBean-out-0")); } @Bean @@ -112,7 +111,7 @@ void testConsumerBeanWithGenericPayload() throws NoSuchMethodException { Assertions.assertThat(data) .containsExactly( - new FunctionalChannelBeanData(methodName, String.class, CONSUMER, methodName + "-in-0")); + new FunctionalChannelBeanData(method, String.class, CONSUMER, methodName + "-in-0")); } @Bean @@ -133,7 +132,7 @@ void testKafkaStreamsConsumerBean() throws NoSuchMethodException { Assertions.assertThat(data) .containsExactly( - new FunctionalChannelBeanData(methodName, String.class, CONSUMER, methodName + "-in-0")); + new FunctionalChannelBeanData(method, String.class, CONSUMER, methodName + "-in-0")); } @Bean