diff --git a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/FileDescriptor.java b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/FileDescriptor.java index ac91951800..f749732c2b 100644 --- a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/FileDescriptor.java +++ b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/FileDescriptor.java @@ -189,11 +189,16 @@ public ServiceClassBuilder newServiceClassBuilder(final ServiceDescriptorProto s @Override public String methodPath(final ServiceDescriptorProto serviceProto, final MethodDescriptorProto methodProto) { + return methodPath(serviceProto, methodProto.getName()); + } + + @Override + public String methodPath(final ServiceDescriptorProto serviceProto, final String methodName) { final StringBuilder sb = new StringBuilder(128).append('/'); if (isNotNullNorEmpty(protoPackageName)) { sb.append(protoPackageName).append('.'); } - sb.append(serviceProto.getName()).append('/').append(methodProto.getName()); + sb.append(serviceProto.getName()).append('/').append(methodName); return sb.toString(); } diff --git a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/GenerationContext.java b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/GenerationContext.java index fea28e8559..21d3656939 100644 --- a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/GenerationContext.java +++ b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/GenerationContext.java @@ -57,4 +57,13 @@ interface GenerationContext { * method. */ String methodPath(ServiceDescriptorProto serviceProto, MethodDescriptorProto methodProto); + + /** + * Get the gRPC H2 path for a method. + * @param serviceProto protobuf descriptor for the service. + * @param methodName name of the method. + * @return the gRPC H2 path for a + * method. + */ + String methodPath(ServiceDescriptorProto serviceProto, String methodName); } diff --git a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/Generator.java b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/Generator.java index a6c95feb7d..6e0074aad6 100644 --- a/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/Generator.java +++ b/servicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/Generator.java @@ -226,10 +226,13 @@ private static final class State { final ClassName clientClass; final ClassName blockingClientClass; + final ServiceClassBuilder container; + private State(ServiceDescriptorProto serviceProto, GenerationContext context, String outerClassName, - int serviceIndex) { + int serviceIndex, ServiceClassBuilder container) { this.serviceProto = serviceProto; this.serviceIndex = serviceIndex; + this.container = container; final String sanitizedProtoName = sanitizeIdentifier(serviceProto.getName(), false); @@ -275,14 +278,14 @@ private State(ServiceDescriptorProto serviceProto, GenerationContext context, St */ TypeSpec.Builder generate(FileDescriptor f, final ServiceDescriptorProto serviceProto, final int serviceIndex) { final ServiceClassBuilder container = context.newServiceClassBuilder(serviceProto); - final State state = new State(serviceProto, context, container.className, serviceIndex); + final State state = new State(serviceProto, context, container.className, serviceIndex, container); if (printJavaDocs) { container.builder.addJavadoc("Class for $L Service", serviceProto.getName()); } addSerializationProviderInit(state, container.builder); - addServiceRpcInterfaces(state, container.builder); + addServiceRpservicetalk-grpc-protoc/src/main/java/io/servicetalk/grpc/protoc/Generator.javacInterfaces(state, container.builder); addServiceInterfaces(state, container.builder); addServiceFactory(state, container.builder); @@ -1650,48 +1653,38 @@ private TypeSpec newServiceInterfaceSpec(final State state, final boolean blocki final List interfaces = state.serviceRpcInterfaces.stream() .filter(intf -> intf.blocking == blocking) .collect(toList()); - for (int i = 0; i < interfaces.size(); ++i) { - final RpcInterface rpcInterface = interfaces.get(i); - final MethodDescriptorProto methodProto = rpcInterface.methodProto; - final ClassName inClass = messageTypesMap.get(methodProto.getInputType()); - final ClassName outClass = messageTypesMap.get(methodProto.getOutputType()); - final String methodName = sanitizeIdentifier(methodProto.getName(), true); - final String methodPath = context.methodPath(state.serviceProto, methodProto).substring(1); - final int methodIndex = i; - final MethodSpec methodSpec = newRpcMethodSpec(inClass, outClass, methodName, - methodProto.getClientStreaming(), - methodProto.getServerStreaming(), - !blocking ? EnumSet.of(INTERFACE) : EnumSet.of(INTERFACE, BLOCKING, SERVER_RESPONSE), - printJavaDocs, (__, spec) -> { - final String errorMessage = "\"Method " + methodPath + " is unimplemented\""; - spec.addModifiers(DEFAULT).addParameter(GrpcServiceContext, ctx); - spec.addAnnotation(Override.class); - if (!blocking) { - final ClassName returnType = methodProto.getServerStreaming() ? Publisher : Single; - spec.addStatement("return $T.failed(new $T(new $T($T.UNIMPLEMENTED, $L)))", - returnType, GrpcStatusException, GrpcStatus, GrpcStatusCode, errorMessage); - } else { - if (!skipDeprecated && methodProto.getServerStreaming()) { - spec.addStatement("$T.super.$L(ctx, request, response)", - rpcInterface.className, methodName); - } else { - spec.addStatement("throw new $T(new $T($T.UNIMPLEMENTED, $L))", - GrpcStatusException, GrpcStatus, GrpcStatusCode, errorMessage); - } - } - if (printJavaDocs) { - extractJavaDocComments(state, methodIndex, spec); - spec.addJavadoc(JAVADOC_PARAM + ctx + - " context associated with this service and request." + lineSeparator()); - } - return spec; - }); + for (final RpcInterface rpcInterface : interfaces) { + final TypeSpec interfaceTypeSpec = state.container.builder.typeSpecs.stream() + .filter(ts -> ts.name.equals(rpcInterface.className.simpleName())) + .findFirst().orElseThrow(IllegalStateException::new); - final boolean isDeprecated = methodSpec.annotations.contains( - AnnotationSpec.builder(Deprecated.class).build()); + for (final MethodSpec methodSpec : interfaceTypeSpec.methodSpecs) { + final boolean isDeprecated = methodSpec.annotations.contains( + AnnotationSpec.builder(Deprecated.class).build()); - if (!isDeprecated || !skipDeprecated) { - interfaceSpecBuilder.addMethod(methodSpec); + if (skipDeprecated && isDeprecated) { + continue; + } + + if (methodSpec.hasModifier(ABSTRACT)) { + final MethodSpec.Builder spec = methodSpec.toBuilder(); + final String methodPath = context.methodPath(state.serviceProto, methodSpec.name); + final String errorMessage = "\"Method " + methodPath.substring(1) + + " is unimplemented\""; + spec.modifiers.remove(ABSTRACT); + spec.addModifiers(DEFAULT).addAnnotation(Override.class); + if (!blocking) { + final ClassName returnType = (methodSpec.returnType.toString().contains("Publisher")) ? + Publisher : Single; + spec.addStatement("return $T.failed(new $T(new $T($T.UNIMPLEMENTED, $L)))", + returnType, GrpcStatusException, GrpcStatus, GrpcStatusCode, + errorMessage); + } else { + spec.addStatement("throw new $T(new $T($T.UNIMPLEMENTED, $L))", + GrpcStatusException, GrpcStatus, GrpcStatusCode, errorMessage); + } + interfaceSpecBuilder.addMethod(spec.build()); + } } } }