From 60414e0ab6c4645801e9e54d744bc6bb862be2d8 Mon Sep 17 00:00:00 2001 From: sam0r040 <93372330+sam0r040@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:38:24 +0200 Subject: [PATCH] feat(core): autogenerate name for header schema if not set already GH-893 (#940) Co-authored-by: Timon Back --- .../common/utils/AsyncAnnotationUtil.java | 12 ++-- .../common/utils/AsyncAnnotationUtilTest.java | 57 +++++++++++++++++-- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java index 229e53070..00538e31b 100644 --- a/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java +++ b/springwolf-core/src/main/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtil.java @@ -43,17 +43,15 @@ public static SchemaObject getAsyncHeaders(AsyncOperation op, StringValueResolve } return AsyncHeadersNotDocumented.NOT_DOCUMENTED; } - if (!StringUtils.hasText(headers.schemaName())) { - throw new IllegalArgumentException("The schemaName in @AsyncOperation.Headers must be set for values: " - + Arrays.toString(headers.values())); - } + String headerSchemaTitle = + StringUtils.hasText(headers.schemaName()) ? headers.schemaName() : generateHeadersSchemaName(headers); String headerDescription = StringUtils.hasText(headers.description()) ? resolver.resolveStringValue(headers.description()) : null; SchemaObject headerSchema = new SchemaObject(); headerSchema.setType(SchemaType.OBJECT); - headerSchema.setTitle(headers.schemaName()); + headerSchema.setTitle(headerSchemaTitle); headerSchema.setDescription(headerDescription); headerSchema.setProperties(new HashMap<>()); @@ -95,6 +93,10 @@ private static String getDescription(List value, .orElse(null); } + private static String generateHeadersSchemaName(AsyncOperation.Headers headers) { + return "Headers-" + Math.abs(headers.hashCode()); + } + public static Map processOperationBindingFromAnnotation( Method method, List operationBindingProcessors) { return operationBindingProcessors.stream() diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java index 21ff98707..b3a1e573f 100644 --- a/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java +++ b/springwolf-core/src/test/java/io/github/springwolf/core/asyncapi/scanners/common/utils/AsyncAnnotationUtilTest.java @@ -6,6 +6,7 @@ import io.github.springwolf.asyncapi.v3.bindings.OperationBinding; import io.github.springwolf.asyncapi.v3.model.channel.message.MessageObject; import io.github.springwolf.asyncapi.v3.model.schema.SchemaObject; +import io.github.springwolf.asyncapi.v3.model.schema.SchemaType; import io.github.springwolf.core.asyncapi.annotations.AsyncListener; import io.github.springwolf.core.asyncapi.annotations.AsyncMessage; import io.github.springwolf.core.asyncapi.annotations.AsyncOperation; @@ -25,7 +26,6 @@ import java.util.List; import java.util.Map; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -99,10 +99,45 @@ void getAsyncHeadersWithoutSchemaName() throws NoSuchMethodException { when(resolver.resolveStringValue(any())) .thenAnswer(invocation -> invocation.getArgument(0).toString() + "Resolved"); - // when + then - assertThatIllegalArgumentException() - .isThrownBy(() -> AsyncAnnotationUtil.getAsyncHeaders(operation, resolver)) - .withMessageContaining("The schemaName in @AsyncOperation.Headers must be set for values"); + // when + SchemaObject headers = AsyncAnnotationUtil.getAsyncHeaders(operation, resolver); + + // then + assertThat(headers) + .isEqualTo(SchemaObject.builder() + .type(SchemaType.OBJECT) + .title("Headers-501004016") + .properties(Map.of( + "headerResolved", + SchemaObject.builder() + .type(SchemaType.STRING) + .title("headerResolved") + .description("descriptionResolved") + .enumValues(List.of("valueResolved")) + .examples(List.of("valueResolved")) + .build())) + .build()); + } + + @Test + void generatedHeaderSchemaNameShouldBeUnique() throws NoSuchMethodException { + // given + Method m1 = ClassWithHeaders.class.getDeclaredMethod("withoutSchemaName", String.class); + AsyncOperation operation1 = m1.getAnnotation(AsyncListener.class).operation(); + + Method m2 = ClassWithHeaders.class.getDeclaredMethod("differentHeadersWithoutSchemaName", String.class); + AsyncOperation operation2 = m2.getAnnotation(AsyncListener.class).operation(); + + StringValueResolver resolver = mock(StringValueResolver.class); + when(resolver.resolveStringValue(any())) + .thenAnswer(invocation -> invocation.getArgument(0).toString() + "Resolved"); + + // when + SchemaObject headers1 = AsyncAnnotationUtil.getAsyncHeaders(operation1, resolver); + SchemaObject headers2 = AsyncAnnotationUtil.getAsyncHeaders(operation2, resolver); + + // then + assertThat(headers1.getTitle()).isNotEqualTo(headers2.getTitle()); } @Test @@ -362,6 +397,18 @@ private void emptyHeaders(String payload) {} }))) @TestOperationBindingProcessor.TestOperationBinding() private void withoutSchemaName(String payload) {} + + @AsyncListener( + operation = + @AsyncOperation( + channelName = "${test.property.test-channel}", + headers = + @AsyncOperation.Headers( + values = { + @AsyncOperation.Headers.Header(name = "header", value = "value") + }))) + @TestOperationBindingProcessor.TestOperationBinding() + private void differentHeadersWithoutSchemaName(String payload) {} } private static class ClassWithMultipleOperationBindingProcessors {