Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): add ChannelObject#channelId and populate ChannelObject#address #797

Merged
merged 2 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions springwolf-asyncapi/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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, "_");
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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",
Expand Down Expand Up @@ -102,4 +115,14 @@ public class ChannelObject extends ExtendableObject implements Channel {
*/
@JsonProperty(value = "bindings")
private Map<String, ChannelBinding> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -33,6 +35,7 @@ public class MessageObject extends ExtendableObject implements Message {
* naming conventions.
*/
@JsonIgnore
@Setter(AccessLevel.NONE)
private String messageId;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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()
Expand Down
Original file line number Diff line number Diff line change
@@ -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}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -64,8 +65,9 @@ private Map.Entry<String, ChannelObject> buildChannel(MethodAndAnnotation<A> 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<String> servers = AsyncAnnotationUtil.getServers(operationAnnotation, resolver);
if (servers != null && !servers.isEmpty()) {
Expand All @@ -76,9 +78,11 @@ private Map.Entry<String, ChannelObject> buildChannel(MethodAndAnnotation<A> 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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String, ChannelObject> mergeChannels(List<Map.Entry<String, ChannelObject>> channelEntries) {
Map<String, ChannelObject> mergedChannels = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -62,11 +63,8 @@ private Stream<Map.Entry<String, ChannelObject>> 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<Method> methods) {
Expand All @@ -77,7 +75,10 @@ private ChannelObject buildChannelItem(ClassAnnotation classAnnotation, Set<Meth
private ChannelObject buildChannelItem(ClassAnnotation classAnnotation, Map<String, MessageReference> messages) {
Map<String, ChannelBinding> channelBinding = bindingFactory.buildChannelBinding(classAnnotation);
Map<String, ChannelBinding> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -63,11 +64,10 @@ private Map.Entry<String, ChannelObject> 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(
Expand All @@ -79,7 +79,10 @@ private ChannelObject buildChannelItem(
private ChannelObject buildChannelItem(MethodAnnotation annotation, MessageObject message) {
Map<String, ChannelBinding> channelBinding = bindingFactory.buildChannelBinding(annotation);
Map<String, ChannelBinding> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -65,26 +65,27 @@ protected Stream<MethodAndAnnotation<A>> 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<String, OperationBinding> operationBinding =
AsyncAnnotationUtil.processOperationBindingFromAnnotation(method, operationBindingProcessors);
Map<String, OperationBinding> opBinding = operationBinding != null ? new HashMap<>(operationBinding) : null;
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();
}
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -44,6 +45,7 @@ public static Map<String, MessageReference> toOperationsMessagesMap(
.stream()
.collect(Collectors.toMap(
MessageObject::getMessageId,
e -> MessageReference.toChannelMessage(channelName, e.getMessageId())));
e -> MessageReference.toChannelMessage(
ReferenceUtil.toValidId(channelName), e.getMessageId())));
}
}
Loading