springwolf-core
springwolf-core copied to clipboard
Duplicate AsyncAPI channel entry for public suspending function in Kotlin
Describe the bug
Annotating a public suspending function in Kotlin with @AsyncListener and/or @AsyncPublisher leads to two channel entries instead of one. Making the annotated method private or removing the suspend keyword resolves the issue. Both workarounds are suboptimal, as they require changing the code design.
Dependencies and versions used
springwolf-core and springwolf-ui version 1.1.0.
Code example Kotlin class:
@Component
class AsyncConsumerProducer {
@AsyncListener(
operation =
AsyncOperation(
channelName = "INCOMING_REQUEST",
description = "Inbound message.",
payloadType = Input::class,
),
)
@AsyncPublisher(
operation =
AsyncOperation(
channelName = "OUTBOUND_RESPONSE",
description = "Outbound message.",
payloadType = Output::class,
),
)
suspend fun consumeAndProduce(input: Input) = Output("result")
}
data class Input(val value: String)
data class Output(val value: String)
application.yaml:
springwolf:
docket:
base-package: com.example.springfoxissue
info:
title: "Title"
version: v1
description: AsyncAPI documentation
servers:
websockets:
protocol: some.protocol
host: localhost
endpoint:
actuator:
enabled: false
enabled: true
pom.xml:
<dependency>
<groupId>io.github.springwolf</groupId>
<artifactId>springwolf-core</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>io.github.springwolf</groupId>
<artifactId>springwolf-ui</artifactId>
<version>1.1.0</version>
</dependency>
Stack trace and error logs
Welcome to Springwolf. Thanks a lot for reporting your first issue. Please check out our contributors guide and feel free to join us on discord.
Hi @ivo-leonov
Thank you for the well described issue report!
We tried to re-produce the issue, but were not successful. Attempt: https://github.com/springwolf/springwolf-core/pull/710
What are we missing?
Dear @timonback, i tried for java and i have duplicate messages, although i used the @AsyncListener which should override the payload in the method itself.
but the topic name and the group name should still be taken from the @KafkaListener annotation, unless you will provide attribute for them in the @AsyncListener annotation
example:
@AsyncListener( operation = @AsyncOperation(payloadType = LearningEvent.class, description = "description", channelName = "lms" )) @KafkaListener(topics = "lms", groupId = "test") public void receiveExamplePayload2( @Payload List<ConsumerRecord<String, LearningEvent>> records, Acknowledgment acknowledgment) { log.info("Received new message in example-queue: {}", records.toString()); }
the generated asyncAPI has :
"channels": { "lms": { "messages": { "com.asyncapi.kafka.dtos.LearningEvent": { "$ref": "#/components/messages/com.asyncapi.kafka.dtos.LearningEvent" }, "org.apache.kafka.clients.consumer.ConsumerRecord": { "$ref": "#/components/messages/org.apache.kafka.clients.consumer.ConsumerRecord" } } } }
My Best Regards
Dear @timonback, any update or work around for this
My Best Regards
Hi @fcmdeveloper1, Please open a separate issue for that as it is not related to the kotlin suspend function.
Have a look at https://www.springwolf.dev/docs/configuration/documenting-messages#unwrapping-the-payload and/or modify one of the springwolf-examples so that your issue is easily reproducible.
Hi @ivo-leonov
Thank you for the well described issue report!
We tried to re-produce the issue, but were not successful. Attempt: #710
What are we missing?
@ivo-leonov Any details? Otherwise, I will go ahead and close the issue.
I created a reproducer here: https://github.com/F43nd1r/springwolf-issue-705-reproducer
Generated docs.yaml contains:
operations:
my-topic_send_publishMessage:
action: send
channel:
$ref: "#/channels/my-topic"
title: my-topic_send
description: Auto-generated description
bindings: {}
messages:
- $ref: "#/channels/my-topic/messages/com.faendir.springwolfissue705reproducer.MyMessage"
my-topic_send_publishMessage$suspendImpl:
action: send
channel:
$ref: "#/channels/my-topic"
title: my-topic_send
description: Auto-generated description
bindings: {}
messages:
- $ref: "#/channels/my-topic/messages/com.faendir.springwolfissue705reproducer.MyMessage"
The second is a synthetic method and should not be considered.
Thank you @F43nd1r for sharing the used dependencies in your example. After copying the configuration and producer from this issue, I was able to reproduce it.
It seems that the kotlin compiler is generating synthetic JVM methods. To address it, I opened: https://github.com/springwolf/springwolf-core/pull/773
The change is staged for release and will be part of the next release.
If you want to try and verify it in your application today, use the latest 1.X.0-SNAPSHOT build as described in our README.md > Testing SNAPSHOT version
Thank you for the report/contribution!
The change is available in the latest release. 🎉
Thank you for the report/contribution and making Springwolf better!