From e223eadafe849e10a3584c47fb8371a8562f6398 Mon Sep 17 00:00:00 2001 From: Marco Ferrer <35935108+marcoferrer@users.noreply.github.com> Date: Thu, 26 Dec 2019 19:57:49 -0500 Subject: [PATCH] Fix method signature code gen to adhere to spec (#99) * fix method signature code gen to adhere to spec * cleanup signature variant parsing impl --- .../generators/builders/GrpcStubBuilder.kt | 44 +++++----- .../ServerStreamingStubExtsBuilder.kt | 66 +++++++------- .../builders/UnaryStubExtsBuilder.kt | 88 ++++++++++--------- .../krotoplus/proto/ProtoMethod.kt | 22 +++-- .../main/proto/message/test_messages.proto | 2 + 5 files changed, 122 insertions(+), 100 deletions(-) diff --git a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/GrpcStubBuilder.kt b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/GrpcStubBuilder.kt index 629cfe3..19c4cbd 100644 --- a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/GrpcStubBuilder.kt +++ b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/GrpcStubBuilder.kt @@ -80,13 +80,13 @@ class GrpcStubBuilder(val context: GeneratorContext){ MethodDescriptor.MethodType.UNARY -> { addFunction(buildUnaryMethod(method)) addFunction(buildUnaryLambdaOverload(method)) - buildUnaryMethodSigOverload(method)?.let { addFunction(it) } + addFunctions(buildUnaryMethodSigOverload(method)) } MethodDescriptor.MethodType.SERVER_STREAMING -> { addFunction(buildServerStreamingMethod(method)) addFunction(buildServerStreamingLambdaOverload(method)) - buildServerStreamingMethodSigOverload(method)?.let { addFunction(it) } + addFunctions(buildServerStreamingMethodSigOverload(method)) } MethodDescriptor.MethodType.CLIENT_STREAMING -> @@ -190,27 +190,29 @@ class GrpcStubBuilder(val context: GeneratorContext){ // Method signature overloads - private fun buildUnaryMethodSigOverload(protoMethod: ProtoMethod): FunSpec? = with(protoMethod){ - if(methodSignatureFields.isEmpty()) - null else FunSpec.builder(functionName) - .addKdoc(attachedComments) - .addModifiers(KModifier.SUSPEND) - .returns(responseClassName) - .addMethodSignatureParameter(methodSignatureFields,context.schema) - .addCode(requestClassName.requestValueMethodSigCodeBlock(methodSignatureFields)) - .addStatement("return %N(request)",functionName) - .build() + private fun buildUnaryMethodSigOverload(protoMethod: ProtoMethod): List = with(protoMethod){ + methodSignatureVariants.map { variant -> + FunSpec.builder(functionName) + .addKdoc(attachedComments) + .addModifiers(KModifier.SUSPEND) + .returns(responseClassName) + .addMethodSignatureParameter(variant,context.schema) + .addCode(requestClassName.requestValueMethodSigCodeBlock(variant)) + .addStatement("return %N(request)",functionName) + .build() + } } - private fun buildServerStreamingMethodSigOverload(protoMethod: ProtoMethod): FunSpec? = with(protoMethod){ - if(methodSignatureFields.isEmpty()) - null else FunSpec.builder(functionName) - .addKdoc(attachedComments) - .returns(CommonClassNames.receiveChannel.parameterizedBy(responseClassName)) - .addMethodSignatureParameter(methodSignatureFields,context.schema) - .addCode(requestClassName.requestValueMethodSigCodeBlock(methodSignatureFields)) - .addStatement("return %N(request)",functionName) - .build() + private fun buildServerStreamingMethodSigOverload(protoMethod: ProtoMethod): List = with(protoMethod){ + methodSignatureVariants.map { variant -> + FunSpec.builder(functionName) + .addKdoc(attachedComments) + .returns(CommonClassNames.receiveChannel.parameterizedBy(responseClassName)) + .addMethodSignatureParameter(variant,context.schema) + .addCode(requestClassName.requestValueMethodSigCodeBlock(variant)) + .addStatement("return %N(request)",functionName) + .build() + } } // Stub companion object diff --git a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/ServerStreamingStubExtsBuilder.kt b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/ServerStreamingStubExtsBuilder.kt index 3e5f0ab..b7b506e 100644 --- a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/ServerStreamingStubExtsBuilder.kt +++ b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/ServerStreamingStubExtsBuilder.kt @@ -37,7 +37,7 @@ class ServerStreamingStubExtsBuilder(val context: GeneratorContext){ val funSpecs = mutableListOf() // Add method signature exts - if(method.methodSignatureFields.isNotEmpty()){ + if(method.methodSignatureVariants.isNotEmpty()){ funSpecs += buildAsyncMethodSigExt(method) funSpecs += buildBlockingMethodSigExt(method) } @@ -57,7 +57,7 @@ class ServerStreamingStubExtsBuilder(val context: GeneratorContext){ } private fun addCoroutineStubExts(funSpecs: MutableList, method: ProtoMethod){ - if(method.methodSignatureFields.isNotEmpty()) { + if(method.methodSignatureVariants.isNotEmpty()) { funSpecs += buildCoroutineMethodSigExt(method) } @@ -84,38 +84,44 @@ class ServerStreamingStubExtsBuilder(val context: GeneratorContext){ // Method Signature Extensions - private fun buildAsyncMethodSigExt(protoMethod: ProtoMethod): FunSpec = with(protoMethod){ - FunSpec.builder(functionName) - .addKdoc(attachedComments) - .receiver(protoService.asyncStubClassName) - .returns(UNIT) - .addMethodSignatureParameter(methodSignatureFields, context.schema) - .addResponseObserverParameter(responseClassName) - .addCode(requestClassName.requestValueMethodSigCodeBlock(methodSignatureFields)) - .addStatement("%N(request, responseObserver)",functionName) - .build() + private fun buildAsyncMethodSigExt(protoMethod: ProtoMethod): List = with(protoMethod){ + methodSignatureVariants.map { variant -> + FunSpec.builder(functionName) + .addKdoc(attachedComments) + .receiver(protoService.asyncStubClassName) + .returns(UNIT) + .addMethodSignatureParameter(variant, context.schema) + .addResponseObserverParameter(responseClassName) + .addCode(requestClassName.requestValueMethodSigCodeBlock(variant)) + .addStatement("%N(request, responseObserver)", functionName) + .build() + } } - private fun buildCoroutineMethodSigExt(protoMethod: ProtoMethod): FunSpec = with(protoMethod){ - FunSpec.builder(functionName) - .addKdoc(attachedComments) - .receiver(protoService.asyncStubClassName) - .addMethodSignatureParameter(methodSignatureFields, context.schema) - .returns(CommonClassNames.receiveChannel.parameterizedBy(responseClassName)) - .addCode(requestClassName.requestValueMethodSigCodeBlock(methodSignatureFields)) - .addStatement("return %N(request)",functionName) - .build() + private fun buildCoroutineMethodSigExt(protoMethod: ProtoMethod): List = with(protoMethod){ + methodSignatureVariants.map { variant -> + FunSpec.builder(functionName) + .addKdoc(attachedComments) + .receiver(protoService.asyncStubClassName) + .addMethodSignatureParameter(variant, context.schema) + .returns(CommonClassNames.receiveChannel.parameterizedBy(responseClassName)) + .addCode(requestClassName.requestValueMethodSigCodeBlock(variant)) + .addStatement("return %N(request)", functionName) + .build() + } } - private fun buildBlockingMethodSigExt(protoMethod: ProtoMethod): FunSpec = with(protoMethod){ - FunSpec.builder(functionName) - .addKdoc(attachedComments) - .receiver(protoService.blockingStubClassName) - .addMethodSignatureParameter(methodSignatureFields, context.schema) - .returns(Iterator::class.asClassName().parameterizedBy(responseClassName)) - .addCode(requestClassName.requestValueMethodSigCodeBlock(methodSignatureFields)) - .addStatement("return %N(request)",functionName) - .build() + private fun buildBlockingMethodSigExt(protoMethod: ProtoMethod): List = with(protoMethod){ + methodSignatureVariants.map { variant -> + FunSpec.builder(functionName) + .addKdoc(attachedComments) + .receiver(protoService.blockingStubClassName) + .addMethodSignatureParameter(variant, context.schema) + .returns(Iterator::class.asClassName().parameterizedBy(responseClassName)) + .addCode(requestClassName.requestValueMethodSigCodeBlock(variant)) + .addStatement("return %N(request)", functionName) + .build() + } } // Lambda Builder Extensions diff --git a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/UnaryStubExtsBuilder.kt b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/UnaryStubExtsBuilder.kt index c60109b..d45c66e 100644 --- a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/UnaryStubExtsBuilder.kt +++ b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/generators/builders/UnaryStubExtsBuilder.kt @@ -36,7 +36,7 @@ class UnaryStubExtsBuilder(val context: GeneratorContext){ val funSpecs = mutableListOf() // Add method signature exts - if(method.methodSignatureFields.isNotEmpty()){ + if(method.methodSignatureVariants.isNotEmpty()){ funSpecs += buildAsyncMethodSigExt(method) funSpecs += buildFutureMethodSigExt(method) funSpecs += buildBlockingMethodSigExt(method) @@ -59,7 +59,7 @@ class UnaryStubExtsBuilder(val context: GeneratorContext){ } private fun addCoroutineStubExts(funSpecs: MutableList, method: ProtoMethod){ - if(method.methodSignatureFields.isNotEmpty()) { + if(method.methodSignatureVariants.isNotEmpty()) { funSpecs += buildCoroutineMethodSigExt(method) } @@ -87,50 +87,58 @@ class UnaryStubExtsBuilder(val context: GeneratorContext){ // Method Signature Extensions - private fun buildAsyncMethodSigExt(protoMethod: ProtoMethod): FunSpec = with(protoMethod){ - FunSpec.builder(functionName) - .addKdoc(attachedComments) - .receiver(protoService.asyncStubClassName) - .addMethodSignatureParameter(methodSignatureFields, context.schema) - .addResponseObserverParameter(responseClassName) - .returns(UNIT) - .addCode(requestClassName.requestValueMethodSigCodeBlock(methodSignatureFields)) - .addStatement("%N(request, responseObserver)",functionName) - .build() + private fun buildAsyncMethodSigExt(protoMethod: ProtoMethod): List = with(protoMethod){ + methodSignatureVariants.map { variant -> + FunSpec.builder(functionName) + .addKdoc(attachedComments) + .receiver(protoService.asyncStubClassName) + .addMethodSignatureParameter(variant, context.schema) + .addResponseObserverParameter(responseClassName) + .returns(UNIT) + .addCode(requestClassName.requestValueMethodSigCodeBlock(variant)) + .addStatement("%N(request, responseObserver)",functionName) + .build() + } } - private fun buildCoroutineMethodSigExt(protoMethod: ProtoMethod): FunSpec = with(protoMethod){ - FunSpec.builder(functionName) - .addKdoc(attachedComments) - .addModifiers(KModifier.SUSPEND) - .receiver(protoService.asyncStubClassName) - .returns(responseClassName) - .addMethodSignatureParameter(methodSignatureFields, context.schema) - .addCode(requestClassName.requestValueMethodSigCodeBlock(methodSignatureFields)) - .addStatement("return %N(request)",functionName) - .build() + private fun buildCoroutineMethodSigExt(protoMethod: ProtoMethod): List = with(protoMethod){ + methodSignatureVariants.map { variant -> + FunSpec.builder(functionName) + .addKdoc(attachedComments) + .addModifiers(KModifier.SUSPEND) + .receiver(protoService.asyncStubClassName) + .returns(responseClassName) + .addMethodSignatureParameter(variant, context.schema) + .addCode(requestClassName.requestValueMethodSigCodeBlock(variant)) + .addStatement("return %N(request)",functionName) + .build() + } } - private fun buildFutureMethodSigExt(protoMethod: ProtoMethod): FunSpec = with(protoMethod){ - FunSpec.builder(functionName) - .addKdoc(attachedComments) - .receiver(protoService.futureStubClassName) - .addMethodSignatureParameter(methodSignatureFields, context.schema) - .returns(CommonClassNames.listenableFuture.parameterizedBy(responseClassName)) - .addCode(requestClassName.requestValueMethodSigCodeBlock(methodSignatureFields)) - .addStatement("return %N(request)",functionName) - .build() + private fun buildFutureMethodSigExt(protoMethod: ProtoMethod): List = with(protoMethod){ + methodSignatureVariants.map { variant -> + FunSpec.builder(functionName) + .addKdoc(attachedComments) + .receiver(protoService.futureStubClassName) + .addMethodSignatureParameter(variant, context.schema) + .returns(CommonClassNames.listenableFuture.parameterizedBy(responseClassName)) + .addCode(requestClassName.requestValueMethodSigCodeBlock(variant)) + .addStatement("return %N(request)",functionName) + .build() + } } - private fun buildBlockingMethodSigExt(protoMethod: ProtoMethod): FunSpec = with(protoMethod){ - FunSpec.builder(functionName) - .addKdoc(attachedComments) - .receiver(protoService.blockingStubClassName) - .returns(responseClassName) - .addMethodSignatureParameter(methodSignatureFields, context.schema) - .addCode(requestClassName.requestValueMethodSigCodeBlock(methodSignatureFields)) - .addStatement("return %N(request)",functionName) - .build() + private fun buildBlockingMethodSigExt(protoMethod: ProtoMethod): List = with(protoMethod){ + methodSignatureVariants.map { variant -> + FunSpec.builder(functionName) + .addKdoc(attachedComments) + .receiver(protoService.blockingStubClassName) + .returns(responseClassName) + .addMethodSignatureParameter(variant, context.schema) + .addCode(requestClassName.requestValueMethodSigCodeBlock(variant)) + .addStatement("return %N(request)", functionName) + .build() + } } // Lambda Builder Extensions diff --git a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/proto/ProtoMethod.kt b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/proto/ProtoMethod.kt index 9396714..db3c692 100644 --- a/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/proto/ProtoMethod.kt +++ b/protoc-gen-kroto-plus/src/main/kotlin/com/github/marcoferrer/krotoplus/proto/ProtoMethod.kt @@ -74,21 +74,25 @@ class ProtoMethod( else -> throw IllegalStateException("Unknown method type") } - val methodSignatureFields: List = getMethodSignatureFields() - + val methodSignatureVariants: List> = getMethodSignatureVariants() } -private fun ProtoMethod.getMethodSignatureFields(): List = - descriptorProto.options +private fun ProtoMethod.getMethodSignatureVariants(): List> { + + val methodSignaturesOptions = descriptorProto.options .runCatching { getExtension(ClientProto.methodSignature) } .getOrNull() ?.takeUnless { it.isEmpty() } - ?.let { signatureFields -> - requestType.descriptorProto.fieldList - .filter { it.name in signatureFields } - } - .orEmpty() + val signatureVariants = methodSignaturesOptions?.map { variant -> + val variantFields = variant.split(",") + + requestType.descriptorProto.fieldList + .filter { it.name in variantFields } + } + + return signatureVariants.orEmpty() +} /** * Comment parsing is based on the following implementation diff --git a/test-api/src/main/proto/message/test_messages.proto b/test-api/src/main/proto/message/test_messages.proto index 2970740..45ae055 100644 --- a/test-api/src/main/proto/message/test_messages.proto +++ b/test-api/src/main/proto/message/test_messages.proto @@ -96,12 +96,14 @@ service __MalformedService__ { rpc say_hello (L1Message1) returns (L1Message2){ option (google.api.method_signature) = "field"; option (google.api.method_signature) = "nested_message"; + option (google.api.method_signature) = "field,nested_message"; }; rpc sayHelloServerStreaming (L1Message1) returns (stream L1Message2){ option (google.api.method_signature) = "field"; option (google.api.method_signature) = "nested_message"; + option (google.api.method_signature) = "field,nested_message"; }; rpc sayHelloStreaming (stream L1Message1) returns (stream L1Message2);