vertx-guide-for-java-devs icon indicating copy to clipboard operation
vertx-guide-for-java-devs copied to clipboard

Example of kotlin version with service proxy

Open xurshid29 opened this issue 6 years ago • 15 comments

Hi, can anybody provide kotlin version of this tutorial with service proxies? I couldn't manage it to work;

Every time I get such error on build:

build/tmp/kapt3/stubs/main/uz/craftier/database/WikiDatabaseService.java:46: error: Could not generate model for uz.craftier.database.WikiDatabaseService.Companion: @VertxGen can only be used with interfaces or enums in uz.craftier.database.WikiDatabaseService.Companion

Here is my interface: screen shot 2018-01-13 at 2 09 58 pm

And, added kapt plugin to build.gradle:

apply plugin: 'kotlin-kapt'

dependencies {
    ...
    kapt "io.vertx:vertx-codegen:$vertx_version:processor"
    compileOnly "io.vertx:vertx-codegen:$vertx_version"
    ...
}

xurshid29 avatar Jan 13 '18 09:01 xurshid29

I ran into the same issue when experimenting with service proxies. The problematic part is the companion object, which trips up the annotation generator.

A possible workaround:

@ProxyGen
@VertxGen
interface MyService {
    fun myMethod(param: String)
}

object MyServiceFactory {
    fun create(vertx: Vertx): MyService{
        return MyServiceImpl(vertx)
    }
    fun createProxy(vertx: Vertx, address: String, options: DeliveryOptions = DeliveryOptions()): MyService {
        return MyServiceVertxEBProxy(vertx, address, options)
    }
}

abelhegedus avatar Feb 28 '18 15:02 abelhegedus

Is it also possible to generate the rx version of the proxy?

desmondtzq avatar Jun 18 '18 09:06 desmondtzq

I have the same problem on rx version of the service proxy..

mustafakibar avatar Jun 21 '18 15:06 mustafakibar

I also get the same problem, and then based on @abelhegedus' idea, here my workaround:

@ProxyGen
interface WikiDatabaseService {

    @Fluent
    fun fetchAllPages(resultHandler: Handler<AsyncResult<JsonArray>>): WikiDatabaseService

    @Fluent
    fun fetchPage(name: String, resultHandler: Handler<AsyncResult<JsonObject>>): WikiDatabaseService

    @Fluent
    fun createPage(title: String, markdown: String, resultHandler: Handler<AsyncResult<Void>>): WikiDatabaseService

    @Fluent
    fun savePage(id: Int, markdown: String, resultHandler: Handler<AsyncResult<Void>>): WikiDatabaseService

    @Fluent
    fun deletePage(id: Int, resultHandler: Handler<AsyncResult<Void>>): WikiDatabaseService

    @GenIgnore
    companion object {
        fun create(dbClient: JDBCClient, sqlQueries: Map<SqlQuery, String>,
                   readyHandler: Handler<AsyncResult<WikiDatabaseService>>): WikiDatabaseService =
                WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler)

        fun createProxy(vertx: Vertx, address: String): WikiDatabaseService =
                WikiDatabaseServiceVertxEBProxy(vertx, address)
    }
}

I added @GenIgnore annotation on companion object because kapt keeps complaining about Map<SqlQuery, String> and JDBCClient are not legal types.

desdulianto avatar Aug 07 '18 06:08 desdulianto

@desmondtzq @mustafakibar To my knowledge there is no way to do this in 1.2.x as interfaces are not allowed to have @JvmStatic members.

However, support for this is added in 1.3 (https://youtrack.jetbrains.com/issue/KT-6301) meaning that the following should work:

@ProxyGen
interface WikiDatabaseService {

    @Fluent
    fun fetchAllPages(resultHandler: Handler<AsyncResult<JsonArray>>): WikiDatabaseService

    @Fluent
    fun fetchPage(name: String, resultHandler: Handler<AsyncResult<JsonObject>>): WikiDatabaseService

    @Fluent
    fun createPage(title: String, markdown: String, resultHandler: Handler<AsyncResult<Void>>): WikiDatabaseService

    @Fluent
    fun savePage(id: Int, markdown: String, resultHandler: Handler<AsyncResult<Void>>): WikiDatabaseService

    @Fluent
    fun deletePage(id: Int, resultHandler: Handler<AsyncResult<Void>>): WikiDatabaseService

    @GenIgnore
    companion object {
        @JvmStatic
        fun create(dbClient: JDBCClient, sqlQueries: Map<SqlQuery, String>,
                   readyHandler: Handler<AsyncResult<WikiDatabaseService>>): WikiDatabaseService =
                WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler)

        @JvmStatic
        fun createProxy(vertx: Vertx, address: String): WikiDatabaseService =
                WikiDatabaseServiceVertxEBProxy(vertx, address)
    }
}

(You can actually use this feature now, as per Michael Bogdanov's comment, though since it's pre-release it's technically not stable.)

rgmz avatar Aug 09 '18 21:08 rgmz

@rgmz , I've tried adding @JvmStatic like you did on Kotlin 1.3.21n and I still have this error ".Companion is not legal for use for a constant type in code generation"

Any other workarounds that you might suggest?

raghumulukutla avatar Mar 28 '19 03:03 raghumulukutla

@raghumulukutla A change introduced in Vert.x 3.6.x inadvertently broke this.

I created a pull request to fix this—hopefully it makes it into the next release, or a viable workaround is provided.


@gmariotti do you have any suggested workarounds to mimic this behaviour?

rgmz avatar Mar 28 '19 03:03 rgmz

@rgmz sorry, I wanted to look into it but I never found the time. With @vietj, we discussed in the past to try to find a solution that wasn't Kotlin specific but I didn't find anything so far

gmariotti avatar Mar 28 '19 08:03 gmariotti

@gmariotti @rgmz Thanks! I've also tried using a Vertx version < 3.6.x. Reproduces the same error.

raghumulukutla avatar Mar 28 '19 12:03 raghumulukutla

@raghumulukutla Can you provide a reproducer? I do not get the error in version 3.5.4.

Try this ad-hoc example: https://github.com/rgmz/vertx-kotlin-service-proxy

rgmz avatar Mar 31 '19 18:03 rgmz

@rgmz I'm sorry, I should correct myself. I do not get the same error. But I do get a kaptKotlin error. Here's the reproducer: https://github.com/raghumulukutla/vertx-guide-kotlin/tree/service_proxy/src/main/kotlin/com/raghu/vertx3guide/wiki/step3/database

WikiDatabaseService.kt

package com.raghu.vertx3guide.wiki.step3.database

import io.vertx.codegen.annotations.Fluent
import io.vertx.codegen.annotations.GenIgnore
import io.vertx.codegen.annotations.ProxyGen
import io.vertx.codegen.annotations.VertxGen
import io.vertx.core.AsyncResult
import io.vertx.core.Handler
import io.vertx.core.Vertx
import io.vertx.core.json.JsonArray
import io.vertx.core.json.JsonObject
import io.vertx.ext.asyncsql.AsyncSQLClient


@ProxyGen
@VertxGen
interface WikiDatabaseService {
  @Fluent
  fun fetchAllPages(resultHandler: Handler<AsyncResult<JsonArray>>):WikiDatabaseService

  @Fluent
  fun fetchPage(name:String,resultHandler: Handler<AsyncResult<JsonObject>>):WikiDatabaseService

  @Fluent
  fun createPage(title:String, markdown:String, resultHandler: Handler<AsyncResult<Void>>):WikiDatabaseService

  @Fluent
  fun savePage(id:Int, markdown:String,resultHandler: Handler<AsyncResult<Void>>):WikiDatabaseService

  @Fluent
  fun deletePage(id:Int, resultHandler: Handler<AsyncResult<Void>>):WikiDatabaseService

  @GenIgnore
  companion object {
    @GenIgnore
    @JvmStatic
    fun create(dbClient:AsyncSQLClient, sqlQueries: HashMap<SqlQuery, String>, readyHandler: Handler<AsyncResult<WikiDatabaseService>>):WikiDatabaseService {
      return WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler)

    }
    @GenIgnore
    @JvmStatic
    fun createProxy(vertx: Vertx, address:String ):WikiDatabaseService {
      return WikiDatabaseServiceVertxEBProxy(vertx, address)
    }
  }

}

Error:

could not generate model for com.raghu.vertx3guide.wiki.step3.database.WikiDatabaseService#create(io.vertx.ext.asyncsql.AsyncSQLClient,java.util.HashMap<com.raghu.vertx3guide.wiki.step3.database.SqlQuery,java.lang.String>,io.vertx.core.Handler<io.vertx.core.AsyncResult<com.raghu.vertx3guide.wiki.step3.database.WikiDatabaseService>>): type java.util.HashMap<com.raghu.vertx3guide.wiki.step3.database.SqlQuery,java.lang.String> is not legal for use for a parameter in code generation
    public static com.raghu.vertx3guide.wiki.step3.database.WikiDatabaseService create(@org.jetbrains.annotations.NotNull()

raghumulukutla avatar Apr 02 '19 04:04 raghumulukutla

just use java interface in kotlin project

liuandong avatar Apr 09 '19 02:04 liuandong

Is extension function a possible workaround? So that we won't need to setup companion object

@ProxyGen
interface WikiDatabaseService{
    ...
}

fun WikiDatabaseService.create(
    dbClient:AsyncSQLClient, 
    sqlQueries: HashMap<SqlQuery, String>, 
    readyHandler: Handler<AsyncResult<WikiDatabaseService>>
):WikiDatabaseService = WikiDatabaseServiceImpl(dbClient, sqlQueries, readyHandler)
fun WikiDatabaseService.createProxy(
    vertx: Vertx, 
    address:String
):WikiDatabaseService = WikiDatabaseServiceVertxEBProxy(vertx, address)

adiosray avatar Dec 02 '19 14:12 adiosray

Is extension function a possible workaround? So that we won't need to setup companion object

Unfortunately Kotlin does not support static extension functions; in order to call create you'd need to already have an instance of WikiDatabaseServiceImpl.

Additionally, non-static methods are not picked up by codegen so you would need to manually define factory methods for everything, e.g. the rxified API.

rgmz avatar Dec 06 '19 00:12 rgmz

@raghumulukutla A change introduced in Vert.x 3.6.x inadvertently broke this.

I created a pull request to fix this—hopefully it makes it into the next release, or a viable workaround is provided.

FYI, once Vert.x 4.1.0 is released this issue should be resolved.

Try this ad-hoc example: https://github.com/rgmz/vertx-kotlin-service-proxy

4.1.0 isn't released yet, but this is now updated to 4.1.0.CR2.

rgmz avatar May 31 '21 13:05 rgmz