Skip to content

Commit c21a013

Browse files
authored
fix: Generator callable generation is based on method type (#3075)
Fixes #3076
1 parent 182ae50 commit c21a013

File tree

5 files changed

+458
-101
lines changed

5 files changed

+458
-101
lines changed

gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java

Lines changed: 159 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,9 @@ public abstract class AbstractTransportServiceStubClassComposer implements Class
105105
private static final String PAGED_CALLABLE_CLASS_MEMBER_PATTERN = "%sPagedCallable";
106106

107107
private static final String BACKGROUND_RESOURCES_MEMBER_NAME = "backgroundResources";
108-
private static final String CALLABLE_NAME = "Callable";
109108
private static final String CALLABLE_FACTORY_MEMBER_NAME = "callableFactory";
110109
protected static final String CALLABLE_CLASS_MEMBER_PATTERN = "%sCallable";
111110
private static final String OPERATION_CALLABLE_CLASS_MEMBER_PATTERN = "%sOperationCallable";
112-
private static final String OPERATION_CALLABLE_NAME = "OperationCallable";
113-
// private static final String OPERATIONS_STUB_MEMBER_NAME = "operationsStub";
114-
protected static final String PAGED_CALLABLE_NAME = "PagedCallable";
115111

116112
protected static final TypeStore FIXED_TYPESTORE = createStaticTypes();
117113

@@ -460,59 +456,63 @@ private Map<String, VariableExpr> createCallableClassMembers(
460456
}
461457
String javaStyleProtoMethodName = JavaStyle.toLowerCamelCase(protoMethod.name());
462458
String callableName = String.format(CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName);
463-
callableClassMembers.put(
464-
callableName,
465-
VariableExpr.withVariable(
466-
Variable.builder()
467-
.setName(callableName)
468-
.setType(getCallableType(protoMethod))
469-
.build()));
459+
callableClassMembers.put(callableName, getCallableExpr(protoMethod, callableName));
470460
if (protoMethod.hasLro()) {
471461
callableName =
472462
String.format(OPERATION_CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName);
473-
callableClassMembers.put(
474-
callableName,
475-
VariableExpr.withVariable(
476-
Variable.builder()
477-
.setName(callableName)
478-
.setType(
479-
TypeNode.withReference(
480-
ConcreteReference.builder()
481-
.setClazz(OperationCallable.class)
482-
.setGenerics(
483-
Arrays.asList(
484-
protoMethod.inputType().reference(),
485-
protoMethod.lro().responseType().reference(),
486-
protoMethod.lro().metadataType().reference()))
487-
.build()))
488-
.build()));
463+
callableClassMembers.put(callableName, getOperationCallableExpr(protoMethod, callableName));
489464
}
490465
if (protoMethod.isPaged()) {
491466
callableName = String.format(PAGED_CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName);
492467
callableClassMembers.put(
493-
callableName,
494-
VariableExpr.withVariable(
495-
Variable.builder()
496-
.setName(callableName)
497-
.setType(
498-
TypeNode.withReference(
499-
getCallableType(protoMethod)
500-
.reference()
501-
.copyAndSetGenerics(
502-
Arrays.asList(
503-
protoMethod.inputType().reference(),
504-
typeStore
505-
.get(
506-
String.format(
507-
PAGED_RESPONSE_TYPE_NAME_PATTERN,
508-
protoMethod.name()))
509-
.reference()))))
510-
.build()));
468+
callableName, getPagedCallableExpr(typeStore, protoMethod, callableName));
511469
}
512470
}
513471
return callableClassMembers;
514472
}
515473

474+
private VariableExpr getCallableExpr(Method protoMethod, String callableName) {
475+
return VariableExpr.withVariable(
476+
Variable.builder().setName(callableName).setType(getCallableType(protoMethod)).build());
477+
}
478+
479+
private VariableExpr getPagedCallableExpr(
480+
TypeStore typeStore, Method protoMethod, String callableName) {
481+
return VariableExpr.withVariable(
482+
Variable.builder()
483+
.setName(callableName)
484+
.setType(
485+
TypeNode.withReference(
486+
getCallableType(protoMethod)
487+
.reference()
488+
.copyAndSetGenerics(
489+
Arrays.asList(
490+
protoMethod.inputType().reference(),
491+
typeStore
492+
.get(
493+
String.format(
494+
PAGED_RESPONSE_TYPE_NAME_PATTERN, protoMethod.name()))
495+
.reference()))))
496+
.build());
497+
}
498+
499+
private VariableExpr getOperationCallableExpr(Method protoMethod, String callableName) {
500+
return VariableExpr.withVariable(
501+
Variable.builder()
502+
.setName(callableName)
503+
.setType(
504+
TypeNode.withReference(
505+
ConcreteReference.builder()
506+
.setClazz(OperationCallable.class)
507+
.setGenerics(
508+
Arrays.asList(
509+
protoMethod.inputType().reference(),
510+
protoMethod.lro().responseType().reference(),
511+
protoMethod.lro().metadataType().reference()))
512+
.build()))
513+
.build());
514+
}
515+
516516
protected List<AnnotationNode> createClassAnnotations(Service service) {
517517
List<AnnotationNode> annotations = new ArrayList<>();
518518
if (!PackageChecker.isGaApi(service.pakkage())) {
@@ -547,7 +547,6 @@ protected List<MethodDefinition> createClassMethods(
547547
service,
548548
typeStore,
549549
classMemberVarExprs,
550-
callableClassMemberVarExprs,
551550
protoMethodNameToDescriptorVarExprs,
552551
classStatements));
553552
javaMethods.addAll(
@@ -646,7 +645,6 @@ protected List<MethodDefinition> createConstructorMethods(
646645
Service service,
647646
TypeStore typeStore,
648647
Map<String, VariableExpr> classMemberVarExprs,
649-
Map<String, VariableExpr> callableClassMemberVarExprs,
650648
Map<String, VariableExpr> protoMethodNameToDescriptorVarExprs,
651649
List<Statement> classStatements) {
652650
TypeNode stubSettingsType =
@@ -786,22 +784,33 @@ protected List<MethodDefinition> createConstructorMethods(
786784
secondCtorStatements.add(EMPTY_LINE_STATEMENT);
787785

788786
// Initialize <method>Callable variables.
789-
secondCtorExprs.addAll(
790-
callableClassMemberVarExprs.entrySet().stream()
791-
.map(
792-
e ->
793-
createCallableInitExpr(
794-
context,
795-
service,
796-
e.getKey(),
797-
e.getValue(),
798-
callableFactoryVarExpr,
799-
settingsVarExpr,
800-
clientContextVarExpr,
801-
operationsStubClassVarExpr,
802-
thisExpr,
803-
javaStyleMethodNameToTransportSettingsVarExprs))
804-
.collect(Collectors.toList()));
787+
// The logic inside createCallableInitExprs() is very similar to createCallableClassMembers().
788+
// It is mostly duplicated because `createCallableClassMembers` returns a heuristic to
789+
// determine the RPC type. The RPCs are mapped by name and the types are determined by the
790+
// generated name and was problematic for certain RPC names. For example, the GetApiOperation
791+
// RPC name would have a mapping of GetApiOperationCallable, and the `createCallableInitExprs`
792+
// method would attempt to generate LRO code because of the `OperationCallable` suffix.
793+
// Instead, we now pass the method object which is the SoT for the type of the method and not
794+
// based on heuristics/ suffix.
795+
for (Method method : service.methods()) {
796+
// Do not generate callables for non supported RPCs (i.e. Bidi-Streaming and Client Streaming
797+
// for HttpJson)
798+
if (!method.isSupportedByTransport(getTransportContext().transport())) {
799+
continue;
800+
}
801+
secondCtorExprs.addAll(
802+
createCallableInitExprs(
803+
context,
804+
service,
805+
method,
806+
typeStore,
807+
callableFactoryVarExpr,
808+
settingsVarExpr,
809+
clientContextVarExpr,
810+
operationsStubClassVarExpr,
811+
thisExpr,
812+
javaStyleMethodNameToTransportSettingsVarExprs));
813+
}
805814
secondCtorStatements.addAll(
806815
secondCtorExprs.stream().map(ExprStatement::withExpr).collect(Collectors.toList()));
807816
secondCtorExprs.clear();
@@ -871,67 +880,116 @@ protected VariableExpr declareLongRunningClient() {
871880
return null;
872881
}
873882

874-
private Expr createCallableInitExpr(
883+
// Can return multiple Exprs for a single RPC. Each of the Exprs will initialize a callable
884+
// in the constructor. The possible combinations are Normal (Unary, Streaming, Batching) and
885+
// either Operation or Paged (if needed). It is not possible to have three callable Exprs
886+
// returned because LROs are not paged, so it will either be an additional LRO or paged callable.
887+
private List<Expr> createCallableInitExprs(
875888
GapicContext context,
876889
Service service,
877-
String callableVarName,
878-
VariableExpr callableVarExpr,
890+
Method method,
891+
TypeStore typeStore,
879892
VariableExpr callableFactoryVarExpr,
880893
VariableExpr settingsVarExpr,
881894
VariableExpr clientContextVarExpr,
882895
VariableExpr operationsStubClassVarExpr,
883896
Expr thisExpr,
884897
Map<String, VariableExpr> javaStyleMethodNameToTransportSettingsVarExprs) {
885-
boolean isOperation = callableVarName.endsWith(OPERATION_CALLABLE_NAME);
886-
boolean isPaged = callableVarName.endsWith(PAGED_CALLABLE_NAME);
887-
int sublength;
888-
if (isOperation) {
889-
sublength = OPERATION_CALLABLE_NAME.length();
890-
} else if (isPaged) {
891-
sublength = PAGED_CALLABLE_NAME.length();
892-
} else {
893-
sublength = CALLABLE_NAME.length();
894-
}
895-
String javaStyleMethodName = callableVarName.substring(0, callableVarName.length() - sublength);
896-
List<Expr> creatorMethodArgVarExprs;
898+
List<Expr> callableInitExprs = new ArrayList<>();
899+
String javaStyleProtoMethodName = JavaStyle.toLowerCamelCase(method.name());
900+
897901
Expr transportSettingsVarExpr =
898-
javaStyleMethodNameToTransportSettingsVarExprs.get(javaStyleMethodName);
899-
if (transportSettingsVarExpr == null && isOperation) {
900-
// Try again, in case the name detection above was inaccurate.
901-
isOperation = false;
902-
sublength = CALLABLE_NAME.length();
903-
javaStyleMethodName = callableVarName.substring(0, callableVarName.length() - sublength);
904-
transportSettingsVarExpr =
905-
javaStyleMethodNameToTransportSettingsVarExprs.get(javaStyleMethodName);
906-
}
902+
javaStyleMethodNameToTransportSettingsVarExprs.get(javaStyleProtoMethodName);
907903
Preconditions.checkNotNull(
908904
transportSettingsVarExpr,
909905
String.format(
910-
"No transport settings variable found for method name %s", javaStyleMethodName));
911-
if (isOperation) {
906+
"No transport settings variable found for method name %s", javaStyleProtoMethodName));
907+
908+
// Build the normal callable which will be generated for every RPC
909+
VariableExpr callableVarExpr =
910+
getCallableExpr(
911+
method, String.format(CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName));
912+
List<Expr> creatorMethodArgVarExprs =
913+
Arrays.asList(
914+
transportSettingsVarExpr,
915+
MethodInvocationExpr.builder()
916+
.setExprReferenceExpr(settingsVarExpr)
917+
.setMethodName(String.format("%sSettings", javaStyleProtoMethodName))
918+
.build(),
919+
clientContextVarExpr);
920+
AssignmentExpr callableExpr =
921+
buildCallableTransportExpr(
922+
context,
923+
service,
924+
callableFactoryVarExpr,
925+
thisExpr,
926+
javaStyleProtoMethodName,
927+
callableVarExpr,
928+
creatorMethodArgVarExprs);
929+
callableInitExprs.add(callableExpr);
930+
931+
// Build an additional paged callable if the RPC is paged. The creatorMethodArgVarExprs is the
932+
// same as the normal callable
933+
if (method.isPaged()) {
934+
callableVarExpr =
935+
getPagedCallableExpr(
936+
typeStore,
937+
method,
938+
String.format(PAGED_CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName));
939+
callableExpr =
940+
buildCallableTransportExpr(
941+
context,
942+
service,
943+
callableFactoryVarExpr,
944+
thisExpr,
945+
javaStyleProtoMethodName,
946+
callableVarExpr,
947+
creatorMethodArgVarExprs);
948+
callableInitExprs.add(callableExpr);
949+
}
950+
951+
// Build an additional operation callable if the RPC is an LRO. Rebuild the
952+
// creatorMethodArgVarExprs as LROs have a special OperationSettings
953+
if (method.hasLro()) {
954+
callableVarExpr =
955+
getOperationCallableExpr(
956+
method,
957+
String.format(OPERATION_CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName));
912958
creatorMethodArgVarExprs =
913959
Arrays.asList(
914960
transportSettingsVarExpr,
915961
MethodInvocationExpr.builder()
916962
.setExprReferenceExpr(settingsVarExpr)
917-
.setMethodName(String.format("%sOperationSettings", javaStyleMethodName))
963+
.setMethodName(String.format("%sOperationSettings", javaStyleProtoMethodName))
918964
.build(),
919965
clientContextVarExpr,
920966
operationsStubClassVarExpr);
921-
} else {
922-
creatorMethodArgVarExprs =
923-
Arrays.asList(
924-
transportSettingsVarExpr,
925-
MethodInvocationExpr.builder()
926-
.setExprReferenceExpr(settingsVarExpr)
927-
.setMethodName(String.format("%sSettings", javaStyleMethodName))
928-
.build(),
929-
clientContextVarExpr);
967+
callableExpr =
968+
buildCallableTransportExpr(
969+
context,
970+
service,
971+
callableFactoryVarExpr,
972+
thisExpr,
973+
javaStyleProtoMethodName,
974+
callableVarExpr,
975+
creatorMethodArgVarExprs);
976+
callableInitExprs.add(callableExpr);
930977
}
931978

932-
String methodName = JavaStyle.toUpperCamelCase(javaStyleMethodName);
979+
return callableInitExprs;
980+
}
981+
982+
private AssignmentExpr buildCallableTransportExpr(
983+
GapicContext context,
984+
Service service,
985+
VariableExpr callableFactoryVarExpr,
986+
Expr thisExpr,
987+
String methodName,
988+
VariableExpr callableVarExpr,
989+
List<Expr> creatorMethodArgVarExprs) {
933990
Optional<String> callableCreatorMethodName =
934-
getCallableCreatorMethodName(context, service, callableVarExpr.type(), methodName);
991+
getCallableCreatorMethodName(
992+
context, service, callableVarExpr.type(), JavaStyle.toUpperCamelCase(methodName));
935993

936994
Expr initExpr;
937995
if (callableCreatorMethodName.isPresent()) {

gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposerTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,13 @@ void generateGrpcServiceStubClass_autopopulateField() {
9292
Assert.assertGoldenClass(this.getClass(), clazz, "GrpcAutoPopulateFieldStub.golden");
9393
Assert.assertEmptySamples(clazz.samples());
9494
}
95+
96+
@Test
97+
void generateGrpcServiceStubClass_callableNameType() {
98+
GapicContext context = GrpcTestProtoLoader.instance().parseCallabeNameType();
99+
Service service = context.services().get(0);
100+
GapicClass clazz = GrpcServiceStubClassComposer.instance().generate(context, service);
101+
Assert.assertGoldenClass(this.getClass(), clazz, "GrpcCallableNameTypeStub.golden");
102+
Assert.assertEmptySamples(clazz.samples());
103+
}
95104
}

0 commit comments

Comments
 (0)