Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,22 @@
String description() default "";

String value() default "";

/**
* The format of the header value according to AsyncAPI specification.
* <p>
* Common formats include:
* <ul>
* <li>"int32" - 32-bit signed integer</li>
* <li>"int64" - 64-bit signed integer</li>
* <li>"date" - RFC 3339 date</li>
* <li>"date-time" - RFC 3339 date-time</li>
* </ul>
*
* @see <a href="https://www.asyncapi.com/docs/reference/specification/v3.0.0#dataTypeFormat">AsyncAPI Data Type Format</a>
* @return the format string, empty by default
*/
String format() default "";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ public static SchemaObject getAsyncHeaders(AsyncOperation op, StringValueResolve

SchemaObject property = new SchemaObject();
property.setType(SchemaType.STRING);

String format = getFormat(headersValues, stringValueResolver);
property.setFormat(format);

property.setTitle(propertyName);
property.setDescription(getDescription(headersValues, stringValueResolver));
List<String> values = getHeaderValues(headersValues, stringValueResolver);
Expand Down Expand Up @@ -100,6 +104,17 @@ private static String getDescription(
.orElse(null);
}

private static String getFormat(
List<AsyncOperation.Headers.Header> value, StringValueResolver stringValueResolver) {
return value.stream()
.map(AsyncOperation.Headers.Header::format)
.map(stringValueResolver::resolveStringValue)
.filter(StringUtils::hasText)
.sorted()
.findFirst()
.orElse(null);
}

public static Map<String, OperationBinding> processOperationBindingFromAnnotation(
Method method, List<OperationBindingProcessor> operationBindingProcessors) {
return operationBindingProcessors.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ private Schema mapSchemaObjectToSwagger(SchemaObject asyncApiSchema) {
.orElse(null));
swaggerSchema.setTypes(asyncApiSchema.getType());
}
// swaggerSchema.setFormat(asyncApiSchema.getFormat());
swaggerSchema.setFormat(asyncApiSchema.getFormat());
swaggerSchema.setDescription(asyncApiSchema.getDescription());
swaggerSchema.setExamples(asyncApiSchema.getExamples());
swaggerSchema.setEnum(asyncApiSchema.getEnumValues());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ void getAsyncHeaders(Class<?> classWithOperationBindingProcessor) throws Excepti
assertThat(headerResolved.getType()).containsExactly("string");
assertThat(headerResolved.getExamples().get(0)).isEqualTo("valueResolved");
assertThat(headerResolved.getDescription()).isEqualTo("descriptionResolved");
assertThat(headerResolved.getFormat()).isEqualTo("int32Resolved");

assertThat(headers.getProperties().containsKey("headerWithoutValueResolved"))
.as(headers.getProperties() + " does not contain key 'headerWithoutValueResolved'")
Expand All @@ -68,6 +69,7 @@ void getAsyncHeaders(Class<?> classWithOperationBindingProcessor) throws Excepti
assertThat(headerWithoutValueResolved.getExamples()).isNull();
assertThat(headerWithoutValueResolved.getEnumValues()).isNull();
assertThat(headerWithoutValueResolved.getDescription()).isEqualTo("descriptionResolved");
assertThat(headerWithoutValueResolved.getFormat()).isEqualTo("Resolved");
}

@Test
Expand Down Expand Up @@ -104,13 +106,14 @@ void getAsyncHeadersWithoutSchemaName() throws Exception {
assertThat(headers)
.isEqualTo(SchemaObject.builder()
.type(SchemaType.OBJECT)
.title("Headers-501004016")
.title("Headers-1585401221")
.properties(Map.of(
"headerResolved",
SchemaObject.builder()
.type(SchemaType.STRING)
.title("headerResolved")
.description("descriptionResolved")
.format("Resolved")
.enumValues(List.of("valueResolved"))
.examples(List.of("valueResolved"))
.build()))
Expand All @@ -134,19 +137,69 @@ void getAsyncHeadersWithoutValue() throws Exception {
assertThat(headers)
.isEqualTo(SchemaObject.builder()
.type(SchemaType.OBJECT)
.title("Headers-472917891")
.title("Headers-1612438838")
.properties(Map.of(
"headerResolved",
SchemaObject.builder()
.type(SchemaType.STRING)
.title("headerResolved")
.description("descriptionResolved")
.format("Resolved")
.enumValues(null)
.examples(null)
.build()))
.build());
}

@Test
void getAsyncHeadersWithFormat() throws Exception {
// given
Method m = ClassWithHeaders.class.getDeclaredMethod("withFormat", String.class);
AsyncOperation operation = m.getAnnotation(AsyncListener.class).operation();

StringValueResolver stringValueResolver = mock(StringValueResolver.class);
when(stringValueResolver.resolveStringValue(any()))
.thenAnswer(invocation -> invocation.getArgument(0).toString() + "Resolved");

// when
SchemaObject headers = AsyncAnnotationUtil.getAsyncHeaders(operation, stringValueResolver);

// then
assertThat(headers)
.isEqualTo(SchemaObject.builder()
.type(SchemaType.OBJECT)
.title("Headers-1701213112")
.properties(Map.of(
"headerResolved",
SchemaObject.builder()
.type(SchemaType.STRING)
.format("int32Resolved")
.title("headerResolved")
.description("descriptionResolved")
.enumValues(null)
.examples(null)
.build()))
.build());
}

@Test
void getAsyncHeadersWithEmptyFormat() throws Exception {
// given
Method m = ClassWithHeaders.class.getDeclaredMethod("withEmptyFormat", String.class);
AsyncOperation operation = m.getAnnotation(AsyncListener.class).operation();

StringValueResolver stringValueResolver = mock(StringValueResolver.class);
when(stringValueResolver.resolveStringValue(any()))
.thenAnswer(invocation -> invocation.getArgument(0).toString());

// when
SchemaObject headers = AsyncAnnotationUtil.getAsyncHeaders(operation, stringValueResolver);

// then
SchemaObject headerProperty = (SchemaObject) headers.getProperties().get("header");
assertThat(headerProperty.getFormat()).isNull();
}

@Test
void generatedHeaderSchemaNameShouldBeUnique() throws Exception {
// given
Expand Down Expand Up @@ -351,7 +404,8 @@ private static class ClassWithOperationBindingProcessor {
@AsyncOperation.Headers.Header(
name = "header",
value = "value",
description = "description"),
description = "description",
format = "int32"),
@AsyncOperation.Headers.Header(
name = "headerWithoutValue",
description = "description")
Expand Down Expand Up @@ -398,7 +452,8 @@ private static class ClassWithAbstractOperationBindingProcessor {
@AsyncOperation.Headers.Header(
name = "header",
value = "value",
description = "description"),
description = "description",
format = "int32"),
@AsyncOperation.Headers.Header(
name = "headerWithoutValue",
description = "description")
Expand Down Expand Up @@ -465,6 +520,36 @@ private void withoutSchemaName(String payload) {}
@TestOperationBindingProcessor.TestOperationBinding()
private void withoutValue(String payload) {}

@AsyncListener(
operation =
@AsyncOperation(
channelName = "${test.property.test-channel}",
headers =
@AsyncOperation.Headers(
values = {
@AsyncOperation.Headers.Header(
name = "header",
description = "description",
format = "int32")
})))
@TestOperationBindingProcessor.TestOperationBinding()
private void withFormat(String payload) {}

@AsyncListener(
operation =
@AsyncOperation(
channelName = "${test.property.test-channel}",
headers =
@AsyncOperation.Headers(
values = {
@AsyncOperation.Headers.Header(
name = "header",
description = "description",
format = "")
})))
@TestOperationBindingProcessor.TestOperationBinding()
private void withEmptyFormat(String payload) {}

@AsyncListener(
operation =
@AsyncOperation(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.examples.kafka.producers;

import io.github.springwolf.core.asyncapi.annotations.AsyncOperation;
import io.github.springwolf.core.asyncapi.annotations.AsyncPublisher;
import io.github.springwolf.examples.kafka.configuration.KafkaConfiguration;
import io.github.springwolf.examples.kafka.dtos.AnotherPayloadDto;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -13,6 +15,27 @@ public class AnotherProducer {
@Autowired
private KafkaTemplate<String, AnotherPayloadDto> kafkaTemplate;

@AsyncPublisher(
operation =
@AsyncOperation(
channelName = "another-topic",
headers =
@AsyncOperation.Headers(
schemaName = "SpringKafkaDefaultHeaders-AnotherTopic",
values = {
@AsyncOperation.Headers.Header(
name = "kafka_messageKey",
description = "Message key",
format = "string"),
@AsyncOperation.Headers.Header(
name = "__TypeId__",
description = "Type ID",
format = "string"),
@AsyncOperation.Headers.Header(
name = "my_key",
description = "my_key",
format = "int32")
})))
public void sendMessage(AnotherPayloadDto msg) {
kafkaTemplate.send(KafkaConfiguration.PRODUCER_TOPIC, msg);
}
Expand Down
Loading