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());
+ }
}
}
}