springwolf-core icon indicating copy to clipboard operation
springwolf-core copied to clipboard

Duplicate AsyncAPI channel entry for public suspending function in Kotlin

Open ivo-leonov opened this issue 1 year ago • 5 comments

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 image

ivo-leonov avatar Apr 16 '24 08:04 ivo-leonov

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.

github-actions[bot] avatar Apr 16 '24 08:04 github-actions[bot]

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?

timonback avatar Apr 19 '24 13:04 timonback

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

fcmdeveloper1 avatar Apr 22 '24 12:04 fcmdeveloper1

Dear @timonback, any update or work around for this

My Best Regards

fcmdeveloper1 avatar Apr 24 '24 08:04 fcmdeveloper1

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.

timonback avatar Apr 24 '24 10:04 timonback

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.

timonback avatar May 24 '24 14:05 timonback

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.

F43nd1r avatar May 27 '24 09:05 F43nd1r

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

timonback avatar May 27 '24 18:05 timonback

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!

github-actions[bot] avatar May 31 '24 16:05 github-actions[bot]

The change is available in the latest release. 🎉

Thank you for the report/contribution and making Springwolf better!

github-actions[bot] avatar May 31 '24 16:05 github-actions[bot]