Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Although I can generate the stubs with io.grpc:protoc-gen-grpc-kotlin I can't implement it #257

Open
jimisdrpc opened this issue Nov 11, 2020 · 17 comments
Assignees

Comments

@jimisdrpc
Copy link

jimisdrpc commented Nov 11, 2020

Issue: I can't implement an object autogenerated from protobuf.

How reproduce: generated a project from micronaut initializer with: gRPC Application type, Java 11, Kotlin. Add io.grpc:protoc-gen-grpc-kotlin on build.gradle, build it, add a controller and try implement GrpcdemoServiceGrpcKt.

image

build.gradle

plugins {
    id "org.jetbrains.kotlin.jvm" version "1.4.10"
    id "org.jetbrains.kotlin.kapt" version "1.4.10"
    id "org.jetbrains.kotlin.plugin.allopen" version "1.4.10"
    id "com.github.johnrengelman.shadow" version "6.1.0"
    id "io.micronaut.application" version '1.0.5'
    id "com.google.protobuf" version "0.8.13"
}

version "0.1"
group "com.mybank"

repositories {
    mavenCentral()
    jcenter()
}

micronaut {
    testRuntime "junit5"
    processing {
        incremental true
        annotations "com.mybank.*"
    }
}

dependencies {
    implementation("io.micronaut:micronaut-validation")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
    implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    implementation("io.micronaut.kotlin:micronaut-kotlin-runtime")
    implementation("io.micronaut:micronaut-runtime")
    implementation("io.micronaut.grpc:micronaut-grpc-runtime")
    implementation("javax.annotation:javax.annotation-api")
    runtimeOnly("ch.qos.logback:logback-classic")
    runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin")
    testImplementation("io.micronaut:micronaut-http-client")

    implementation("io.grpc:grpc-kotlin-stub:${grpcKotlinVersion}")
}

mainClassName = "com.mybank.ApplicationKt"
java {
    sourceCompatibility = JavaVersion.toVersion('11')
}

compileKotlin {
    kotlinOptions {
        jvmTarget = '11'
    }
}
compileTestKotlin {
    kotlinOptions {
        jvmTarget = '11'
    }
}



sourceSets {
    main {
        java {
            srcDirs 'build/generated/source/proto/main/grpc'
            srcDirs 'build/generated/source/proto/main/java'
        }
    }
}

protobuf {
    protoc { artifact = "com.google.protobuf:protoc:3.13.0" }
    plugins {
        grpc { artifact = "io.grpc:protoc-gen-grpc-java:1.32.1" }
        grpckt { artifact = "io.grpc:protoc-gen-grpc-kotlin:${grpcKotlinVersion}" }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
            grpckt {}
        }
    }
}

gradle.properties

micronautVersion=2.1.3
kotlinVersion=1.4.10
grpcKotlinVersion=0.1.2

auto generated stubs while gradle build

package com.mybank

import com.mybank.GrpcdemoServiceGrpc.getServiceDescriptor
import io.grpc.CallOptions
import io.grpc.CallOptions.DEFAULT
import io.grpc.Channel
import io.grpc.Metadata
import io.grpc.MethodDescriptor
import io.grpc.ServerServiceDefinition
import io.grpc.ServerServiceDefinition.builder
import io.grpc.ServiceDescriptor
import io.grpc.Status.UNIMPLEMENTED
import io.grpc.StatusException
import io.grpc.kotlin.AbstractCoroutineServerImpl
import io.grpc.kotlin.AbstractCoroutineStub
import io.grpc.kotlin.ClientCalls.unaryRpc
import io.grpc.kotlin.ServerCalls.unaryServerMethodDefinition
import io.grpc.kotlin.StubFor
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmStatic

/**
 * Holder for Kotlin coroutine-based client and server APIs for com.mybank.GrpcdemoService.
 */
object GrpcdemoServiceGrpcKt {
  @JvmStatic
  val serviceDescriptor: ServiceDescriptor
    get() = GrpcdemoServiceGrpc.getServiceDescriptor()

  val sendMethod: MethodDescriptor<GrpcdemoRequest, GrpcdemoReply>
    @JvmStatic
    get() = GrpcdemoServiceGrpc.getsendMethod()

  /**
   * A stub for issuing RPCs to a(n) com.mybank.GrpcdemoService service as suspending coroutines.
   */
  @StubFor(GrpcdemoServiceGrpc::class)
  class GrpcdemoServiceCoroutineStub @JvmOverloads constructor(
    channel: Channel,
    callOptions: CallOptions = DEFAULT
  ) : AbstractCoroutineStub<GrpcdemoServiceCoroutineStub>(channel, callOptions) {
    override fun build(channel: Channel, callOptions: CallOptions): GrpcdemoServiceCoroutineStub =
        GrpcdemoServiceCoroutineStub(channel, callOptions)

    /**
     * Executes this RPC and returns the response message, suspending until the RPC completes
     * with [`Status.OK`][io.grpc.Status].  If the RPC completes with another status, a
     * corresponding
     * [StatusException] is thrown.  If this coroutine is cancelled, the RPC is also cancelled
     * with the corresponding exception as a cause.
     *
     * @param request The request message to send to the server.
     *
     * @return The single response from the server.
     */
    suspend fun send(request: GrpcdemoRequest): GrpcdemoReply = unaryRpc(
      channel,
      GrpcdemoServiceGrpc.getSendMethod(),
      request,
      callOptions,
      Metadata()
    )}

  /**
   * Skeletal implementation of the com.mybank.GrpcdemoService service based on Kotlin coroutines.
   */
  abstract class GrpcdemoServiceCoroutineImplBase(
    coroutineContext: CoroutineContext = EmptyCoroutineContext
  ) : AbstractCoroutineServerImpl(coroutineContext) {
    /**
     * Returns the response to an RPC for com.mybank.GrpcdemoService.send.
     *
     * If this method fails with a [StatusException], the RPC will fail with the corresponding
     * [io.grpc.Status].  If this method fails with a [java.util.concurrent.CancellationException],
     * the RPC will fail
     * with status `Status.CANCELLED`.  If this method fails for any other reason, the RPC will
     * fail with `Status.UNKNOWN` with the exception as a cause.
     *
     * @param request The request from the client.
     */
    open suspend fun send(request: GrpcdemoRequest): GrpcdemoReply = throw
        StatusException(UNIMPLEMENTED.withDescription("Method com.mybank.GrpcdemoService.send is unimplemented"))

    final override fun bindService(): ServerServiceDefinition = builder(getServiceDescriptor())
      .addMethod(unaryServerMethodDefinition(
      context = this.context,
      descriptor = GrpcdemoServiceGrpc.getSendMethod(),
      implementation = ::send
    )).build()
  }
}

All the rest are exactly the same from micronaut.launch

Possible solution: there is an example I downloaded and staret it successsfuly and called it from BloomRPC. It is from oficial examples. Looking at it I see a much more complex gradle.

plugins {
    id "org.jetbrains.kotlin.jvm" version "1.3.72"
    id "org.jetbrains.kotlin.kapt" version "1.3.72"
    id "org.jetbrains.kotlin.plugin.allopen" version "1.3.72"
    id "application"
    id 'com.google.protobuf' version '0.8.13'
}

version "0.2"
group "helloworld"

repositories {
    mavenLocal()
    jcenter()
}

configurations {
    // for dependencies that are needed for development only
    developmentOnly
}

dependencies {
    kapt(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion"))
    kapt("io.micronaut:micronaut-inject-java")
    kapt("io.micronaut:micronaut-validation")

    implementation(enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion"))
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
    implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinxCoroutinesVersion")
    implementation("io.micronaut:micronaut-runtime")
//    implementation("io.micronaut.grpc:micronaut-grpc-runtime")
    implementation("io.micronaut.grpc:micronaut-grpc-server-runtime:$micronautGrpcVersion")
    implementation("io.micronaut.grpc:micronaut-grpc-client-runtime:$micronautGrpcVersion")
    implementation("io.grpc:grpc-kotlin-stub:${grpcKotlinVersion}")

    runtimeOnly("ch.qos.logback:logback-classic:1.2.3")
    runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8")

    kaptTest("io.micronaut:micronaut-inject-java")

    testImplementation enforcedPlatform("io.micronaut:micronaut-bom:$micronautVersion")
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.0")
    testImplementation("io.micronaut.test:micronaut-test-junit5")
    testImplementation("org.mockito:mockito-junit-jupiter:2.22.0")

    testRuntime("org.junit.jupiter:junit-jupiter-engine:5.3.0")
    testRuntime("org.jetbrains.spek:spek-junit-platform-engine:1.1.5")
}

test.classpath += configurations.developmentOnly

mainClassName = "helloworld.Application"

test {
    useJUnitPlatform()
}

allOpen {
	annotation("io.micronaut.aop.Around")
}

compileKotlin {
	kotlinOptions {
	    jvmTarget = '1.8' 
	    //Will retain parameter names for Java reflection
	    javaParameters = true 
	}
}
//compileKotlin.dependsOn(generateProto)

compileTestKotlin {
	kotlinOptions {
	    jvmTarget = '1.8' 
	    javaParameters = true 
	}
}

tasks.withType(JavaExec) {
    classpath += configurations.developmentOnly
    jvmArgs('-XX:TieredStopAtLevel=1', '-Dcom.sun.management.jmxremote')
}

sourceSets {
    main {
        java {
            srcDirs 'build/generated/source/proto/main/grpc'
            srcDirs 'build/generated/source/proto/main/grpckt'
            srcDirs 'build/generated/source/proto/main/java'
        }
    }
}

protobuf {
    protoc { artifact = "com.google.protobuf:protoc:${protocVersion}" }
    plugins {
        grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" }
        grpckt { artifact = "io.grpc:protoc-gen-grpc-kotlin:${grpcKotlinVersion}" }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
            grpckt {}
        }
    }
}

Question: what I am missing in order to implement the autogenerated stubs? Do I need more gradle dependencies beyond io.grpc:protoc-gen-grpc-kotlin? Am I in right direction? If not, what should I do in order to implement the send rpc method from demo project downloaded from Micronaut.launch?

PS.: when I tried the most recent version from io.grpc:protoc-gen-grpc-kotlin gradle complains so I just use 0.1.2 which is the same from official example. This is not an issue for me as long as it is not related to my problem.

@jimisdrpc
Copy link
Author

Sorry for terrible format. I added the code inside the "Insert Code" space created. I tried re-edit but I couldn't. Basically I added two main files: build.gradle that I downloaded from micronaut.launch and I have just added io.grpc:protoc-gen-grpc-kotlin
and the build.gradle from official example. Hopefully who reads it can understand it.

@jimisdrpc
Copy link
Author

@jeffbrown in case it helps, I tried copied all build.gradle from example provided to the project generated from Micronaut.Launch and I had the same issue. On another hand, the inverse works: I copied my proto file to the example provided and it works. This gives me a clue that there is something extra in the example provided that is mmissed in project generated from micronaut.launch

@jeffscottbrown
Copy link

I tried copied all build.gradle from example provided to the project generated from Micronaut.Launch and I had the same issue

If the example you are talking about is the one at github.com/micronaut-projects/micronaut-grpc/tree/c8ec599ad1b696d432efecb10145105074f3d26a/examples/hello-world-kotlin, be aware that project is using Micronaut 2.0.0.M3 and your project is using Micronaut 2.1.3.

@jimisdrpc
Copy link
Author

jimisdrpc commented Nov 13, 2020

@jeffbrown thanks. Well, my project is generated from Micronaut Laucher. I assume this is the best source for starting a fresh and up-to-date project with proper dependencie versions. Have you successfuly downloaded a grpc application from micronaut launcher and created successfully a proto and its endpoint in Kotlin? If so than would mind to share with me?

@morrle
Copy link

morrle commented Nov 13, 2020

modify sourceSets in build.gradle file

sourceSets {
    main {
        java {
            srcDirs 'build/generated/source/proto/main/grpc'
            srcDirs 'build/generated/source/proto/main/grpckt' // load the generated kotlin file
            srcDirs 'build/generated/source/proto/main/java'
        }
    }
}

@jimisdrpc
Copy link
Author

jimisdrpc commented Nov 13, 2020

@morrle thanks, but same issue. May I ask you if you can share with me a very simple project evoulated from Micronaut Launcher with Kotlin? I am really stuck.

I tried again. The steps are:

1 - I generated grpcApplication/kotlin from Micronaut Launcher.
2 - added these lines in build.gradle

plugins {
 ...
    id "com.google.protobuf" version "0.8.13"
...
dependencies {
...
    implementation("io.grpc:grpc-kotlin-stub:0.1.2")
...
sourceSets {
    main {
        java {
...
            srcDirs 'build/generated/source/proto/main/grpckt' // load the generated kotlin file
...
protobuf {
...
            grpckt {}}

3 - I tried to implement the proto example which came with autogenerated project

import javax.inject.Singleton

@Singleton
class MyEndpoint : GrpcdemoServiceGrpcKt.GrpcdemoServiceCoroutineImplBase() {
    override suspend fun send(request: GrpcdemoRequest): GrpcdemoReply {
        return GrpcdemoReply.newBuilder().setMessage("test").build()
    }
}

Here is the error when I tried gradle clean build

image

Here is the whole build.gradle

plugins {
    id "org.jetbrains.kotlin.jvm" version "1.4.10"
    id "org.jetbrains.kotlin.kapt" version "1.4.10"
    id "org.jetbrains.kotlin.plugin.allopen" version "1.4.10"
    id "com.github.johnrengelman.shadow" version "6.1.0"
    id "io.micronaut.application" version '1.0.5'

    id "com.google.protobuf" version "0.8.13"
}

version "0.1"
group "com.mybank"

repositories {
    mavenCentral()
    jcenter()
}

micronaut {
    testRuntime "junit5"
    processing {
        incremental true
        annotations "com.mybank.*"
    }
}

dependencies {
    implementation("io.micronaut:micronaut-validation")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
    implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    implementation("io.micronaut.kotlin:micronaut-kotlin-runtime")
    implementation("io.micronaut:micronaut-runtime")
    implementation("io.micronaut.grpc:micronaut-grpc-runtime")
    implementation("javax.annotation:javax.annotation-api")

    implementation("io.grpc:grpc-kotlin-stub:0.1.2")

    runtimeOnly("ch.qos.logback:logback-classic")
    runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin")
    testImplementation("io.micronaut:micronaut-http-client")

}

mainClassName = "com.mybank.ApplicationKt"
java {
    sourceCompatibility = JavaVersion.toVersion('11')
}

compileKotlin {
    kotlinOptions {
        jvmTarget = '11'
    }
}
compileTestKotlin {
    kotlinOptions {
        jvmTarget = '11'
    }
}



sourceSets {
    main {
        java {
            srcDirs 'build/generated/source/proto/main/grpc'

            srcDirs 'build/generated/source/proto/main/grpckt' // load the generated kotlin file
            srcDirs 'build/generated/source/proto/main/java'
        }
    }
}

protobuf {
    protoc { artifact = "com.google.protobuf:protoc:3.13.0" }
    plugins {
        grpc { artifact = "io.grpc:protoc-gen-grpc-java:1.32.1" }

        grpckt { artifact = "io.grpc:protoc-gen-grpc-kotlin:0.1.2" }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}

            grpckt {}}
    }
}

The rest is exactly what I downloaded from micronaut launcher.

@jimisdrpc
Copy link
Author

Well, I am still looking forward to find a solution for this. Normally, we expected from frameworks launchers/initializers to be precise with dependencies.

@graemerocher
Copy link
Contributor

@jimisdrpc seems to be an issue specific to Kotlin, will investigate ... thanks for the report

@graemerocher
Copy link
Contributor

So the statement "Normally, we expected from frameworks launchers/initializers to be precise with dependencies." is inaccurate in that frameworks and launchers typically only include libraries and features when a stable release of a library is present and you are not using the raw output from the launcher, you are modifying the code to introduce protoc-gen-grpc-kotlin which is in an alpha/beta/prerelease state

@jimisdrpc
Copy link
Author

@graemerocher ok, you are right. I didn't know protoc-gen-grpc-kotlin wasn't in stable version. As far as I can see, looking at https://mvnrepository.com/artifact/io.grpc/protoc-gen-grpc-kotlin I don't get this point. BTW, I can give a try with Java e remove this dependencie.

@asarkar
Copy link

asarkar commented Nov 17, 2020

@jimisdrpc Have you considered grpc-kotlin by Google? I used it with a Spring Boot project, and although not GA yet, it is doing a good job so far.

@jimisdrpc
Copy link
Author

@asarkar , thanks for suggestion. Good to know. I will give a try. It is worth to me as long as it runs well with Micronaut.

@marcoscouto
Copy link
Contributor

@jimisdrpc i think this last error is because in your file .proto you write the "sendMethod" with the first letter in lower case, you should try write like this "SendMethod", i have the same error and i fix it with this change.

@asarkar
Copy link

asarkar commented Dec 15, 2020

@marcoscouto Naming in proto file is a convention, not a rule. If not following the convention results in an error, it’s a bug.

@jimisdrpc
Copy link
Author

@graemerocher Since December 8th I can say https://mvnrepository.com/artifact/io.grpc/protoc-gen-grpc-kotlin/1.0.0 is in stable version, right?

Do you see any point in this build.gradle?

plugins {
    id("org.jetbrains.kotlin.jvm") version "1.4.10"
    id("org.jetbrains.kotlin.kapt") version "1.4.10"
    id("org.jetbrains.kotlin.plugin.allopen") version "1.4.10"
    id("com.github.johnrengelman.shadow") version "6.1.0"
    id("io.micronaut.application") version "1.2.0"
    id("com.google.protobuf") version "0.8.13"
}

version = "0.1"
group = "com.tolearn"

repositories {
    mavenCentral()
    jcenter()
}

micronaut {
    testRuntime("junit5")
    processing {
        incremental(true)
        annotations("com.tolearn.*")
    }
}

dependencies {
    implementation("io.micronaut:micronaut-validation")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
    implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    implementation("io.micronaut.kotlin:micronaut-kotlin-runtime")
    implementation("io.micronaut:micronaut-runtime")
    implementation("io.micronaut.grpc:micronaut-grpc-runtime")
    implementation("javax.annotation:javax.annotation-api")
    implementation("io.micronaut:micronaut-http-client")
    implementation("io.micronaut:micronaut-tracing")

    implementation("io.grpc:protoc-gen-grpc-kotlin:1.0.0")

    runtimeOnly("io.jaegertracing:jaeger-thrift")
    runtimeOnly("ch.qos.logback:logback-classic")
    runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin")
}


application {
    mainClass.set("com.tolearn.ApplicationKt")
}

java {
    sourceCompatibility = JavaVersion.toVersion("11")
}

tasks {
    compileKotlin {
        kotlinOptions {
            jvmTarget = "11"
        }
    }
    compileTestKotlin {
        kotlinOptions {
            jvmTarget = "11"
        }
    }


}

sourceSets {
    main {
        java {
            srcDirs("build/generated/source/proto/main/grpc")
            srcDirs 'build/generated/source/proto/main/grpckt'
            srcDirs("build/generated/source/proto/main/java")
        }
    }
}

protobuf {
    protoc { artifact = "com.google.protobuf:protoc:3.14.0" }
    plugins {
        grpc { artifact = "io.grpc:protoc-gen-grpc-java:1.33.1" }
        grpckt { artifact = "io.grpc:protoc-gen-grpc-kotlin:1.0.0" }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
            grpckt {}
        }
    }
}

My goal is use protoc-gen-grpc-kotlin so the stubs will be generated in Kotlin with supend function (Coroutine context).

@graemerocher graemerocher self-assigned this Feb 12, 2021
@graemerocher
Copy link
Contributor

graemerocher commented Feb 12, 2021

Here is an example build.gradle.kts that works for me with Kotlin 1.4.30:

import com.google.protobuf.gradle.*
plugins {
    id("org.jetbrains.kotlin.jvm") version "1.4.30"
    id("org.jetbrains.kotlin.kapt") version "1.4.30"
    id("org.jetbrains.kotlin.plugin.allopen") version "1.4.10"
    id("com.github.johnrengelman.shadow") version "6.1.0"
    id("io.micronaut.application") version "1.3.3"
    id("com.google.protobuf") version "0.8.13"
}

version = "0.1"
group = "tmp"

val kotlinVersion=project.properties.get("kotlinVersion")
repositories {
    mavenCentral()
    jcenter()
}

micronaut {
    testRuntime("junit5")
    processing {
        incremental(true)
        annotations("tmp.*")
    }
}

dependencies {
    implementation("io.micronaut:micronaut-validation")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
    implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    implementation("io.micronaut.kotlin:micronaut-kotlin-runtime")
    implementation("io.micronaut:micronaut-runtime")
    implementation("io.micronaut.grpc:micronaut-grpc-runtime")
    implementation("io.grpc:grpc-kotlin-stub:1.0.0")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2")
    runtimeOnly("ch.qos.logback:logback-classic")
    runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin")
    testImplementation("io.micronaut:micronaut-http-client")
}


application {
    mainClass.set("tmp.ApplicationKt")
}

java {
    sourceCompatibility = JavaVersion.toVersion("1.8")
}

tasks {
    compileKotlin {
        kotlinOptions {
            jvmTarget = "1.8"
        }
    }
    compileTestKotlin {
        kotlinOptions {
            jvmTarget = "1.8"
        }
    }


}
sourceSets {
    main {
        java {
            srcDirs("build/generated/source/proto/main/grpc")
            srcDirs("build/generated/source/proto/main/java")
        }
    }
}

protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:3.14.0"
    }
    plugins {
        id("grpc") {
            artifact = "io.grpc:protoc-gen-grpc-java:1.33.1"
        }
        id("grpckt") {
            artifact = "io.grpc:protoc-gen-grpc-kotlin:1.0.0:jdk7@jar"
        }        
    }
    generateProtoTasks {
        ofSourceSet("main").forEach {
            it.plugins {
                // Apply the "grpc" plugin whose spec is defined above, without options.
                id("grpc")
                id("grpckt")
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants