Skip to content

Commit

Permalink
refactor how we determine which methods need a default implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mgodave committed Nov 22, 2024
1 parent 9120c33 commit 49ebbe2
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,13 @@ interface GenerationContext {
* method.
*/
String methodPath(ServiceDescriptorProto serviceProto, MethodDescriptorProto methodProto);

/**
* Get the <a href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md">gRPC H2 path</a> for a method.
* @param serviceProto protobuf descriptor for the service.
* @param methodName name of the method.
* @return the <a href="https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md">gRPC H2 path</a> for a
* method.
*/
String methodPath(ServiceDescriptorProto serviceProto, String methodName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -1650,48 +1653,38 @@ private TypeSpec newServiceInterfaceSpec(final State state, final boolean blocki
final List<RpcInterface> 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());
}
}
}
}
Expand Down

0 comments on commit 49ebbe2

Please sign in to comment.