Skip to content

Commit 4e59a68

Browse files
committed
[2/3]Implement Paged Callable Method (#608)
1 parent a876211 commit 4e59a68

File tree

11 files changed

+571
-15
lines changed

11 files changed

+571
-15
lines changed

src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,8 @@ private static List<MethodDefinition> createServiceMethods(
501501
createLroCallableMethod(service, method, types, messageTypes, resourceNames));
502502
}
503503
if (method.isPaged()) {
504-
javaMethods.add(createPagedCallableMethod(service, method, types));
504+
javaMethods.add(
505+
createPagedCallableMethod(service, method, types, messageTypes, resourceNames));
505506
}
506507
javaMethods.add(createCallableMethod(service, method, types));
507508
}
@@ -702,16 +703,13 @@ private static MethodDefinition createCallableMethod(
702703
}
703704

704705
private static MethodDefinition createPagedCallableMethod(
705-
Service service, Method method, Map<String, TypeNode> types) {
706-
// TODO(summerji): Implement sample code for paged callable method and pass in actual map of
707-
// Messages and ResourceNames
706+
Service service,
707+
Method method,
708+
Map<String, TypeNode> types,
709+
Map<String, Message> messageTypes,
710+
Map<String, ResourceName> resourceNames) {
708711
return createCallableMethod(
709-
service,
710-
method,
711-
CallableMethodKind.PAGED,
712-
types,
713-
Collections.emptyMap(),
714-
Collections.emptyMap());
712+
service, method, CallableMethodKind.PAGED, types, messageTypes, resourceNames);
715713
}
716714

717715
private static MethodDefinition createCallableMethod(
@@ -763,8 +761,7 @@ private static MethodDefinition createCallableMethod(
763761
.build();
764762

765763
Optional<String> sampleCode = Optional.empty();
766-
// TODO (summerji): Implement sample code for CallableMethodKind.PAGED and
767-
// CallableMethodKind.REGULAR
764+
// TODO (summerji): Implement sample code for CallableMethodKind.REGULAR
768765
if (callableMethodKind.equals(CallableMethodKind.LRO)) {
769766
sampleCode =
770767
Optional.of(
@@ -774,6 +771,15 @@ private static MethodDefinition createCallableMethod(
774771
resourceNames,
775772
messageTypes));
776773
}
774+
if (callableMethodKind.equals(CallableMethodKind.PAGED)) {
775+
sampleCode =
776+
Optional.of(
777+
ServiceClientSampleCodeComposer.composePagedCallableMethodHeaderSampleCode(
778+
method,
779+
types.get(ClassNames.getServiceClientClassName(service)),
780+
resourceNames,
781+
messageTypes));
782+
}
777783

778784
return MethodDefinition.builder()
779785
.setHeaderCommentStatements(

src/main/java/com/google/api/generator/gapic/composer/ServiceClientSampleCodeComposer.java

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.google.api.generator.gapic.composer;
1616

17+
import com.google.api.core.ApiFuture;
1718
import com.google.api.gax.core.FixedCredentialsProvider;
1819
import com.google.api.gax.longrunning.OperationFuture;
1920
import com.google.api.generator.engine.ast.AssignmentExpr;
@@ -398,6 +399,121 @@ public static String composeLroCallableMethodHeaderSampleCode(
398399
.build());
399400
}
400401

402+
public static String composePagedCallableMethodHeaderSampleCode(
403+
Method method,
404+
TypeNode clientType,
405+
Map<String, ResourceName> resourceNames,
406+
Map<String, Message> messageTypes) {
407+
VariableExpr clientVarExpr =
408+
VariableExpr.withVariable(
409+
Variable.builder()
410+
.setName(JavaStyle.toLowerCamelCase(clientType.reference().name()))
411+
.setType(clientType)
412+
.build());
413+
// Assign method's request variable with the default value.
414+
VariableExpr requestVarExpr =
415+
VariableExpr.withVariable(
416+
Variable.builder().setName("request").setType(method.inputType()).build());
417+
Message requestMessage = messageTypes.get(method.inputType().reference().simpleName());
418+
Preconditions.checkNotNull(requestMessage);
419+
Expr requestBuilderExpr =
420+
DefaultValueComposer.createSimpleMessageBuilderExpr(
421+
requestMessage, resourceNames, messageTypes);
422+
AssignmentExpr requestAssignmentExpr =
423+
AssignmentExpr.builder()
424+
.setVariableExpr(requestVarExpr.toBuilder().setIsDecl(true).build())
425+
.setValueExpr(requestBuilderExpr)
426+
.build();
427+
428+
List<Expr> bodyExprs = new ArrayList<>();
429+
bodyExprs.add(requestAssignmentExpr);
430+
431+
// Find the repeated field.
432+
Message methodOutputMessage = messageTypes.get(method.outputType().reference().simpleName());
433+
Field repeatedPagedResultsField = methodOutputMessage.findAndUnwrapFirstRepeatedField();
434+
Preconditions.checkNotNull(
435+
repeatedPagedResultsField,
436+
String.format(
437+
"No repeated field found on message %s for method %s",
438+
methodOutputMessage.name(), method.name()));
439+
TypeNode repeatedResponseType = repeatedPagedResultsField.type();
440+
441+
// Create ApiFuture Variable Expression with assign value by invoking client paged callable
442+
// method.
443+
// e.g. ApiFuture<ListExclusionsPagedResponse> future =
444+
// configServiceV2Client.listExclusionsPagedCallable().futureCall(request);
445+
TypeNode apiFutureType =
446+
TypeNode.withReference(
447+
ConcreteReference.builder()
448+
.setClazz(ApiFuture.class)
449+
.setGenerics(repeatedResponseType.reference())
450+
.build());
451+
VariableExpr apiFutureVarExpr =
452+
VariableExpr.withVariable(
453+
Variable.builder().setName("future").setType(apiFutureType).build());
454+
MethodInvocationExpr pagedCallableFutureMethodExpr =
455+
MethodInvocationExpr.builder()
456+
.setExprReferenceExpr(clientVarExpr)
457+
.setMethodName(
458+
String.format("%sPagedCallable", JavaStyle.toLowerCamelCase(method.name())))
459+
.build();
460+
pagedCallableFutureMethodExpr =
461+
MethodInvocationExpr.builder()
462+
.setExprReferenceExpr(pagedCallableFutureMethodExpr)
463+
.setMethodName("futureCall")
464+
.setArguments(requestVarExpr)
465+
.setReturnType(apiFutureType)
466+
.build();
467+
AssignmentExpr apiFutureAssignmentExpr =
468+
AssignmentExpr.builder()
469+
.setVariableExpr(apiFutureVarExpr.toBuilder().setIsDecl(true).build())
470+
.setValueExpr(pagedCallableFutureMethodExpr)
471+
.build();
472+
bodyExprs.add(apiFutureAssignmentExpr);
473+
474+
List<Statement> bodyStatements =
475+
bodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList());
476+
bodyExprs.clear();
477+
478+
// Add line comment
479+
bodyStatements.add(CommentStatement.withComment(LineComment.withComment("Do something.")));
480+
481+
// For-loop on repeated response element
482+
// e.g. for (ListExclusionsResponse element : future.get().iterateAll()) {
483+
// // doThingsWith(element);
484+
// }
485+
VariableExpr repeatedResponseVarExpr =
486+
VariableExpr.withVariable(
487+
Variable.builder().setName("element").setType(repeatedResponseType).build());
488+
MethodInvocationExpr futureGetIterateAllMethodExpr =
489+
MethodInvocationExpr.builder()
490+
.setExprReferenceExpr(apiFutureVarExpr)
491+
.setMethodName("get")
492+
.build();
493+
futureGetIterateAllMethodExpr =
494+
MethodInvocationExpr.builder()
495+
.setExprReferenceExpr(futureGetIterateAllMethodExpr)
496+
.setMethodName("iterateAll")
497+
.setReturnType(repeatedResponseType)
498+
.build();
499+
CommentStatement lineCommentStatement =
500+
CommentStatement.withComment(LineComment.withComment("doThingsWith(element);"));
501+
ForStatement repeatedResponseForStatement =
502+
ForStatement.builder()
503+
.setLocalVariableExpr(repeatedResponseVarExpr.toBuilder().setIsDecl(true).build())
504+
.setCollectionExpr(futureGetIterateAllMethodExpr)
505+
.setBody(Arrays.asList(lineCommentStatement))
506+
.build();
507+
bodyStatements.add(repeatedResponseForStatement);
508+
509+
return SampleCodeWriter.write(
510+
TryCatchStatement.builder()
511+
.setTryResourceExpr(assignClientVariableWithCreateMethodExpr(clientVarExpr))
512+
.setTryBody(bodyStatements)
513+
.setIsSampleCode(true)
514+
.build());
515+
}
516+
401517
private static List<Statement> composeUnaryRpcMethodSampleCodeBodyStatements(
402518
Method method,
403519
VariableExpr clientVarExpr,

src/test/java/com/google/api/generator/gapic/composer/ServiceClientSampleCodeComposerTest.java

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,4 +1505,180 @@ public void validComposeLroCallableMethodHeaderSampleCode_withReturnVoid() {
15051505
"}");
15061506
assertEquals(results, expected);
15071507
}
1508+
1509+
// ================================Paged Callable Method Sample Code ====================//
1510+
@Test
1511+
public void validComposePagedCallableMethodHeaderSampleCode() {
1512+
FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor();
1513+
Map<String, ResourceName> resourceNames = Parser.parseResourceNames(echoFileDescriptor);
1514+
Map<String, Message> messageTypes = Parser.parseMessages(echoFileDescriptor);
1515+
TypeNode clientType =
1516+
TypeNode.withReference(
1517+
VaporReference.builder()
1518+
.setName("EchoClient")
1519+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1520+
.build());
1521+
TypeNode inputType =
1522+
TypeNode.withReference(
1523+
VaporReference.builder()
1524+
.setName("PagedExpandRequest")
1525+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1526+
.build());
1527+
TypeNode outputType =
1528+
TypeNode.withReference(
1529+
VaporReference.builder()
1530+
.setName("PagedExpandResponse")
1531+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1532+
.build());
1533+
Method method =
1534+
Method.builder()
1535+
.setName("PagedExpand")
1536+
.setInputType(inputType)
1537+
.setOutputType(outputType)
1538+
.setIsPaged(true)
1539+
.build();
1540+
String results =
1541+
ServiceClientSampleCodeComposer.composePagedCallableMethodHeaderSampleCode(
1542+
method, clientType, resourceNames, messageTypes);
1543+
String expected =
1544+
LineFormatter.lines(
1545+
"try (EchoClient echoClient = EchoClient.create()) {\n",
1546+
" PagedExpandRequest request =\n",
1547+
" PagedExpandRequest.newBuilder()\n",
1548+
" .setContent(\"content951530617\")\n",
1549+
" .setPageSize(883849137)\n",
1550+
" .setPageToken(\"pageToken873572522\")\n",
1551+
" .build();\n",
1552+
" ApiFuture<EchoResponse> future = echoClient.pagedExpandPagedCallable().futureCall(request);\n",
1553+
" // Do something.\n",
1554+
" for (EchoResponse element : future.get().iterateAll()) {\n",
1555+
" // doThingsWith(element);\n",
1556+
" }\n",
1557+
"}");
1558+
assertEquals(results, expected);
1559+
}
1560+
1561+
@Test
1562+
public void invalidComposePagedCallableMethodHeaderSampleCode_inputTypeNotExistInMessage() {
1563+
FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor();
1564+
Map<String, ResourceName> resourceNames = Parser.parseResourceNames(echoFileDescriptor);
1565+
Map<String, Message> messageTypes = Parser.parseMessages(echoFileDescriptor);
1566+
TypeNode clientType =
1567+
TypeNode.withReference(
1568+
VaporReference.builder()
1569+
.setName("EchoClient")
1570+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1571+
.build());
1572+
TypeNode inputType =
1573+
TypeNode.withReference(
1574+
VaporReference.builder()
1575+
.setName("NotExistRequest")
1576+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1577+
.build());
1578+
TypeNode outputType =
1579+
TypeNode.withReference(
1580+
VaporReference.builder()
1581+
.setName("PagedExpandResponse")
1582+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1583+
.build());
1584+
Method method =
1585+
Method.builder()
1586+
.setName("PagedExpand")
1587+
.setInputType(inputType)
1588+
.setOutputType(outputType)
1589+
.setIsPaged(true)
1590+
.build();
1591+
assertThrows(
1592+
NullPointerException.class,
1593+
() ->
1594+
ServiceClientSampleCodeComposer.composePagedCallableMethodHeaderSampleCode(
1595+
method, clientType, resourceNames, messageTypes));
1596+
}
1597+
1598+
@Test
1599+
public void invalidComposePagedCallableMethodHeaderSampleCode_noExistMethodResponse() {
1600+
FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor();
1601+
Map<String, ResourceName> resourceNames = Parser.parseResourceNames(echoFileDescriptor);
1602+
Map<String, Message> messageTypes = Parser.parseMessages(echoFileDescriptor);
1603+
TypeNode clientType =
1604+
TypeNode.withReference(
1605+
VaporReference.builder()
1606+
.setName("EchoClient")
1607+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1608+
.build());
1609+
TypeNode inputType =
1610+
TypeNode.withReference(
1611+
VaporReference.builder()
1612+
.setName("EchoRequest")
1613+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1614+
.build());
1615+
TypeNode outputType =
1616+
TypeNode.withReference(
1617+
VaporReference.builder()
1618+
.setName("NoExistResponse")
1619+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1620+
.build());
1621+
Method method =
1622+
Method.builder()
1623+
.setName("PagedExpand")
1624+
.setInputType(inputType)
1625+
.setOutputType(outputType)
1626+
.setIsPaged(true)
1627+
.build();
1628+
assertThrows(
1629+
NullPointerException.class,
1630+
() ->
1631+
ServiceClientSampleCodeComposer.composePagedCallableMethodHeaderSampleCode(
1632+
method, clientType, resourceNames, messageTypes));
1633+
}
1634+
1635+
@Test
1636+
public void invalidComposePagedCallableMethodHeaderSampleCode_noRepeatedResponse() {
1637+
FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor();
1638+
Map<String, ResourceName> resourceNames = Parser.parseResourceNames(echoFileDescriptor);
1639+
Map<String, Message> messageTypes = Parser.parseMessages(echoFileDescriptor);
1640+
TypeNode clientType =
1641+
TypeNode.withReference(
1642+
VaporReference.builder()
1643+
.setName("EchoClient")
1644+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1645+
.build());
1646+
TypeNode inputType =
1647+
TypeNode.withReference(
1648+
VaporReference.builder()
1649+
.setName("EchoRequest")
1650+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1651+
.build());
1652+
TypeNode outputType =
1653+
TypeNode.withReference(
1654+
VaporReference.builder()
1655+
.setName("NoRepeatedResponse")
1656+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1657+
.build());
1658+
Method method =
1659+
Method.builder()
1660+
.setName("PagedExpand")
1661+
.setInputType(inputType)
1662+
.setOutputType(outputType)
1663+
.setIsPaged(true)
1664+
.build();
1665+
Field responseField = Field.builder().setName("response").setType(TypeNode.STRING).build();
1666+
Message noRepeatedResponseMessage =
1667+
Message.builder()
1668+
.setName("NoRepeatedResponse")
1669+
.setType(
1670+
TypeNode.withReference(
1671+
VaporReference.builder()
1672+
.setName("NoRepeatedResponse")
1673+
.setPakkage(SHOWCASE_PACKAGE_NAME)
1674+
.build()))
1675+
.setFields(Arrays.asList(responseField))
1676+
.build();
1677+
messageTypes.put("NoRepeatedResponse", noRepeatedResponseMessage);
1678+
assertThrows(
1679+
NullPointerException.class,
1680+
() ->
1681+
ServiceClientSampleCodeComposer.composePagedCallableMethodHeaderSampleCode(
1682+
method, clientType, resourceNames, messageTypes));
1683+
}
15081684
}

0 commit comments

Comments
 (0)