Search in sources :

Example 1 with HttpBindings

use of com.google.api.generator.gapic.model.HttpBindings in project gapic-generator-java by googleapis.

the class Parser method parseMethods.

@VisibleForTesting
static List<Method> parseMethods(ServiceDescriptor serviceDescriptor, String servicePackage, Map<String, Message> messageTypes, Map<String, ResourceName> resourceNames, Optional<GapicServiceConfig> serviceConfigOpt, Set<ResourceName> outputArgResourceNames, Transport transport) {
    List<Method> methods = new ArrayList<>();
    for (MethodDescriptor protoMethod : serviceDescriptor.getMethods()) {
        // Parse the method.
        TypeNode inputType = TypeParser.parseType(protoMethod.getInputType());
        Method.Builder methodBuilder = Method.builder();
        if (protoMethod.getFile().toProto().hasSourceCodeInfo()) {
            SourceCodeInfoLocation protoMethodLocation = SOURCE_CODE_INFO_PARSER.getLocation(protoMethod);
            if (!Objects.isNull(protoMethodLocation) && !Strings.isNullOrEmpty(protoMethodLocation.getLeadingComments())) {
                methodBuilder.setDescription(protoMethodLocation.getLeadingComments());
            }
        }
        boolean isDeprecated = false;
        if (protoMethod.getOptions().hasDeprecated()) {
            isDeprecated = protoMethod.getOptions().getDeprecated();
        }
        Message inputMessage = messageTypes.get(inputType.reference().fullName());
        Preconditions.checkNotNull(inputMessage, String.format("No message found for %s", inputType.reference().fullName()));
        HttpBindings httpBindings = HttpRuleParser.parse(protoMethod, inputMessage, messageTypes);
        boolean isBatching = !serviceConfigOpt.isPresent() ? false : serviceConfigOpt.get().hasBatchingSetting(/* protoPakkage */
        protoMethod.getFile().getPackage(), serviceDescriptor.getName(), protoMethod.getName());
        boolean operationPollingMethod = protoMethod.getOptions().hasExtension(ExtendedOperationsProto.operationPollingMethod) ? protoMethod.getOptions().getExtension(ExtendedOperationsProto.operationPollingMethod) : false;
        RoutingHeaderRule routingHeaderRule = RoutingRuleParser.parse(protoMethod, inputMessage, messageTypes);
        methods.add(methodBuilder.setName(protoMethod.getName()).setInputType(inputType).setOutputType(TypeParser.parseType(protoMethod.getOutputType())).setStream(Method.toStream(protoMethod.isClientStreaming(), protoMethod.isServerStreaming())).setLro(parseLro(servicePackage, protoMethod, messageTypes)).setMethodSignatures(MethodSignatureParser.parseMethodSignatures(protoMethod, servicePackage, inputType, messageTypes, resourceNames, outputArgResourceNames)).setHttpBindings(httpBindings).setRoutingHeaderRule(routingHeaderRule).setIsBatching(isBatching).setPageSizeFieldName(parsePageSizeFieldName(protoMethod, messageTypes, transport)).setIsDeprecated(isDeprecated).setOperationPollingMethod(operationPollingMethod).build());
        // Any input type that has a resource reference will need a resource name helper class.
        for (Field field : inputMessage.fields()) {
            if (field.hasResourceReference()) {
                String resourceTypeString = field.resourceReference().resourceTypeString();
                ResourceName resourceName = null;
                // versus example.com/FooBar.
                if (resourceTypeString.indexOf(SLASH) < 0) {
                    Optional<String> actualResourceTypeNameOpt = resourceNames.keySet().stream().filter(k -> k.substring(k.lastIndexOf(SLASH) + 1).equals(resourceTypeString)).findFirst();
                    if (actualResourceTypeNameOpt.isPresent()) {
                        resourceName = resourceNames.get(actualResourceTypeNameOpt.get());
                    }
                } else {
                    resourceName = resourceNames.get(resourceTypeString);
                }
                if (ResourceNameConstants.WILDCARD_PATTERN.equals(resourceTypeString)) {
                    resourceName = WILDCARD_RESOURCE_NAME;
                } else {
                    Preconditions.checkNotNull(resourceName, String.format("Resource name %s not found; parsing field %s in message %s in method %s", resourceTypeString, field.name(), inputMessage.name(), protoMethod.getName()));
                }
                outputArgResourceNames.add(resourceName);
            }
        }
    }
    return methods;
}
Also used : HttpBindings(com.google.api.generator.gapic.model.HttpBindings) CodeGeneratorRequest(com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest) Arrays(java.util.Arrays) RoutingHeaderRule(com.google.api.generator.gapic.model.RoutingHeaderRule) OperationInfo(com.google.longrunning.OperationInfo) GapicServiceConfig(com.google.api.generator.gapic.model.GapicServiceConfig) DescriptorValidationException(com.google.protobuf.Descriptors.DescriptorValidationException) Field(com.google.api.generator.gapic.model.Field) Method(com.google.api.generator.gapic.model.Method) HttpRule(com.google.api.HttpRule) LongrunningOperation(com.google.api.generator.gapic.model.LongrunningOperation) Map(java.util.Map) ResourceProto(com.google.api.ResourceProto) FieldOptions(com.google.protobuf.DescriptorProtos.FieldOptions) FileDescriptor(com.google.protobuf.Descriptors.FileDescriptor) BiMap(com.google.common.collect.BiMap) ResourceDescriptor(com.google.api.ResourceDescriptor) ImmutableSet(com.google.common.collect.ImmutableSet) ResourceReference(com.google.api.generator.gapic.model.ResourceReference) Collection(java.util.Collection) Set(java.util.Set) FieldDescriptor(com.google.protobuf.Descriptors.FieldDescriptor) OperationsProto(com.google.longrunning.OperationsProto) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) ResourceNameConstants(com.google.api.generator.gapic.utils.ResourceNameConstants) List(java.util.List) FileDescriptorProto(com.google.protobuf.DescriptorProtos.FileDescriptorProto) EnumDescriptor(com.google.protobuf.Descriptors.EnumDescriptor) DocumentationRule(com.google.api.DocumentationRule) Optional(java.util.Optional) Transport(com.google.api.generator.gapic.model.Transport) GapicContext(com.google.api.generator.gapic.model.GapicContext) GapicLanguageSettings(com.google.api.generator.gapic.model.GapicLanguageSettings) IntStream(java.util.stream.IntStream) VaporReference(com.google.api.generator.engine.ast.VaporReference) TypeNode(com.google.api.generator.engine.ast.TypeNode) GapicLroRetrySettings(com.google.api.generator.gapic.model.GapicLroRetrySettings) Descriptor(com.google.protobuf.Descriptors.Descriptor) HashMap(java.util.HashMap) Function(java.util.function.Function) OperationResponseMapping(com.google.cloud.OperationResponseMapping) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Strings(com.google.common.base.Strings) MethodDescriptor(com.google.protobuf.Descriptors.MethodDescriptor) GapicBatchingSettings(com.google.api.generator.gapic.model.GapicBatchingSettings) Maps(com.google.common.collect.Maps) ResourceName(com.google.api.generator.gapic.model.ResourceName) Service(com.google.api.generator.gapic.model.Service) HashBiMap(com.google.common.collect.HashBiMap) ServiceOptions(com.google.protobuf.DescriptorProtos.ServiceOptions) ExtendedOperationsProto(com.google.cloud.ExtendedOperationsProto) EnumValueDescriptor(com.google.protobuf.Descriptors.EnumValueDescriptor) Preconditions(com.google.common.base.Preconditions) ServiceDescriptor(com.google.protobuf.Descriptors.ServiceDescriptor) OperationResponse(com.google.api.generator.gapic.model.OperationResponse) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Message(com.google.api.generator.gapic.model.Message) MethodOptions(com.google.protobuf.DescriptorProtos.MethodOptions) Collections(java.util.Collections) ClientProto(com.google.api.ClientProto) MessageOptions(com.google.protobuf.DescriptorProtos.MessageOptions) SourceCodeInfoLocation(com.google.api.generator.gapic.model.SourceCodeInfoLocation) Message(com.google.api.generator.gapic.model.Message) HttpBindings(com.google.api.generator.gapic.model.HttpBindings) ResourceName(com.google.api.generator.gapic.model.ResourceName) ArrayList(java.util.ArrayList) Method(com.google.api.generator.gapic.model.Method) MethodDescriptor(com.google.protobuf.Descriptors.MethodDescriptor) Field(com.google.api.generator.gapic.model.Field) SourceCodeInfoLocation(com.google.api.generator.gapic.model.SourceCodeInfoLocation) RoutingHeaderRule(com.google.api.generator.gapic.model.RoutingHeaderRule) TypeNode(com.google.api.generator.engine.ast.TypeNode) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 2 with HttpBindings

use of com.google.api.generator.gapic.model.HttpBindings in project gapic-generator-java by googleapis.

the class HttpRuleParserTest method parseHttpAnnotation_multipleBindings.

@Test
public void parseHttpAnnotation_multipleBindings() {
    FileDescriptor testingFileDescriptor = TestingOuterClass.getDescriptor();
    ServiceDescriptor testingService = testingFileDescriptor.getServices().get(0);
    assertEquals("Testing", testingService.getName());
    Map<String, Message> messages = Parser.parseMessages(testingFileDescriptor);
    // VerityTest method.
    MethodDescriptor rpcMethod = testingService.getMethods().get(testingService.getMethods().size() - 1);
    Message inputMessage = messages.get("com.google.showcase.v1beta1.VerifyTestRequest");
    HttpBindings httpBindings = HttpRuleParser.parse(rpcMethod, inputMessage, messages);
    assertThat(httpBindings.pathParameters().stream().map(HttpBinding::name).collect(Collectors.toList())).containsExactly("answer", "foo", "name", "test_to_verify.name", "type");
}
Also used : Message(com.google.api.generator.gapic.model.Message) HttpBindings(com.google.api.generator.gapic.model.HttpBindings) ServiceDescriptor(com.google.protobuf.Descriptors.ServiceDescriptor) MethodDescriptor(com.google.protobuf.Descriptors.MethodDescriptor) FileDescriptor(com.google.protobuf.Descriptors.FileDescriptor) Test(org.junit.Test)

Example 3 with HttpBindings

use of com.google.api.generator.gapic.model.HttpBindings in project gapic-generator-java by googleapis.

the class Parser method parseServices.

public static List<Service> parseServices(CodeGeneratorRequest request, Map<String, Message> messageTypes, Map<String, ResourceName> resourceNames, Set<ResourceName> outputArgResourceNames, Optional<com.google.api.Service> serviceYamlProtoOpt, Optional<GapicServiceConfig> serviceConfigOpt, List<Service> outputMixinServices, Transport transport) {
    Map<String, FileDescriptor> fileDescriptors = getFilesToGenerate(request);
    List<Service> services = new ArrayList<>();
    for (String fileToGenerate : request.getFileToGenerateList()) {
        FileDescriptor fileDescriptor = Preconditions.checkNotNull(fileDescriptors.get(fileToGenerate), "Missing file descriptor for [%s]", fileToGenerate);
        services.addAll(parseService(fileDescriptor, messageTypes, resourceNames, serviceYamlProtoOpt, serviceConfigOpt, outputArgResourceNames, transport));
    }
    // Prevent codegen for mixed-in services if there are other services present, since that is an
    // indicator that we are not generating a GAPIC client for the mixed-in service on its own.
    Function<Service, String> serviceFullNameFn = s -> String.format("%s.%s", s.protoPakkage(), s.name());
    Set<Service> blockedCodegenMixinApis = new HashSet<>();
    Set<Service> definedServices = new HashSet<>();
    for (Service s : services) {
        if (MIXIN_ALLOWLIST.contains(serviceFullNameFn.apply(s))) {
            blockedCodegenMixinApis.add(s);
        } else {
            definedServices.add(s);
        }
    }
    // It's very unlikely the blocklisted APIs will contain the other, or any other service.
    boolean servicesContainBlocklistedApi = !blockedCodegenMixinApis.isEmpty() && !definedServices.isEmpty();
    // Service names that are stated in the YAML file (as mixins). Used to filter
    // blockedCodegenMixinApis.
    Set<String> mixedInApis = !serviceYamlProtoOpt.isPresent() ? Collections.emptySet() : serviceYamlProtoOpt.get().getApisList().stream().filter(a -> MIXIN_ALLOWLIST.contains(a.getName())).map(a -> a.getName()).collect(Collectors.toSet());
    // Holds the methods to be mixed in.
    // Key: proto_package.ServiceName.RpcName.
    // Value: HTTP rules, which clobber those in the proto.
    // Assumes that http.rules.selector always specifies RPC names in the above format.
    Map<String, HttpBindings> mixedInMethodsToHttpRules = new HashMap<>();
    Map<String, String> mixedInMethodsToDocs = new HashMap<>();
    // Parse HTTP rules and documentation, which will override the proto.
    if (serviceYamlProtoOpt.isPresent()) {
        for (HttpRule httpRule : serviceYamlProtoOpt.get().getHttp().getRulesList()) {
            HttpBindings httpBindings = HttpRuleParser.parseHttpRule(httpRule);
            if (httpBindings == null) {
                continue;
            }
            for (String rpcFullNameRaw : httpRule.getSelector().split(",")) {
                String rpcFullName = rpcFullNameRaw.trim();
                mixedInMethodsToHttpRules.put(rpcFullName, httpBindings);
            }
        }
        for (DocumentationRule docRule : serviceYamlProtoOpt.get().getDocumentation().getRulesList()) {
            for (String rpcFullNameRaw : docRule.getSelector().split(",")) {
                String rpcFullName = rpcFullNameRaw.trim();
                mixedInMethodsToDocs.put(rpcFullName, docRule.getDescription());
            }
        }
    }
    // Sort potential mixin services alphabetically.
    List<Service> orderedBlockedCodegenMixinApis = blockedCodegenMixinApis.stream().sorted((s1, s2) -> s2.name().compareTo(s1.name())).collect(Collectors.toList());
    Set<String> apiDefinedRpcs = new HashSet<>();
    for (Service service : services) {
        if (orderedBlockedCodegenMixinApis.contains(service)) {
            continue;
        }
        apiDefinedRpcs.addAll(service.methods().stream().map(m -> m.name()).collect(Collectors.toSet()));
    }
    // Mix-in APIs only if the protos are present and they're defined in the service.yaml file.
    Set<Service> outputMixinServiceSet = new HashSet<>();
    if (servicesContainBlocklistedApi && !mixedInApis.isEmpty()) {
        for (int i = 0; i < services.size(); i++) {
            Service originalService = services.get(i);
            List<Method> updatedOriginalServiceMethods = new ArrayList<>(originalService.methods());
            // If mixin APIs are present, add the methods to all other services.
            for (Service mixinService : orderedBlockedCodegenMixinApis) {
                final String mixinServiceFullName = serviceFullNameFn.apply(mixinService);
                if (!mixedInApis.contains(mixinServiceFullName)) {
                    continue;
                }
                Function<Method, String> methodToFullProtoNameFn = m -> String.format("%s.%s", mixinServiceFullName, m.name());
                // Filter mixed-in methods based on those listed in the HTTP rules section of
                // service.yaml.
                List<Method> updatedMixinMethods = mixinService.methods().stream().filter(m -> mixedInMethodsToHttpRules.containsKey(methodToFullProtoNameFn.apply(m))).map(m -> {
                    // HTTP rules and RPC documentation in the service.yaml file take
                    // precedence.
                    String fullMethodName = methodToFullProtoNameFn.apply(m);
                    HttpBindings httpBindings = mixedInMethodsToHttpRules.containsKey(fullMethodName) ? mixedInMethodsToHttpRules.get(fullMethodName) : m.httpBindings();
                    String docs = mixedInMethodsToDocs.containsKey(fullMethodName) ? mixedInMethodsToDocs.get(fullMethodName) : m.description();
                    return m.toBuilder().setHttpBindings(httpBindings).setDescription(docs).build();
                }).collect(Collectors.toList());
                // Overridden RPCs defined in the protos take precedence.
                updatedMixinMethods.stream().filter(m -> !apiDefinedRpcs.contains(m.name())).forEach(m -> updatedOriginalServiceMethods.add(m.toBuilder().setMixedInApiName(serviceFullNameFn.apply(mixinService)).build()));
                // Sort by method name, to ensure a deterministic method ordering (for tests).
                updatedMixinMethods = updatedMixinMethods.stream().sorted((m1, m2) -> m2.name().compareTo(m1.name())).collect(Collectors.toList());
                outputMixinServiceSet.add(mixinService.toBuilder().setMethods(updatedMixinMethods).build());
            }
            services.set(i, originalService.toBuilder().setMethods(updatedOriginalServiceMethods).build());
        }
    }
    if (servicesContainBlocklistedApi) {
        services = services.stream().filter(s -> !MIXIN_ALLOWLIST.contains(serviceFullNameFn.apply(s))).collect(Collectors.toList());
    }
    // Use a list to ensure ordering for deterministic tests.
    outputMixinServices.addAll(outputMixinServiceSet.stream().sorted((s1, s2) -> s2.name().compareTo(s1.name())).collect(Collectors.toList()));
    return services;
}
Also used : HttpBindings(com.google.api.generator.gapic.model.HttpBindings) CodeGeneratorRequest(com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest) Arrays(java.util.Arrays) RoutingHeaderRule(com.google.api.generator.gapic.model.RoutingHeaderRule) OperationInfo(com.google.longrunning.OperationInfo) GapicServiceConfig(com.google.api.generator.gapic.model.GapicServiceConfig) DescriptorValidationException(com.google.protobuf.Descriptors.DescriptorValidationException) Field(com.google.api.generator.gapic.model.Field) Method(com.google.api.generator.gapic.model.Method) HttpRule(com.google.api.HttpRule) LongrunningOperation(com.google.api.generator.gapic.model.LongrunningOperation) Map(java.util.Map) ResourceProto(com.google.api.ResourceProto) FieldOptions(com.google.protobuf.DescriptorProtos.FieldOptions) FileDescriptor(com.google.protobuf.Descriptors.FileDescriptor) BiMap(com.google.common.collect.BiMap) ResourceDescriptor(com.google.api.ResourceDescriptor) ImmutableSet(com.google.common.collect.ImmutableSet) ResourceReference(com.google.api.generator.gapic.model.ResourceReference) Collection(java.util.Collection) Set(java.util.Set) FieldDescriptor(com.google.protobuf.Descriptors.FieldDescriptor) OperationsProto(com.google.longrunning.OperationsProto) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) ResourceNameConstants(com.google.api.generator.gapic.utils.ResourceNameConstants) List(java.util.List) FileDescriptorProto(com.google.protobuf.DescriptorProtos.FileDescriptorProto) EnumDescriptor(com.google.protobuf.Descriptors.EnumDescriptor) DocumentationRule(com.google.api.DocumentationRule) Optional(java.util.Optional) Transport(com.google.api.generator.gapic.model.Transport) GapicContext(com.google.api.generator.gapic.model.GapicContext) GapicLanguageSettings(com.google.api.generator.gapic.model.GapicLanguageSettings) IntStream(java.util.stream.IntStream) VaporReference(com.google.api.generator.engine.ast.VaporReference) TypeNode(com.google.api.generator.engine.ast.TypeNode) GapicLroRetrySettings(com.google.api.generator.gapic.model.GapicLroRetrySettings) Descriptor(com.google.protobuf.Descriptors.Descriptor) HashMap(java.util.HashMap) Function(java.util.function.Function) OperationResponseMapping(com.google.cloud.OperationResponseMapping) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Strings(com.google.common.base.Strings) MethodDescriptor(com.google.protobuf.Descriptors.MethodDescriptor) GapicBatchingSettings(com.google.api.generator.gapic.model.GapicBatchingSettings) Maps(com.google.common.collect.Maps) ResourceName(com.google.api.generator.gapic.model.ResourceName) Service(com.google.api.generator.gapic.model.Service) HashBiMap(com.google.common.collect.HashBiMap) ServiceOptions(com.google.protobuf.DescriptorProtos.ServiceOptions) ExtendedOperationsProto(com.google.cloud.ExtendedOperationsProto) EnumValueDescriptor(com.google.protobuf.Descriptors.EnumValueDescriptor) Preconditions(com.google.common.base.Preconditions) ServiceDescriptor(com.google.protobuf.Descriptors.ServiceDescriptor) OperationResponse(com.google.api.generator.gapic.model.OperationResponse) VisibleForTesting(com.google.common.annotations.VisibleForTesting) Message(com.google.api.generator.gapic.model.Message) MethodOptions(com.google.protobuf.DescriptorProtos.MethodOptions) Collections(java.util.Collections) ClientProto(com.google.api.ClientProto) MessageOptions(com.google.protobuf.DescriptorProtos.MessageOptions) SourceCodeInfoLocation(com.google.api.generator.gapic.model.SourceCodeInfoLocation) HttpBindings(com.google.api.generator.gapic.model.HttpBindings) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) Service(com.google.api.generator.gapic.model.Service) Method(com.google.api.generator.gapic.model.Method) FileDescriptor(com.google.protobuf.Descriptors.FileDescriptor) HttpRule(com.google.api.HttpRule) DocumentationRule(com.google.api.DocumentationRule) HashSet(java.util.HashSet)

Example 4 with HttpBindings

use of com.google.api.generator.gapic.model.HttpBindings in project gapic-generator-java by googleapis.

the class HttpRuleParserTest method parseHttpAnnotation_basic.

@Test
public void parseHttpAnnotation_basic() {
    FileDescriptor testingFileDescriptor = TestingOuterClass.getDescriptor();
    ServiceDescriptor testingService = testingFileDescriptor.getServices().get(0);
    assertEquals("Testing", testingService.getName());
    Map<String, Message> messages = Parser.parseMessages(testingFileDescriptor);
    // CreateSession method.
    MethodDescriptor rpcMethod = testingService.getMethods().get(0);
    Message inputMessage = messages.get("com.google.showcase.v1beta1.CreateSessionRequest");
    HttpBindings httpBindings = HttpRuleParser.parse(rpcMethod, inputMessage, messages);
    assertTrue(httpBindings.pathParameters().isEmpty());
    // GetSession method.
    rpcMethod = testingService.getMethods().get(1);
    inputMessage = messages.get("com.google.showcase.v1beta1.GetSessionRequest");
    httpBindings = HttpRuleParser.parse(rpcMethod, inputMessage, messages);
    assertThat(httpBindings.pathParameters().stream().map(HttpBinding::name).collect(Collectors.toList())).containsExactly("name");
}
Also used : Message(com.google.api.generator.gapic.model.Message) HttpBindings(com.google.api.generator.gapic.model.HttpBindings) ServiceDescriptor(com.google.protobuf.Descriptors.ServiceDescriptor) MethodDescriptor(com.google.protobuf.Descriptors.MethodDescriptor) FileDescriptor(com.google.protobuf.Descriptors.FileDescriptor) Test(org.junit.Test)

Aggregations

HttpBindings (com.google.api.generator.gapic.model.HttpBindings)4 Message (com.google.api.generator.gapic.model.Message)4 FileDescriptor (com.google.protobuf.Descriptors.FileDescriptor)4 MethodDescriptor (com.google.protobuf.Descriptors.MethodDescriptor)4 ServiceDescriptor (com.google.protobuf.Descriptors.ServiceDescriptor)4 ClientProto (com.google.api.ClientProto)2 DocumentationRule (com.google.api.DocumentationRule)2 HttpRule (com.google.api.HttpRule)2 ResourceDescriptor (com.google.api.ResourceDescriptor)2 ResourceProto (com.google.api.ResourceProto)2 TypeNode (com.google.api.generator.engine.ast.TypeNode)2 VaporReference (com.google.api.generator.engine.ast.VaporReference)2 Field (com.google.api.generator.gapic.model.Field)2 GapicBatchingSettings (com.google.api.generator.gapic.model.GapicBatchingSettings)2 GapicContext (com.google.api.generator.gapic.model.GapicContext)2 GapicLanguageSettings (com.google.api.generator.gapic.model.GapicLanguageSettings)2 GapicLroRetrySettings (com.google.api.generator.gapic.model.GapicLroRetrySettings)2 GapicServiceConfig (com.google.api.generator.gapic.model.GapicServiceConfig)2 LongrunningOperation (com.google.api.generator.gapic.model.LongrunningOperation)2 Method (com.google.api.generator.gapic.model.Method)2