diff --git a/springwolf-asyncapi/build.gradle b/springwolf-asyncapi/build.gradle index b3ebe77d2..2aa8cac02 100644 --- a/springwolf-asyncapi/build.gradle +++ b/springwolf-asyncapi/build.gradle @@ -26,6 +26,7 @@ dependencies { testImplementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${jacksonVersion}" testImplementation "io.swagger.core.v3:swagger-core-jakarta:${swaggerVersion}" testImplementation "net.javacrumbs.json-unit:json-unit-assertj:${jsonUnitAssertJVersion}" + testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/ReferenceUtil.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/ReferenceUtil.java new file mode 100644 index 000000000..2768130ec --- /dev/null +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/ReferenceUtil.java @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.asyncapi.v3.model; + +public class ReferenceUtil { + private static final String FORBIDDEN_ID_CHARACTER = "/"; + + public static String toValidId(String name) { + return name.replaceAll(FORBIDDEN_ID_CHARACTER, "_"); + } +} diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelObject.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelObject.java index ecd62685e..d00422c89 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelObject.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelObject.java @@ -1,17 +1,21 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.asyncapi.v3.model.channel; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; import io.github.springwolf.asyncapi.v3.model.ExtendableObject; import io.github.springwolf.asyncapi.v3.model.ExternalDocumentation; import io.github.springwolf.asyncapi.v3.model.Tag; import io.github.springwolf.asyncapi.v3.model.channel.message.Message; +import io.github.springwolf.asyncapi.v3.model.server.ServerReference; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.Setter; import java.util.List; import java.util.Map; @@ -27,6 +31,15 @@ @AllArgsConstructor @EqualsAndHashCode(callSuper = true) public class ChannelObject extends ExtendableObject implements Channel { + /** + * An identifier for the described channel. + * The channelId value is case-sensitive. + * Tools and libraries MAY use the channelId to uniquely identify a channel, + * therefore, it is RECOMMENDED to follow common programming naming conventions. + */ + @JsonIgnore + @Setter(AccessLevel.NONE) + private String channelId; /** * An optional string representation of this channel's address. The address is typically the "topic name", @@ -102,4 +115,14 @@ public class ChannelObject extends ExtendableObject implements Channel { */ @JsonProperty(value = "bindings") private Map bindings; + + /* + * Override the getChannelId to guarantee that there's always a value. Defaults to 'address' + */ + public String getChannelId() { + if (channelId == null) { + return this.address; + } + return channelId; + } } diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelReference.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelReference.java index bdae87404..a147f9f03 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelReference.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelReference.java @@ -21,7 +21,11 @@ public String getRef() { return ref; } - public static ChannelReference fromChannel(String channelName) { - return new ChannelReference("#/channels/" + channelName); + public static ChannelReference fromChannel(ChannelObject channel) { + return new ChannelReference("#/channels/" + channel.getChannelId()); + } + + public static ChannelReference fromChannel(String channelId) { + return new ChannelReference("#/channels/" + channelId); } } diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageObject.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageObject.java index 9b1ff989e..4210b7e0e 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageObject.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageObject.java @@ -8,11 +8,13 @@ import io.github.springwolf.asyncapi.v3.model.ExternalDocumentation; import io.github.springwolf.asyncapi.v3.model.Tag; import io.github.springwolf.asyncapi.v3.model.channel.CorrelationID; +import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import lombok.Setter; import java.util.List; import java.util.Map; @@ -33,6 +35,7 @@ public class MessageObject extends ExtendableObject implements Message { * naming conventions. */ @JsonIgnore + @Setter(AccessLevel.NONE) private String messageId; /** diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageReference.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageReference.java index 4bb00559c..fa344a862 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageReference.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/message/MessageReference.java @@ -38,12 +38,12 @@ public static MessageReference toComponentMessage(String messageId) { return new MessageReference("#/components/messages/" + messageId); } - public static MessageReference toChannelMessage(String channelName, MessageObject message) { - return new MessageReference("#/channels/" + channelName + "/messages/" + message.getMessageId()); + public static MessageReference toChannelMessage(String channelId, MessageObject message) { + return new MessageReference("#/channels/" + channelId + "/messages/" + message.getMessageId()); } - public static MessageReference toChannelMessage(String channelName, String messageId) { - return new MessageReference("#/channels/" + channelName + "/messages/" + messageId); + public static MessageReference toChannelMessage(String channelId, String messageId) { + return new MessageReference("#/channels/" + channelId + "/messages/" + messageId); } public static MessageReference toSchema(String schemaName) { diff --git a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ServerReference.java b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/server/ServerReference.java similarity index 91% rename from springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ServerReference.java rename to springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/server/ServerReference.java index 8ccd21464..879cdde80 100644 --- a/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/channel/ServerReference.java +++ b/springwolf-asyncapi/src/main/java/io/github/springwolf/asyncapi/v3/model/server/ServerReference.java @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -package io.github.springwolf.asyncapi.v3.model.channel; +package io.github.springwolf.asyncapi.v3.model.server; import com.fasterxml.jackson.annotation.JsonIgnore; import io.github.springwolf.asyncapi.v3.model.Reference; diff --git a/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/jackson/DefaultAsyncApiSerializerServiceIntegrationTest.java b/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/jackson/DefaultAsyncApiSerializerServiceIntegrationTest.java index a268b0bc7..d0266aeb0 100644 --- a/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/jackson/DefaultAsyncApiSerializerServiceIntegrationTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/jackson/DefaultAsyncApiSerializerServiceIntegrationTest.java @@ -8,7 +8,6 @@ import io.github.springwolf.asyncapi.v3.model.AsyncAPI; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.springwolf.asyncapi.v3.model.channel.ServerReference; import io.github.springwolf.asyncapi.v3.model.channel.message.Message; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; @@ -23,6 +22,7 @@ import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; import io.github.springwolf.asyncapi.v3.model.server.Server; +import io.github.springwolf.asyncapi.v3.model.server.ServerReference; import org.junit.jupiter.api.Test; import java.io.IOException; @@ -110,7 +110,7 @@ private AsyncAPI getAsyncAPITestObject() { .info(info) .defaultContentType("application/json") .servers(Map.of("production", productionServer)) - .channels(Map.of("new-user", newUserChannel)) + .channels(Map.of(newUserChannel.getChannelId(), newUserChannel)) .components( Components.builder().schemas(schemas).messages(messages).build()) .operations(Map.of("new-user_listenerMethod_subscribe", newUserOperation)) diff --git a/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/AsyncAPITest.java b/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/AsyncAPITest.java index 1c8a188bb..de1352a62 100644 --- a/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/AsyncAPITest.java +++ b/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/AsyncAPITest.java @@ -57,6 +57,7 @@ void shouldCreateSimpleAsyncAPI() throws IOException { .build(); var channelUserSignedup = ChannelObject.builder() + .channelId("userSignedup") .address("user/signedup") .messages(Map.of(userSignUpMessage.getMessageId(), MessageReference.toComponentMessage("UserSignedUp"))) .build(); @@ -67,7 +68,7 @@ void shouldCreateSimpleAsyncAPI() throws IOException { .version("1.0.0") .description("This service is in charge of processing user signups") .build()) - .channels(Map.of("userSignedup", channelUserSignedup)) + .channels(Map.of(channelUserSignedup.getChannelId(), channelUserSignedup)) .operations(Map.of( "sendUserSignedup", Operation.builder() diff --git a/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/ReferenceUtilTest.java b/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/ReferenceUtilTest.java new file mode 100644 index 000000000..f795f143e --- /dev/null +++ b/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/ReferenceUtilTest.java @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: Apache-2.0 +package io.github.springwolf.asyncapi.v3.model; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ReferenceUtilTest { + @Test + void shouldCorrectIllegalCharacter() { + String name = "users/{userId}"; + + assertThat(ReferenceUtil.toValidId(name)).isEqualTo("users_{userId}"); + } +} diff --git a/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelObjectTest.java b/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelObjectTest.java index 4672a6fab..2b3963f7d 100644 --- a/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelObjectTest.java +++ b/springwolf-asyncapi/src/test/java/io/github/springwolf/asyncapi/v3/model/channel/ChannelObjectTest.java @@ -9,6 +9,7 @@ import io.github.springwolf.asyncapi.v3.model.ExternalDocumentation; import io.github.springwolf.asyncapi.v3.model.Tag; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; +import io.github.springwolf.asyncapi.v3.model.server.ServerReference; import org.junit.jupiter.api.Test; import java.io.IOException; diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java index 3d0f06426..e77c30dfb 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/AsyncAnnotationChannelsScanner.java @@ -1,12 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.channels; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; -import io.github.springwolf.asyncapi.v3.model.channel.ServerReference; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.asyncapi.v3.model.server.Server; +import io.github.springwolf.asyncapi.v3.model.server.ServerReference; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.ChannelsScanner; @@ -64,8 +65,9 @@ private Map.Entry buildChannel(MethodAndAnnotation met AsyncOperation operationAnnotation = this.asyncAnnotationProvider.getAsyncOperation(methodAndAnnotation.annotation()); String channelName = resolver.resolveStringValue(operationAnnotation.channelName()); + String channelId = ReferenceUtil.toValidId(channelName); - Operation operation = buildOperation(operationAnnotation, methodAndAnnotation.method(), channelName); + Operation operation = buildOperation(operationAnnotation, methodAndAnnotation.method(), channelId); List servers = AsyncAnnotationUtil.getServers(operationAnnotation, resolver); if (servers != null && !servers.isEmpty()) { @@ -76,9 +78,11 @@ private Map.Entry buildChannel(MethodAndAnnotation met MessageObject message = buildMessage(operationAnnotation, methodAndAnnotation.method()); ChannelObject channelItem = channelBuilder + .channelId(channelId) + .address(channelName) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - return Map.entry(channelName, channelItem); + return Map.entry(channelItem.getChannelId(), channelItem); } /** diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMerger.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMerger.java index 4b5e602d2..2aedbe427 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMerger.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMerger.java @@ -23,7 +23,7 @@ private ChannelMerger() {} * Messages within channels are merged * * @param channelEntries Ordered pairs of channel name to Channel - * @return A map of channelName to a single Channel + * @return A map of channelId to a single Channel */ public static Map mergeChannels(List> channelEntries) { Map mergedChannels = new HashMap<>(); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java index 22a9c5dbd..b455c2257 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScanner.java @@ -2,6 +2,7 @@ package io.github.springwolf.core.asyncapi.scanners.channels.annotations; import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.core.asyncapi.components.ComponentsService; @@ -62,11 +63,8 @@ private Stream> mapClassToChannel(Class comp return Stream.empty(); } - String channelName = bindingFactory.getChannelName(classAnnotation); - ChannelObject channelItem = buildChannelItem(classAnnotation, annotatedMethods); - - return Stream.of(Map.entry(channelName, channelItem)); + return Stream.of(Map.entry(channelItem.getChannelId(), channelItem)); } private ChannelObject buildChannelItem(ClassAnnotation classAnnotation, Set methods) { @@ -77,7 +75,10 @@ private ChannelObject buildChannelItem(ClassAnnotation classAnnotation, Set messages) { Map channelBinding = bindingFactory.buildChannelBinding(classAnnotation); Map chBinding = channelBinding != null ? new HashMap<>(channelBinding) : null; + String channelName = bindingFactory.getChannelName(classAnnotation); return ChannelObject.builder() + .channelId(ReferenceUtil.toValidId(channelName)) + .address(channelName) .bindings(chBinding) .messages(new HashMap<>(messages)) .build(); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java index 7b967daf4..825a99101 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScanner.java @@ -2,6 +2,7 @@ package io.github.springwolf.core.asyncapi.scanners.channels.annotations; import io.github.springwolf.asyncapi.v3.bindings.ChannelBinding; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; @@ -63,11 +64,10 @@ private Map.Entry mapMethodToChannel(Method method) { MethodAnnotation annotation = AnnotationScannerUtil.findAnnotationOrThrow(methodAnnotationClass, method); NamedSchemaObject payloadSchema = payloadMethodService.extractSchema(method); + SchemaObject headerSchema = headerClassExtractor.extractHeader(method, payloadSchema); ChannelObject channelItem = buildChannelItem(annotation, payloadSchema, headerSchema); - - String channelName = bindingFactory.getChannelName(annotation); - return Map.entry(channelName, channelItem); + return Map.entry(channelItem.getChannelId(), channelItem); } private ChannelObject buildChannelItem( @@ -79,7 +79,10 @@ private ChannelObject buildChannelItem( private ChannelObject buildChannelItem(MethodAnnotation annotation, MessageObject message) { Map channelBinding = bindingFactory.buildChannelBinding(annotation); Map chBinding = channelBinding != null ? new HashMap<>(channelBinding) : null; + String channelName = bindingFactory.getChannelName(annotation); return ChannelObject.builder() + .channelId(ReferenceUtil.toValidId(channelName)) + .address(channelName) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .bindings(chBinding) .build(); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java index 8c0b6fc5f..3d094afe5 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/AsyncAnnotationScanner.java @@ -24,9 +24,9 @@ import io.github.springwolf.core.asyncapi.scanners.common.utils.TextUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.context.EmbeddedValueResolverAware; import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; import org.springframework.util.StringValueResolver; import java.lang.annotation.Annotation; @@ -65,15 +65,16 @@ protected Stream> getAnnotatedMethods(Class type) { .map(annotation -> new MethodAndAnnotation<>(method, annotation))); } - protected Operation buildOperation(AsyncOperation asyncOperation, Method method, String channelName) { + protected Operation buildOperation(AsyncOperation asyncOperation, Method method, String channelId) { String description = this.resolver.resolveStringValue(asyncOperation.description()); - if (!StringUtils.hasText(description)) { + if (StringUtils.isBlank(description)) { description = "Auto-generated description"; } else { description = TextUtils.trimIndent(description); } - String operationTitle = channelName + "_" + this.asyncAnnotationProvider.getOperationType().type; + String operationTitle = + StringUtils.joinWith("_", channelId, this.asyncAnnotationProvider.getOperationType().type); Map operationBinding = AsyncAnnotationUtil.processOperationBindingFromAnnotation(method, operationBindingProcessors); @@ -81,10 +82,10 @@ protected Operation buildOperation(AsyncOperation asyncOperation, Method method, MessageObject message = buildMessage(asyncOperation, method); return Operation.builder() - .channel(ChannelReference.fromChannel(channelName)) + .channel(ChannelReference.fromChannel(channelId)) .description(description) .title(operationTitle) - .messages(List.of(MessageReference.toChannelMessage(channelName, message))) + .messages(List.of(MessageReference.toChannelMessage(channelId, message))) .bindings(opBinding) .build(); } @@ -103,10 +104,10 @@ protected MessageObject buildMessage(AsyncOperation operationData, Method method .build()); String description = operationData.message().description(); - if (!StringUtils.hasText(description) && payloadSchema.schema() != null) { + if (StringUtils.isBlank(description) && payloadSchema.schema() != null) { description = payloadSchema.schema().getDescription(); } - if (StringUtils.hasText(description)) { + if (StringUtils.isNotBlank(description)) { description = this.resolver.resolveStringValue(description); description = TextUtils.trimIndent(description); } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelper.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelper.java index 61a219ea9..ccd3c37ed 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelper.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelper.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.common; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import lombok.extern.slf4j.Slf4j; @@ -44,6 +45,7 @@ public static Map toOperationsMessagesMap( .stream() .collect(Collectors.toMap( MessageObject::getMessageId, - e -> MessageReference.toChannelMessage(channelName, e.getMessageId()))); + e -> MessageReference.toChannelMessage( + ReferenceUtil.toValidId(channelName), e.getMessageId()))); } } diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java index 24e874b82..e08f15111 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/AsyncAnnotationOperationsScanner.java @@ -1,6 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.operations.annotations; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; import io.github.springwolf.core.asyncapi.components.ComponentsService; @@ -12,6 +13,7 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadAsyncOperationService; import io.github.springwolf.core.asyncapi.scanners.operations.OperationMerger; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import java.lang.annotation.Annotation; import java.util.List; @@ -53,10 +55,14 @@ private Map.Entry buildOperation(MethodAndAnnotation metho AsyncOperation operationAnnotation = this.asyncAnnotationProvider.getAsyncOperation(methodAndAnnotation.annotation()); String channelName = resolver.resolveStringValue(operationAnnotation.channelName()); - String operationId = channelName + "_" + this.asyncAnnotationProvider.getOperationType().type + "_" - + methodAndAnnotation.method().getName(); + String channelId = ReferenceUtil.toValidId(channelName); + String operationId = StringUtils.joinWith( + "_", + channelId, + this.asyncAnnotationProvider.getOperationType().type, + methodAndAnnotation.method().getName()); - Operation operation = buildOperation(operationAnnotation, methodAndAnnotation.method(), channelName); + Operation operation = buildOperation(operationAnnotation, methodAndAnnotation.method(), channelId); operation.setAction(this.asyncAnnotationProvider.getOperationType()); return Map.entry(operationId, operation); diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java index 0e068a266..554a45d8f 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScanner.java @@ -2,6 +2,7 @@ package io.github.springwolf.core.asyncapi.scanners.operations.annotations; import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.operation.Operation; @@ -14,6 +15,7 @@ import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadMethodService; import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -65,7 +67,8 @@ private Stream> mapClassToOperation(Class compon } String channelName = bindingFactory.getChannelName(classAnnotation); - String operationId = channelName + "_" + OperationAction.RECEIVE + "_" + component.getSimpleName(); + String operationId = StringUtils.joinWith( + "_", ReferenceUtil.toValidId(channelName), OperationAction.RECEIVE, component.getSimpleName()); Operation operation = buildOperation(classAnnotation, annotatedMethods); @@ -84,7 +87,7 @@ private Operation buildOperation(ClassAnnotation classAnnotation, Map mapMethodToOperation(Method method) { MethodAnnotation annotation = AnnotationScannerUtil.findAnnotationOrThrow(methodAnnotationClass, method); String channelName = bindingFactory.getChannelName(annotation); - String operationId = channelName + "_" + OperationAction.RECEIVE + "_" + method.getName(); + String operationId = StringUtils.joinWith( + "_", ReferenceUtil.toValidId(channelName), OperationAction.RECEIVE, method.getName()); + NamedSchemaObject payloadSchema = payloadMethodParameterService.extractSchema(method); SchemaObject headerSchema = headerClassExtractor.extractHeader(method, payloadSchema); @@ -83,12 +87,12 @@ private Operation buildOperation( private Operation buildOperation(MethodAnnotation annotation, MessageObject message) { Map operationBinding = bindingFactory.buildOperationBinding(annotation); Map opBinding = operationBinding != null ? new HashMap<>(operationBinding) : null; - String channelName = bindingFactory.getChannelName(annotation); + String channelId = ReferenceUtil.toValidId(bindingFactory.getChannelName(annotation)); return Operation.builder() .action(OperationAction.RECEIVE) - .channel(ChannelReference.fromChannel(channelName)) - .messages(List.of(MessageReference.toChannelMessage(channelName, message))) + .channel(ChannelReference.fromChannel(channelId)) + .messages(List.of(MessageReference.toChannelMessage(channelId, message))) .bindings(opBinding) .build(); } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMergerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMergerTest.java index 4f8f9b28c..f0fa992d2 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMergerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/ChannelMergerTest.java @@ -16,31 +16,31 @@ class ChannelMergerTest { @Test - void shouldNotMergeDifferentChannelNames() { + void shouldNotMergeDifferentchannelIds() { // given - String channelName1 = "channel1"; - String channelName2 = "channel2"; + String channelId1 = "channel1"; + String channelId2 = "channel2"; ChannelObject publisherChannel = ChannelObject.builder().build(); ChannelObject subscriberChannel = ChannelObject.builder().build(); // when Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelName1, publisherChannel), Map.entry(channelName2, subscriberChannel))); + Arrays.asList(Map.entry(channelId1, publisherChannel), Map.entry(channelId2, subscriberChannel))); // then assertThat(mergedChannels).hasSize(2); } @Test - void shouldMergeEqualChannelNamesIntoOneChannel() { + void shouldMergeEqualchannelIdsIntoOneChannel() { // given - String channelName = "channel"; + String channelId = "channel"; ChannelObject publisherChannel = ChannelObject.builder().build(); ChannelObject subscriberChannel = ChannelObject.builder().build(); // when Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelName, publisherChannel), Map.entry(channelName, subscriberChannel))); + Arrays.asList(Map.entry(channelId, publisherChannel), Map.entry(channelId, subscriberChannel))); // then assertThat(mergedChannels).hasSize(1); @@ -49,7 +49,7 @@ void shouldMergeEqualChannelNamesIntoOneChannel() { @Test void shouldUseFirstChannelFound() { // given - String channelName = "channel"; + String channelId = "channel"; ChannelObject publisherChannel1 = ChannelObject.builder().title("channel1").build(); ChannelObject publisherChannel2 = @@ -57,10 +57,10 @@ void shouldUseFirstChannelFound() { // when Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelName, publisherChannel1), Map.entry(channelName, publisherChannel2))); + Arrays.asList(Map.entry(channelId, publisherChannel1), Map.entry(channelId, publisherChannel2))); // then - assertThat(mergedChannels).hasSize(1).hasEntrySatisfying(channelName, it -> { + assertThat(mergedChannels).hasSize(1).hasEntrySatisfying(channelId, it -> { assertThat(it.getTitle()).isEqualTo("channel1"); }); } @@ -68,7 +68,7 @@ void shouldUseFirstChannelFound() { @Test void shouldMergeDifferentMessagesForSameChannel() { // given - String channelName = "channel"; + String channelId = "channel"; MessageObject message1 = MessageObject.builder() .name(String.class.getCanonicalName()) .description("This is a string") @@ -93,14 +93,14 @@ void shouldMergeDifferentMessagesForSameChannel() { // when Map mergedChannels = ChannelMerger.mergeChannels(Arrays.asList( - Map.entry(channelName, publisherChannel1), - Map.entry(channelName, publisherChannel2), - Map.entry(channelName, publisherChannel3))); + Map.entry(channelId, publisherChannel1), + Map.entry(channelId, publisherChannel2), + Map.entry(channelId, publisherChannel3))); // then expectedMessage only includes message1 and message2. // Message3 is not included as it is identical in terms of payload type (Message#name) to message 2 var expectedMessages = MessageHelper.toMessagesMap(Set.of(message1, message2)); - assertThat(mergedChannels).hasSize(1).hasEntrySatisfying(channelName, it -> { + assertThat(mergedChannels).hasSize(1).hasEntrySatisfying(channelId, it -> { assertThat(it.getMessages()).containsExactlyInAnyOrderEntriesOf(expectedMessages); }); } @@ -108,7 +108,7 @@ void shouldMergeDifferentMessagesForSameChannel() { @Test void shouldUseOtherMessageIfFirstMessageIsMissingForChannels() { // given - String channelName = "channel"; + String channelId = "channel"; MessageObject message2 = MessageObject.builder() .name(String.class.getCanonicalName()) .description("This is a string") @@ -120,12 +120,12 @@ void shouldUseOtherMessageIfFirstMessageIsMissingForChannels() { // when Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelName, publisherChannel1), Map.entry(channelName, publisherChannel2))); + Arrays.asList(Map.entry(channelId, publisherChannel1), Map.entry(channelId, publisherChannel2))); // then expectedMessage message2 var expectedMessages = Map.of(message2.getName(), message2); - assertThat(mergedChannels).hasSize(1).hasEntrySatisfying(channelName, it -> { + assertThat(mergedChannels).hasSize(1).hasEntrySatisfying(channelId, it -> { assertThat(it.getMessages()).hasSize(1); assertThat(it.getMessages()).containsExactlyInAnyOrderEntriesOf(expectedMessages); }); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java index 3ab774513..d8bf2c0d5 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/AsyncAnnotationChannelsScannerTest.java @@ -1,19 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 package io.github.springwolf.core.asyncapi.scanners.channels.annotations; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; -import io.github.springwolf.asyncapi.v3.model.channel.ChannelReference; -import io.github.springwolf.asyncapi.v3.model.channel.ServerReference; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessagePayload; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageReference; import io.github.springwolf.asyncapi.v3.model.info.Info; -import io.github.springwolf.asyncapi.v3.model.operation.Operation; import io.github.springwolf.asyncapi.v3.model.operation.OperationAction; import io.github.springwolf.asyncapi.v3.model.schema.MultiFormatSchema; import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.asyncapi.v3.model.server.Server; +import io.github.springwolf.asyncapi.v3.model.server.ServerReference; import io.github.springwolf.core.asyncapi.annotations.AsyncListener; import io.github.springwolf.core.asyncapi.annotations.AsyncMessage; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; @@ -64,6 +63,8 @@ import static org.mockito.Mockito.when; class AsyncAnnotationChannelsScannerTest { + private static final String CHANNEL = "test/channel"; + private static final String CHANNEL_ID = ReferenceUtil.toValidId(CHANNEL); private final AsyncAnnotationScanner.AsyncAnnotationProvider asyncAnnotationProvider = new AsyncAnnotationScanner.AsyncAnnotationProvider<>() { @@ -122,7 +123,7 @@ public void setup() { channelScanner.setEmbeddedValueResolver(stringValueResolver); when(stringValueResolver.resolveStringValue(any())) .thenAnswer(invocation -> switch ((String) invocation.getArgument(0)) { - case "${test.property.test-channel}" -> "test-channel"; + case "${test.property.test-channel}" -> CHANNEL; case "${test.property.description}" -> "description"; case "${test.property.server1}" -> "server1"; case "${test.property.server2}" -> "server2"; @@ -169,11 +170,13 @@ void scan_componentChannelHasListenerMethod() { .build(); ChannelObject expectedChannel = ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) .bindings(null) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry("test-channel", expectedChannel)); + assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); } @Test @@ -184,7 +187,7 @@ void scan_componentHasListenerMethodWithUnknownServer() { assertThatThrownBy(channelScanner::scan) .isInstanceOf(IllegalArgumentException.class) .hasMessage( - "Operation 'test-channel_send' defines unknown server ref 'server3'. This AsyncApi defines these server(s): [server1, server2]"); + "Operation 'test_channel_send' defines unknown server ref 'server3'. This AsyncApi defines these server(s): [server1, server2]"); } @Test @@ -211,12 +214,14 @@ void scan_componentHasListenerMethodWithAllAttributes() { .build(); ChannelObject expectedChannel = ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) .bindings(null) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .servers(List.of(ServerReference.fromServer("server1"), ServerReference.fromServer("server2"))) .build(); - assertThat(actualChannels).containsExactly(Map.entry("test-channel", expectedChannel)); + assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); } @Test @@ -244,11 +249,15 @@ void scan_componentHasMultipleListenerAnnotations() { .build(); ChannelObject expectedChannel1 = ChannelObject.builder() + .channelId("test-channel-1") + .address("test-channel-1") .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .bindings(null) .build(); ChannelObject expectedChannel2 = ChannelObject.builder() + .channelId("test-channel-2") + .address("test-channel-2") .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .bindings(null) .build(); @@ -284,11 +293,13 @@ void scan_componentHasAsyncMethodAnnotation() { .build(); ChannelObject expectedChannel = ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) .bindings(null) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry("test-channel", expectedChannel)); + assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); } private static class ClassWithoutListenerAnnotation { @@ -298,7 +309,7 @@ private void methodWithoutAnnotation() {} private static class ClassWithListenerAnnotation { - @AsyncListener(operation = @AsyncOperation(channelName = "test-channel")) + @AsyncListener(operation = @AsyncOperation(channelName = CHANNEL)) private void methodWithAnnotation(SimpleFoo payload) {} private void methodWithoutAnnotation() {} @@ -309,7 +320,7 @@ private static class ClassWithListenerAnnotationWithInvalidServer { @AsyncListener( operation = @AsyncOperation( - channelName = "test-channel", + channelName = CHANNEL, description = "test channel operation description", servers = {"server3"})) private void methodWithAnnotation(SimpleFoo payload) {} @@ -350,7 +361,7 @@ private static class ClassWithMessageAnnotation { @AsyncListener( operation = @AsyncOperation( - channelName = "test-channel", + channelName = CHANNEL, description = "test channel operation description", message = @AsyncMessage( @@ -391,20 +402,20 @@ void scan_componentHasOnlyDeclaredMethods(Class clazz) { .build(); ChannelObject expectedChannel = ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) .bindings(null) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry("test-channel", expectedChannel)); + assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); } private static class ClassImplementingInterface implements ClassInterface { @AsyncListener( operation = - @AsyncOperation( - channelName = "test-channel", - description = "test channel operation description")) + @AsyncOperation(channelName = CHANNEL, description = "test channel operation description")) @Override public void methodFromInterface(String payload) {} } @@ -422,9 +433,7 @@ public void methodFromInterface(String payload) {} interface ClassInterfaceWithAnnotation { @AsyncListener( operation = - @AsyncOperation( - channelName = "test-channel", - description = "test channel operation description")) + @AsyncOperation(channelName = CHANNEL, description = "test channel operation description")) void methodFromInterface(T payload); } } @@ -455,21 +464,14 @@ void scan_componentHasListenerMethodWithMetaAnnotation() { .bindings(EMPTY_MAP) .build(); - Operation expectedOperation = Operation.builder() - .action(OperationAction.SEND) - .channel(ChannelReference.fromChannel("test-channel")) - .description("test channel operation description") - .title("test-channel_send") - .bindings(EMPTY_MAP) - .messages(List.of(MessageReference.toChannelMessage("test-channel", message))) - .build(); - ChannelObject expectedChannel = ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) .bindings(null) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry("test-channel", expectedChannel)); + assertThat(actualChannels).containsExactly(Map.entry(CHANNEL_ID, expectedChannel)); } public static class ClassWithMetaAnnotation { @@ -481,10 +483,7 @@ void methodFromInterface(String payload) {} @Retention(RetentionPolicy.RUNTIME) @Inherited @AsyncListener( - operation = - @AsyncOperation( - channelName = "test-channel", - description = "test channel operation description")) + operation = @AsyncOperation(channelName = CHANNEL, description = "test channel operation description")) public @interface AsyncListenerMetaAnnotation {} } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java index 8e47a3fe1..2ee4faff3 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerIntegrationTest.java @@ -4,6 +4,7 @@ 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.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; @@ -158,11 +159,13 @@ void scan_componentWithOneMethodLevelAnnotation() { .build(); ChannelObject expectedChannel = ChannelObject.builder() + .channelId(TestBindingFactory.CHANNEL_ID) + .address(TestBindingFactory.CHANNEL) .bindings(TestBindingFactory.defaultChannelBinding) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL, expectedChannel)); + assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannel)); } @TestClassListener @@ -212,6 +215,8 @@ void scan_componentWithMultipleRabbitHandlerMethods() { .build(); ChannelObject expectedChannel = ChannelObject.builder() + .channelId(TestBindingFactory.CHANNEL_ID) + .address(TestBindingFactory.CHANNEL) .bindings(TestBindingFactory.defaultChannelBinding) .messages(Map.of( fooMessage.getMessageId(), @@ -220,7 +225,7 @@ void scan_componentWithMultipleRabbitHandlerMethods() { MessageReference.toComponentMessage(barMessage))) .build(); - assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL, expectedChannel)); + assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannel)); } @TestClassListener @@ -253,13 +258,14 @@ private static class SimpleFoo { static class TestBindingFactory implements BindingFactory { - public static final String CHANNEL = "test-channel"; + public static final String CHANNEL = "test/channel"; + public static final String CHANNEL_ID = ReferenceUtil.toValidId(CHANNEL); public static final Map defaultMessageBinding = - Map.of(CHANNEL, new TestBindingFactory.TestMessageBinding()); + Map.of(CHANNEL_ID, new TestBindingFactory.TestMessageBinding()); public static final Map defaultChannelBinding = - Map.of(CHANNEL, new TestBindingFactory.TestChannelBinding()); + Map.of(CHANNEL_ID, new TestBindingFactory.TestChannelBinding()); public static final Map defaultOperationBinding = - Map.of(CHANNEL, new TestBindingFactory.TestOperationBinding()); + Map.of(CHANNEL_ID, new TestBindingFactory.TestOperationBinding()); @Override public String getChannelName(TestClassListener annotation) { diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java index e263c9d9f..fc652e58f 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationClassLevelChannelsScannerTest.java @@ -17,6 +17,7 @@ import io.github.springwolf.asyncapi.v3.model.schema.SchemaReference; import io.github.springwolf.core.asyncapi.components.ComponentsService; import io.github.springwolf.core.asyncapi.scanners.bindings.BindingFactory; +import io.github.springwolf.core.asyncapi.scanners.channels.annotations.SpringAnnotationClassLevelChannelsScannerIntegrationTest.TestBindingFactory; import io.github.springwolf.core.asyncapi.scanners.common.headers.AsyncHeadersNotDocumented; import io.github.springwolf.core.asyncapi.scanners.common.headers.HeaderClassExtractor; import io.github.springwolf.core.asyncapi.scanners.common.payload.NamedSchemaObject; @@ -54,7 +55,7 @@ class SpringAnnotationClassLevelChannelsScannerTest { headerClassExtractor, componentsService); - private static final String CHANNEL = "test-channel"; + private static final String CHANNEL = "test/channel"; private static final Map defaultOperationBinding = Map.of("protocol", new AMQPOperationBinding()); private static final Map defaultMessageBinding = @@ -100,11 +101,13 @@ void scan_componentHasTestListenerMethods() { .build(); ChannelObject expectedChannelItem = ChannelObject.builder() + .channelId(TestBindingFactory.CHANNEL_ID) + .address(TestBindingFactory.CHANNEL) .bindings(defaultChannelBinding) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(channels).containsExactly(Map.entry(CHANNEL, expectedChannelItem)); + assertThat(channels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannelItem)); } @TestClassListener diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java index fafa1b8dc..4271bc012 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerIntegrationTest.java @@ -4,6 +4,7 @@ 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.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; @@ -137,11 +138,13 @@ void scan_componentHasListenerMethod() { .build(); ChannelObject expectedChannel = ChannelObject.builder() + .channelId(TestBindingFactory.CHANNEL_ID) + .address(TestBindingFactory.CHANNEL) .bindings(defaultChannelBinding) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL, expectedChannel)); + assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannel)); } private static class ClassWithListenerAnnotation { @@ -190,20 +193,24 @@ void scan_componentHasTestListenerMethods_multiplePayloads() { .build(); ChannelObject expectedChannelItem = ChannelObject.builder() + .channelId(TestBindingFactory.CHANNEL_ID) + .address(TestBindingFactory.CHANNEL) .messages(Map.of( messageSimpleFoo.getMessageId(), MessageReference.toComponentMessage(messageSimpleFoo))) .bindings(defaultChannelBinding) .build(); ChannelObject expectedChannelItem2 = ChannelObject.builder() + .channelId(TestBindingFactory.CHANNEL_ID) + .address(TestBindingFactory.CHANNEL) .bindings(defaultChannelBinding) .messages(Map.of(messageString.getMessageId(), MessageReference.toComponentMessage(messageString))) .build(); assertThat(channels) .containsExactlyInAnyOrder( - Map.entry(TestBindingFactory.CHANNEL, expectedChannelItem), - Map.entry(TestBindingFactory.CHANNEL, expectedChannelItem2)); + Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannelItem), + Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannelItem2)); } private static class ClassWithTestListenerAnnotationMultiplePayloads { @@ -240,11 +247,13 @@ void scan_componentHasListenerMetaMethod() { .build(); ChannelObject expectedChannel = ChannelObject.builder() + .channelId(TestBindingFactory.CHANNEL_ID) + .address(TestBindingFactory.CHANNEL) .bindings(defaultChannelBinding) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL, expectedChannel)); + assertThat(actualChannels).containsExactly(Map.entry(TestBindingFactory.CHANNEL_ID, expectedChannel)); } private static class ClassWithListenerMetaAnnotation { @@ -276,13 +285,14 @@ private static class SimpleFoo { static class TestBindingFactory implements BindingFactory { - public static final String CHANNEL = "test-channel"; + public static final String CHANNEL = "test/channel"; + public static final String CHANNEL_ID = ReferenceUtil.toValidId(CHANNEL); public static final Map defaultMessageBinding = - Map.of(CHANNEL, new TestBindingFactory.TestMessageBinding()); + Map.of(CHANNEL_ID, new TestBindingFactory.TestMessageBinding()); public static final Map defaultChannelBinding = - Map.of(CHANNEL, new TestBindingFactory.TestChannelBinding()); + Map.of(CHANNEL_ID, new TestBindingFactory.TestChannelBinding()); public static final Map defaultOperationBinding = - Map.of(CHANNEL, new TestBindingFactory.TestOperationBinding()); + Map.of(CHANNEL_ID, new TestBindingFactory.TestOperationBinding()); @Override public String getChannelName(TestChannelListener annotation) { diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java index 438cd5c3c..8639790df 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/channels/annotations/SpringAnnotationMethodLevelChannelsScannerTest.java @@ -7,6 +7,7 @@ import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPChannelBinding; import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPMessageBinding; import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding; +import io.github.springwolf.asyncapi.v3.model.ReferenceUtil; import io.github.springwolf.asyncapi.v3.model.channel.ChannelObject; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageHeaders; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; @@ -53,7 +54,8 @@ class SpringAnnotationMethodLevelChannelsScannerTest { headerClassExtractor, componentsService); - private static final String CHANNEL = "test-channel"; + private static final String CHANNEL = "test/channel"; + private static final String CHANNEL_ID = ReferenceUtil.toValidId(CHANNEL); private static final Map defaultOperationBinding = Map.of("protocol", new AMQPOperationBinding()); private static final Map defaultMessageBinding = @@ -108,11 +110,13 @@ void scan_componentHasTestListenerMethods() { .build(); ChannelObject expectedChannelItem = ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) .bindings(defaultChannelBinding) .messages(Map.of(message.getMessageId(), MessageReference.toComponentMessage(message))) .build(); - assertThat(channels).containsExactly(Map.entry(CHANNEL, expectedChannelItem)); + assertThat(channels).containsExactly(Map.entry(CHANNEL_ID, expectedChannelItem)); } private static class ClassWithTestListenerAnnotation { @@ -158,10 +162,14 @@ void scan_componentHasMultipleTestListenerMethods() { .build(); ChannelObject methodChannel = ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) .bindings(defaultChannelBinding) .messages(Map.of(stringMessage.getMessageId(), MessageReference.toComponentMessage(stringMessage))) .build(); ChannelObject anotherMethodChannel = ChannelObject.builder() + .channelId(CHANNEL_ID) + .address(CHANNEL) .bindings(defaultChannelBinding) .messages( Map.of(simpleFooMessage.getMessageId(), MessageReference.toComponentMessage(simpleFooMessage))) @@ -169,7 +177,7 @@ void scan_componentHasMultipleTestListenerMethods() { assertThat(channels) .containsExactlyInAnyOrderElementsOf( - List.of(Map.entry(CHANNEL, methodChannel), Map.entry(CHANNEL, anotherMethodChannel))); + List.of(Map.entry(CHANNEL_ID, methodChannel), Map.entry(CHANNEL_ID, anotherMethodChannel))); } private static class ClassWithMultipleTestListenerAnnotation { diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelperTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelperTest.java index 97de486f5..cbcc8f2ac 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelperTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/MessageHelperTest.java @@ -25,7 +25,7 @@ void toMessageObjectOrComposition_emptySet() { @Test void toOperationsMessageObjectOrComposition_emptySet() { // When messages set is empty, the method should fail - assertThatThrownBy(() -> toOperationsMessagesMap("channel", Collections.emptySet())) + assertThatThrownBy(() -> toOperationsMessagesMap("channelId", Collections.emptySet())) .isInstanceOf(IllegalArgumentException.class); } @@ -56,11 +56,11 @@ void toMessagesMap_oneMessage() { void toOperationsMessagesMap_oneMessage() { MessageObject message = MessageObject.builder().name("foo").build(); - var messagesMap = toOperationsMessagesMap("channelName", Set.of(message)); + var messagesMap = toOperationsMessagesMap("channelId", Set.of(message)); assertThat(messagesMap) .containsExactlyInAnyOrderEntriesOf( - Map.of("foo", MessageReference.toChannelMessage("channelName", message))); + Map.of("foo", MessageReference.toChannelMessage("channelId", message))); } @Test @@ -85,14 +85,14 @@ void toOperationsMessagesMap_multipleMessages() { MessageObject message2 = MessageObject.builder().name("bar").build(); - var messages = toOperationsMessagesMap("channelName", Set.of(message1, message2)); + var messages = toOperationsMessagesMap("channelId", Set.of(message1, message2)); assertThat(messages) .containsExactlyInAnyOrderEntriesOf(Map.of( "bar", - MessageReference.toChannelMessage("channelName", message2), + MessageReference.toChannelMessage("channelId", message2), "foo", - MessageReference.toChannelMessage("channelName", message1))); + MessageReference.toChannelMessage("channelId", message1))); } @Test @@ -140,14 +140,14 @@ void toOperationsMessagesMap_multipleMessages_remove_duplicates() { .description("This is message 3, but in essence the same payload type as message 2") .build(); - var messages = toOperationsMessagesMap("channelName", Set.of(message1, message2, message3)); + var messages = toOperationsMessagesMap("channelId", Set.of(message1, message2, message3)); // we do not have any guarantee whether message2 or message3 won the deduplication. assertThat(messages) .hasSize(2) - .containsValue(MessageReference.toChannelMessage("channelName", message1)) + .containsValue(MessageReference.toChannelMessage("channelId", message1)) .containsAnyOf( - entry("bar", MessageReference.toChannelMessage("channelName", message2)), - entry("bar", MessageReference.toChannelMessage("channelName", message3))); + entry("bar", MessageReference.toChannelMessage("channelId", message2)), + entry("bar", MessageReference.toChannelMessage("channelId", message3))); } } diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationMergerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationMergerTest.java index ff8c82376..484fdf306 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationMergerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/OperationMergerTest.java @@ -76,7 +76,7 @@ void shouldUseFirstOperationFound() { @Test void shouldMergeDifferentMessageForSameOperation() { // given - String channelName = "channel"; + String channelId = "channel"; String operationId = "operation"; MessageObject message1 = MessageObject.builder() .name(String.class.getCanonicalName()) @@ -90,9 +90,9 @@ void shouldMergeDifferentMessageForSameOperation() { .name(Integer.class.getCanonicalName()) .description("This is also an integer, but in essence the same payload type") .build(); - MessageReference messageRef1 = MessageReference.toChannelMessage(channelName, message1); - MessageReference messageRef2 = MessageReference.toChannelMessage(channelName, message2); - MessageReference messageRef3 = MessageReference.toChannelMessage(channelName, message3); + MessageReference messageRef1 = MessageReference.toChannelMessage(channelId, message1); + MessageReference messageRef2 = MessageReference.toChannelMessage(channelId, message2); + MessageReference messageRef3 = MessageReference.toChannelMessage(channelId, message3); Operation senderOperation1 = Operation.builder() .action(OperationAction.SEND) @@ -126,7 +126,7 @@ void shouldMergeDifferentMessageForSameOperation() { @Test void shouldUseOtherMessageIfFirstMessageIsMissingForChannels() { // given - String channelName = "channel"; + String channelId = "channel"; MessageObject message2 = MessageObject.builder() .messageId(String.class.getCanonicalName()) .name(String.class.getCanonicalName()) @@ -139,12 +139,12 @@ void shouldUseOtherMessageIfFirstMessageIsMissingForChannels() { // when Map mergedChannels = ChannelMerger.mergeChannels( - Arrays.asList(Map.entry(channelName, publisherChannel1), Map.entry(channelName, publisherChannel2))); + Arrays.asList(Map.entry(channelId, publisherChannel1), Map.entry(channelId, publisherChannel2))); // then expectedMessage message2 var expectedMessages = Map.of(message2.getMessageId(), message2); - assertThat(mergedChannels).hasSize(1).hasEntrySatisfying(channelName, it -> { + assertThat(mergedChannels).hasSize(1).hasEntrySatisfying(channelId, it -> { assertThat(it.getMessages()).hasSize(1); assertThat(it.getMessages()).containsExactlyInAnyOrderEntriesOf(expectedMessages); }); @@ -153,7 +153,7 @@ void shouldUseOtherMessageIfFirstMessageIsMissingForChannels() { @Test void shouldUseOtherMessageIfFirstMessageIsMissingForOperations() { // given - String channelName = "channel-name"; + String channelId = "channel-name-id"; MessageObject message2 = MessageObject.builder() .messageId(String.class.getCanonicalName()) .name(String.class.getCanonicalName()) @@ -166,14 +166,14 @@ void shouldUseOtherMessageIfFirstMessageIsMissingForOperations() { Operation publishOperation2 = Operation.builder() .action(OperationAction.SEND) .title("publisher2") - .messages(List.of(MessageReference.toChannelMessage(channelName, message2))) + .messages(List.of(MessageReference.toChannelMessage(channelId, message2))) .build(); // when Map mergedOperations = OperationMerger.mergeOperations( Arrays.asList(Map.entry("publisher1", publishOperation1), Map.entry("publisher1", publishOperation2))); // then expectedMessage message2 - var expectedMessage = MessageReference.toChannelMessage(channelName, message2); + var expectedMessage = MessageReference.toChannelMessage(channelId, message2); assertThat(mergedOperations).hasSize(1).hasEntrySatisfying("publisher1", it -> { assertThat(it.getMessages()).hasSize(1); diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java index 7b698655c..5a56a17cc 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/operations/annotations/SpringAnnotationClassLevelOperationsScannerTest.java @@ -56,7 +56,7 @@ class SpringAnnotationClassLevelOperationsScannerTest { headerClassExtractor, componentsService); - private static final String CHANNEL = "test-channel"; + private static final String CHANNEL_ID = "test-channel-id"; private static final Map defaultOperationBinding = Map.of("protocol", new AMQPOperationBinding()); private static final Map defaultMessageBinding = @@ -67,7 +67,7 @@ class SpringAnnotationClassLevelOperationsScannerTest { @BeforeEach void setUp() { // when - when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL); + when(bindingFactory.getChannelName(any())).thenReturn(CHANNEL_ID); doReturn(defaultOperationBinding).when(bindingFactory).buildOperationBinding(any()); doReturn(defaultChannelBinding).when(bindingFactory).buildChannelBinding(any()); @@ -103,11 +103,11 @@ void scan_componentHasTestListenerMethods() { Operation expectedOperation = Operation.builder() .action(OperationAction.RECEIVE) - .channel(ChannelReference.fromChannel(CHANNEL)) - .messages(List.of(MessageReference.toChannelMessage(CHANNEL, message))) + .channel(ChannelReference.fromChannel(CHANNEL_ID)) + .messages(List.of(MessageReference.toChannelMessage(CHANNEL_ID, message))) .bindings(Map.of("protocol", AMQPOperationBinding.builder().build())) .build(); - String operationName = CHANNEL + "_receive_ClassWithTestListenerAnnotation"; + String operationName = CHANNEL_ID + "_receive_ClassWithTestListenerAnnotation"; assertThat(operations).containsExactly(Map.entry(operationName, expectedOperation)); } 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 cb22783f3..0ed94502f 100644 --- a/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-amqp-example/src/test/resources/asyncapi.json @@ -26,6 +26,7 @@ }, "channels": { "another-queue": { + "address": "another-queue", "messages": { "io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" @@ -46,6 +47,7 @@ } }, "example-queue": { + "address": "example-queue", "messages": { "io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.ExamplePayloadDto" @@ -66,6 +68,7 @@ } }, "example-topic-exchange": { + "address": "example-topic-exchange", "messages": { "io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" @@ -73,6 +76,7 @@ } }, "example-topic-routing-key": { + "address": "example-topic-routing-key", "messages": { "io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" @@ -93,6 +97,7 @@ } }, "multi-payload-queue": { + "address": "multi-payload-queue", "messages": { "io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.amqp.dtos.AnotherPayloadDto" diff --git a/springwolf-examples/springwolf-jms-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-jms-example/src/test/resources/asyncapi.json index e5a6a7d32..4edb9a9a5 100644 --- a/springwolf-examples/springwolf-jms-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-jms-example/src/test/resources/asyncapi.json @@ -23,6 +23,7 @@ }, "channels": { "another-queue": { + "address": "another-queue", "messages": { "io.github.springwolf.examples.jms.dtos.AnotherPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.jms.dtos.AnotherPayloadDto" @@ -30,6 +31,7 @@ } }, "example-queue": { + "address": "example-queue", "messages": { "io.github.springwolf.examples.jms.dtos.ExamplePayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.jms.dtos.ExamplePayloadDto" 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 1963552e9..fef2dc6af 100644 --- a/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-kafka-example/src/test/resources/asyncapi.json @@ -23,6 +23,7 @@ }, "channels": { "another-topic": { + "address": "another-topic", "messages": { "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" @@ -35,6 +36,7 @@ } }, "avro-topic": { + "address": "avro-topic", "messages": { "io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dto.avro.AnotherPayloadAvroDto" @@ -42,6 +44,7 @@ } }, "example-topic": { + "address": "example-topic", "messages": { "io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.ExamplePayloadDto" @@ -54,6 +57,7 @@ } }, "integer-topic": { + "address": "integer-topic", "messages": { "java.lang.Number": { "$ref": "#/components/messages/java.lang.Number" @@ -66,6 +70,7 @@ } }, "multi-payload-topic": { + "address": "multi-payload-topic", "messages": { "io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto" @@ -79,6 +84,7 @@ } }, "no-payload-used-topic": { + "address": "no-payload-used-topic", "messages": { "PayloadNotUsed": { "$ref": "#/components/messages/PayloadNotUsed" @@ -91,6 +97,7 @@ } }, "protobuf-topic": { + "address": "protobuf-topic", "messages": { "io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dto.proto.ExamplePayloadProtobufDto$Message" @@ -103,6 +110,7 @@ } }, "string-topic": { + "address": "string-topic", "messages": { "io.github.springwolf.examples.kafka.consumers.StringConsumer$StringEnvelope": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.consumers.StringConsumer$StringEnvelope" @@ -113,6 +121,7 @@ } }, "topic-defined-via-asyncPublisher-annotation": { + "address": "topic-defined-via-asyncPublisher-annotation", "messages": { "io.github.springwolf.examples.kafka.dtos.NestedPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.NestedPayloadDto" @@ -125,6 +134,7 @@ ] }, "vehicle-topic": { + "address": "vehicle-topic", "messages": { "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase" @@ -137,6 +147,7 @@ } }, "xml-topic": { + "address": "xml-topic", "messages": { "io.github.springwolf.examples.kafka.dtos.XmlPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.XmlPayloadDto" @@ -144,6 +155,7 @@ } }, "yaml-topic": { + "address": "yaml-topic", "messages": { "io.github.springwolf.examples.kafka.dtos.YamlPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.YamlPayloadDto" diff --git a/springwolf-examples/springwolf-sns-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-sns-example/src/test/resources/asyncapi.json index 70bff2f17..0cbc92e3c 100644 --- a/springwolf-examples/springwolf-sns-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-sns-example/src/test/resources/asyncapi.json @@ -23,6 +23,7 @@ }, "channels": { "another-topic": { + "address": "another-topic", "messages": { "io.github.springwolf.examples.sns.dtos.AnotherPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.sns.dtos.AnotherPayloadDto" @@ -30,6 +31,7 @@ } }, "example-topic": { + "address": "example-topic", "messages": { "io.github.springwolf.examples.sns.dtos.ExamplePayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.sns.dtos.ExamplePayloadDto" diff --git a/springwolf-examples/springwolf-sqs-example/src/test/resources/asyncapi.json b/springwolf-examples/springwolf-sqs-example/src/test/resources/asyncapi.json index cdeadc251..2596a8215 100644 --- a/springwolf-examples/springwolf-sqs-example/src/test/resources/asyncapi.json +++ b/springwolf-examples/springwolf-sqs-example/src/test/resources/asyncapi.json @@ -23,6 +23,7 @@ }, "channels": { "another-queue": { + "address": "another-queue", "messages": { "io.github.springwolf.examples.sqs.dtos.AnotherPayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.sqs.dtos.AnotherPayloadDto" @@ -30,6 +31,7 @@ } }, "example-queue": { + "address": "example-queue", "messages": { "io.github.springwolf.examples.sqs.dtos.ExamplePayloadDto": { "$ref": "#/components/messages/io.github.springwolf.examples.sqs.dtos.ExamplePayloadDto" 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 59c9ac379..79986f09b 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 @@ -72,14 +72,14 @@ private boolean isChannelBean(FunctionalChannelBeanData beanData) { } private Map.Entry toChannelEntry(FunctionalChannelBeanData beanData) { - String channelName = cloudStreamBindingsProperties + String channelId = cloudStreamBindingsProperties .getBindings() .get(beanData.cloudStreamBinding()) .getDestination(); ChannelObject channelItem = buildChannel(beanData); - return Map.entry(channelName, channelItem); + return Map.entry(channelId, channelItem); } private ChannelObject buildChannel(FunctionalChannelBeanData beanData) { 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 119ace53d..68ba9b797 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 @@ -67,18 +67,18 @@ private boolean isChannelBean(FunctionalChannelBeanData beanData) { } private Map.Entry toOperationEntry(FunctionalChannelBeanData beanData) { - String channelName = cloudStreamBindingsProperties + String channelId = cloudStreamBindingsProperties .getBindings() .get(beanData.cloudStreamBinding()) .getDestination(); - String operationId = buildOperationId(beanData, channelName); - Operation operation = buildOperation(beanData, channelName); + String operationId = buildOperationId(beanData, channelId); + Operation operation = buildOperation(beanData, channelId); return Map.entry(operationId, operation); } - private Operation buildOperation(FunctionalChannelBeanData beanData, String channelName) { + private Operation buildOperation(FunctionalChannelBeanData beanData, String channelId) { Class payloadType = beanData.payloadType(); String modelName = payloadService.buildSchema(payloadType).name(); String headerModelName = componentsService.registerSchema(AsyncHeadersNotDocumented.NOT_DOCUMENTED); @@ -93,8 +93,8 @@ private Operation buildOperation(FunctionalChannelBeanData beanData, String chan var builder = Operation.builder() .description("Auto-generated description") - .channel(ChannelReference.fromChannel(channelName)) - .messages(List.of(MessageReference.toChannelMessage(channelName, message))) + .channel(ChannelReference.fromChannel(channelId)) + .messages(List.of(MessageReference.toChannelMessage(channelId, message))) .bindings(buildOperationBinding()); if (beanData.beanType() == FunctionalChannelBeanData.BeanType.CONSUMER) { builder.action(OperationAction.RECEIVE); @@ -132,10 +132,10 @@ private String getProtocolName() { new IllegalStateException("There must be at least one server define in the AsyncApiDocker")); } - private String buildOperationId(FunctionalChannelBeanData beanData, String channelName) { + private String buildOperationId(FunctionalChannelBeanData beanData, String channelId) { String operationName = beanData.beanType() == FunctionalChannelBeanData.BeanType.CONSUMER ? "publish" : "subscribe"; - return String.format("%s_%s_%s", channelName, operationName, beanData.elementName()); + return String.format("%s_%s_%s", channelId, operationName, beanData.elementName()); } }