From 35cc21c3ea5cbd5fd9efcc609f8a1757a7adab2b Mon Sep 17 00:00:00 2001 From: Gabriel Gonzalez Date: Mon, 23 Aug 2021 04:53:10 -0400 Subject: [PATCH 1/9] DIREGAPIC LRO implementation without annotations (#826) * fix ServiceStub Goldens * fix Stub golden * fix Stub golden * fix CallableFactory golden * fix java format * add annotation placement comments * only add machinery to methods that return operation * add grpc file that contained method that was edited on abstract class * update HttpJsonComplianceStub.golden * java format --- WORKSPACE | 2 +- .../AbstractServiceStubClassComposer.java | 16 +- .../grpc/GrpcServiceStubClassComposer.java | 6 +- ...onServiceCallableFactoryClassComposer.java | 131 +++++++- .../HttpJsonServiceStubClassComposer.java | 297 +++++++++++++++++- .../HttpJsonComplianceCallableFactory.golden | 13 +- .../HttpJsonAddressesCallableFactory.java | 12 +- .../v1/stub/HttpJsonAddressesStub.java | 49 +++ ...tpJsonRegionOperationsCallableFactory.java | 12 +- .../v1/stub/HttpJsonRegionOperationsStub.java | 26 ++ 10 files changed, 550 insertions(+), 14 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 7468b3246d..1b8335256f 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -32,7 +32,7 @@ jvm_maven_import_external( # gapic-generator-java dependencies to match the order in googleapis repository, # which in its turn, prioritizes actual generated clients runtime dependencies # over the generator dependencies. -_gax_java_version = "1.65.1" +_gax_java_version = "2.2.0" http_archive( name = "com_google_api_gax_java", diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java index 034c94c949..524f8f6361 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java @@ -52,6 +52,7 @@ import com.google.api.generator.gapic.model.GapicClass; import com.google.api.generator.gapic.model.GapicClass.Kind; import com.google.api.generator.gapic.model.GapicContext; +import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; @@ -159,12 +160,14 @@ public GapicClass generate(GapicContext context, Service service) { .setType(getTransportContext().stubCallableFactoryType()) .build())); + Map messageTypes = context.messages(); List classStatements = createClassStatements( service, protoMethodNameToDescriptorVarExprs, callableClassMemberVarExprs, - classMemberVarExprs); + classMemberVarExprs, + messageTypes); StubCommentComposer commentComposer = new StubCommentComposer(getTransportContext().transportName()); @@ -193,7 +196,7 @@ public GapicClass generate(GapicContext context, Service service) { } protected abstract Statement createMethodDescriptorVariableDecl( - Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr); + Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr, Map messageTypes); protected abstract List createOperationsStubGetterMethod( VariableExpr operationsStubVarExpr); @@ -212,10 +215,11 @@ protected List createClassStatements( Service service, Map protoMethodNameToDescriptorVarExprs, Map callableClassMemberVarExprs, - Map classMemberVarExprs) { + Map classMemberVarExprs, + Map messageTypes) { List classStatements = new ArrayList<>(); for (Statement statement : - createMethodDescriptorVariableDecls(service, protoMethodNameToDescriptorVarExprs)) { + createMethodDescriptorVariableDecls(service, protoMethodNameToDescriptorVarExprs, messageTypes)) { classStatements.add(statement); classStatements.add(EMPTY_LINE_STATEMENT); } @@ -228,12 +232,12 @@ protected List createClassStatements( } protected List createMethodDescriptorVariableDecls( - Service service, Map protoMethodNameToDescriptorVarExprs) { + Service service, Map protoMethodNameToDescriptorVarExprs, Map messageTypes) { return service.methods().stream() .map( m -> createMethodDescriptorVariableDecl( - service, m, protoMethodNameToDescriptorVarExprs.get(m.name()))) + service, m, protoMethodNameToDescriptorVarExprs.get(m.name()), messageTypes)) .collect(Collectors.toList()); } diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java index f079aba780..3fc25a95b2 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java @@ -34,6 +34,7 @@ import com.google.api.generator.gapic.composer.common.AbstractServiceStubClassComposer; import com.google.api.generator.gapic.composer.store.TypeStore; import com.google.api.generator.gapic.model.HttpBindings.HttpBinding; +import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; @@ -85,7 +86,10 @@ private static TypeStore createStaticTypes() { @Override protected Statement createMethodDescriptorVariableDecl( - Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr) { + Service service, + Method protoMethod, + VariableExpr methodDescriptorVarExpr, + Map messageTypes) { MethodInvocationExpr methodDescriptorMaker = MethodInvocationExpr.builder() .setMethodName("newBuilder") diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java index f9c4045cb9..191c1d15fa 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java @@ -16,14 +16,27 @@ import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.httpjson.ApiMessage; +import com.google.api.gax.httpjson.HttpJsonCallableFactory; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; +import com.google.api.gax.rpc.OperationCallable; +import com.google.api.gax.rpc.UnaryCallable; import com.google.api.generator.engine.ast.AnnotationNode; +import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.ConcreteReference; +import com.google.api.generator.engine.ast.ExprStatement; import com.google.api.generator.engine.ast.MethodDefinition; +import com.google.api.generator.engine.ast.MethodInvocationExpr; +import com.google.api.generator.engine.ast.NewObjectExpr; +import com.google.api.generator.engine.ast.Statement; import com.google.api.generator.engine.ast.TypeNode; -import com.google.api.generator.engine.ast.ValueExpr; +import com.google.api.generator.engine.ast.VaporReference; +import com.google.api.generator.engine.ast.Variable; +import com.google.api.generator.engine.ast.VariableExpr; import com.google.api.generator.gapic.composer.common.AbstractServiceCallableFactoryClassComposer; import com.google.api.generator.gapic.composer.store.TypeStore; import com.google.api.generator.gapic.model.Service; +import com.google.longrunning.Operation; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -90,6 +103,7 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { "The surface for long-running operations is not stable yet and may change in the" + " future."); + // Generate generic method without the body MethodDefinition method = createGenericCallableMethod( typeStore, @@ -104,6 +118,119 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { .map(n -> (Object) n) .collect(Collectors.toList()), Arrays.asList(betaAnnotation)); - return method.toBuilder().setReturnExpr(ValueExpr.createNullExpr()).build(); + + List createOperationCallableBody = new ArrayList(2); + + List arguments = method.arguments(); + Variable httpJsonCallSettingsVar = arguments.get(0).variable(); + Variable callSettingsVar = arguments.get(1).variable(); + Variable clientContextVar = arguments.get(2).variable(); + Variable operationsStub = arguments.get(3).variable(); + // Generate innerCallable + VariableExpr innerCallableVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setName("innerCallable") + .setType( + TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) + .build()) + .setTemplateObjects(Arrays.asList(requestTemplateName, methodVariantName)) + .build(); + MethodInvocationExpr getInitialCallSettingsExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(VariableExpr.withVariable(callSettingsVar)) + .setMethodName("getInitialCallSettings") + .build(); + MethodInvocationExpr createBaseUnaryCallableExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType( + TypeNode.withReference(ConcreteReference.withClazz(HttpJsonCallableFactory.class))) + .setMethodName("createBaseUnaryCallable") + .setArguments( + VariableExpr.withVariable(httpJsonCallSettingsVar), + getInitialCallSettingsExpr, + VariableExpr.withVariable(clientContextVar)) + .setReturnType(TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) + .build(); + AssignmentExpr innerCallableAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(innerCallableVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(createBaseUnaryCallableExpr) + .build(); + createOperationCallableBody.add(ExprStatement.withExpr(innerCallableAssignExpr)); + + // Generate initialCallable + VariableExpr initialCallableVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setName("initialCallable") + .setType( + TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) + .build()) + .setTemplateObjects(Arrays.asList(requestTemplateName, methodVariantName)) + .build(); + MethodInvocationExpr getMethodDescriptorExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(VariableExpr.withVariable(httpJsonCallSettingsVar)) + .setMethodName("getMethodDescriptor") + .build(); + MethodInvocationExpr getOperationSnapshotFactoryExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(getMethodDescriptorExpr) + .setMethodName("getOperationSnapshotFactory") + .build(); + // This is a temporary solution + VaporReference requestT = + VaporReference.builder() + .setName("RequestT") + .setPakkage("com.google.cloud.compute.v1.stub") + .build(); + TypeNode operationSnapshotCallableType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(HttpJsonOperationSnapshotCallable.class) + .setGenerics(requestT, ConcreteReference.withClazz(Operation.class)) + .build()); + NewObjectExpr initialCallableObject = + NewObjectExpr.builder() + .setType(operationSnapshotCallableType) + .setIsGeneric(true) + .setArguments(innerCallableVarExpr, getOperationSnapshotFactoryExpr) + .build(); + AssignmentExpr initialCallableAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(initialCallableVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(initialCallableObject) + .build(); + createOperationCallableBody.add(ExprStatement.withExpr(initialCallableAssignExpr)); + + // Generate return statement + MethodInvocationExpr longRunningClient = + MethodInvocationExpr.builder() + .setExprReferenceExpr(VariableExpr.withVariable(operationsStub)) + .setMethodName("longRunningClient") + .build(); + MethodInvocationExpr createOperationCallable = + MethodInvocationExpr.builder() + .setStaticReferenceType( + TypeNode.withReference(ConcreteReference.withClazz(HttpJsonCallableFactory.class))) + .setMethodName("createOperationCallable") + .setArguments( + VariableExpr.withVariable(callSettingsVar), + VariableExpr.withVariable(clientContextVar), + longRunningClient, + initialCallableVarExpr) + .setReturnType( + TypeNode.withReference(ConcreteReference.withClazz(OperationCallable.class))) + .build(); + + // Add body and return statement to method + return method + .toBuilder() + .setBody(createOperationCallableBody) + .setReturnExpr(createOperationCallable) + .build(); } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java index 901dceacc6..66fdfb2b4e 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java @@ -19,10 +19,12 @@ import com.google.api.gax.httpjson.ApiMethodDescriptor; import com.google.api.gax.httpjson.FieldsExtractor; import com.google.api.gax.httpjson.HttpJsonCallSettings; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshot; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.httpjson.ProtoMessageRequestFormatter; import com.google.api.gax.httpjson.ProtoMessageResponseParser; import com.google.api.gax.httpjson.ProtoRestSerializer; +import com.google.api.gax.longrunning.OperationSnapshot; import com.google.api.generator.engine.ast.AnnotationNode; import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.ConcreteReference; @@ -34,16 +36,19 @@ import com.google.api.generator.engine.ast.MethodDefinition; import com.google.api.generator.engine.ast.MethodInvocationExpr; import com.google.api.generator.engine.ast.NewObjectExpr; +import com.google.api.generator.engine.ast.PrimitiveValue; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; import com.google.api.generator.engine.ast.StringObjectValue; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; +import com.google.api.generator.engine.ast.VaporReference; import com.google.api.generator.engine.ast.Variable; import com.google.api.generator.engine.ast.VariableExpr; import com.google.api.generator.gapic.composer.common.AbstractServiceStubClassComposer; import com.google.api.generator.gapic.composer.store.TypeStore; import com.google.api.generator.gapic.model.HttpBindings.HttpBinding; +import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; @@ -91,7 +96,10 @@ private static TypeStore createStaticTypes() { @Override protected Statement createMethodDescriptorVariableDecl( - Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr) { + Service service, + Method protoMethod, + VariableExpr methodDescriptorVarExpr, + Map messageTypes) { MethodInvocationExpr expr = MethodInvocationExpr.builder() .setMethodName("newBuilder") @@ -116,6 +124,22 @@ protected Statement createMethodDescriptorVariableDecl( methodMaker.apply("setRequestFormatter", getRequestFormatterExpr(protoMethod)).apply(expr); expr = methodMaker.apply("setResponseParser", setResponseParserExpr(protoMethod)).apply(expr); + // System.out.println(protoMethod.outputType().reference().simpleName()); + if (protoMethod.outputType().reference().simpleName().equals("Operation")) { + expr = + methodMaker + .apply( + "setOperationSnapshotFactory", + setOperationSnapshotFactoryExpr(protoMethod, messageTypes)) + .apply(expr); + expr = + methodMaker + .apply( + "setPollingRequestFactory", + setPollingRequestFactoryExpr(protoMethod, messageTypes)) + .apply(expr); + } + expr = MethodInvocationExpr.builder() .setMethodName("build") @@ -356,6 +380,277 @@ private List setResponseParserExpr(Method protoMethod) { return Collections.singletonList(expr); } + private List setOperationSnapshotFactoryExpr( + Method protoMethod, Map messageTypes) { + + BiFunction, Function> + methodMaker = getMethodMaker(); + + // Generate input varibles for create() + VariableExpr requestVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(protoMethod.inputType()).setName("request").build()); + VariableExpr responseVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(protoMethod.outputType()).setName("response").build()); + + List createBody = new ArrayList(4); + + // Generate opName + // This will be replaced and edited based on annotations + TypeNode stringBuilderType = + TypeNode.withReference(ConcreteReference.withClazz(StringBuilder.class)); + VariableExpr opNameVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(stringBuilderType).setName("opName").build()); + MethodInvocationExpr getId = + MethodInvocationExpr.builder() + .setMethodName("getId") + .setExprReferenceExpr(responseVarExpr) + .build(); + Expr opNameObjectExpr = + NewObjectExpr.builder().setType(stringBuilderType).setArguments(getId).build(); + AssignmentExpr opNameAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(opNameVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(opNameObjectExpr) + .build(); + createBody.add(ExprStatement.withExpr(opNameAssignExpr)); + + // Generate changes opName + // This will be replaced and edited based on annotations + MethodInvocationExpr requestGetProjectExpr = + MethodInvocationExpr.builder() + .setMethodName("getProject") + .setExprReferenceExpr(requestVarExpr) + .build(); + ValueExpr colonValueExpr = + ValueExpr.builder().setValue(StringObjectValue.builder().setValue(":").build()).build(); + MethodInvocationExpr opNameAppendColonProjectExpr = + MethodInvocationExpr.builder() + .setMethodName("append") + .setArguments(colonValueExpr) + .setExprReferenceExpr(opNameVarExpr) + .build(); + opNameAppendColonProjectExpr = + methodMaker + .apply("append", Collections.singletonList(requestGetProjectExpr)) + .apply(opNameAppendColonProjectExpr); + createBody.add(ExprStatement.withExpr(opNameAppendColonProjectExpr)); + + // Generate changes to opName + MethodInvocationExpr requestGetRegionExpr = + MethodInvocationExpr.builder() + .setMethodName("getRegion") + .setExprReferenceExpr(requestVarExpr) + .build(); + MethodInvocationExpr opNameAppendColonRegionExpr = + MethodInvocationExpr.builder() + .setMethodName("append") + .setArguments(colonValueExpr) + .setExprReferenceExpr(opNameVarExpr) + .build(); + opNameAppendColonRegionExpr = + methodMaker + .apply("append", Collections.singletonList(requestGetRegionExpr)) + .apply(opNameAppendColonRegionExpr); + createBody.add(ExprStatement.withExpr(opNameAppendColonRegionExpr)); + + // Generate check status expression + // This will be replaced and edited based on annotations + MethodInvocationExpr getStatusExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName("getStatus") + .build(); + TypeNode statusType = + TypeNode.withReference( + VaporReference.builder() + .setName("Status") + .setPakkage("com.google.cloud.compute.v1") + .setIsStaticImport(false) + .build()); + VariableExpr statusDoneExpr = + VariableExpr.builder() + .setVariable(Variable.builder().setName("DONE").setType(TypeNode.INT).build()) + .setStaticReferenceType(statusType) + .build(); + MethodInvocationExpr statusEqualsExpr = + methodMaker.apply("equals", Collections.singletonList(statusDoneExpr)).apply(getStatusExpr); + + // Generate return statement + TypeNode httpJsonOperationSnapshotType = + TypeNode.withReference(ConcreteReference.withClazz(HttpJsonOperationSnapshot.class)); + MethodInvocationExpr newBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(httpJsonOperationSnapshotType) + .setMethodName("newBuilder") + .build(); + MethodInvocationExpr opNameToStringExpr = + MethodInvocationExpr.builder() + .setMethodName("toString") + .setExprReferenceExpr(opNameVarExpr) + .build(); + // This will be replaced and edited based on annotations + MethodInvocationExpr getHttpErrorStatusCodeExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName("getHttpErrorStatusCode") + .build(); + // This will be replaced and edited based on annotations + MethodInvocationExpr getHttpErrorMessageExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName("getHttpErrorMessage") + .build(); + newBuilderExpr = + methodMaker + .apply("setName", Collections.singletonList(opNameToStringExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setMetadata", Collections.singletonList(responseVarExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setDone", Collections.singletonList(statusEqualsExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setResponse", Collections.singletonList(responseVarExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setError", Arrays.asList(getHttpErrorStatusCodeExpr, getHttpErrorMessageExpr)) + .apply(newBuilderExpr); + TypeNode operationSnapshotType = + TypeNode.withReference( + ConcreteReference.builder().setClazz(OperationSnapshot.class).build()); + MethodInvocationExpr buildExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(newBuilderExpr) + .setMethodName("build") + .setReturnType(operationSnapshotType) + .build(); + + // Generate lambda anonymous class + return Collections.singletonList( + LambdaExpr.builder() + .setArguments( + requestVarExpr.toBuilder().setIsDecl(true).build(), + responseVarExpr.toBuilder().setIsDecl(true).build()) + .setBody(createBody) + .setReturnExpr(buildExpr) + .build()); + } + + private List setPollingRequestFactoryExpr( + Method protoMethod, Map messageTypes) { + + BiFunction, Function> + methodMaker = getMethodMaker(); + + List createBody = new ArrayList(1); + + // Generate input variables for create + VariableExpr compoundOperationIdVarExpr = + VariableExpr.builder() + .setVariable( + Variable.builder().setType(TypeNode.STRING).setName("compoundOperationId").build()) + .build(); + + // Generate idComponenets + TypeNode listStringType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(List.class) + .setGenerics(ConcreteReference.withClazz(String.class)) + .build()); + TypeNode arrayListStringType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(ArrayList.class) + .setGenerics(ConcreteReference.withClazz(String.class)) + .build()); + TypeNode arraysType = TypeNode.withReference(ConcreteReference.withClazz(Arrays.class)); + VariableExpr idComponentsVarExpr = + VariableExpr.withVariable( + Variable.builder().setName("idComponents").setType(listStringType).build()); + MethodInvocationExpr compoundOperationIdSplitExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(compoundOperationIdVarExpr) + .setMethodName("split") + .setArguments(ValueExpr.withValue(StringObjectValue.withValue(":"))) + .setReturnType(arrayListStringType) + .build(); + MethodInvocationExpr asListExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(arraysType) + .setMethodName("asList") + .setArguments(compoundOperationIdSplitExpr) + .setReturnType(arrayListStringType) + .build(); + AssignmentExpr idComponentsAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(idComponentsVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(asListExpr) + .build(); + createBody.add(ExprStatement.withExpr(idComponentsAssignExpr)); + + // Generate return statement + // This will be replaced and edited based on annotations + TypeNode getRegionOperationRequestType = + TypeNode.withReference( + VaporReference.builder() + .setName("GetRegionOperationRequest") + .setPakkage("com.google.cloud.compute.v1") + .setIsStaticImport(false) + .build()); + MethodInvocationExpr newBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(getRegionOperationRequestType) + .setMethodName("newBuilder") + .build(); + newBuilderExpr = + methodMaker + .apply("setOperation", Collections.singletonList(getExpr(idComponentsVarExpr, "0"))) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setProject", Collections.singletonList(getExpr(idComponentsVarExpr, "1"))) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setRegion", Collections.singletonList(getExpr(idComponentsVarExpr, "2"))) + .apply(newBuilderExpr); + MethodInvocationExpr buildExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(newBuilderExpr) + .setMethodName("build") + .setReturnType(getRegionOperationRequestType) + .build(); + + // Return lambda anonymous class + return Collections.singletonList( + LambdaExpr.builder() + .setArguments(compoundOperationIdVarExpr.toBuilder().setIsDecl(true).build()) + .setBody(createBody) + .setReturnExpr(buildExpr) + .build()); + } + + // returns var.get(num); + private MethodInvocationExpr getExpr(VariableExpr var, String num) { + return MethodInvocationExpr.builder() + .setExprReferenceExpr(var) + .setMethodName("get") + .setArguments( + ValueExpr.builder() + .setValue(PrimitiveValue.builder().setValue(num).setType(TypeNode.INT).build()) + .build()) + .build(); + } + private Expr createFieldsExtractorClassInstance( Method method, TypeNode extractorReturnType, diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden index 7d6032778d..0b58310417 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden @@ -5,6 +5,7 @@ import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.httpjson.ApiMessage; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.rpc.BatchingCallSettings; import com.google.api.gax.rpc.ClientContext; @@ -13,6 +14,8 @@ import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; +import com.google.cloud.compute.v1.stub.RequestT; +import com.google.longrunning.Operation; import javax.annotation.Generated; // AUTO-GENERATED DOCUMENTATION AND CLASS. @@ -63,6 +66,14 @@ public class HttpJsonComplianceCallableFactory OperationCallSettings callSettings, ClientContext clientContext, BackgroundResource operationsStub) { - return null; + UnaryCallable innerCallable = + HttpJsonCallableFactory.createBaseUnaryCallable( + httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); + UnaryCallable initialCallable = + new HttpJsonOperationSnapshotCallable( + innerCallable, + httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); + return HttpJsonCallableFactory.createOperationCallable( + callSettings, clientContext, operationsStub.longRunningClient(), initialCallable); } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java index afa275a6f5..49347e5792 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java @@ -21,6 +21,7 @@ import com.google.api.gax.httpjson.ApiMessage; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.rpc.BatchingCallSettings; import com.google.api.gax.rpc.ClientContext; @@ -29,6 +30,7 @@ import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; +import com.google.longrunning.Operation; import javax.annotation.Generated; // AUTO-GENERATED DOCUMENTATION AND CLASS. @@ -79,6 +81,14 @@ OperationCallable createOperationCallable( OperationCallSettings callSettings, ClientContext clientContext, BackgroundResource operationsStub) { - return null; + UnaryCallable innerCallable = + HttpJsonCallableFactory.createBaseUnaryCallable( + httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); + UnaryCallable initialCallable = + new HttpJsonOperationSnapshotCallable( + innerCallable, + httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); + return HttpJsonCallableFactory.createOperationCallable( + callSettings, clientContext, operationsStub.longRunningClient(), initialCallable); } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java index d8d960d342..e2d4a26060 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java @@ -26,21 +26,26 @@ import com.google.api.gax.core.BackgroundResourceAggregation; import com.google.api.gax.httpjson.ApiMethodDescriptor; import com.google.api.gax.httpjson.HttpJsonCallSettings; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshot; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.httpjson.ProtoMessageRequestFormatter; import com.google.api.gax.httpjson.ProtoMessageResponseParser; import com.google.api.gax.httpjson.ProtoRestSerializer; +import com.google.api.gax.longrunning.OperationSnapshot; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.UnaryCallable; import com.google.cloud.compute.v1.AddressAggregatedList; import com.google.cloud.compute.v1.AddressList; import com.google.cloud.compute.v1.AggregatedListAddressesRequest; import com.google.cloud.compute.v1.DeleteAddressRequest; +import com.google.cloud.compute.v1.GetRegionOperationRequest; import com.google.cloud.compute.v1.InsertAddressRequest; import com.google.cloud.compute.v1.ListAddressesRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Status; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -137,6 +142,28 @@ public class HttpJsonAddressesStub extends AddressesStub { ProtoMessageResponseParser.newBuilder() .setDefaultInstance(Operation.getDefaultInstance()) .build()) + .setOperationSnapshotFactory( + (DeleteAddressRequest request, Operation response) -> { + StringBuilder opName = new StringBuilder(response.getId()); + opName.append(":").append(request.getProject()); + opName.append(":").append(request.getRegion()); + return HttpJsonOperationSnapshot.newBuilder() + .setName(opName.toString()) + .setMetadata(response) + .setDone(response.getStatus().equals(Status.DONE)) + .setResponse(response) + .setError(response.getHttpErrorStatusCode(), response.getHttpErrorMessage()) + .build(); + }) + .setPollingRequestFactory( + compoundOperationId -> { + List idComponents = Arrays.asList(compoundOperationId.split(":")); + return GetRegionOperationRequest.newBuilder() + .setOperation(idComponents.get(0)) + .setProject(idComponents.get(1)) + .setRegion(idComponents.get(2)) + .build(); + }) .build(); private static final ApiMethodDescriptor insertMethodDescriptor = @@ -174,6 +201,28 @@ public class HttpJsonAddressesStub extends AddressesStub { ProtoMessageResponseParser.newBuilder() .setDefaultInstance(Operation.getDefaultInstance()) .build()) + .setOperationSnapshotFactory( + (InsertAddressRequest request, Operation response) -> { + StringBuilder opName = new StringBuilder(response.getId()); + opName.append(":").append(request.getProject()); + opName.append(":").append(request.getRegion()); + return HttpJsonOperationSnapshot.newBuilder() + .setName(opName.toString()) + .setMetadata(response) + .setDone(response.getStatus().equals(Status.DONE)) + .setResponse(response) + .setError(response.getHttpErrorStatusCode(), response.getHttpErrorMessage()) + .build(); + }) + .setPollingRequestFactory( + compoundOperationId -> { + List idComponents = Arrays.asList(compoundOperationId.split(":")); + return GetRegionOperationRequest.newBuilder() + .setOperation(idComponents.get(0)) + .setProject(idComponents.get(1)) + .setRegion(idComponents.get(2)) + .build(); + }) .build(); private static final ApiMethodDescriptor listMethodDescriptor = diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java index 6dac14a84e..6113b5f496 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java @@ -21,6 +21,7 @@ import com.google.api.gax.httpjson.ApiMessage; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.rpc.BatchingCallSettings; import com.google.api.gax.rpc.ClientContext; @@ -29,6 +30,7 @@ import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; +import com.google.longrunning.Operation; import javax.annotation.Generated; // AUTO-GENERATED DOCUMENTATION AND CLASS. @@ -79,6 +81,14 @@ OperationCallable createOperationCallable( OperationCallSettings callSettings, ClientContext clientContext, BackgroundResource operationsStub) { - return null; + UnaryCallable innerCallable = + HttpJsonCallableFactory.createBaseUnaryCallable( + httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); + UnaryCallable initialCallable = + new HttpJsonOperationSnapshotCallable( + innerCallable, + httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); + return HttpJsonCallableFactory.createOperationCallable( + callSettings, clientContext, operationsStub.longRunningClient(), initialCallable); } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java index 9d90915792..47bc6a36a7 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java @@ -23,16 +23,20 @@ import com.google.api.gax.core.BackgroundResourceAggregation; import com.google.api.gax.httpjson.ApiMethodDescriptor; import com.google.api.gax.httpjson.HttpJsonCallSettings; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshot; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.httpjson.ProtoMessageRequestFormatter; import com.google.api.gax.httpjson.ProtoMessageResponseParser; import com.google.api.gax.httpjson.ProtoRestSerializer; +import com.google.api.gax.longrunning.OperationSnapshot; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.UnaryCallable; import com.google.cloud.compute.v1.GetRegionOperationRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.Status; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -79,6 +83,28 @@ public class HttpJsonRegionOperationsStub extends RegionOperationsStub { ProtoMessageResponseParser.newBuilder() .setDefaultInstance(Operation.getDefaultInstance()) .build()) + .setOperationSnapshotFactory( + (GetRegionOperationRequest request, Operation response) -> { + StringBuilder opName = new StringBuilder(response.getId()); + opName.append(":").append(request.getProject()); + opName.append(":").append(request.getRegion()); + return HttpJsonOperationSnapshot.newBuilder() + .setName(opName.toString()) + .setMetadata(response) + .setDone(response.getStatus().equals(Status.DONE)) + .setResponse(response) + .setError(response.getHttpErrorStatusCode(), response.getHttpErrorMessage()) + .build(); + }) + .setPollingRequestFactory( + compoundOperationId -> { + List idComponents = Arrays.asList(compoundOperationId.split(":")); + return GetRegionOperationRequest.newBuilder() + .setOperation(idComponents.get(0)) + .setProject(idComponents.get(1)) + .setRegion(idComponents.get(2)) + .build(); + }) .build(); private final UnaryCallable getCallable; From 00d94ed6a15d9f75874691ffc875df6f1af223e3 Mon Sep 17 00:00:00 2001 From: Vadym Matsishevskyi <25311427+vam-google@users.noreply.github.com> Date: Tue, 24 Aug 2021 01:02:39 -0700 Subject: [PATCH 2/9] Diregapic lro (#828) * feat: enable self signed jwt for gapic clients (#794) * feat: enable self signed jwt for gapic clients * resolve comments * update gax version * update goldens * update golden files * chore: release 2.1.0 (#827) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> * ingegrate with latest googleapis and googleapis-discovery * ingegrate with latest googleapis and googleapis-discovery Co-authored-by: arithmetic1728 <58957152+arithmetic1728@users.noreply.github.com> Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 7 ++ WORKSPACE | 2 +- repositories.bzl | 10 ++- .../java/com/google/api/generator/BUILD.bazel | 1 + .../google/api/generator/ProtoRegistry.java | 2 + ...tractServiceStubSettingsClassComposer.java | 60 +++++++------ .../ServiceStubSettingsClassComposer.java | 43 +++++++++ .../DeprecatedServiceStubSettings.golden | 4 +- .../grpc/goldens/EchoStubSettings.golden | 4 +- .../LoggingServiceV2StubSettings.golden | 4 +- .../grpc/goldens/PublisherStubSettings.golden | 4 +- .../cloud/asset/v1/AssetServiceClient.java | 88 ++++++++++++++++--- .../asset/v1/AssetServiceClientTest.java | 58 ++++++++++++ .../cloud/asset/v1/AssetServiceSettings.java | 15 +++- .../cloud/asset/v1/MockAssetServiceImpl.java | 21 +++++ .../google/cloud/asset/v1/gapic_metadata.json | 3 + .../google/cloud/asset/v1/package-info.java | 1 + .../cloud/asset/v1/stub/AssetServiceStub.java | 9 +- .../v1/stub/AssetServiceStubSettings.java | 48 ++++++++-- .../asset/v1/stub/GrpcAssetServiceStub.java | 36 +++++++- .../cloud/compute/v1/AddressesClientTest.java | 8 +- .../v1/RegionOperationsClientTest.java | 4 +- .../v1/stub/IamCredentialsStubSettings.java | 4 +- .../iam/v1/stub/IAMPolicyStubSettings.java | 4 +- .../KeyManagementServiceStubSettings.java | 4 +- .../v1/stub/LibraryServiceStubSettings.java | 4 +- .../v2/stub/ConfigServiceV2StubSettings.java | 4 +- .../v2/stub/LoggingServiceV2StubSettings.java | 4 +- .../v2/stub/MetricsServiceV2StubSettings.java | 4 +- .../pubsub/v1/SubscriptionAdminClient.java | 2 + .../v1/SubscriptionAdminClientTest.java | 7 ++ .../cloud/pubsub/v1/TopicAdminClient.java | 2 + .../cloud/pubsub/v1/TopicAdminClientTest.java | 6 ++ .../pubsub/v1/stub/PublisherStubSettings.java | 4 +- .../v1/stub/SchemaServiceStubSettings.java | 4 +- .../v1/stub/SubscriberStubSettings.java | 4 +- .../v1beta1/stub/CloudRedisStubSettings.java | 4 +- .../storage/v2/stub/StorageStubSettings.java | 4 +- version.txt | 2 +- 39 files changed, 418 insertions(+), 81 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5679cf07f3..47548ec096 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [2.1.0](https://www.github.com/googleapis/gapic-generator-java/compare/v2.0.1...v2.1.0) (2021-08-17) + + +### Features + +* enable self signed jwt for gapic clients ([#794](https://www.github.com/googleapis/gapic-generator-java/issues/794)) ([1b7ee1e](https://www.github.com/googleapis/gapic-generator-java/commit/1b7ee1e3911e1c8ecab9a94d68d7a59b437d2449)) + ### [2.0.1](https://www.github.com/googleapis/gapic-generator-java/compare/v2.0.0...v2.0.1) (2021-08-06) diff --git a/WORKSPACE b/WORKSPACE index 1b8335256f..21e5f8ea67 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -32,7 +32,7 @@ jvm_maven_import_external( # gapic-generator-java dependencies to match the order in googleapis repository, # which in its turn, prioritizes actual generated clients runtime dependencies # over the generator dependencies. -_gax_java_version = "2.2.0" +_gax_java_version = "2.3.0" http_archive( name = "com_google_api_gax_java", diff --git a/repositories.bzl b/repositories.bzl index 67493dba45..f2074f578d 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -59,18 +59,20 @@ def gapic_generator_java_repositories(): _maybe( http_archive, name = "com_google_googleapis", - strip_prefix = "googleapis-efecdbf96311bb705d619459280ffc651b10844a", + strip_prefix = "googleapis-ba30d8097582039ac4cc4e21b4e4baa426423075", urls = [ - "https://github.com/googleapis/googleapis/archive/efecdbf96311bb705d619459280ffc651b10844a.zip", + "https://github.com/googleapis/googleapis/archive/ba30d8097582039ac4cc4e21b4e4baa426423075.zip", ], ) + # TODO: replace with upstream googleapis-discovery link once + # https://github.com/googleapis/googleapis-discovery/pull/59 is merged _maybe( http_archive, name = "com_google_googleapis_discovery", - strip_prefix = "googleapis-discovery-abf4cec1ce9e02e4d7d650bf66137c347cdd0d44", + strip_prefix = "googleapis-discovery-2872d382ff767518e63d59ececf5d6f9224b21b4", urls = [ - "https://github.com/googleapis/googleapis-discovery/archive/abf4cec1ce9e02e4d7d650bf66137c347cdd0d44.zip", + "https://github.com/vam-google/googleapis-discovery/archive/2872d382ff767518e63d59ececf5d6f9224b21b4.zip", ], ) diff --git a/src/main/java/com/google/api/generator/BUILD.bazel b/src/main/java/com/google/api/generator/BUILD.bazel index de7f95f193..4e678b5b7d 100644 --- a/src/main/java/com/google/api/generator/BUILD.bazel +++ b/src/main/java/com/google/api/generator/BUILD.bazel @@ -39,6 +39,7 @@ java_library( "//src/main/java/com/google/api/generator/gapic/model", "//src/main/java/com/google/api/generator/util", "@com_google_googleapis//google/api:api_java_proto", + "@com_google_googleapis//google/cloud:extended_operations_java_proto", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_guava_guava//jar", "@com_google_protobuf//:protobuf_java", diff --git a/src/main/java/com/google/api/generator/ProtoRegistry.java b/src/main/java/com/google/api/generator/ProtoRegistry.java index da4806bba0..d4cce56dcf 100644 --- a/src/main/java/com/google/api/generator/ProtoRegistry.java +++ b/src/main/java/com/google/api/generator/ProtoRegistry.java @@ -18,6 +18,7 @@ import com.google.api.ClientProto; import com.google.api.FieldBehaviorProto; import com.google.api.ResourceProto; +import com.google.cloud.ExtendedOperationsProto; import com.google.longrunning.OperationsProto; import com.google.protobuf.ExtensionRegistry; @@ -29,5 +30,6 @@ public static void registerAllExtensions(ExtensionRegistry extensionRegistry) { ClientProto.registerAllExtensions(extensionRegistry); ResourceProto.registerAllExtensions(extensionRegistry); FieldBehaviorProto.registerAllExtensions(extensionRegistry); + ExtendedOperationsProto.registerAllExtensions(extensionRegistry); } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java index 1d89768a58..c999fccb9d 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java @@ -139,8 +139,6 @@ public abstract class AbstractServiceStubSettingsClassComposer implements ClassC protected static final TypeStore FIXED_TYPESTORE = createStaticTypes(); - private static final VariableExpr DEFAULT_SERVICE_SCOPES_VAR_EXPR = - createDefaultServiceScopesVarExpr(); private static final VariableExpr NESTED_UNARY_METHOD_SETTINGS_BUILDERS_VAR_EXPR = createNestedUnaryMethodSettingsBuildersVarExpr(); private static final VariableExpr NESTED_RETRYABLE_CODE_DEFINITIONS_VAR_EXPR = @@ -150,6 +148,9 @@ public abstract class AbstractServiceStubSettingsClassComposer implements ClassC private final TransportContext transportContext; + protected static final VariableExpr DEFAULT_SERVICE_SCOPES_VAR_EXPR = + createDefaultServiceScopesVarExpr(); + protected AbstractServiceStubSettingsClassComposer(TransportContext transportContext) { this.transportContext = transportContext; } @@ -197,6 +198,33 @@ public GapicClass generate(GapicContext context, Service service) { return GapicClass.create(GapicClass.Kind.STUB, classDef); } + protected MethodDefinition createDefaultCredentialsProviderBuilderMethod() { + TypeNode returnType = + TypeNode.withReference( + ConcreteReference.withClazz(GoogleCredentialsProvider.Builder.class)); + MethodInvocationExpr credsProviderBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(FIXED_TYPESTORE.get("GoogleCredentialsProvider")) + .setMethodName("newBuilder") + .build(); + credsProviderBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(credsProviderBuilderExpr) + .setMethodName("setScopesToApply") + .setArguments(DEFAULT_SERVICE_SCOPES_VAR_EXPR) + .setReturnType(returnType) + .build(); + return MethodDefinition.builder() + .setHeaderCommentStatements( + SettingsCommentComposer.DEFAULT_CREDENTIALS_PROVIDER_BUILDER_METHOD_COMMENT) + .setScope(ScopeNode.PUBLIC) + .setIsStatic(true) + .setReturnType(returnType) + .setName("defaultCredentialsProviderBuilder") + .setReturnExpr(credsProviderBuilderExpr) + .build(); + } + protected abstract MethodDefinition createDefaultTransportTransportProviderBuilderMethod(); protected abstract MethodDefinition createDefaultApiClientHeaderProviderBuilderMethod( @@ -992,33 +1020,7 @@ private List createDefaultHelperAndGetterMethods( .setReturnExpr(DEFAULT_SERVICE_SCOPES_VAR_EXPR) .build()); - // Create the defaultCredentialsProviderBuilder method. - returnType = - TypeNode.withReference( - ConcreteReference.withClazz(GoogleCredentialsProvider.Builder.class)); - MethodInvocationExpr credsProviderBuilderExpr = - MethodInvocationExpr.builder() - .setStaticReferenceType(FIXED_TYPESTORE.get("GoogleCredentialsProvider")) - .setMethodName("newBuilder") - .build(); - credsProviderBuilderExpr = - MethodInvocationExpr.builder() - .setExprReferenceExpr(credsProviderBuilderExpr) - .setMethodName("setScopesToApply") - .setArguments(DEFAULT_SERVICE_SCOPES_VAR_EXPR) - .setReturnType(returnType) - .build(); - javaMethods.add( - MethodDefinition.builder() - .setHeaderCommentStatements( - SettingsCommentComposer.DEFAULT_CREDENTIALS_PROVIDER_BUILDER_METHOD_COMMENT) - .setScope(ScopeNode.PUBLIC) - .setIsStatic(true) - .setReturnType(returnType) - .setName("defaultCredentialsProviderBuilder") - .setReturnExpr(credsProviderBuilderExpr) - .build()); - + javaMethods.add(createDefaultCredentialsProviderBuilderMethod()); javaMethods.add(createDefaultTransportTransportProviderBuilderMethod()); javaMethods.add(createDefaultTransportChannelProviderMethod()); javaMethods.add(createDefaultApiClientHeaderProviderBuilderMethod(service, typeStore)); diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposer.java index ceba11ee62..6d0b8e221d 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposer.java @@ -14,6 +14,7 @@ package com.google.api.generator.gapic.composer.grpc; +import com.google.api.gax.core.GoogleCredentialsProvider; import com.google.api.gax.grpc.GaxGrpcProperties; import com.google.api.gax.grpc.GrpcTransportChannel; import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider; @@ -22,6 +23,7 @@ import com.google.api.generator.engine.ast.ConcreteReference; import com.google.api.generator.engine.ast.MethodDefinition; import com.google.api.generator.engine.ast.MethodInvocationExpr; +import com.google.api.generator.engine.ast.PrimitiveValue; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.StringObjectValue; import com.google.api.generator.engine.ast.TypeNode; @@ -94,6 +96,47 @@ protected MethodDefinition createDefaultTransportTransportProviderBuilderMethod( .build(); } + @Override + protected MethodDefinition createDefaultCredentialsProviderBuilderMethod() { + TypeNode returnType = + TypeNode.withReference( + ConcreteReference.withClazz(GoogleCredentialsProvider.Builder.class)); + MethodInvocationExpr credsProviderBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(FIXED_TYPESTORE.get("GoogleCredentialsProvider")) + .setMethodName("newBuilder") + .build(); + credsProviderBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(credsProviderBuilderExpr) + .setMethodName("setScopesToApply") + .setArguments(DEFAULT_SERVICE_SCOPES_VAR_EXPR) + .setReturnType(returnType) + .build(); + + // This section is specific to GAPIC clients. It sets UseJwtAccessWithScope value to true to + // enable self signed JWT feature. + credsProviderBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(credsProviderBuilderExpr) + .setMethodName("setUseJwtAccessWithScope") + .setArguments( + ValueExpr.withValue( + PrimitiveValue.builder().setType(TypeNode.BOOLEAN).setValue("true").build())) + .setReturnType(returnType) + .build(); + + return MethodDefinition.builder() + .setHeaderCommentStatements( + SettingsCommentComposer.DEFAULT_CREDENTIALS_PROVIDER_BUILDER_METHOD_COMMENT) + .setScope(ScopeNode.PUBLIC) + .setIsStatic(true) + .setReturnType(returnType) + .setName("defaultCredentialsProviderBuilder") + .setReturnExpr(credsProviderBuilderExpr) + .build(); + } + @Override protected MethodDefinition createDefaultApiClientHeaderProviderBuilderMethod( Service service, TypeStore typeStore) { diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/DeprecatedServiceStubSettings.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/DeprecatedServiceStubSettings.golden index ddfdcde395..899b03bbce 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/DeprecatedServiceStubSettings.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/DeprecatedServiceStubSettings.golden @@ -120,7 +120,9 @@ public class DeprecatedServiceStubSettings extends StubSettings { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/LoggingServiceV2StubSettings.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/LoggingServiceV2StubSettings.golden index 1de81fd223..cc308eb5de 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/LoggingServiceV2StubSettings.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/LoggingServiceV2StubSettings.golden @@ -440,7 +440,9 @@ public class LoggingServiceV2StubSettings extends StubSettings { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClient.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClient.java index 1860b0cca4..af1cc6dd1f 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClient.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClient.java @@ -54,6 +54,7 @@ * .addAllAssetNames(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setReadTimeWindow(TimeWindow.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * BatchGetAssetsHistoryResponse response = assetServiceClient.batchGetAssetsHistory(request); * } @@ -190,6 +191,7 @@ public final OperationsClient getOperationsClient() { * .addAllAssetTypes(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setOutputConfig(OutputConfig.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * ExportAssetsResponse response = assetServiceClient.exportAssetsAsync(request).get(); * } @@ -225,6 +227,7 @@ public final OperationFuture exportAs * .addAllAssetTypes(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setOutputConfig(OutputConfig.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * OperationFuture future = * assetServiceClient.exportAssetsOperationCallable().futureCall(request); @@ -260,6 +263,7 @@ public final OperationFuture exportAs * .addAllAssetTypes(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setOutputConfig(OutputConfig.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * ApiFuture future = assetServiceClient.exportAssetsCallable().futureCall(request); * // Do something. @@ -340,6 +344,7 @@ public final ListAssetsPagedResponse listAssets(String parent) { * .setContentType(ContentType.forNumber(0)) * .setPageSize(883849137) * .setPageToken("pageToken873572522") + * .addAllRelationshipTypes(new ArrayList()) * .build(); * for (Asset element : assetServiceClient.listAssets(request).iterateAll()) { * // doThingsWith(element); @@ -370,6 +375,7 @@ public final ListAssetsPagedResponse listAssets(ListAssetsRequest request) { * .setContentType(ContentType.forNumber(0)) * .setPageSize(883849137) * .setPageToken("pageToken873572522") + * .addAllRelationshipTypes(new ArrayList()) * .build(); * ApiFuture future = assetServiceClient.listAssetsPagedCallable().futureCall(request); * // Do something. @@ -399,6 +405,7 @@ public final UnaryCallable listAsset * .setContentType(ContentType.forNumber(0)) * .setPageSize(883849137) * .setPageToken("pageToken873572522") + * .addAllRelationshipTypes(new ArrayList()) * .build(); * while (true) { * ListAssetsResponse response = assetServiceClient.listAssetsCallable().call(request); @@ -437,6 +444,7 @@ public final UnaryCallable listAssetsCall * .addAllAssetNames(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setReadTimeWindow(TimeWindow.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * BatchGetAssetsHistoryResponse response = assetServiceClient.batchGetAssetsHistory(request); * } @@ -468,6 +476,7 @@ public final BatchGetAssetsHistoryResponse batchGetAssetsHistory( * .addAllAssetNames(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setReadTimeWindow(TimeWindow.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * ApiFuture future = * assetServiceClient.batchGetAssetsHistoryCallable().futureCall(request); @@ -924,8 +933,8 @@ public final UnaryCallable deleteFeedCallable() { *
  • `kmsKey:key` to find Cloud resources encrypted with a customer-managed encryption key * whose name contains the word "key". *
  • `state:ACTIVE` to find Cloud resources whose state contains "ACTIVE" as a word. - *
  • `NOT state:ACTIVE` to find {{gcp_name}} resources whose state doesn't contain - * "ACTIVE" as a word. + *
  • `NOT state:ACTIVE` to find Cloud resources whose state doesn't contain "ACTIVE" as a + * word. *
  • `createTime<1609459200` to find Cloud resources that were created before * "2021-01-01 00:00:00 UTC". 1609459200 is the epoch timestamp of "2021-01-01 00:00:00 * UTC" in seconds. @@ -985,6 +994,7 @@ public final SearchAllResourcesPagedResponse searchAllResources( * .setPageSize(883849137) * .setPageToken("pageToken873572522") * .setOrderBy("orderBy-1207110587") + * .setReadMask(FieldMask.newBuilder().build()) * .build(); * for (ResourceSearchResult element : * assetServiceClient.searchAllResources(request).iterateAll()) { @@ -1019,6 +1029,7 @@ public final SearchAllResourcesPagedResponse searchAllResources( * .setPageSize(883849137) * .setPageToken("pageToken873572522") * .setOrderBy("orderBy-1207110587") + * .setReadMask(FieldMask.newBuilder().build()) * .build(); * ApiFuture future = * assetServiceClient.searchAllResourcesPagedCallable().futureCall(request); @@ -1052,6 +1063,7 @@ public final SearchAllResourcesPagedResponse searchAllResources( * .setPageSize(883849137) * .setPageToken("pageToken873572522") * .setOrderBy("orderBy-1207110587") + * .setReadMask(FieldMask.newBuilder().build()) * .build(); * while (true) { * SearchAllResourcesResponse response = @@ -1314,8 +1326,8 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * [AnalyzeIamPolicyResponse][google.cloud.asset.v1.AnalyzeIamPolicyResponse]. This method * implements the [google.longrunning.Operation][google.longrunning.Operation], which allows you * to track the operation status. We recommend intervals of at least 2 seconds with exponential - * backoff retry to poll the operation result. The metadata contains the request to help callers - * to map responses to requests. + * backoff retry to poll the operation result. The metadata contains the metadata for the + * long-running operation. * *

    Sample code: * @@ -1335,7 +1347,7 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ public final OperationFuture< - AnalyzeIamPolicyLongrunningResponse, AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningResponse, AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningAsync(AnalyzeIamPolicyLongrunningRequest request) { return analyzeIamPolicyLongrunningOperationCallable().futureCall(request); } @@ -1348,8 +1360,8 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * [AnalyzeIamPolicyResponse][google.cloud.asset.v1.AnalyzeIamPolicyResponse]. This method * implements the [google.longrunning.Operation][google.longrunning.Operation], which allows you * to track the operation status. We recommend intervals of at least 2 seconds with exponential - * backoff retry to poll the operation result. The metadata contains the request to help callers - * to map responses to requests. + * backoff retry to poll the operation result. The metadata contains the metadata for the + * long-running operation. * *

    Sample code: * @@ -1360,7 +1372,7 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * .setAnalysisQuery(IamPolicyAnalysisQuery.newBuilder().build()) * .setOutputConfig(IamPolicyAnalysisOutputConfig.newBuilder().build()) * .build(); - * OperationFuture + * OperationFuture * future = * assetServiceClient.analyzeIamPolicyLongrunningOperationCallable().futureCall(request); * // Do something. @@ -1371,7 +1383,7 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r public final OperationCallable< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationCallable() { return stub.analyzeIamPolicyLongrunningOperationCallable(); } @@ -1384,8 +1396,8 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r * [AnalyzeIamPolicyResponse][google.cloud.asset.v1.AnalyzeIamPolicyResponse]. This method * implements the [google.longrunning.Operation][google.longrunning.Operation], which allows you * to track the operation status. We recommend intervals of at least 2 seconds with exponential - * backoff retry to poll the operation result. The metadata contains the request to help callers - * to map responses to requests. + * backoff retry to poll the operation result. The metadata contains the metadata for the + * long-running operation. * *

    Sample code: * @@ -1408,6 +1420,60 @@ public final AnalyzeIamPolicyResponse analyzeIamPolicy(AnalyzeIamPolicyRequest r return stub.analyzeIamPolicyLongrunningCallable(); } + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Analyze moving a resource to a specified destination without kicking off the actual move. The + * analysis is best effort depending on the user's permissions of viewing different hierarchical + * policies and configurations. The policies and configuration are subject to change before the + * actual resource migration takes place. + * + *

    Sample code: + * + *

    {@code
    +   * try (AssetServiceClient assetServiceClient = AssetServiceClient.create()) {
    +   *   AnalyzeMoveRequest request =
    +   *       AnalyzeMoveRequest.newBuilder()
    +   *           .setResource("resource-341064690")
    +   *           .setDestinationParent("destinationParent-1733659048")
    +   *           .build();
    +   *   AnalyzeMoveResponse response = assetServiceClient.analyzeMove(request);
    +   * }
    +   * }
    + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final AnalyzeMoveResponse analyzeMove(AnalyzeMoveRequest request) { + return analyzeMoveCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Analyze moving a resource to a specified destination without kicking off the actual move. The + * analysis is best effort depending on the user's permissions of viewing different hierarchical + * policies and configurations. The policies and configuration are subject to change before the + * actual resource migration takes place. + * + *

    Sample code: + * + *

    {@code
    +   * try (AssetServiceClient assetServiceClient = AssetServiceClient.create()) {
    +   *   AnalyzeMoveRequest request =
    +   *       AnalyzeMoveRequest.newBuilder()
    +   *           .setResource("resource-341064690")
    +   *           .setDestinationParent("destinationParent-1733659048")
    +   *           .build();
    +   *   ApiFuture future =
    +   *       assetServiceClient.analyzeMoveCallable().futureCall(request);
    +   *   // Do something.
    +   *   AnalyzeMoveResponse response = future.get();
    +   * }
    +   * }
    + */ + public final UnaryCallable analyzeMoveCallable() { + return stub.analyzeMoveCallable(); + } + @Override public final void close() { stub.close(); diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClientTest.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClientTest.java index de8ca67414..41f50cea3a 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClientTest.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceClientTest.java @@ -113,6 +113,7 @@ public void exportAssetsTest() throws Exception { .addAllAssetTypes(new ArrayList()) .setContentType(ContentType.forNumber(0)) .setOutputConfig(OutputConfig.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); ExportAssetsResponse actualResponse = client.exportAssetsAsync(request).get(); @@ -127,6 +128,8 @@ public void exportAssetsTest() throws Exception { Assert.assertEquals(request.getAssetTypesList(), actualRequest.getAssetTypesList()); Assert.assertEquals(request.getContentType(), actualRequest.getContentType()); Assert.assertEquals(request.getOutputConfig(), actualRequest.getOutputConfig()); + Assert.assertEquals( + request.getRelationshipTypesList(), actualRequest.getRelationshipTypesList()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -146,6 +149,7 @@ public void exportAssetsExceptionTest() throws Exception { .addAllAssetTypes(new ArrayList()) .setContentType(ContentType.forNumber(0)) .setOutputConfig(OutputConfig.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); client.exportAssetsAsync(request).get(); Assert.fail("No exception raised"); @@ -258,6 +262,7 @@ public void batchGetAssetsHistoryTest() throws Exception { .addAllAssetNames(new ArrayList()) .setContentType(ContentType.forNumber(0)) .setReadTimeWindow(TimeWindow.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); BatchGetAssetsHistoryResponse actualResponse = client.batchGetAssetsHistory(request); @@ -272,6 +277,8 @@ public void batchGetAssetsHistoryTest() throws Exception { Assert.assertEquals(request.getAssetNamesList(), actualRequest.getAssetNamesList()); Assert.assertEquals(request.getContentType(), actualRequest.getContentType()); Assert.assertEquals(request.getReadTimeWindow(), actualRequest.getReadTimeWindow()); + Assert.assertEquals( + request.getRelationshipTypesList(), actualRequest.getRelationshipTypesList()); Assert.assertTrue( channelProvider.isHeaderSent( ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), @@ -290,6 +297,7 @@ public void batchGetAssetsHistoryExceptionTest() throws Exception { .addAllAssetNames(new ArrayList()) .setContentType(ContentType.forNumber(0)) .setReadTimeWindow(TimeWindow.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); client.batchGetAssetsHistory(request); Assert.fail("No exception raised"); @@ -308,6 +316,7 @@ public void createFeedTest() throws Exception { .setContentType(ContentType.forNumber(0)) .setFeedOutputConfig(FeedOutputConfig.newBuilder().build()) .setCondition(Expr.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); mockAssetService.addResponse(expectedResponse); @@ -351,6 +360,7 @@ public void getFeedTest() throws Exception { .setContentType(ContentType.forNumber(0)) .setFeedOutputConfig(FeedOutputConfig.newBuilder().build()) .setCondition(Expr.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); mockAssetService.addResponse(expectedResponse); @@ -394,6 +404,7 @@ public void getFeedTest2() throws Exception { .setContentType(ContentType.forNumber(0)) .setFeedOutputConfig(FeedOutputConfig.newBuilder().build()) .setCondition(Expr.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); mockAssetService.addResponse(expectedResponse); @@ -473,6 +484,7 @@ public void updateFeedTest() throws Exception { .setContentType(ContentType.forNumber(0)) .setFeedOutputConfig(FeedOutputConfig.newBuilder().build()) .setCondition(Expr.newBuilder().build()) + .addAllRelationshipTypes(new ArrayList()) .build(); mockAssetService.addResponse(expectedResponse); @@ -777,4 +789,50 @@ public void analyzeIamPolicyLongrunningExceptionTest() throws Exception { Assert.assertEquals(StatusCode.Code.INVALID_ARGUMENT, apiException.getStatusCode().getCode()); } } + + @Test + public void analyzeMoveTest() throws Exception { + AnalyzeMoveResponse expectedResponse = + AnalyzeMoveResponse.newBuilder().addAllMoveAnalysis(new ArrayList()).build(); + mockAssetService.addResponse(expectedResponse); + + AnalyzeMoveRequest request = + AnalyzeMoveRequest.newBuilder() + .setResource("resource-341064690") + .setDestinationParent("destinationParent-1733659048") + .build(); + + AnalyzeMoveResponse actualResponse = client.analyzeMove(request); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockAssetService.getRequests(); + Assert.assertEquals(1, actualRequests.size()); + AnalyzeMoveRequest actualRequest = ((AnalyzeMoveRequest) actualRequests.get(0)); + + Assert.assertEquals(request.getResource(), actualRequest.getResource()); + Assert.assertEquals(request.getDestinationParent(), actualRequest.getDestinationParent()); + Assert.assertEquals(request.getView(), actualRequest.getView()); + Assert.assertTrue( + channelProvider.isHeaderSent( + ApiClientHeaderProvider.getDefaultApiClientHeaderKey(), + GaxGrpcProperties.getDefaultApiClientHeaderPattern())); + } + + @Test + public void analyzeMoveExceptionTest() throws Exception { + StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT); + mockAssetService.addException(exception); + + try { + AnalyzeMoveRequest request = + AnalyzeMoveRequest.newBuilder() + .setResource("resource-341064690") + .setDestinationParent("destinationParent-1733659048") + .build(); + client.analyzeMove(request); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } } diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceSettings.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceSettings.java index df338c00a9..8bca7d5631 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceSettings.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/AssetServiceSettings.java @@ -154,12 +154,17 @@ public UnaryCallSettings deleteFeedSettings() { public OperationCallSettings< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings() { return ((AssetServiceStubSettings) getStubSettings()) .analyzeIamPolicyLongrunningOperationSettings(); } + /** Returns the object with the settings used for calls to analyzeMove. */ + public UnaryCallSettings analyzeMoveSettings() { + return ((AssetServiceStubSettings) getStubSettings()).analyzeMoveSettings(); + } + public static final AssetServiceSettings create(AssetServiceStubSettings stub) throws IOException { return new AssetServiceSettings.Builder(stub.toBuilder()).build(); @@ -338,11 +343,17 @@ public UnaryCallSettings.Builder deleteFeedSettings() public OperationCallSettings.Builder< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings() { return getStubSettingsBuilder().analyzeIamPolicyLongrunningOperationSettings(); } + /** Returns the builder for the settings used for calls to analyzeMove. */ + public UnaryCallSettings.Builder + analyzeMoveSettings() { + return getStubSettingsBuilder().analyzeMoveSettings(); + } + @Override public AssetServiceSettings build() throws IOException { return new AssetServiceSettings(this); diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/MockAssetServiceImpl.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/MockAssetServiceImpl.java index 643691d8d4..f72ed1eaa6 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/MockAssetServiceImpl.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/MockAssetServiceImpl.java @@ -310,4 +310,25 @@ public void analyzeIamPolicyLongrunning( Exception.class.getName()))); } } + + @Override + public void analyzeMove( + AnalyzeMoveRequest request, StreamObserver responseObserver) { + Object response = responses.poll(); + if (response instanceof AnalyzeMoveResponse) { + requests.add(request); + responseObserver.onNext(((AnalyzeMoveResponse) response)); + responseObserver.onCompleted(); + } else if (response instanceof Exception) { + responseObserver.onError(((Exception) response)); + } else { + responseObserver.onError( + new IllegalArgumentException( + String.format( + "Unrecognized response type %s for method AnalyzeMove, expected %s or %s", + response == null ? "null" : response.getClass().getName(), + AnalyzeMoveResponse.class.getName(), + Exception.class.getName()))); + } + } } diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/gapic_metadata.json b/test/integration/goldens/asset/com/google/cloud/asset/v1/gapic_metadata.json index ea1187e7ac..05ba5ae5ea 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/gapic_metadata.json +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/gapic_metadata.json @@ -16,6 +16,9 @@ "AnalyzeIamPolicyLongrunning": { "methods": ["analyzeIamPolicyLongrunningAsync", "analyzeIamPolicyLongrunningOperationCallable", "analyzeIamPolicyLongrunningCallable"] }, + "AnalyzeMove": { + "methods": ["analyzeMove", "analyzeMoveCallable"] + }, "BatchGetAssetsHistory": { "methods": ["batchGetAssetsHistory", "batchGetAssetsHistoryCallable"] }, diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/package-info.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/package-info.java index 27db247ed3..d07bbc1fb7 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/package-info.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/package-info.java @@ -31,6 +31,7 @@ * .addAllAssetNames(new ArrayList()) * .setContentType(ContentType.forNumber(0)) * .setReadTimeWindow(TimeWindow.newBuilder().build()) + * .addAllRelationshipTypes(new ArrayList()) * .build(); * BatchGetAssetsHistoryResponse response = assetServiceClient.batchGetAssetsHistory(request); * } diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStub.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStub.java index 462d7e2922..f3b324ba29 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStub.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStub.java @@ -23,10 +23,13 @@ import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.UnaryCallable; +import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningMetadata; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningResponse; import com.google.cloud.asset.v1.AnalyzeIamPolicyRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyResponse; +import com.google.cloud.asset.v1.AnalyzeMoveRequest; +import com.google.cloud.asset.v1.AnalyzeMoveResponse; import com.google.cloud.asset.v1.BatchGetAssetsHistoryRequest; import com.google.cloud.asset.v1.BatchGetAssetsHistoryResponse; import com.google.cloud.asset.v1.CreateFeedRequest; @@ -132,7 +135,7 @@ public UnaryCallable deleteFeedCallable() { public OperationCallable< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationCallable() { throw new UnsupportedOperationException( "Not implemented: analyzeIamPolicyLongrunningOperationCallable()"); @@ -144,6 +147,10 @@ public UnaryCallable deleteFeedCallable() { "Not implemented: analyzeIamPolicyLongrunningCallable()"); } + public UnaryCallable analyzeMoveCallable() { + throw new UnsupportedOperationException("Not implemented: analyzeMoveCallable()"); + } + @Override public abstract void close(); } diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStubSettings.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStubSettings.java index d5f851bb3b..30012d98c6 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStubSettings.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/AssetServiceStubSettings.java @@ -46,10 +46,13 @@ import com.google.api.gax.rpc.TransportChannelProvider; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; +import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningMetadata; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningResponse; import com.google.cloud.asset.v1.AnalyzeIamPolicyRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyResponse; +import com.google.cloud.asset.v1.AnalyzeMoveRequest; +import com.google.cloud.asset.v1.AnalyzeMoveResponse; import com.google.cloud.asset.v1.Asset; import com.google.cloud.asset.v1.BatchGetAssetsHistoryRequest; import com.google.cloud.asset.v1.BatchGetAssetsHistoryResponse; @@ -147,8 +150,9 @@ public class AssetServiceStubSettings extends StubSettings + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings; + private final UnaryCallSettings analyzeMoveSettings; private static final PagedListDescriptor LIST_ASSETS_PAGE_STR_DESC = @@ -413,11 +417,16 @@ public UnaryCallSettings deleteFeedSettings() { public OperationCallSettings< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings() { return analyzeIamPolicyLongrunningOperationSettings; } + /** Returns the object with the settings used for calls to analyzeMove. */ + public UnaryCallSettings analyzeMoveSettings() { + return analyzeMoveSettings; + } + @BetaApi("A restructuring of stub classes is planned, so this may break in the future") public AssetServiceStub createStub() throws IOException { if (getTransportChannelProvider() @@ -452,7 +461,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ @@ -508,6 +519,7 @@ protected AssetServiceStubSettings(Builder settingsBuilder) throws IOException { settingsBuilder.analyzeIamPolicyLongrunningSettings().build(); analyzeIamPolicyLongrunningOperationSettings = settingsBuilder.analyzeIamPolicyLongrunningOperationSettings().build(); + analyzeMoveSettings = settingsBuilder.analyzeMoveSettings().build(); } /** Builder for AssetServiceStubSettings. */ @@ -543,8 +555,10 @@ public static class Builder extends StubSettings.Builder + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings; + private final UnaryCallSettings.Builder + analyzeMoveSettings; private static final ImmutableMap> RETRYABLE_CODE_DEFINITIONS; @@ -564,6 +578,7 @@ public static class Builder extends StubSettings.BuildernewArrayList(StatusCode.Code.UNAVAILABLE))); + definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList())); RETRYABLE_CODE_DEFINITIONS = definitions.build(); } @@ -613,6 +628,8 @@ public static class Builder extends StubSettings.Builder>of( @@ -652,7 +670,8 @@ protected Builder(ClientContext clientContext) { searchAllResourcesSettings, searchAllIamPoliciesSettings, analyzeIamPolicySettings, - analyzeIamPolicyLongrunningSettings); + analyzeIamPolicyLongrunningSettings, + analyzeMoveSettings); initDefaults(this); } @@ -675,6 +694,7 @@ protected Builder(AssetServiceStubSettings settings) { settings.analyzeIamPolicyLongrunningSettings.toBuilder(); analyzeIamPolicyLongrunningOperationSettings = settings.analyzeIamPolicyLongrunningOperationSettings.toBuilder(); + analyzeMoveSettings = settings.analyzeMoveSettings.toBuilder(); unaryMethodSettingsBuilders = ImmutableList.>of( @@ -689,7 +709,8 @@ protected Builder(AssetServiceStubSettings settings) { searchAllResourcesSettings, searchAllIamPoliciesSettings, analyzeIamPolicySettings, - analyzeIamPolicyLongrunningSettings); + analyzeIamPolicyLongrunningSettings, + analyzeMoveSettings); } private static Builder createDefault() { @@ -766,6 +787,11 @@ private static Builder initDefaults(Builder builder) { .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); + builder + .analyzeMoveSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); + builder .exportAssetsOperationSettings() .setInitialCallSettings( @@ -804,7 +830,7 @@ private static Builder initDefaults(Builder builder) { AnalyzeIamPolicyLongrunningResponse.class)) .setMetadataTransformer( ProtoOperationTransformers.MetadataTransformer.create( - AnalyzeIamPolicyLongrunningRequest.class)) + AnalyzeIamPolicyLongrunningMetadata.class)) .setPollingAlgorithm( OperationTimedPollAlgorithm.create( RetrySettings.newBuilder() @@ -920,11 +946,17 @@ public UnaryCallSettings.Builder deleteFeedSettings() public OperationCallSettings.Builder< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationSettings() { return analyzeIamPolicyLongrunningOperationSettings; } + /** Returns the builder for the settings used for calls to analyzeMove. */ + public UnaryCallSettings.Builder + analyzeMoveSettings() { + return analyzeMoveSettings; + } + @Override public AssetServiceStubSettings build() throws IOException { return new AssetServiceStubSettings(this); diff --git a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java index d884f02bf9..d467435938 100644 --- a/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java +++ b/test/integration/goldens/asset/com/google/cloud/asset/v1/stub/GrpcAssetServiceStub.java @@ -27,10 +27,13 @@ import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.UnaryCallable; +import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningMetadata; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyLongrunningResponse; import com.google.cloud.asset.v1.AnalyzeIamPolicyRequest; import com.google.cloud.asset.v1.AnalyzeIamPolicyResponse; +import com.google.cloud.asset.v1.AnalyzeMoveRequest; +import com.google.cloud.asset.v1.AnalyzeMoveResponse; import com.google.cloud.asset.v1.BatchGetAssetsHistoryRequest; import com.google.cloud.asset.v1.BatchGetAssetsHistoryResponse; import com.google.cloud.asset.v1.CreateFeedRequest; @@ -180,6 +183,16 @@ public class GrpcAssetServiceStub extends AssetServiceStub { .setResponseMarshaller(ProtoUtils.marshaller(Operation.getDefaultInstance())) .build(); + private static final MethodDescriptor + analyzeMoveMethodDescriptor = + MethodDescriptor.newBuilder() + .setType(MethodDescriptor.MethodType.UNARY) + .setFullMethodName("google.cloud.asset.v1.AssetService/AnalyzeMove") + .setRequestMarshaller(ProtoUtils.marshaller(AnalyzeMoveRequest.getDefaultInstance())) + .setResponseMarshaller( + ProtoUtils.marshaller(AnalyzeMoveResponse.getDefaultInstance())) + .build(); + private final UnaryCallable exportAssetsCallable; private final OperationCallable exportAssetsOperationCallable; @@ -207,8 +220,9 @@ public class GrpcAssetServiceStub extends AssetServiceStub { private final OperationCallable< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationCallable; + private final UnaryCallable analyzeMoveCallable; private final BackgroundResource backgroundResources; private final GrpcOperationsStub operationsStub; @@ -382,6 +396,16 @@ protected GrpcAssetServiceStub( return params.build(); }) .build(); + GrpcCallSettings analyzeMoveTransportSettings = + GrpcCallSettings.newBuilder() + .setMethodDescriptor(analyzeMoveMethodDescriptor) + .setParamsExtractor( + request -> { + ImmutableMap.Builder params = ImmutableMap.builder(); + params.put("resource", String.valueOf(request.getResource())); + return params.build(); + }) + .build(); this.exportAssetsCallable = callableFactory.createUnaryCallable( @@ -452,6 +476,9 @@ protected GrpcAssetServiceStub( settings.analyzeIamPolicyLongrunningOperationSettings(), clientContext, operationsStub); + this.analyzeMoveCallable = + callableFactory.createUnaryCallable( + analyzeMoveTransportSettings, settings.analyzeMoveSettings(), clientContext); this.backgroundResources = new BackgroundResourceAggregation(clientContext.getBackgroundResources()); @@ -553,11 +580,16 @@ public UnaryCallable deleteFeedCallable() { public OperationCallable< AnalyzeIamPolicyLongrunningRequest, AnalyzeIamPolicyLongrunningResponse, - AnalyzeIamPolicyLongrunningRequest> + AnalyzeIamPolicyLongrunningMetadata> analyzeIamPolicyLongrunningOperationCallable() { return analyzeIamPolicyLongrunningOperationCallable; } + @Override + public UnaryCallable analyzeMoveCallable() { + return analyzeMoveCallable; + } + @Override public final void close() { try { diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java index bc7d9c2a16..24d06c2f69 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java @@ -141,7 +141,7 @@ public void deleteTest() throws Exception { .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") .setHttpErrorStatusCode(1386087020) - .setId("id3355") + .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") .setName("name3373707") @@ -151,7 +151,7 @@ public void deleteTest() throws Exception { .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") .setStatusMessage("statusMessage-958704715") - .setTargetId("targetId-441951604") + .setTargetId(-815576439) .setTargetLink("targetLink486368555") .setUser("user3599307") .addAllWarnings(new ArrayList()) @@ -210,7 +210,7 @@ public void insertTest() throws Exception { .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") .setHttpErrorStatusCode(1386087020) - .setId("id3355") + .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") .setName("name3373707") @@ -220,7 +220,7 @@ public void insertTest() throws Exception { .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") .setStatusMessage("statusMessage-958704715") - .setTargetId("targetId-441951604") + .setTargetId(-815576439) .setTargetLink("targetLink486368555") .setUser("user3599307") .addAllWarnings(new ArrayList()) diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java index 7f6b78232a..d41b1f5191 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java @@ -83,7 +83,7 @@ public void getTest() throws Exception { .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") .setHttpErrorStatusCode(1386087020) - .setId("id3355") + .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") .setName("name3373707") @@ -93,7 +93,7 @@ public void getTest() throws Exception { .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") .setStatusMessage("statusMessage-958704715") - .setTargetId("targetId-441951604") + .setTargetId(-815576439) .setTargetLink("targetLink486368555") .setUser("user3599307") .addAllWarnings(new ArrayList()) diff --git a/test/integration/goldens/credentials/com/google/cloud/iam/credentials/v1/stub/IamCredentialsStubSettings.java b/test/integration/goldens/credentials/com/google/cloud/iam/credentials/v1/stub/IamCredentialsStubSettings.java index 45338c519e..26792da200 100644 --- a/test/integration/goldens/credentials/com/google/cloud/iam/credentials/v1/stub/IamCredentialsStubSettings.java +++ b/test/integration/goldens/credentials/com/google/cloud/iam/credentials/v1/stub/IamCredentialsStubSettings.java @@ -150,7 +150,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/iam/com/google/iam/v1/stub/IAMPolicyStubSettings.java b/test/integration/goldens/iam/com/google/iam/v1/stub/IAMPolicyStubSettings.java index 0c1876afa5..03c10fcb73 100644 --- a/test/integration/goldens/iam/com/google/iam/v1/stub/IAMPolicyStubSettings.java +++ b/test/integration/goldens/iam/com/google/iam/v1/stub/IAMPolicyStubSettings.java @@ -137,7 +137,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/kms/com/google/cloud/kms/v1/stub/KeyManagementServiceStubSettings.java b/test/integration/goldens/kms/com/google/cloud/kms/v1/stub/KeyManagementServiceStubSettings.java index 830ca8ca8d..e3faa10060 100644 --- a/test/integration/goldens/kms/com/google/cloud/kms/v1/stub/KeyManagementServiceStubSettings.java +++ b/test/integration/goldens/kms/com/google/cloud/kms/v1/stub/KeyManagementServiceStubSettings.java @@ -657,7 +657,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/library/com/google/cloud/example/library/v1/stub/LibraryServiceStubSettings.java b/test/integration/goldens/library/com/google/cloud/example/library/v1/stub/LibraryServiceStubSettings.java index 614a5b7c98..159cd561a6 100644 --- a/test/integration/goldens/library/com/google/cloud/example/library/v1/stub/LibraryServiceStubSettings.java +++ b/test/integration/goldens/library/com/google/cloud/example/library/v1/stub/LibraryServiceStubSettings.java @@ -316,7 +316,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/ConfigServiceV2StubSettings.java b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/ConfigServiceV2StubSettings.java index 942d01f547..faf8137eea 100644 --- a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/ConfigServiceV2StubSettings.java +++ b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/ConfigServiceV2StubSettings.java @@ -526,7 +526,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/LoggingServiceV2StubSettings.java b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/LoggingServiceV2StubSettings.java index ae4a0acbb2..3f3b507702 100644 --- a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/LoggingServiceV2StubSettings.java +++ b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/LoggingServiceV2StubSettings.java @@ -456,7 +456,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/MetricsServiceV2StubSettings.java b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/MetricsServiceV2StubSettings.java index 5694e24035..3cf4be8d73 100644 --- a/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/MetricsServiceV2StubSettings.java +++ b/test/integration/goldens/logging/com/google/cloud/logging/v2/stub/MetricsServiceV2StubSettings.java @@ -224,7 +224,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java index a6adbe6945..01e6bd03a6 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClient.java @@ -485,6 +485,7 @@ public final Subscription createSubscription( * .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) * .setRetryPolicy(RetryPolicy.newBuilder().build()) * .setDetached(true) + * .setTopicMessageRetentionDuration(Duration.newBuilder().build()) * .build(); * Subscription response = subscriptionAdminClient.createSubscription(request); * } @@ -529,6 +530,7 @@ public final Subscription createSubscription(Subscription request) { * .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) * .setRetryPolicy(RetryPolicy.newBuilder().build()) * .setDetached(true) + * .setTopicMessageRetentionDuration(Duration.newBuilder().build()) * .build(); * ApiFuture future = * subscriptionAdminClient.createSubscriptionCallable().futureCall(request); diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClientTest.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClientTest.java index dd1bd27dac..9d53a7554a 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClientTest.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/SubscriptionAdminClientTest.java @@ -149,6 +149,7 @@ public void createSubscriptionTest() throws Exception { .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) .setRetryPolicy(RetryPolicy.newBuilder().build()) .setDetached(true) + .setTopicMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockSubscriber.addResponse(expectedResponse); @@ -209,6 +210,7 @@ public void createSubscriptionTest2() throws Exception { .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) .setRetryPolicy(RetryPolicy.newBuilder().build()) .setDetached(true) + .setTopicMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockSubscriber.addResponse(expectedResponse); @@ -269,6 +271,7 @@ public void createSubscriptionTest3() throws Exception { .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) .setRetryPolicy(RetryPolicy.newBuilder().build()) .setDetached(true) + .setTopicMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockSubscriber.addResponse(expectedResponse); @@ -329,6 +332,7 @@ public void createSubscriptionTest4() throws Exception { .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) .setRetryPolicy(RetryPolicy.newBuilder().build()) .setDetached(true) + .setTopicMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockSubscriber.addResponse(expectedResponse); @@ -389,6 +393,7 @@ public void getSubscriptionTest() throws Exception { .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) .setRetryPolicy(RetryPolicy.newBuilder().build()) .setDetached(true) + .setTopicMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockSubscriber.addResponse(expectedResponse); @@ -439,6 +444,7 @@ public void getSubscriptionTest2() throws Exception { .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) .setRetryPolicy(RetryPolicy.newBuilder().build()) .setDetached(true) + .setTopicMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockSubscriber.addResponse(expectedResponse); @@ -489,6 +495,7 @@ public void updateSubscriptionTest() throws Exception { .setDeadLetterPolicy(DeadLetterPolicy.newBuilder().build()) .setRetryPolicy(RetryPolicy.newBuilder().build()) .setDetached(true) + .setTopicMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockSubscriber.addResponse(expectedResponse); diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClient.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClient.java index 802fe3e940..be0a3a2e42 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClient.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClient.java @@ -237,6 +237,7 @@ public final Topic createTopic(String name) { * .setKmsKeyName("kmsKeyName412586233") * .setSchemaSettings(SchemaSettings.newBuilder().build()) * .setSatisfiesPzs(true) + * .setMessageRetentionDuration(Duration.newBuilder().build()) * .build(); * Topic response = topicAdminClient.createTopic(request); * } @@ -266,6 +267,7 @@ public final Topic createTopic(Topic request) { * .setKmsKeyName("kmsKeyName412586233") * .setSchemaSettings(SchemaSettings.newBuilder().build()) * .setSatisfiesPzs(true) + * .setMessageRetentionDuration(Duration.newBuilder().build()) * .build(); * ApiFuture future = topicAdminClient.createTopicCallable().futureCall(request); * // Do something. diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClientTest.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClientTest.java index 09b8de0f90..02d6a55850 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClientTest.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/TopicAdminClientTest.java @@ -37,6 +37,7 @@ import com.google.iam.v1.TestIamPermissionsResponse; import com.google.protobuf.AbstractMessage; import com.google.protobuf.ByteString; +import com.google.protobuf.Duration; import com.google.protobuf.Empty; import com.google.protobuf.FieldMask; import com.google.pubsub.v1.DeleteTopicRequest; @@ -125,6 +126,7 @@ public void createTopicTest() throws Exception { .setKmsKeyName("kmsKeyName412586233") .setSchemaSettings(SchemaSettings.newBuilder().build()) .setSatisfiesPzs(true) + .setMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockPublisher.addResponse(expectedResponse); @@ -168,6 +170,7 @@ public void createTopicTest2() throws Exception { .setKmsKeyName("kmsKeyName412586233") .setSchemaSettings(SchemaSettings.newBuilder().build()) .setSatisfiesPzs(true) + .setMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockPublisher.addResponse(expectedResponse); @@ -211,6 +214,7 @@ public void updateTopicTest() throws Exception { .setKmsKeyName("kmsKeyName412586233") .setSchemaSettings(SchemaSettings.newBuilder().build()) .setSatisfiesPzs(true) + .setMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockPublisher.addResponse(expectedResponse); @@ -341,6 +345,7 @@ public void getTopicTest() throws Exception { .setKmsKeyName("kmsKeyName412586233") .setSchemaSettings(SchemaSettings.newBuilder().build()) .setSatisfiesPzs(true) + .setMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockPublisher.addResponse(expectedResponse); @@ -384,6 +389,7 @@ public void getTopicTest2() throws Exception { .setKmsKeyName("kmsKeyName412586233") .setSchemaSettings(SchemaSettings.newBuilder().build()) .setSatisfiesPzs(true) + .setMessageRetentionDuration(Duration.newBuilder().build()) .build(); mockPublisher.addResponse(expectedResponse); diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/PublisherStubSettings.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/PublisherStubSettings.java index e5ea4e34bc..166775ec3c 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/PublisherStubSettings.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/PublisherStubSettings.java @@ -490,7 +490,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/SchemaServiceStubSettings.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/SchemaServiceStubSettings.java index 00489c3f74..fb8a87653d 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/SchemaServiceStubSettings.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/SchemaServiceStubSettings.java @@ -254,7 +254,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/SubscriberStubSettings.java b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/SubscriberStubSettings.java index 00ad4dd1c6..567da1624b 100644 --- a/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/SubscriberStubSettings.java +++ b/test/integration/goldens/pubsub/com/google/cloud/pubsub/v1/stub/SubscriberStubSettings.java @@ -395,7 +395,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/redis/com/google/cloud/redis/v1beta1/stub/CloudRedisStubSettings.java b/test/integration/goldens/redis/com/google/cloud/redis/v1beta1/stub/CloudRedisStubSettings.java index c6e6faa442..b92734fabc 100644 --- a/test/integration/goldens/redis/com/google/cloud/redis/v1beta1/stub/CloudRedisStubSettings.java +++ b/test/integration/goldens/redis/com/google/cloud/redis/v1beta1/stub/CloudRedisStubSettings.java @@ -306,7 +306,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/test/integration/goldens/storage/com/google/storage/v2/stub/StorageStubSettings.java b/test/integration/goldens/storage/com/google/storage/v2/stub/StorageStubSettings.java index 7a10ecf5e4..85c8639848 100644 --- a/test/integration/goldens/storage/com/google/storage/v2/stub/StorageStubSettings.java +++ b/test/integration/goldens/storage/com/google/storage/v2/stub/StorageStubSettings.java @@ -157,7 +157,9 @@ public static List getDefaultServiceScopes() { /** Returns a builder for the default credentials for this service. */ public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() { - return GoogleCredentialsProvider.newBuilder().setScopesToApply(DEFAULT_SERVICE_SCOPES); + return GoogleCredentialsProvider.newBuilder() + .setScopesToApply(DEFAULT_SERVICE_SCOPES) + .setUseJwtAccessWithScope(true); } /** Returns a builder for the default ChannelProvider for this service. */ diff --git a/version.txt b/version.txt index 38f77a65b3..7ec1d6db40 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.0.1 +2.1.0 From d7b29e05d7cfda1eb1a3b09d7ad7d625cab4bde1 Mon Sep 17 00:00:00 2001 From: Gabriel Gonzalez Date: Fri, 3 Sep 2021 19:36:29 -0400 Subject: [PATCH 3/9] Feat: Implement DIREGAPIC LRO annotations (#832) * fix ServiceStub Goldens * fix Stub golden * fix Stub golden * fix CallableFactory golden * fix java format * add annotation placement comments * only add machinery to methods that return operation * add grpc file that contained method that was edited on abstract class * update HttpJsonComplianceStub.golden * java format * add initial methods from annotations * add initial methods from annotations * Implement annotations * java format * fix package for Status * fix CallableFactory generics * java format * initialize new fields in message for parser test * set default value for operation_polling_method * add brackets to if statement * remove comments and invoke methods * add brackets to if statements and remove invoke methods * java formet --- WORKSPACE | 1 + ...ctServiceCallableFactoryClassComposer.java | 16 +- .../AbstractServiceStubClassComposer.java | 41 +- ...pcServiceCallableFactoryClassComposer.java | 9 +- ...onServiceCallableFactoryClassComposer.java | 56 ++- .../HttpJsonServiceStubClassComposer.java | 351 +++++++++++++----- .../api/generator/gapic/model/Message.java | 20 +- .../api/generator/gapic/model/Method.java | 21 +- .../gapic/model/OperationResponse.java | 56 +++ .../generator/gapic/protoparser/BUILD.bazel | 1 + .../generator/gapic/protoparser/Parser.java | 51 +++ .../HttpJsonComplianceCallableFactory.golden | 7 +- .../HttpJsonAddressesCallableFactory.java | 7 +- .../v1/stub/HttpJsonAddressesStub.java | 30 +- ...tpJsonRegionOperationsCallableFactory.java | 7 +- .../v1/stub/HttpJsonRegionOperationsStub.java | 21 +- 16 files changed, 532 insertions(+), 163 deletions(-) create mode 100644 src/main/java/com/google/api/generator/gapic/model/OperationResponse.java diff --git a/WORKSPACE b/WORKSPACE index 21e5f8ea67..cc406611a9 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -32,6 +32,7 @@ jvm_maven_import_external( # gapic-generator-java dependencies to match the order in googleapis repository, # which in its turn, prioritizes actual generated clients runtime dependencies # over the generator dependencies. + _gax_java_version = "2.3.0" http_archive( diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java index b3f4c7ee74..d643c9726b 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java @@ -41,6 +41,7 @@ import com.google.api.generator.gapic.model.GapicClass; import com.google.api.generator.gapic.model.GapicClass.Kind; import com.google.api.generator.gapic.model.GapicContext; +import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.Service; import java.util.ArrayList; import java.util.Arrays; @@ -68,6 +69,13 @@ public GapicClass generate(GapicContext context, Service service) { GapicClass.Kind kind = Kind.STUB; String pakkage = String.format("%s.stub", service.pakkage()); + String operationService = ""; + for(Method method : service.methods()) { + if(method.operationService() != null) { + operationService = method.operationService(); + } + } + StubCommentComposer commentComposer = new StubCommentComposer(getTransportContext().transportName()); ClassDefinition classDef = @@ -79,7 +87,7 @@ public GapicClass generate(GapicContext context, Service service) { .setAnnotations(createClassAnnotations(service, typeStore)) .setImplementsTypes(createClassImplements(typeStore)) .setName(className) - .setMethods(createClassMethods(typeStore)) + .setMethods(createClassMethods(typeStore, operationService)) .setScope(ScopeNode.PUBLIC) .build(); return GapicClass.create(kind, classDef); @@ -112,12 +120,12 @@ protected List createClassAnnotations(Service service, TypeStore */ protected abstract List createClassImplements(TypeStore typeStore); - protected List createClassMethods(TypeStore typeStore) { + protected List createClassMethods(TypeStore typeStore, String operationService) { return Arrays.asList( createUnaryCallableMethod(typeStore), createPagedCallableMethod(typeStore), createBatchingCallableMethod(typeStore), - createOperationCallableMethod(typeStore)); + createOperationCallableMethod(typeStore, operationService)); } protected MethodDefinition createUnaryCallableMethod(TypeStore typeStore) { @@ -182,7 +190,7 @@ protected MethodDefinition createBatchingCallableMethod(TypeStore typeStore) { .collect(Collectors.toList())); } - protected abstract MethodDefinition createOperationCallableMethod(TypeStore typeStore); + protected abstract MethodDefinition createOperationCallableMethod(TypeStore typeStore, String operationService); protected MethodDefinition createGenericCallableMethod( TypeStore typeStore, diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java index 524f8f6361..3202684691 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java @@ -57,6 +57,7 @@ import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.longrunning.Operation; import java.io.IOException; @@ -152,6 +153,12 @@ public GapicClass generate(GapicContext context, Service service) { .setType(getTransportContext().transportOperationsStubType()) .build())); } + + boolean operationPollingMethod = checkOperationPollingMethod(service); + if(operationPollingMethod) { + declareLongRunningClient(classMemberVarExprs); + } + classMemberVarExprs.put( CALLABLE_FACTORY_MEMBER_NAME, VariableExpr.withVariable( @@ -383,7 +390,7 @@ protected List createClassMethods( createOperationsStubGetterMethod(classMemberVarExprs.get(OPERATIONS_STUB_MEMBER_NAME))); javaMethods.addAll(createCallableGetterMethods(callableClassMemberVarExprs)); javaMethods.addAll( - createStubOverrideMethods(classMemberVarExprs.get(BACKGROUND_RESOURCES_MEMBER_NAME))); + createStubOverrideMethods(classMemberVarExprs.get(BACKGROUND_RESOURCES_MEMBER_NAME), service)); return javaMethods; } @@ -625,12 +632,16 @@ protected List createConstructorMethods( secondCtorExprs.clear(); secondCtorStatements.add(EMPTY_LINE_STATEMENT); + + secondCtorStatements.addAll(createLongRunningClient(service, typeStore)); + // Instantiate backgroundResources. MethodInvocationExpr getBackgroundResourcesMethodExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(clientContextVarExpr) .setMethodName("getBackgroundResources") .build(); + VariableExpr backgroundResourcesVarExpr = classMemberVarExprs.get("backgroundResources"); secondCtorExprs.add( AssignmentExpr.builder() @@ -655,6 +666,14 @@ protected List createConstructorMethods( return Arrays.asList(firstCtor, secondCtor); } + protected List createLongRunningClient(Service service, TypeStore typeStore) { + return ImmutableList.of(); + } + + protected void declareLongRunningClient(Map classMemberVarExprs) { + + } + private static Expr createCallableInitExpr( String callableVarName, VariableExpr callableVarExpr, @@ -762,7 +781,7 @@ private static List createCallableGetterMethods( } private List createStubOverrideMethods( - VariableExpr backgroundResourcesVarExpr) { + VariableExpr backgroundResourcesVarExpr, Service service) { Function methodMakerStarterFn = methodName -> MethodDefinition.builder() @@ -826,6 +845,11 @@ private List createStubOverrideMethods( .build()) .build(); List javaMethods = new ArrayList<>(); + //TODO: check for operation polling method + boolean operationPollingMethod = checkOperationPollingMethod(service); + if (operationPollingMethod) { + getterLongRunningClient(javaMethods); + } javaMethods.add( methodMakerStarterFn .apply("close") @@ -898,6 +922,19 @@ private List createStubOverrideMethods( return javaMethods; } + private boolean checkOperationPollingMethod(Service service) { + for(Method method : service.methods()) { + if(method.isOperationPollingMethod()) { + return true; + } + } + return false; + } + + protected void getterLongRunningClient(List javaMethods) { + + } + private TypeStore createDynamicTypes(Service service, String stubPakkage) { TypeStore typeStore = new TypeStore(); typeStore.putAll( diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java index 5698f5a443..06bb6695b2 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java @@ -45,8 +45,10 @@ protected List createClassImplements(TypeStore typeStore) { return Arrays.asList(getTransportContext().stubCallableFactoryType()); } - protected List createClassMethods(TypeStore typeStore) { - List classMethods = new ArrayList<>(super.createClassMethods(typeStore)); + protected List createClassMethods( + TypeStore typeStore, String operationService) { + List classMethods = + new ArrayList<>(super.createClassMethods(typeStore, operationService)); classMethods.addAll( Arrays.asList( createBidiStreamingCallableMethod(typeStore), @@ -98,7 +100,8 @@ protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { } @Override - protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { + protected MethodDefinition createOperationCallableMethod( + TypeStore typeStore, String operationService) { String methodVariantName = "Operation"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java index 191c1d15fa..919e6c973c 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java @@ -15,7 +15,6 @@ package com.google.api.generator.gapic.composer.rest; import com.google.api.gax.core.BackgroundResource; -import com.google.api.gax.httpjson.ApiMessage; import com.google.api.gax.httpjson.HttpJsonCallableFactory; import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.rpc.OperationCallable; @@ -47,7 +46,7 @@ public class HttpJsonServiceCallableFactoryClassComposer new HttpJsonServiceCallableFactoryClassComposer(); private static final TypeNode MESSAGE_TYPE = - TypeNode.withReference(ConcreteReference.withClazz(ApiMessage.class)); + TypeNode.withReference(ConcreteReference.withClazz(Operation.class)); private static final TypeNode BACKGROUND_RESOURCE_TYPE = TypeNode.withReference(ConcreteReference.withClazz(BackgroundResource.class)); @@ -86,7 +85,8 @@ protected List createClassImplements(TypeStore typeStore) { } @Override - protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { + protected MethodDefinition createOperationCallableMethod( + TypeStore typeStore, String operationService) { String methodVariantName = "Operation"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; @@ -104,6 +104,7 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { + " future."); // Generate generic method without the body + // TODO: change static usages to vapor references MethodDefinition method = createGenericCallableMethod( typeStore, @@ -119,13 +120,25 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { .collect(Collectors.toList()), Arrays.asList(betaAnnotation)); + // if (operationService.equals("")) { + // return method.toBuilder().setReturnExpr(ValueExpr.createNullExpr()).build(); + // } + List createOperationCallableBody = new ArrayList(2); - List arguments = method.arguments(); + List arguments = new ArrayList<>(method.arguments()); + // Variable stubVar = arguments.get(3).variable(); + // stubVar = Variable.builder() + // .setName(stubVar.identifier().name()) + // .setType(typeStore.get(operationService+"Stub")) + // .build(); + // arguments.set(3,VariableExpr.withVariable(stubVar)); + // method = method.toBuilder().setArguments(arguments).build(); + Variable httpJsonCallSettingsVar = arguments.get(0).variable(); - Variable callSettingsVar = arguments.get(1).variable(); + Variable operationCallSettingsVar = arguments.get(1).variable(); Variable clientContextVar = arguments.get(2).variable(); - Variable operationsStub = arguments.get(3).variable(); + Variable operationsStubVar = arguments.get(3).variable(); // Generate innerCallable VariableExpr innerCallableVarExpr = VariableExpr.builder() @@ -139,7 +152,7 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { .build(); MethodInvocationExpr getInitialCallSettingsExpr = MethodInvocationExpr.builder() - .setExprReferenceExpr(VariableExpr.withVariable(callSettingsVar)) + .setExprReferenceExpr(VariableExpr.withVariable(operationCallSettingsVar)) .setMethodName("getInitialCallSettings") .build(); MethodInvocationExpr createBaseUnaryCallableExpr = @@ -160,6 +173,20 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { .build(); createOperationCallableBody.add(ExprStatement.withExpr(innerCallableAssignExpr)); + // This is a temporary solution + VaporReference requestT = + VaporReference.builder() + .setName("RequestT") + .setPakkage("com.google.cloud.compute.v1.stub") + .build(); + + TypeNode initialCallableType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(HttpJsonOperationSnapshotCallable.class) + .setGenerics(requestT, ConcreteReference.withClazz(Operation.class)) + .build()); + // Generate initialCallable VariableExpr initialCallableVarExpr = VariableExpr.builder() @@ -167,9 +194,9 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { Variable.builder() .setName("initialCallable") .setType( - TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) + initialCallableType) // TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) .build()) - .setTemplateObjects(Arrays.asList(requestTemplateName, methodVariantName)) + // .setTemplateObjects(Arrays.asList(requestTemplateName, "OperationSnapshot")) .build(); MethodInvocationExpr getMethodDescriptorExpr = MethodInvocationExpr.builder() @@ -181,12 +208,7 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { .setExprReferenceExpr(getMethodDescriptorExpr) .setMethodName("getOperationSnapshotFactory") .build(); - // This is a temporary solution - VaporReference requestT = - VaporReference.builder() - .setName("RequestT") - .setPakkage("com.google.cloud.compute.v1.stub") - .build(); + TypeNode operationSnapshotCallableType = TypeNode.withReference( ConcreteReference.builder() @@ -209,7 +231,7 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { // Generate return statement MethodInvocationExpr longRunningClient = MethodInvocationExpr.builder() - .setExprReferenceExpr(VariableExpr.withVariable(operationsStub)) + .setExprReferenceExpr(VariableExpr.withVariable(operationsStubVar)) .setMethodName("longRunningClient") .build(); MethodInvocationExpr createOperationCallable = @@ -218,7 +240,7 @@ protected MethodDefinition createOperationCallableMethod(TypeStore typeStore) { TypeNode.withReference(ConcreteReference.withClazz(HttpJsonCallableFactory.class))) .setMethodName("createOperationCallable") .setArguments( - VariableExpr.withVariable(callSettingsVar), + VariableExpr.withVariable(operationCallSettingsVar), VariableExpr.withVariable(clientContextVar), longRunningClient, initialCallableVarExpr) diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java index 66fdfb2b4e..d00e23c5fc 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java @@ -19,12 +19,15 @@ import com.google.api.gax.httpjson.ApiMethodDescriptor; import com.google.api.gax.httpjson.FieldsExtractor; import com.google.api.gax.httpjson.HttpJsonCallSettings; +import com.google.api.gax.httpjson.HttpJsonLongRunningClient; import com.google.api.gax.httpjson.HttpJsonOperationSnapshot; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.httpjson.ProtoMessageRequestFormatter; import com.google.api.gax.httpjson.ProtoMessageResponseParser; import com.google.api.gax.httpjson.ProtoRestSerializer; import com.google.api.gax.longrunning.OperationSnapshot; +import com.google.api.gax.rpc.LongRunningClient; +import com.google.api.gax.rpc.UnaryCallable; import com.google.api.generator.engine.ast.AnnotationNode; import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.ConcreteReference; @@ -40,18 +43,22 @@ import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; import com.google.api.generator.engine.ast.StringObjectValue; +import com.google.api.generator.engine.ast.ThisObjectValue; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; import com.google.api.generator.engine.ast.VaporReference; import com.google.api.generator.engine.ast.Variable; import com.google.api.generator.engine.ast.VariableExpr; import com.google.api.generator.gapic.composer.common.AbstractServiceStubClassComposer; +import com.google.api.generator.gapic.composer.common.TransportContext; import com.google.api.generator.gapic.composer.store.TypeStore; import com.google.api.generator.gapic.model.HttpBindings.HttpBinding; import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; +import com.google.api.generator.gapic.model.OperationResponse; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; +import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.Arrays; @@ -124,14 +131,15 @@ protected Statement createMethodDescriptorVariableDecl( methodMaker.apply("setRequestFormatter", getRequestFormatterExpr(protoMethod)).apply(expr); expr = methodMaker.apply("setResponseParser", setResponseParserExpr(protoMethod)).apply(expr); - // System.out.println(protoMethod.outputType().reference().simpleName()); - if (protoMethod.outputType().reference().simpleName().equals("Operation")) { + if (protoMethod.isOperationPollingMethod() || protoMethod.operationService() != null) { expr = methodMaker .apply( "setOperationSnapshotFactory", setOperationSnapshotFactoryExpr(protoMethod, messageTypes)) .apply(expr); + } + if (protoMethod.isOperationPollingMethod()) { expr = methodMaker .apply( @@ -167,6 +175,10 @@ protected List createOperationsStubGetterMethod( return Collections.emptyList(); } + public HttpJsonServiceStubClassComposer(TransportContext transportContext) { + super(transportContext); + } + @Override protected Expr createTransportSettingsInitExpr( Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr) { @@ -380,9 +392,62 @@ private List setResponseParserExpr(Method protoMethod) { return Collections.singletonList(expr); } + // Generates get[camelCase(fieldName)] + private String getMethodFormat(String fieldName) { + return "get" + JavaStyle.toUpperCamelCase(fieldName); + } + + // Generates set[camelCase(fieldName)] + private String setMethodFormat(String fieldName) { + return "set" + JavaStyle.toUpperCamelCase(fieldName); + } + + // Generates: [nameVar].append(":").append([requestVar].get[FieldName]()); + private ExprStatement appendField( + VariableExpr nameVar, VariableExpr requestVar, String fieldName) { + BiFunction, Function> + methodMaker = getMethodMaker(); + ValueExpr colonValueExpr = + ValueExpr.builder().setValue(StringObjectValue.builder().setValue(":").build()).build(); + MethodInvocationExpr opNameAppendColonExpr = + MethodInvocationExpr.builder() + .setMethodName("append") + .setArguments(colonValueExpr) + .setExprReferenceExpr(nameVar) + .build(); + MethodInvocationExpr getField = + MethodInvocationExpr.builder() + .setExprReferenceExpr(requestVar) + .setMethodName(getMethodFormat(fieldName)) + .build(); + opNameAppendColonExpr = + methodMaker + .apply("append", Collections.singletonList(getField)) + .apply(opNameAppendColonExpr); + return ExprStatement.withExpr(opNameAppendColonExpr); + } + + // returns var.get(num); + private MethodInvocationExpr getExpr(VariableExpr var, String num) { + return MethodInvocationExpr.builder() + .setExprReferenceExpr(var) + .setMethodName("get") + .setArguments( + ValueExpr.builder() + .setValue(PrimitiveValue.builder().setValue(num).setType(TypeNode.INT).build()) + .build()) + .build(); + } + private List setOperationSnapshotFactoryExpr( Method protoMethod, Map messageTypes) { + Message inputOperationMessage = + messageTypes.get(protoMethod.inputType().reference().fullName()); + Message outputOperationMessage = + messageTypes.get(protoMethod.outputType().reference().fullName()); + OperationResponse operationResponse = outputOperationMessage.operationResponse(); + BiFunction, Function> methodMaker = getMethodMaker(); @@ -397,7 +462,6 @@ private List setOperationSnapshotFactoryExpr( List createBody = new ArrayList(4); // Generate opName - // This will be replaced and edited based on annotations TypeNode stringBuilderType = TypeNode.withReference(ConcreteReference.withClazz(StringBuilder.class)); VariableExpr opNameVarExpr = @@ -405,8 +469,8 @@ private List setOperationSnapshotFactoryExpr( Variable.builder().setType(stringBuilderType).setName("opName").build()); MethodInvocationExpr getId = MethodInvocationExpr.builder() - .setMethodName("getId") .setExprReferenceExpr(responseVarExpr) + .setMethodName(getMethodFormat(operationResponse.getNameFieldName())) .build(); Expr opNameObjectExpr = NewObjectExpr.builder().setType(stringBuilderType).setArguments(getId).build(); @@ -417,57 +481,34 @@ private List setOperationSnapshotFactoryExpr( .build(); createBody.add(ExprStatement.withExpr(opNameAssignExpr)); - // Generate changes opName - // This will be replaced and edited based on annotations - MethodInvocationExpr requestGetProjectExpr = - MethodInvocationExpr.builder() - .setMethodName("getProject") - .setExprReferenceExpr(requestVarExpr) - .build(); - ValueExpr colonValueExpr = - ValueExpr.builder().setValue(StringObjectValue.builder().setValue(":").build()).build(); - MethodInvocationExpr opNameAppendColonProjectExpr = - MethodInvocationExpr.builder() - .setMethodName("append") - .setArguments(colonValueExpr) - .setExprReferenceExpr(opNameVarExpr) - .build(); - opNameAppendColonProjectExpr = - methodMaker - .apply("append", Collections.singletonList(requestGetProjectExpr)) - .apply(opNameAppendColonProjectExpr); - createBody.add(ExprStatement.withExpr(opNameAppendColonProjectExpr)); - - // Generate changes to opName - MethodInvocationExpr requestGetRegionExpr = - MethodInvocationExpr.builder() - .setMethodName("getRegion") - .setExprReferenceExpr(requestVarExpr) - .build(); - MethodInvocationExpr opNameAppendColonRegionExpr = - MethodInvocationExpr.builder() - .setMethodName("append") - .setArguments(colonValueExpr) - .setExprReferenceExpr(opNameVarExpr) - .build(); - opNameAppendColonRegionExpr = - methodMaker - .apply("append", Collections.singletonList(requestGetRegionExpr)) - .apply(opNameAppendColonRegionExpr); - createBody.add(ExprStatement.withExpr(opNameAppendColonRegionExpr)); + // Generate compound operation name + if (!protoMethod.isOperationPollingMethod()) { + // TODO: Change to ordered map + Map requestFields = inputOperationMessage.operationRequestFields(); + List fieldAnnotationNames = new ArrayList(requestFields.keySet()); + Collections.sort(fieldAnnotationNames); + for (String fieldName : fieldAnnotationNames) { + createBody.add(appendField(opNameVarExpr, requestVarExpr, requestFields.get(fieldName))); + } + } - // Generate check status expression - // This will be replaced and edited based on annotations + // Generate check for status == done MethodInvocationExpr getStatusExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(responseVarExpr) - .setMethodName("getStatus") + .setMethodName(getMethodFormat(operationResponse.getStatusFieldName())) .build(); + + String statusTypeName = operationResponse.getStatusFieldTypeName(); + String statusClassName = statusTypeName.substring(statusTypeName.lastIndexOf('.') + 1); + String statusPackage = protoMethod.servicePackage(); // "com" + + // statusTypeName.substring(0,statusTypeName.lastIndexOf('.')); + TypeNode statusType = TypeNode.withReference( VaporReference.builder() - .setName("Status") - .setPakkage("com.google.cloud.compute.v1") + .setName(statusClassName) + .setPakkage(statusPackage + "." + protoMethod.outputType().reference().simpleName()) .setIsStaticImport(false) .build()); VariableExpr statusDoneExpr = @@ -476,33 +517,38 @@ private List setOperationSnapshotFactoryExpr( .setStaticReferenceType(statusType) .build(); MethodInvocationExpr statusEqualsExpr = - methodMaker.apply("equals", Collections.singletonList(statusDoneExpr)).apply(getStatusExpr); + MethodInvocationExpr.builder() + .setExprReferenceExpr(statusDoneExpr) + .setMethodName("equals") + .setArguments(getStatusExpr) + .build(); // Generate return statement TypeNode httpJsonOperationSnapshotType = TypeNode.withReference(ConcreteReference.withClazz(HttpJsonOperationSnapshot.class)); - MethodInvocationExpr newBuilderExpr = - MethodInvocationExpr.builder() - .setStaticReferenceType(httpJsonOperationSnapshotType) - .setMethodName("newBuilder") - .build(); + + // Generate getter methods from annotations MethodInvocationExpr opNameToStringExpr = MethodInvocationExpr.builder() - .setMethodName("toString") .setExprReferenceExpr(opNameVarExpr) + .setMethodName("toString") .build(); - // This will be replaced and edited based on annotations MethodInvocationExpr getHttpErrorStatusCodeExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(responseVarExpr) - .setMethodName("getHttpErrorStatusCode") + .setMethodName(getMethodFormat(operationResponse.getErrorCodeFieldName())) .build(); - // This will be replaced and edited based on annotations MethodInvocationExpr getHttpErrorMessageExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(responseVarExpr) - .setMethodName("getHttpErrorMessage") + .setMethodName(getMethodFormat(operationResponse.getErrorMessageFieldName())) .build(); + MethodInvocationExpr newBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(httpJsonOperationSnapshotType) + .setMethodName("newBuilder") + .build(); + newBuilderExpr = methodMaker .apply("setName", Collections.singletonList(opNameToStringExpr)) @@ -546,10 +592,12 @@ private List setOperationSnapshotFactoryExpr( private List setPollingRequestFactoryExpr( Method protoMethod, Map messageTypes) { - BiFunction, Function> methodMaker = getMethodMaker(); + Message inputOperationMessage = + messageTypes.get(protoMethod.inputType().reference().fullName()); + List createBody = new ArrayList(1); // Generate input variables for create @@ -598,36 +646,49 @@ private List setPollingRequestFactoryExpr( createBody.add(ExprStatement.withExpr(idComponentsAssignExpr)); // Generate return statement - // This will be replaced and edited based on annotations - TypeNode getRegionOperationRequestType = - TypeNode.withReference( - VaporReference.builder() - .setName("GetRegionOperationRequest") - .setPakkage("com.google.cloud.compute.v1") - .setIsStaticImport(false) - .build()); + TypeNode getOperationRequestType = TypeNode.withReference(protoMethod.inputType().reference()); MethodInvocationExpr newBuilderExpr = MethodInvocationExpr.builder() - .setStaticReferenceType(getRegionOperationRequestType) + .setStaticReferenceType(getOperationRequestType) .setMethodName("newBuilder") .build(); - newBuilderExpr = - methodMaker - .apply("setOperation", Collections.singletonList(getExpr(idComponentsVarExpr, "0"))) - .apply(newBuilderExpr); - newBuilderExpr = - methodMaker - .apply("setProject", Collections.singletonList(getExpr(idComponentsVarExpr, "1"))) - .apply(newBuilderExpr); - newBuilderExpr = - methodMaker - .apply("setRegion", Collections.singletonList(getExpr(idComponentsVarExpr, "2"))) - .apply(newBuilderExpr); + BiMap responseFieldsMap = inputOperationMessage.operationResponseFields(); + List responseFieldAnnotationNames = new ArrayList(responseFieldsMap.keySet()); + Collections.sort(responseFieldAnnotationNames); + Set responseFieldsNames = responseFieldsMap.inverse().keySet(); + Set allFieldsNames = inputOperationMessage.fieldMap().keySet(); + ArrayList nonResponseFieldsNames = new ArrayList(); + for (String fieldName : allFieldsNames) { + if (!responseFieldsNames.contains(fieldName)) { + nonResponseFieldsNames.add(fieldName); + } + } + Collections.sort(nonResponseFieldsNames); + int index = 0; + for (String fieldAnnotationName : responseFieldAnnotationNames) { + newBuilderExpr = + methodMaker + .apply( + setMethodFormat(responseFieldsMap.get(fieldAnnotationName)), + Collections.singletonList(getExpr(idComponentsVarExpr, Integer.toString(index)))) + .apply(newBuilderExpr); + index++; + } + for (String fieldName : nonResponseFieldsNames) { + newBuilderExpr = + methodMaker + .apply( + setMethodFormat(fieldName), + Collections.singletonList(getExpr(idComponentsVarExpr, Integer.toString(index)))) + .apply(newBuilderExpr); + index++; + } + MethodInvocationExpr buildExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(newBuilderExpr) .setMethodName("build") - .setReturnType(getRegionOperationRequestType) + .setReturnType(getOperationRequestType) .build(); // Return lambda anonymous class @@ -639,18 +700,6 @@ private List setPollingRequestFactoryExpr( .build()); } - // returns var.get(num); - private MethodInvocationExpr getExpr(VariableExpr var, String num) { - return MethodInvocationExpr.builder() - .setExprReferenceExpr(var) - .setMethodName("get") - .setArguments( - ValueExpr.builder() - .setValue(PrimitiveValue.builder().setValue(num).setType(TypeNode.INT).build()) - .build()) - .build(); - } - private Expr createFieldsExtractorClassInstance( Method method, TypeNode extractorReturnType, @@ -809,4 +858,120 @@ private List getHttpMethodTypeExpr(Method protoMethod) { .build(); return Collections.singletonList(expr); } + + @Override + protected List createLongRunningClient(Service service, TypeStore typeStore) { + boolean operation_polling_method = false; + Method protoMethod = null; + for (Method method : service.methods()) { + if (method.isOperationPollingMethod()) { + protoMethod = method; + operation_polling_method = true; + break; + } + } + if (operation_polling_method) { + Expr thisExpr = + ValueExpr.withValue( + ThisObjectValue.withType( + typeStore.get( + getTransportContext() + .classNames() + .getTransportServiceStubClassName(service)))); + + VariableExpr callable = + VariableExpr.withVariable( + Variable.builder() + .setName(protoMethod.name().toLowerCase() + "Callable") + .setType(TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) + .build()); + VariableExpr methodDescriptor = + VariableExpr.withVariable( + Variable.builder() + .setName(protoMethod.name().toLowerCase() + "MethodDescriptor") + .setType( + TypeNode.withReference( + ConcreteReference.withClazz(ApiMethodDescriptor.class))) + .build()); + + TypeNode httpJsonLongRunningClientType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(HttpJsonLongRunningClient.class) + .setGenerics( + Arrays.asList( + protoMethod.inputType().reference(), + protoMethod.outputType().reference())) + .build()); + + NewObjectExpr HttpJsonLongRunningClient = + NewObjectExpr.builder() + .setType(httpJsonLongRunningClientType) + .setArguments( + Arrays.asList( + callable, + MethodInvocationExpr.builder() + .setExprReferenceExpr(methodDescriptor) + .setMethodName("getOperationSnapshotFactory") + .build(), + MethodInvocationExpr.builder() + .setExprReferenceExpr(methodDescriptor) + .setMethodName("getPollingRequestFactory") + .build())) + .build(); + + AssignmentExpr assignLongRunningClient = + AssignmentExpr.builder() + .setVariableExpr( + VariableExpr.builder() + .setExprReferenceExpr(thisExpr) + .setVariable( + Variable.builder() + .setName("longRunningClient") + .setType( + TypeNode.withReference( + ConcreteReference.withClazz(LongRunningClient.class))) + .build()) + .build()) + .setValueExpr(HttpJsonLongRunningClient) + .build(); + + return Arrays.asList(ExprStatement.withExpr(assignLongRunningClient)); + } else { + return Collections.emptyList(); + } + } + + @Override + protected void declareLongRunningClient(Map classMemberVarExprs) { + classMemberVarExprs.put( + "longRunningClient", + VariableExpr.withVariable( + Variable.builder() + .setName("longRunningClient") + .setType( + TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class))) + .build())); + } + + @Override + protected void getterLongRunningClient(List javaMethods) { + VariableExpr longRunningClient = + VariableExpr.withVariable( + Variable.builder() + .setName("longRunningClient") + .setType( + TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class))) + .build()); + + javaMethods.add( + MethodDefinition.builder() + .setName("longRunningClient") + .setScope(ScopeNode.PUBLIC) + .setIsOverride(true) + .setReturnType( + TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class))) + .setReturnExpr(longRunningClient) + .build()); + } } diff --git a/src/main/java/com/google/api/generator/gapic/model/Message.java b/src/main/java/com/google/api/generator/gapic/model/Message.java index c58e62582e..51245444fe 100644 --- a/src/main/java/com/google/api/generator/gapic/model/Message.java +++ b/src/main/java/com/google/api/generator/gapic/model/Message.java @@ -18,6 +18,8 @@ import com.google.api.generator.engine.ast.Reference; import com.google.api.generator.engine.ast.TypeNode; import com.google.auto.value.AutoValue; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.util.Arrays; @@ -51,6 +53,12 @@ public abstract class Message { public abstract ImmutableMap fieldMap(); + public abstract OperationResponse operationResponse(); + + public abstract Map operationRequestFields(); + + public abstract BiMap operationResponseFields(); + // The resource name annotation (and definition) in this message. Optional. // Expected dto be empty for messages that have no such definition. @Nullable @@ -103,7 +111,10 @@ public static Builder builder() { .setOuterNestedTypes(Collections.emptyList()) .setFields(Collections.emptyList()) .setFieldMap(Collections.emptyMap()) - .setEnumValues(Collections.emptyMap()); + .setEnumValues(Collections.emptyMap()) + .setOperationResponseFields(HashBiMap.create()) + .setOperationRequestFields(Collections.emptyMap()) + .setOperationResponse(OperationResponse.builder().build()); } @AutoValue.Builder @@ -129,6 +140,13 @@ public Builder setEnumValues(List names, List numbers) { public abstract Builder setOuterNestedTypes(List outerNestedTypes); + public abstract Builder setOperationResponse(OperationResponse operationResponse); + + public abstract Builder setOperationRequestFields(Map operationRequestFields); + + public abstract Builder setOperationResponseFields( + BiMap operationRequestFields); + abstract Builder setFieldMap(Map fieldMap); abstract ImmutableList fields(); diff --git a/src/main/java/com/google/api/generator/gapic/model/Method.java b/src/main/java/com/google/api/generator/gapic/model/Method.java index 56a1403098..aaf3f4a596 100644 --- a/src/main/java/com/google/api/generator/gapic/model/Method.java +++ b/src/main/java/com/google/api/generator/gapic/model/Method.java @@ -66,6 +66,14 @@ public boolean isPaged() { // [["content", "error"], ["content", "error", "info"]]. public abstract ImmutableList> methodSignatures(); + public abstract boolean operationPollingMethod(); + + @Nullable + public abstract String operationService(); + + @Nullable + public abstract String servicePackage(); + public boolean hasLro() { return lro() != null; } @@ -82,6 +90,10 @@ public boolean isMixin() { return mixedInApiName() != null; } + public boolean isOperationPollingMethod() { + return operationPollingMethod(); + } + public abstract Builder toBuilder(); public static Builder builder() { @@ -89,7 +101,8 @@ public static Builder builder() { .setStream(Stream.NONE) .setMethodSignatures(ImmutableList.of()) .setIsBatching(false) - .setIsDeprecated(false); + .setIsDeprecated(false) + .setOperationPollingMethod(false); } public static Stream toStream(boolean isClientStreaming, boolean isServerStreaming) { @@ -131,6 +144,12 @@ public abstract static class Builder { public abstract Builder setIsDeprecated(boolean isDeprecated); + public abstract Builder setOperationPollingMethod(boolean operationPollingMethod); + + public abstract Builder setOperationService(String operationService); + + public abstract Builder setServicePackage(String servicePackage); + public abstract Method build(); } } diff --git a/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java b/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java new file mode 100644 index 0000000000..1a141479ac --- /dev/null +++ b/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java @@ -0,0 +1,56 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.api.generator.gapic.model; + +import com.google.auto.value.AutoValue; +import javax.annotation.Nullable; + +@AutoValue +public abstract class OperationResponse { + @Nullable + public abstract String getNameFieldName(); + + @Nullable + public abstract String getStatusFieldName(); + + @Nullable + public abstract String getErrorCodeFieldName(); + + @Nullable + public abstract String getErrorMessageFieldName(); + + @Nullable + public abstract String getStatusFieldTypeName(); + + public static Builder builder() { + return new AutoValue_OperationResponse.Builder(); + } + + @AutoValue.Builder + public abstract static class Builder { + public abstract Builder setNameFieldName(String nameFieldName); + + public abstract Builder setStatusFieldName(String val); + + public abstract Builder setErrorCodeFieldName(String val); + + public abstract Builder setErrorMessageFieldName(String val); + + public abstract Builder setStatusFieldTypeName(String className); + + public abstract OperationResponse build(); + } +} diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/BUILD.bazel b/src/main/java/com/google/api/generator/gapic/protoparser/BUILD.bazel index 6cccdd373a..904b7fbf2b 100644 --- a/src/main/java/com/google/api/generator/gapic/protoparser/BUILD.bazel +++ b/src/main/java/com/google/api/generator/gapic/protoparser/BUILD.bazel @@ -30,6 +30,7 @@ java_library( "@com_google_code_findbugs_jsr305//jar", "@com_google_code_gson//jar", "@com_google_googleapis//google/api:api_java_proto", + "@com_google_googleapis//google/cloud:extended_operations_java_proto", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_guava_guava//jar", "@com_google_protobuf//:protobuf_java", diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java index 42e2abaa2f..0fdbb86c2b 100644 --- a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java +++ b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java @@ -30,15 +30,20 @@ import com.google.api.generator.gapic.model.LongrunningOperation; import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; +import com.google.api.generator.gapic.model.OperationResponse; import com.google.api.generator.gapic.model.ResourceName; import com.google.api.generator.gapic.model.ResourceReference; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.model.SourceCodeInfoLocation; import com.google.api.generator.gapic.model.Transport; import com.google.api.generator.gapic.utils.ResourceNameConstants; +import com.google.cloud.ExtendedOperationsProto; +import com.google.cloud.OperationResponseMapping; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.base.Strings; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Maps; import com.google.longrunning.OperationInfo; @@ -554,6 +559,35 @@ private static Map parseMessages( } } TypeNode messageType = TypeParser.parseType(messageDescriptor); + + List fields = messageDescriptor.getFields(); + HashMap operationRequestFields = new HashMap(); + BiMap operationResponseFields = HashBiMap.create(); + OperationResponse.Builder operationResponse = OperationResponse.builder(); + for (FieldDescriptor fd : fields) { + if (fd.getOptions().hasExtension(ExtendedOperationsProto.operationRequestField)) { + String orf = fd.getOptions().getExtension(ExtendedOperationsProto.operationRequestField); + operationRequestFields.put(orf, fd.getName()); + } + if (fd.getOptions().hasExtension(ExtendedOperationsProto.operationResponseField)) { + String orf = fd.getOptions().getExtension(ExtendedOperationsProto.operationResponseField); + operationResponseFields.put(orf, fd.getName()); + } + if (fd.getOptions().hasExtension(ExtendedOperationsProto.operationField)) { + OperationResponseMapping orm = + fd.getOptions().getExtension(ExtendedOperationsProto.operationField); + if (orm.equals(OperationResponseMapping.NAME)) { + operationResponse.setNameFieldName(fd.getName()); + } else if (orm.equals(OperationResponseMapping.STATUS)) { + operationResponse.setStatusFieldName(fd.getName()); + operationResponse.setStatusFieldTypeName(fd.toProto().getTypeName()); + } else if (orm.equals(OperationResponseMapping.ERROR_CODE)) { + operationResponse.setErrorCodeFieldName(fd.getName()); + } else if (orm.equals(OperationResponseMapping.ERROR_MESSAGE)) { + operationResponse.setErrorMessageFieldName(fd.getName()); + } + } + } messages.put( messageType.reference().fullName(), Message.builder() @@ -562,6 +596,9 @@ private static Map parseMessages( .setFullProtoName(messageDescriptor.getFullName()) .setFields(parseFields(messageDescriptor, outputResourceReferencesSeen)) .setOuterNestedTypes(outerNestedTypes) + .setOperationRequestFields(operationRequestFields) + .setOperationResponseFields(operationResponseFields) + .setOperationResponse(operationResponse.build()) .build()); return messages; } @@ -664,6 +701,17 @@ static List parseMethods( serviceDescriptor.getName(), protoMethod.getName()); + boolean operationPollingMethod = + protoMethod.getOptions().hasExtension(ExtendedOperationsProto.operationPollingMethod) + ? protoMethod + .getOptions() + .getExtension(ExtendedOperationsProto.operationPollingMethod) + : false; + String operationService = + protoMethod.getOptions().hasExtension(ExtendedOperationsProto.operationService) + ? protoMethod.getOptions().getExtension(ExtendedOperationsProto.operationService) + : null; + methods.add( methodBuilder .setName(protoMethod.getName()) @@ -684,6 +732,9 @@ static List parseMethods( .setIsBatching(isBatching) .setPageSizeFieldName(parsePageSizeFieldName(protoMethod, messageTypes, transport)) .setIsDeprecated(isDeprecated) + .setOperationPollingMethod(operationPollingMethod) + .setOperationService(operationService) + .setServicePackage(servicePackage) .build()); // Any input type that has a resource reference will need a resource name helper class. diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden index 0b58310417..f2b65c4025 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden @@ -2,7 +2,6 @@ package com.google.showcase.v1beta1.stub; import com.google.api.core.BetaApi; import com.google.api.gax.core.BackgroundResource; -import com.google.api.gax.httpjson.ApiMessage; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; @@ -27,7 +26,7 @@ import javax.annotation.Generated; @BetaApi @Generated("by gapic-generator-java") public class HttpJsonComplianceCallableFactory - implements HttpJsonStubCallableFactory { + implements HttpJsonStubCallableFactory { @Override public UnaryCallable createUnaryCallable( @@ -62,14 +61,14 @@ public class HttpJsonComplianceCallableFactory @Override public OperationCallable createOperationCallable( - HttpJsonCallSettings httpJsonCallSettings, + HttpJsonCallSettings httpJsonCallSettings, OperationCallSettings callSettings, ClientContext clientContext, BackgroundResource operationsStub) { UnaryCallable innerCallable = HttpJsonCallableFactory.createBaseUnaryCallable( httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); - UnaryCallable initialCallable = + HttpJsonOperationSnapshotCallable initialCallable = new HttpJsonOperationSnapshotCallable( innerCallable, httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java index 49347e5792..b9e0385e12 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java @@ -18,7 +18,6 @@ import com.google.api.core.BetaApi; import com.google.api.gax.core.BackgroundResource; -import com.google.api.gax.httpjson.ApiMessage; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; @@ -42,7 +41,7 @@ @Generated("by gapic-generator-java") @BetaApi public class HttpJsonAddressesCallableFactory - implements HttpJsonStubCallableFactory { + implements HttpJsonStubCallableFactory { @Override public UnaryCallable createUnaryCallable( @@ -77,14 +76,14 @@ public UnaryCallable createBatchingCa @Override public OperationCallable createOperationCallable( - HttpJsonCallSettings httpJsonCallSettings, + HttpJsonCallSettings httpJsonCallSettings, OperationCallSettings callSettings, ClientContext clientContext, BackgroundResource operationsStub) { UnaryCallable innerCallable = HttpJsonCallableFactory.createBaseUnaryCallable( httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); - UnaryCallable initialCallable = + HttpJsonOperationSnapshotCallable initialCallable = new HttpJsonOperationSnapshotCallable( innerCallable, httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java index e2d4a26060..d79d2cc64a 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java @@ -38,14 +38,12 @@ import com.google.cloud.compute.v1.AddressList; import com.google.cloud.compute.v1.AggregatedListAddressesRequest; import com.google.cloud.compute.v1.DeleteAddressRequest; -import com.google.cloud.compute.v1.GetRegionOperationRequest; import com.google.cloud.compute.v1.InsertAddressRequest; import com.google.cloud.compute.v1.ListAddressesRequest; import com.google.cloud.compute.v1.Operation; -import com.google.cloud.compute.v1.Status; +import com.google.cloud.compute.v1.Operation.Status; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -144,26 +142,17 @@ public class HttpJsonAddressesStub extends AddressesStub { .build()) .setOperationSnapshotFactory( (DeleteAddressRequest request, Operation response) -> { - StringBuilder opName = new StringBuilder(response.getId()); + StringBuilder opName = new StringBuilder(response.getName()); opName.append(":").append(request.getProject()); opName.append(":").append(request.getRegion()); return HttpJsonOperationSnapshot.newBuilder() .setName(opName.toString()) .setMetadata(response) - .setDone(response.getStatus().equals(Status.DONE)) + .setDone(Status.DONE.equals(response.getStatus())) .setResponse(response) .setError(response.getHttpErrorStatusCode(), response.getHttpErrorMessage()) .build(); }) - .setPollingRequestFactory( - compoundOperationId -> { - List idComponents = Arrays.asList(compoundOperationId.split(":")); - return GetRegionOperationRequest.newBuilder() - .setOperation(idComponents.get(0)) - .setProject(idComponents.get(1)) - .setRegion(idComponents.get(2)) - .build(); - }) .build(); private static final ApiMethodDescriptor insertMethodDescriptor = @@ -203,26 +192,17 @@ public class HttpJsonAddressesStub extends AddressesStub { .build()) .setOperationSnapshotFactory( (InsertAddressRequest request, Operation response) -> { - StringBuilder opName = new StringBuilder(response.getId()); + StringBuilder opName = new StringBuilder(response.getName()); opName.append(":").append(request.getProject()); opName.append(":").append(request.getRegion()); return HttpJsonOperationSnapshot.newBuilder() .setName(opName.toString()) .setMetadata(response) - .setDone(response.getStatus().equals(Status.DONE)) + .setDone(Status.DONE.equals(response.getStatus())) .setResponse(response) .setError(response.getHttpErrorStatusCode(), response.getHttpErrorMessage()) .build(); }) - .setPollingRequestFactory( - compoundOperationId -> { - List idComponents = Arrays.asList(compoundOperationId.split(":")); - return GetRegionOperationRequest.newBuilder() - .setOperation(idComponents.get(0)) - .setProject(idComponents.get(1)) - .setRegion(idComponents.get(2)) - .build(); - }) .build(); private static final ApiMethodDescriptor listMethodDescriptor = diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java index 6113b5f496..b775dbba59 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java @@ -18,7 +18,6 @@ import com.google.api.core.BetaApi; import com.google.api.gax.core.BackgroundResource; -import com.google.api.gax.httpjson.ApiMessage; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; @@ -42,7 +41,7 @@ @Generated("by gapic-generator-java") @BetaApi public class HttpJsonRegionOperationsCallableFactory - implements HttpJsonStubCallableFactory { + implements HttpJsonStubCallableFactory { @Override public UnaryCallable createUnaryCallable( @@ -77,14 +76,14 @@ public UnaryCallable createBatchingCa @Override public OperationCallable createOperationCallable( - HttpJsonCallSettings httpJsonCallSettings, + HttpJsonCallSettings httpJsonCallSettings, OperationCallSettings callSettings, ClientContext clientContext, BackgroundResource operationsStub) { UnaryCallable innerCallable = HttpJsonCallableFactory.createBaseUnaryCallable( httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); - UnaryCallable initialCallable = + HttpJsonOperationSnapshotCallable initialCallable = new HttpJsonOperationSnapshotCallable( innerCallable, httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java index 47bc6a36a7..1949dd2c60 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java @@ -23,6 +23,7 @@ import com.google.api.gax.core.BackgroundResourceAggregation; import com.google.api.gax.httpjson.ApiMethodDescriptor; import com.google.api.gax.httpjson.HttpJsonCallSettings; +import com.google.api.gax.httpjson.HttpJsonLongRunningClient; import com.google.api.gax.httpjson.HttpJsonOperationSnapshot; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.httpjson.ProtoMessageRequestFormatter; @@ -30,10 +31,11 @@ import com.google.api.gax.httpjson.ProtoRestSerializer; import com.google.api.gax.longrunning.OperationSnapshot; import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.rpc.LongRunningClient; import com.google.api.gax.rpc.UnaryCallable; import com.google.cloud.compute.v1.GetRegionOperationRequest; import com.google.cloud.compute.v1.Operation; -import com.google.cloud.compute.v1.Status; +import com.google.cloud.compute.v1.Operation.Status; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -85,13 +87,11 @@ public class HttpJsonRegionOperationsStub extends RegionOperationsStub { .build()) .setOperationSnapshotFactory( (GetRegionOperationRequest request, Operation response) -> { - StringBuilder opName = new StringBuilder(response.getId()); - opName.append(":").append(request.getProject()); - opName.append(":").append(request.getRegion()); + StringBuilder opName = new StringBuilder(response.getName()); return HttpJsonOperationSnapshot.newBuilder() .setName(opName.toString()) .setMetadata(response) - .setDone(response.getStatus().equals(Status.DONE)) + .setDone(Status.DONE.equals(response.getStatus())) .setResponse(response) .setError(response.getHttpErrorStatusCode(), response.getHttpErrorMessage()) .build(); @@ -110,6 +110,7 @@ public class HttpJsonRegionOperationsStub extends RegionOperationsStub { private final UnaryCallable getCallable; private final BackgroundResource backgroundResources; + private final LongRunningClient longRunningClient; private final HttpJsonStubCallableFactory callableFactory; public static final HttpJsonRegionOperationsStub create(RegionOperationsStubSettings settings) @@ -160,6 +161,11 @@ protected HttpJsonRegionOperationsStub( callableFactory.createUnaryCallable( getTransportSettings, settings.getSettings(), clientContext); + this.longRunningClient = + new HttpJsonLongRunningClient( + getCallable, + getMethodDescriptor.getOperationSnapshotFactory(), + getMethodDescriptor.getPollingRequestFactory()); this.backgroundResources = new BackgroundResourceAggregation(clientContext.getBackgroundResources()); } @@ -176,6 +182,11 @@ public UnaryCallable getCallable() { return getCallable; } + @Override + public LongRunningClient longRunningClient() { + return longRunningClient; + } + @Override public final void close() { try { From 957f69a0dc063e77b5e49da28f0a6d9a4a6c3bdb Mon Sep 17 00:00:00 2001 From: Vadym Matsishevskyi <25311427+vam-google@users.noreply.github.com> Date: Mon, 6 Sep 2021 14:01:46 -0700 Subject: [PATCH 4/9] fix: fix diregapic-lro logic (#834) There are 2 more things left: 1) longRunnignOperation() getter method on the transport-agnostic (parent) class 2) proper (transport-specific) Response and Metadata transformers for OperationSettings initialization --- ...ctServiceCallableFactoryClassComposer.java | 55 ++++++---- .../AbstractServiceStubClassComposer.java | 50 ++++++--- .../common/ServiceClientClassComposer.java | 6 +- .../common/ServiceStubClassComposer.java | 10 +- ...pcServiceCallableFactoryClassComposer.java | 38 ++++--- ...onServiceCallableFactoryClassComposer.java | 47 ++++---- .../HttpJsonServiceStubClassComposer.java | 56 ++++------ .../gapic/model/LongrunningOperation.java | 20 ++-- .../api/generator/gapic/model/Method.java | 10 -- .../gapic/model/OperationResponse.java | 10 +- .../api/generator/gapic/model/Service.java | 30 ++++++ .../generator/gapic/protoparser/Parser.java | 60 +++++++---- .../HttpJsonComplianceCallableFactory.golden | 1 - .../ServiceClientSampleCodeComposerTest.java | 60 +++++++++-- .../gapic/protoparser/ParserTest.java | 4 +- .../cloud/compute/v1/AddressesClient.java | 89 +++++++++++++--- .../cloud/compute/v1/AddressesClientTest.java | 43 +++++--- .../cloud/compute/v1/AddressesSettings.java | 31 +++++- .../cloud/compute/v1/gapic_metadata.json | 4 +- .../google/cloud/compute/v1/package-info.java | 7 +- .../cloud/compute/v1/stub/AddressesStub.java | 13 +++ .../v1/stub/AddressesStubSettings.java | 100 +++++++++++++++++- .../HttpJsonAddressesCallableFactory.java | 7 +- .../v1/stub/HttpJsonAddressesStub.java | 29 +++++ 24 files changed, 562 insertions(+), 218 deletions(-) diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java index d643c9726b..ea3898051c 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java @@ -41,7 +41,6 @@ import com.google.api.generator.gapic.model.GapicClass; import com.google.api.generator.gapic.model.GapicClass.Kind; import com.google.api.generator.gapic.model.GapicContext; -import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.Service; import java.util.ArrayList; import java.util.Arrays; @@ -63,19 +62,13 @@ protected TransportContext getTransportContext() { @Override public GapicClass generate(GapicContext context, Service service) { - TypeStore typeStore = createTypes(); + TypeStore typeStore = createTypes(service); + String className = getTransportContext().classNames().getTransportServiceCallableFactoryClassName(service); GapicClass.Kind kind = Kind.STUB; String pakkage = String.format("%s.stub", service.pakkage()); - String operationService = ""; - for(Method method : service.methods()) { - if(method.operationService() != null) { - operationService = method.operationService(); - } - } - StubCommentComposer commentComposer = new StubCommentComposer(getTransportContext().transportName()); ClassDefinition classDef = @@ -85,9 +78,9 @@ public GapicClass generate(GapicContext context, Service service) { commentComposer.createTransportServiceCallableFactoryClassHeaderComments( service.name(), service.isDeprecated())) .setAnnotations(createClassAnnotations(service, typeStore)) - .setImplementsTypes(createClassImplements(typeStore)) + .setImplementsTypes(createClassImplements(typeStore, service)) .setName(className) - .setMethods(createClassMethods(typeStore, operationService)) + .setMethods(createClassMethods(service, typeStore)) .setScope(ScopeNode.PUBLIC) .build(); return GapicClass.create(kind, classDef); @@ -118,22 +111,23 @@ protected List createClassAnnotations(Service service, TypeStore * @return {@code TypeNode} containing the interface to be implemented by the generated callable * factory class. */ - protected abstract List createClassImplements(TypeStore typeStore); + protected abstract List createClassImplements(TypeStore typeStore, Service service); - protected List createClassMethods(TypeStore typeStore, String operationService) { + protected List createClassMethods(Service service, TypeStore typeStore) { return Arrays.asList( - createUnaryCallableMethod(typeStore), - createPagedCallableMethod(typeStore), - createBatchingCallableMethod(typeStore), - createOperationCallableMethod(typeStore, operationService)); + createUnaryCallableMethod(service, typeStore), + createPagedCallableMethod(service, typeStore), + createBatchingCallableMethod(service, typeStore), + createOperationCallableMethod(service, typeStore)); } - protected MethodDefinition createUnaryCallableMethod(TypeStore typeStore) { + protected MethodDefinition createUnaryCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Unary"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -148,7 +142,7 @@ protected MethodDefinition createUnaryCallableMethod(TypeStore typeStore) { .collect(Collectors.toList())); } - protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { + protected MethodDefinition createPagedCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Paged"; String requestTemplateName = "RequestT"; String pagedResponseTemplateName = "PagedListResponseT"; @@ -156,6 +150,7 @@ protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName, pagedResponseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ "Unary", @@ -170,12 +165,13 @@ protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { .collect(Collectors.toList())); } - protected MethodDefinition createBatchingCallableMethod(TypeStore typeStore) { + protected MethodDefinition createBatchingCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Batching"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ "Unary", @@ -190,9 +186,11 @@ protected MethodDefinition createBatchingCallableMethod(TypeStore typeStore) { .collect(Collectors.toList())); } - protected abstract MethodDefinition createOperationCallableMethod(TypeStore typeStore, String operationService); + protected abstract MethodDefinition createOperationCallableMethod( + Service service, TypeStore typeStore); protected MethodDefinition createGenericCallableMethod( + Service service, TypeStore typeStore, List methodTemplateNames, String returnCallableKindName, @@ -202,6 +200,7 @@ protected MethodDefinition createGenericCallableMethod( String callSettingsVariantName, List callSettingsTemplateObjects) { return createGenericCallableMethod( + service, typeStore, methodTemplateNames, returnCallableKindName, @@ -214,6 +213,7 @@ protected MethodDefinition createGenericCallableMethod( } protected MethodDefinition createGenericCallableMethod( + Service service, TypeStore typeStore, List methodTemplateNames, String returnCallableKindName, @@ -265,7 +265,7 @@ protected MethodDefinition createGenericCallableMethod( .setVariable( Variable.builder() .setName("operationsStub") - .setType(getTransportContext().operationsStubType()) + .setType(getOperationsStubType(service)) .build()) .setIsDecl(true) .build()); @@ -296,7 +296,16 @@ protected MethodDefinition createGenericCallableMethod( .build(); } - private static TypeStore createTypes() { + protected TypeNode getOperationsStubType(Service service) { + TypeNode opeationsStubType = service.operationServiceStubType(); + if (opeationsStubType == null) { + opeationsStubType = getTransportContext().operationsStubType(); + } + return opeationsStubType; + } + + + private TypeStore createTypes(Service service) { List concreteClazzes = Arrays.asList( // Gax-java classes. diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java index 3202684691..8935e0b00c 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java @@ -44,6 +44,7 @@ import com.google.api.generator.engine.ast.TryCatchStatement; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; +import com.google.api.generator.engine.ast.VaporReference; import com.google.api.generator.engine.ast.Variable; import com.google.api.generator.engine.ast.VariableExpr; import com.google.api.generator.gapic.composer.comment.StubCommentComposer; @@ -63,6 +64,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -144,19 +146,25 @@ public GapicClass generate(GapicContext context, Service service) { .setName(BACKGROUND_RESOURCES_MEMBER_NAME) .setType(FIXED_TYPESTORE.get("BackgroundResource")) .build())); - if (getTransportContext().transportOperationsStubType() != null) { + + + TypeNode opeationsStubType = getTransportOperationsStubType(service); + if (opeationsStubType != null) { classMemberVarExprs.put( OPERATIONS_STUB_MEMBER_NAME, VariableExpr.withVariable( Variable.builder() .setName(OPERATIONS_STUB_MEMBER_NAME) - .setType(getTransportContext().transportOperationsStubType()) + .setType(opeationsStubType) .build())); } boolean operationPollingMethod = checkOperationPollingMethod(service); if(operationPollingMethod) { - declareLongRunningClient(classMemberVarExprs); + VariableExpr longRunningVarExpr = declareLongRunningClient(); + if (longRunningVarExpr != null) { + classMemberVarExprs.put("longRunningClient", longRunningVarExpr); + } } classMemberVarExprs.put( @@ -554,14 +562,16 @@ protected List createConstructorMethods( .setValueExpr(callableFactoryVarExpr) .build()); VariableExpr operationsStubClassVarExpr = classMemberVarExprs.get(OPERATIONS_STUB_MEMBER_NAME); - if (getTransportContext().transportOperationsStubType() != null) { + + TypeNode opeationsStubType = getTransportOperationsStubType(service); + if (opeationsStubType != null) { secondCtorExprs.add( AssignmentExpr.builder() .setVariableExpr( operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) .setValueExpr( MethodInvocationExpr.builder() - .setStaticReferenceType(getTransportContext().transportOperationsStubType()) + .setStaticReferenceType(opeationsStubType) .setMethodName("create") .setArguments(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr)) .setReturnType(operationsStubClassVarExpr.type()) @@ -670,8 +680,8 @@ protected List createLongRunningClient(Service service, TypeStore typ return ImmutableList.of(); } - protected void declareLongRunningClient(Map classMemberVarExprs) { - + protected VariableExpr declareLongRunningClient() { + return null; } private static Expr createCallableInitExpr( @@ -845,10 +855,8 @@ private List createStubOverrideMethods( .build()) .build(); List javaMethods = new ArrayList<>(); - //TODO: check for operation polling method - boolean operationPollingMethod = checkOperationPollingMethod(service); - if (operationPollingMethod) { - getterLongRunningClient(javaMethods); + if (service.operationPollingMethod() != null) { + javaMethods.addAll(createLongRunningClientGetter()); } javaMethods.add( methodMakerStarterFn @@ -931,8 +939,8 @@ private boolean checkOperationPollingMethod(Service service) { return false; } - protected void getterLongRunningClient(List javaMethods) { - + protected List createLongRunningClientGetter() { + return Collections.emptyList(); } private TypeStore createDynamicTypes(Service service, String stubPakkage) { @@ -1002,4 +1010,20 @@ protected String getProtoRpcFullMethodName(Service protoService, Method protoMet return String.format( "%s.%s/%s", protoService.protoPakkage(), protoService.name(), protoMethod.name()); } + + protected TypeNode getTransportOperationsStubType(Service service) { + TypeNode transportOpeationsStubType = service.operationServiceStubType(); + if (transportOpeationsStubType == null) { + transportOpeationsStubType = getTransportContext().transportOperationsStubType(); + } + else { + transportOpeationsStubType = TypeNode.withReference( + VaporReference.builder() + .setName("HttpJson" + transportOpeationsStubType.reference().simpleName()) + .setPakkage(transportOpeationsStubType.reference().pakkage()) + .build()); + } + + return transportOpeationsStubType; + } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposer.java index 5a38db0562..4f804822f1 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposer.java @@ -129,7 +129,7 @@ public GapicClass generate(GapicContext context, Service service) { String className = ClassNames.getServiceClientClassName(service); GapicClass.Kind kind = Kind.MAIN; String pakkage = service.pakkage(); - boolean hasLroClient = hasLroMethods(service); + boolean hasLroClient = exposeOperationsClient(service); Map> grpcRpcsToJavaMethodNames = new HashMap<>(); @@ -216,9 +216,9 @@ private static List createClassMethods( return methods; } - private static boolean hasLroMethods(Service service) { + private static boolean exposeOperationsClient(Service service) { for (Method method : service.methods()) { - if (method.hasLro()) { + if (method.hasLro() && method.lro().operationServiceStubType() == null) { return true; } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposer.java index 9d16f98f88..1c8bed3ccb 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposer.java @@ -112,7 +112,11 @@ private static List createClassMethods( boolean hasLroClient = hasLroMethods(service); List methods = new ArrayList<>(); if (hasLroClient) { - methods.add(createOperationsStubGetter(typeStore)); + TypeNode operationsStubType = service.operationServiceStubType(); + if (operationsStubType == null) { + operationsStubType = typeStore.get("OperationsStub"); + } + methods.add(createOperationsStubGetter(typeStore, operationsStubType)); } methods.addAll(createCallableGetters(service, messageTypes, typeStore)); methods.addAll(createBackgroundResourceMethodOverrides()); @@ -203,11 +207,11 @@ private static MethodDefinition createCallableGetterHelper( .build(); } - private static MethodDefinition createOperationsStubGetter(TypeStore typeStore) { + private static MethodDefinition createOperationsStubGetter(TypeStore typeStore, TypeNode operationsStubType) { String methodName = "getOperationsStub"; return MethodDefinition.builder() .setScope(ScopeNode.PUBLIC) - .setReturnType(typeStore.get("OperationsStub")) + .setReturnType(operationsStubType) .setName(methodName) .setBody(createThrowUOEBody(methodName, typeStore)) .build(); diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java index 06bb6695b2..38446187e8 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java @@ -19,6 +19,7 @@ import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.gapic.composer.common.AbstractServiceCallableFactoryClassComposer; import com.google.api.generator.gapic.composer.store.TypeStore; +import com.google.api.generator.gapic.model.Service; import com.google.longrunning.Operation; import java.util.ArrayList; import java.util.Arrays; @@ -41,28 +42,30 @@ public static GrpcServiceCallableFactoryClassComposer instance() { } @Override - protected List createClassImplements(TypeStore typeStore) { + protected List createClassImplements(TypeStore typeStore, Service service) { return Arrays.asList(getTransportContext().stubCallableFactoryType()); } - protected List createClassMethods( - TypeStore typeStore, String operationService) { + @Override + protected List createClassMethods(Service service, TypeStore typeStore) { List classMethods = - new ArrayList<>(super.createClassMethods(typeStore, operationService)); + new ArrayList<>(super.createClassMethods(service, typeStore)); classMethods.addAll( Arrays.asList( - createBidiStreamingCallableMethod(typeStore), - createServerStreamingCallableMethod(typeStore), - createClientStreamingCallableMethod(typeStore))); + createBidiStreamingCallableMethod(service, typeStore), + createServerStreamingCallableMethod(service, typeStore), + createClientStreamingCallableMethod(service, typeStore))); return classMethods; } - protected MethodDefinition createUnaryCallableMethod(TypeStore typeStore) { + @Override + protected MethodDefinition createUnaryCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Unary"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -77,7 +80,8 @@ protected MethodDefinition createUnaryCallableMethod(TypeStore typeStore) { .collect(Collectors.toList())); } - protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { + @Override + protected MethodDefinition createPagedCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Paged"; String requestTemplateName = "RequestT"; String pagedResponseTemplateName = "PagedListResponseT"; @@ -85,6 +89,7 @@ protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName, pagedResponseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ "Unary", @@ -100,14 +105,14 @@ protected MethodDefinition createPagedCallableMethod(TypeStore typeStore) { } @Override - protected MethodDefinition createOperationCallableMethod( - TypeStore typeStore, String operationService) { + protected MethodDefinition createOperationCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Operation"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName, "MetadataT"); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -120,12 +125,13 @@ protected MethodDefinition createOperationCallableMethod( .collect(Collectors.toList())); } - private MethodDefinition createBidiStreamingCallableMethod(TypeStore typeStore) { + private MethodDefinition createBidiStreamingCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "BidiStreaming"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -140,12 +146,14 @@ private MethodDefinition createBidiStreamingCallableMethod(TypeStore typeStore) .collect(Collectors.toList())); } - private MethodDefinition createServerStreamingCallableMethod(TypeStore typeStore) { + private MethodDefinition createServerStreamingCallableMethod( + Service service, TypeStore typeStore) { String methodVariantName = "ServerStreaming"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, @@ -160,12 +168,14 @@ private MethodDefinition createServerStreamingCallableMethod(TypeStore typeStore .collect(Collectors.toList())); } - private MethodDefinition createClientStreamingCallableMethod(TypeStore typeStore) { + private MethodDefinition createClientStreamingCallableMethod( + Service service, TypeStore typeStore) { String methodVariantName = "ClientStreaming"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName); return createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java index 919e6c973c..7f8a966859 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java @@ -14,7 +14,6 @@ package com.google.api.generator.gapic.composer.rest; -import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.httpjson.HttpJsonCallableFactory; import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.rpc.OperationCallable; @@ -45,10 +44,8 @@ public class HttpJsonServiceCallableFactoryClassComposer private static final HttpJsonServiceCallableFactoryClassComposer INSTANCE = new HttpJsonServiceCallableFactoryClassComposer(); - private static final TypeNode MESSAGE_TYPE = + private static final TypeNode DEFAULT_OPERATION_TYPE = TypeNode.withReference(ConcreteReference.withClazz(Operation.class)); - private static final TypeNode BACKGROUND_RESOURCE_TYPE = - TypeNode.withReference(ConcreteReference.withClazz(BackgroundResource.class)); private HttpJsonServiceCallableFactoryClassComposer() { super(RestContext.instance()); @@ -73,23 +70,29 @@ protected List createClassAnnotations(Service service, TypeStore } @Override - protected List createClassImplements(TypeStore typeStore) { + protected List createClassImplements(TypeStore typeStore, Service service) { + TypeNode operationsStubType = getOperationsStubType(service); + + TypeNode operationType = service.operationType(); + if (operationType == null) { + operationType = DEFAULT_OPERATION_TYPE; + } + return Arrays.asList( TypeNode.withReference( getTransportContext() .stubCallableFactoryType() .reference() .copyAndSetGenerics( - Arrays.asList( - MESSAGE_TYPE.reference(), BACKGROUND_RESOURCE_TYPE.reference())))); + Arrays.asList(operationType.reference(), operationsStubType.reference())))); } @Override - protected MethodDefinition createOperationCallableMethod( - TypeStore typeStore, String operationService) { + protected MethodDefinition createOperationCallableMethod(Service service, TypeStore typeStore) { String methodVariantName = "Operation"; String requestTemplateName = "RequestT"; String responseTemplateName = "ResponseT"; + List methodTemplateNames = Arrays.asList(requestTemplateName, responseTemplateName, "MetadataT"); @@ -104,36 +107,28 @@ protected MethodDefinition createOperationCallableMethod( + " future."); // Generate generic method without the body - // TODO: change static usages to vapor references + TypeNode operationType = service.operationType(); + if (operationType == null) { + operationType = DEFAULT_OPERATION_TYPE; + } MethodDefinition method = createGenericCallableMethod( + service, typeStore, /*methodTemplateNames=*/ methodTemplateNames, /*returnCallableKindName=*/ methodVariantName, /*returnCallableTemplateNames=*/ methodTemplateNames, /*methodVariantName=*/ methodVariantName, /*httpJsonCallSettingsTemplateObjects=*/ Arrays.asList( - requestTemplateName, MESSAGE_TYPE), + requestTemplateName, operationType), /*callSettingsVariantName=*/ methodVariantName, /*callSettingsTemplateObjects=*/ methodTemplateNames.stream() .map(n -> (Object) n) .collect(Collectors.toList()), Arrays.asList(betaAnnotation)); - // if (operationService.equals("")) { - // return method.toBuilder().setReturnExpr(ValueExpr.createNullExpr()).build(); - // } - List createOperationCallableBody = new ArrayList(2); - List arguments = new ArrayList<>(method.arguments()); - // Variable stubVar = arguments.get(3).variable(); - // stubVar = Variable.builder() - // .setName(stubVar.identifier().name()) - // .setType(typeStore.get(operationService+"Stub")) - // .build(); - // arguments.set(3,VariableExpr.withVariable(stubVar)); - // method = method.toBuilder().setArguments(arguments).build(); Variable httpJsonCallSettingsVar = arguments.get(0).variable(); Variable operationCallSettingsVar = arguments.get(1).variable(); @@ -177,14 +172,14 @@ protected MethodDefinition createOperationCallableMethod( VaporReference requestT = VaporReference.builder() .setName("RequestT") - .setPakkage("com.google.cloud.compute.v1.stub") + .setPakkage(service.pakkage() + ".stub") .build(); TypeNode initialCallableType = TypeNode.withReference( ConcreteReference.builder() .setClazz(HttpJsonOperationSnapshotCallable.class) - .setGenerics(requestT, ConcreteReference.withClazz(Operation.class)) + .setGenerics(requestT, operationType.reference()) .build()); // Generate initialCallable @@ -213,7 +208,7 @@ protected MethodDefinition createOperationCallableMethod( TypeNode.withReference( ConcreteReference.builder() .setClazz(HttpJsonOperationSnapshotCallable.class) - .setGenerics(requestT, ConcreteReference.withClazz(Operation.class)) + .setGenerics(requestT, operationType.reference()) .build()); NewObjectExpr initialCallableObject = NewObjectExpr.builder() diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java index d00e23c5fc..39974fe44a 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java @@ -131,7 +131,7 @@ protected Statement createMethodDescriptorVariableDecl( methodMaker.apply("setRequestFormatter", getRequestFormatterExpr(protoMethod)).apply(expr); expr = methodMaker.apply("setResponseParser", setResponseParserExpr(protoMethod)).apply(expr); - if (protoMethod.isOperationPollingMethod() || protoMethod.operationService() != null) { + if (protoMethod.isOperationPollingMethod() || protoMethod.hasLro()) { expr = methodMaker .apply( @@ -139,6 +139,7 @@ protected Statement createMethodDescriptorVariableDecl( setOperationSnapshotFactoryExpr(protoMethod, messageTypes)) .apply(expr); } + if (protoMethod.isOperationPollingMethod()) { expr = methodMaker @@ -470,7 +471,7 @@ private List setOperationSnapshotFactoryExpr( MethodInvocationExpr getId = MethodInvocationExpr.builder() .setExprReferenceExpr(responseVarExpr) - .setMethodName(getMethodFormat(operationResponse.getNameFieldName())) + .setMethodName(getMethodFormat(operationResponse.nameFieldName())) .build(); Expr opNameObjectExpr = NewObjectExpr.builder().setType(stringBuilderType).setArguments(getId).build(); @@ -496,19 +497,17 @@ private List setOperationSnapshotFactoryExpr( MethodInvocationExpr getStatusExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(responseVarExpr) - .setMethodName(getMethodFormat(operationResponse.getStatusFieldName())) + .setMethodName(getMethodFormat(operationResponse.statusFieldName())) .build(); - String statusTypeName = operationResponse.getStatusFieldTypeName(); + String statusTypeName = operationResponse.statusFieldTypeName(); String statusClassName = statusTypeName.substring(statusTypeName.lastIndexOf('.') + 1); - String statusPackage = protoMethod.servicePackage(); // "com" + - // statusTypeName.substring(0,statusTypeName.lastIndexOf('.')); TypeNode statusType = TypeNode.withReference( VaporReference.builder() .setName(statusClassName) - .setPakkage(statusPackage + "." + protoMethod.outputType().reference().simpleName()) + .setPakkage(protoMethod.outputType().reference().fullName()) .setIsStaticImport(false) .build()); VariableExpr statusDoneExpr = @@ -536,12 +535,12 @@ private List setOperationSnapshotFactoryExpr( MethodInvocationExpr getHttpErrorStatusCodeExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(responseVarExpr) - .setMethodName(getMethodFormat(operationResponse.getErrorCodeFieldName())) + .setMethodName(getMethodFormat(operationResponse.errorCodeFieldName())) .build(); MethodInvocationExpr getHttpErrorMessageExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(responseVarExpr) - .setMethodName(getMethodFormat(operationResponse.getErrorMessageFieldName())) + .setMethodName(getMethodFormat(operationResponse.errorMessageFieldName())) .build(); MethodInvocationExpr newBuilderExpr = MethodInvocationExpr.builder() @@ -861,16 +860,8 @@ private List getHttpMethodTypeExpr(Method protoMethod) { @Override protected List createLongRunningClient(Service service, TypeStore typeStore) { - boolean operation_polling_method = false; - Method protoMethod = null; - for (Method method : service.methods()) { - if (method.isOperationPollingMethod()) { - protoMethod = method; - operation_polling_method = true; - break; - } - } - if (operation_polling_method) { + Method pollingMethod = service.operationPollingMethod(); + if (pollingMethod != null) { Expr thisExpr = ValueExpr.withValue( ThisObjectValue.withType( @@ -882,13 +873,13 @@ protected List createLongRunningClient(Service service, TypeStore typ VariableExpr callable = VariableExpr.withVariable( Variable.builder() - .setName(protoMethod.name().toLowerCase() + "Callable") + .setName(pollingMethod.name().toLowerCase() + "Callable") .setType(TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) .build()); VariableExpr methodDescriptor = VariableExpr.withVariable( Variable.builder() - .setName(protoMethod.name().toLowerCase() + "MethodDescriptor") + .setName(pollingMethod.name().toLowerCase() + "MethodDescriptor") .setType( TypeNode.withReference( ConcreteReference.withClazz(ApiMethodDescriptor.class))) @@ -900,8 +891,8 @@ protected List createLongRunningClient(Service service, TypeStore typ .setClazz(HttpJsonLongRunningClient.class) .setGenerics( Arrays.asList( - protoMethod.inputType().reference(), - protoMethod.outputType().reference())) + pollingMethod.inputType().reference(), + pollingMethod.outputType().reference())) .build()); NewObjectExpr HttpJsonLongRunningClient = @@ -943,19 +934,16 @@ protected List createLongRunningClient(Service service, TypeStore typ } @Override - protected void declareLongRunningClient(Map classMemberVarExprs) { - classMemberVarExprs.put( - "longRunningClient", - VariableExpr.withVariable( - Variable.builder() - .setName("longRunningClient") - .setType( - TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class))) - .build())); + protected VariableExpr declareLongRunningClient() { + return VariableExpr.withVariable( + Variable.builder() + .setName("longRunningClient") + .setType(TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class))) + .build()); } @Override - protected void getterLongRunningClient(List javaMethods) { + protected List createLongRunningClientGetter() { VariableExpr longRunningClient = VariableExpr.withVariable( Variable.builder() @@ -964,7 +952,7 @@ protected void getterLongRunningClient(List javaMethods) { TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class))) .build()); - javaMethods.add( + return ImmutableList.of( MethodDefinition.builder() .setName("longRunningClient") .setScope(ScopeNode.PUBLIC) diff --git a/src/main/java/com/google/api/generator/gapic/model/LongrunningOperation.java b/src/main/java/com/google/api/generator/gapic/model/LongrunningOperation.java index c2b425e2f8..e23e8a6ee3 100644 --- a/src/main/java/com/google/api/generator/gapic/model/LongrunningOperation.java +++ b/src/main/java/com/google/api/generator/gapic/model/LongrunningOperation.java @@ -16,6 +16,7 @@ import com.google.api.generator.engine.ast.TypeNode; import com.google.auto.value.AutoValue; +import javax.annotation.Nullable; @AutoValue public abstract class LongrunningOperation { @@ -23,22 +24,21 @@ public abstract class LongrunningOperation { public abstract TypeNode metadataType(); - public static LongrunningOperation withTypes(TypeNode responseType, TypeNode metadataType) { - return builder().setResponseType(responseType).setMetadataType(metadataType).build(); - } + @Nullable + public abstract TypeNode operationServiceStubType(); - // Private. - static Builder builder() { + public static Builder builder() { return new AutoValue_LongrunningOperation.Builder(); } - // Private. @AutoValue.Builder - abstract static class Builder { - abstract Builder setResponseType(TypeNode responseType); + public abstract static class Builder { + public abstract Builder setResponseType(TypeNode responseType); + + public abstract Builder setMetadataType(TypeNode metadataType); - abstract Builder setMetadataType(TypeNode metadataType); + public abstract Builder setOperationServiceStubType(TypeNode operationServiceType); - abstract LongrunningOperation build(); + public abstract LongrunningOperation build(); } } diff --git a/src/main/java/com/google/api/generator/gapic/model/Method.java b/src/main/java/com/google/api/generator/gapic/model/Method.java index aaf3f4a596..286bd8c84e 100644 --- a/src/main/java/com/google/api/generator/gapic/model/Method.java +++ b/src/main/java/com/google/api/generator/gapic/model/Method.java @@ -68,12 +68,6 @@ public boolean isPaged() { public abstract boolean operationPollingMethod(); - @Nullable - public abstract String operationService(); - - @Nullable - public abstract String servicePackage(); - public boolean hasLro() { return lro() != null; } @@ -146,10 +140,6 @@ public abstract static class Builder { public abstract Builder setOperationPollingMethod(boolean operationPollingMethod); - public abstract Builder setOperationService(String operationService); - - public abstract Builder setServicePackage(String servicePackage); - public abstract Method build(); } } diff --git a/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java b/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java index 1a141479ac..20543d3fc8 100644 --- a/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java +++ b/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java @@ -21,19 +21,19 @@ @AutoValue public abstract class OperationResponse { @Nullable - public abstract String getNameFieldName(); + public abstract String nameFieldName(); @Nullable - public abstract String getStatusFieldName(); + public abstract String statusFieldName(); @Nullable - public abstract String getErrorCodeFieldName(); + public abstract String errorCodeFieldName(); @Nullable - public abstract String getErrorMessageFieldName(); + public abstract String errorMessageFieldName(); @Nullable - public abstract String getStatusFieldTypeName(); + public abstract String statusFieldTypeName(); public static Builder builder() { return new AutoValue_OperationResponse.Builder(); diff --git a/src/main/java/com/google/api/generator/gapic/model/Service.java b/src/main/java/com/google/api/generator/gapic/model/Service.java index f21125fb54..ace91051bc 100644 --- a/src/main/java/com/google/api/generator/gapic/model/Service.java +++ b/src/main/java/com/google/api/generator/gapic/model/Service.java @@ -14,6 +14,7 @@ package com.google.api.generator.gapic.model; +import com.google.api.generator.engine.ast.TypeNode; import com.google.auto.value.AutoValue; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; @@ -49,6 +50,35 @@ public boolean hasDescription() { return !Strings.isNullOrEmpty(description()); } + public Method operationPollingMethod() { + for (Method method : methods()) { + if (method.isOperationPollingMethod()) { + return method; + } + } + return null; + } + + public TypeNode operationServiceStubType() { + for (Method method : methods()) { + if (method.hasLro() && method.lro().operationServiceStubType() != null) { + // All methods within the same service must have the same operationServiceTypeName if + // present + return method.lro().operationServiceStubType(); + } + } + return null; + } + + public TypeNode operationType() { + for (Method method : methods()) { + if (method.hasLro() && method.lro().operationServiceStubType() != null) { + return method.outputType(); + } + } + return null; + } + public abstract Builder toBuilder(); public static Builder builder() { diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java index 0fdbb86c2b..a5f227a3d7 100644 --- a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java +++ b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java @@ -20,6 +20,7 @@ import com.google.api.ResourceDescriptor; import com.google.api.ResourceProto; import com.google.api.generator.engine.ast.TypeNode; +import com.google.api.generator.engine.ast.VaporReference; import com.google.api.generator.gapic.model.Field; import com.google.api.generator.gapic.model.GapicBatchingSettings; import com.google.api.generator.gapic.model.GapicContext; @@ -707,11 +708,6 @@ static List parseMethods( .getOptions() .getExtension(ExtendedOperationsProto.operationPollingMethod) : false; - String operationService = - protoMethod.getOptions().hasExtension(ExtendedOperationsProto.operationService) - ? protoMethod.getOptions().getExtension(ExtendedOperationsProto.operationService) - : null; - methods.add( methodBuilder .setName(protoMethod.getName()) @@ -719,7 +715,7 @@ static List parseMethods( .setOutputType(TypeParser.parseType(protoMethod.getOutputType())) .setStream( Method.toStream(protoMethod.isClientStreaming(), protoMethod.isServerStreaming())) - .setLro(parseLro(protoMethod, messageTypes)) + .setLro(parseLro(servicePackage, protoMethod, messageTypes)) .setMethodSignatures( MethodSignatureParser.parseMethodSignatures( protoMethod, @@ -733,8 +729,6 @@ static List parseMethods( .setPageSizeFieldName(parsePageSizeFieldName(protoMethod, messageTypes, transport)) .setIsDeprecated(isDeprecated) .setOperationPollingMethod(operationPollingMethod) - .setOperationService(operationService) - .setServicePackage(servicePackage) .build()); // Any input type that has a resource reference will need a resource name helper class. @@ -776,18 +770,43 @@ static List parseMethods( @VisibleForTesting static LongrunningOperation parseLro( - MethodDescriptor methodDescriptor, Map messageTypes) { + String servicePackage, MethodDescriptor methodDescriptor, Map messageTypes) { MethodOptions methodOptions = methodDescriptor.getOptions(); - if (!methodOptions.hasExtension(OperationsProto.operationInfo)) { - return null; + + TypeNode operationServiceStubType = null; + String responseTypeName = null; + String metadataTypeName = null; + + if (methodOptions.hasExtension(OperationsProto.operationInfo)) { + OperationInfo lroInfo = + methodDescriptor.getOptions().getExtension(OperationsProto.operationInfo); + responseTypeName = lroInfo.getResponseType(); + metadataTypeName = lroInfo.getMetadataType(); + } + if (methodOptions.hasExtension(ExtendedOperationsProto.operationService)) { + // TODO: support full package name for operations_service annotation value + String opServiceName = methodOptions.getExtension(ExtendedOperationsProto.operationService); + operationServiceStubType = + TypeNode.withReference( + VaporReference.builder() + .setName(opServiceName + "Stub") + .setPakkage(servicePackage + ".stub") + .build()); + + if (responseTypeName == null) { + responseTypeName = methodDescriptor.getOutputType().getFullName(); + } + if (metadataTypeName == null) { + metadataTypeName = methodDescriptor.getOutputType().getFullName(); + } } - OperationInfo lroInfo = - methodDescriptor.getOptions().getExtension(OperationsProto.operationInfo); + if (responseTypeName == null || metadataTypeName == null) { + return null; + } - // These can be short names (e.g. FooMessage) or fully-qualified names with the *proto* package. - String responseTypeName = lroInfo.getResponseType(); - String metadataTypeName = lroInfo.getMetadataType(); + Message responseMessage = null; + Message metadataMessage = null; int lastDotIndex = responseTypeName.lastIndexOf('.'); boolean isResponseTypeNameShortOnly = lastDotIndex < 0; @@ -799,9 +818,6 @@ static LongrunningOperation parseLro( String metadataTypeShortName = lastDotIndex >= 0 ? metadataTypeName.substring(lastDotIndex + 1) : metadataTypeName; - Message responseMessage = null; - Message metadataMessage = null; - // The messageTypes map keys to the Java fully-qualified name. for (Map.Entry messageEntry : messageTypes.entrySet()) { String messageKey = messageEntry.getKey(); @@ -844,7 +860,11 @@ static LongrunningOperation parseLro( "LRO metadata message %s not found in method %s", metadataTypeName, methodDescriptor.getName())); - return LongrunningOperation.withTypes(responseMessage.type(), metadataMessage.type()); + return LongrunningOperation.builder() + .setResponseType(responseMessage.type()) + .setMetadataType(metadataMessage.type()) + .setOperationServiceStubType(operationServiceStubType) + .build(); } @VisibleForTesting diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden index f2b65c4025..8db61290e0 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden @@ -13,7 +13,6 @@ import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; -import com.google.cloud.compute.v1.stub.RequestT; import com.google.longrunning.Operation; import javax.annotation.Generated; diff --git a/src/test/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposerTest.java index 4031df1c0a..e3ca743d8d 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposerTest.java +++ b/src/test/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposerTest.java @@ -104,7 +104,11 @@ public void composeClassHeaderMethodSampleCode_firstMethodIsNotUnaryRpc() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); TypeNode ttlTypeNode = TypeNode.withReference( VaporReference.builder().setName("Duration").setPakkage(PROTO_PACKAGE_NAME).build()); @@ -1252,7 +1256,11 @@ public void validComposeRpcMethodHeaderSampleCode_lroUnaryRpcWithNoMethodArgumen .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -1305,7 +1313,11 @@ public void validComposeRpcMethodHeaderSampleCode_lroRpcWithReturnResponseType() .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); TypeNode ttlTypeNode = TypeNode.withReference( VaporReference.builder().setName("Duration").setPakkage(PROTO_PACKAGE_NAME).build()); @@ -1372,7 +1384,11 @@ public void validComposeRpcMethodHeaderSampleCode_lroRpcWithReturnVoid() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); TypeNode ttlTypeNode = TypeNode.withReference( VaporReference.builder().setName("Duration").setPakkage(PROTO_PACKAGE_NAME).build()); @@ -1528,7 +1544,11 @@ public void validComposeRpcDefaultMethodHeaderSampleCode_hasLroMethodWithReturnR .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -1581,7 +1601,11 @@ public void validComposeRpcDefaultMethodHeaderSampleCode_hasLroMethodWithReturnV .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -1732,7 +1756,11 @@ public void validComposeLroCallableMethodHeaderSampleCode_withReturnResponse() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -1784,7 +1812,11 @@ public void validComposeLroCallableMethodHeaderSampleCode_withReturnVoid() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -2348,7 +2380,11 @@ public void validComposeRegularCallableMethodHeaderSampleCode_lroRpc() { .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") @@ -2399,7 +2435,11 @@ public void validComposeRegularCallableMethodHeaderSampleCode_lroRpcWithReturnVo .setName("WaitMetadata") .setPakkage(SHOWCASE_PACKAGE_NAME) .build()); - LongrunningOperation lro = LongrunningOperation.withTypes(responseType, metadataType); + LongrunningOperation lro = + LongrunningOperation.builder() + .setResponseType(responseType) + .setMetadataType(metadataType) + .build(); Method method = Method.builder() .setName("Wait") diff --git a/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java b/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java index d9a31c9fd4..c9e6dbd3e2 100644 --- a/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java +++ b/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java @@ -201,7 +201,7 @@ public void parseLro_missingResponseType() { assertEquals("Wait", waitMethodDescriptor.getName()); messageTypes.remove("com.google.showcase.v1beta1.WaitResponse"); assertThrows( - NullPointerException.class, () -> Parser.parseLro(waitMethodDescriptor, messageTypes)); + NullPointerException.class, () -> Parser.parseLro("", waitMethodDescriptor, messageTypes)); } @Test @@ -211,7 +211,7 @@ public void parseLro_missingMetadataType() { assertEquals("Wait", waitMethodDescriptor.getName()); messageTypes.remove("com.google.showcase.v1beta1.WaitMetadata"); assertThrows( - NullPointerException.class, () -> Parser.parseLro(waitMethodDescriptor, messageTypes)); + NullPointerException.class, () -> Parser.parseLro("", waitMethodDescriptor, messageTypes)); } @Test diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java index eb9db7ce24..7173f3bce5 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java @@ -20,9 +20,11 @@ import com.google.api.core.ApiFutures; import com.google.api.core.BetaApi; import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.paging.AbstractFixedSizeCollection; import com.google.api.gax.paging.AbstractPage; import com.google.api.gax.paging.AbstractPagedListResponse; +import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.PageContext; import com.google.api.gax.rpc.UnaryCallable; import com.google.cloud.compute.v1.stub.AddressesStub; @@ -46,9 +48,10 @@ *
    {@code
      * try (AddressesClient addressesClient = AddressesClient.create()) {
      *   String project = "project-309310695";
    - *   String region = "region-934795532";
    - *   String address = "address-1147692044";
    - *   Operation response = addressesClient.delete(project, region, address);
    + *   for (Map.Entry element :
    + *       addressesClient.aggregatedList(project).iterateAll()) {
    + *     // doThingsWith(element);
    + *   }
      * }
      * }
    * @@ -284,7 +287,7 @@ public final AggregatedListPagedResponse aggregatedList(AggregatedListAddressesR * String project = "project-309310695"; * String region = "region-934795532"; * String address = "address-1147692044"; - * Operation response = addressesClient.delete(project, region, address); + * Operation response = addressesClient.deleteAsync(project, region, address).get(); * } * } * @@ -293,14 +296,15 @@ public final AggregatedListPagedResponse aggregatedList(AggregatedListAddressesR * @param address Name of the address resource to delete. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final Operation delete(String project, String region, String address) { + public final OperationFuture deleteAsync( + String project, String region, String address) { DeleteAddressRequest request = DeleteAddressRequest.newBuilder() .setProject(project) .setRegion(region) .setAddress(address) .build(); - return delete(request); + return deleteAsync(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD. @@ -318,15 +322,42 @@ public final Operation delete(String project, String region, String address) { * .setRegion("region-934795532") * .setRequestId("requestId693933066") * .build(); - * Operation response = addressesClient.delete(request); + * Operation response = addressesClient.deleteAsync(request).get(); * } * } * * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final Operation delete(DeleteAddressRequest request) { - return deleteCallable().call(request); + public final OperationFuture deleteAsync(DeleteAddressRequest request) { + return deleteOperationCallable().futureCall(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Deletes the specified address resource. + * + *

    Sample code: + * + *

    {@code
    +   * try (AddressesClient addressesClient = AddressesClient.create()) {
    +   *   DeleteAddressRequest request =
    +   *       DeleteAddressRequest.newBuilder()
    +   *           .setAddress("address-1147692044")
    +   *           .setProject("project-309310695")
    +   *           .setRegion("region-934795532")
    +   *           .setRequestId("requestId693933066")
    +   *           .build();
    +   *   OperationFuture future =
    +   *       addressesClient.deleteOperationCallable().futureCall(request);
    +   *   // Do something.
    +   *   Operation response = future.get();
    +   * }
    +   * }
    + */ + public final OperationCallable + deleteOperationCallable() { + return stub.deleteOperationCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD. @@ -365,7 +396,7 @@ public final UnaryCallable deleteCallable() { * String project = "project-309310695"; * String region = "region-934795532"; * Address addressResource = Address.newBuilder().build(); - * Operation response = addressesClient.insert(project, region, addressResource); + * Operation response = addressesClient.insertAsync(project, region, addressResource).get(); * } * } * @@ -374,14 +405,15 @@ public final UnaryCallable deleteCallable() { * @param addressResource The body resource for this request * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final Operation insert(String project, String region, Address addressResource) { + public final OperationFuture insertAsync( + String project, String region, Address addressResource) { InsertAddressRequest request = InsertAddressRequest.newBuilder() .setProject(project) .setRegion(region) .setAddressResource(addressResource) .build(); - return insert(request); + return insertAsync(request); } // AUTO-GENERATED DOCUMENTATION AND METHOD. @@ -399,15 +431,42 @@ public final Operation insert(String project, String region, Address addressReso * .setRegion("region-934795532") * .setRequestId("requestId693933066") * .build(); - * Operation response = addressesClient.insert(request); + * Operation response = addressesClient.insertAsync(request).get(); * } * } * * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ - public final Operation insert(InsertAddressRequest request) { - return insertCallable().call(request); + public final OperationFuture insertAsync(InsertAddressRequest request) { + return insertOperationCallable().futureCall(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Creates an address resource in the specified project by using the data included in the request. + * + *

    Sample code: + * + *

    {@code
    +   * try (AddressesClient addressesClient = AddressesClient.create()) {
    +   *   InsertAddressRequest request =
    +   *       InsertAddressRequest.newBuilder()
    +   *           .setAddressResource(Address.newBuilder().build())
    +   *           .setProject("project-309310695")
    +   *           .setRegion("region-934795532")
    +   *           .setRequestId("requestId693933066")
    +   *           .build();
    +   *   OperationFuture future =
    +   *       addressesClient.insertOperationCallable().futureCall(request);
    +   *   // Do something.
    +   *   Operation response = future.get();
    +   * }
    +   * }
    + */ + public final OperationCallable + insertOperationCallable() { + return stub.insertOperationCallable(); } // AUTO-GENERATED DOCUMENTATION AND METHOD. diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java index 24d06c2f69..04f3ea46b9 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java @@ -30,12 +30,15 @@ import com.google.api.gax.rpc.testing.FakeStatusCode; import com.google.cloud.compute.v1.stub.HttpJsonAddressesStub; import com.google.common.collect.Lists; +import com.google.longrunning.Operation; +import com.google.protobuf.Any; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; import javax.annotation.Generated; import org.junit.After; import org.junit.AfterClass; @@ -132,8 +135,8 @@ public void aggregatedListExceptionTest() throws Exception { @Test public void deleteTest() throws Exception { - Operation expectedResponse = - Operation.newBuilder() + com.google.cloud.compute.v1.Operation expectedResponse = + com.google.cloud.compute.v1.Operation.newBuilder() .setClientOperationId("clientOperationId-1230366697") .setCreationTimestamp("creationTimestamp-370203401") .setDescription("description-1724546052") @@ -157,13 +160,20 @@ public void deleteTest() throws Exception { .addAllWarnings(new ArrayList()) .setZone("zone3744684") .build(); - mockService.addResponse(expectedResponse); + Operation resultOperation = + Operation.newBuilder() + .setName("deleteTest") + .setDone(true) + .setResponse(Any.pack(expectedResponse)) + .build(); + mockService.addResponse(resultOperation); String project = "project-309310695"; String region = "region-934795532"; String address = "address-1147692044"; - Operation actualResponse = client.delete(project, region, address); + com.google.cloud.compute.v1.Operation actualResponse = + client.deleteAsync(project, region, address).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockService.getRequestPaths(); @@ -192,17 +202,16 @@ public void deleteExceptionTest() throws Exception { String project = "project-309310695"; String region = "region-934795532"; String address = "address-1147692044"; - client.delete(project, region, address); + client.deleteAsync(project, region, address).get(); Assert.fail("No exception raised"); - } catch (InvalidArgumentException e) { - // Expected exception. + } catch (ExecutionException e) { } } @Test public void insertTest() throws Exception { - Operation expectedResponse = - Operation.newBuilder() + com.google.cloud.compute.v1.Operation expectedResponse = + com.google.cloud.compute.v1.Operation.newBuilder() .setClientOperationId("clientOperationId-1230366697") .setCreationTimestamp("creationTimestamp-370203401") .setDescription("description-1724546052") @@ -226,13 +235,20 @@ public void insertTest() throws Exception { .addAllWarnings(new ArrayList()) .setZone("zone3744684") .build(); - mockService.addResponse(expectedResponse); + Operation resultOperation = + Operation.newBuilder() + .setName("insertTest") + .setDone(true) + .setResponse(Any.pack(expectedResponse)) + .build(); + mockService.addResponse(resultOperation); String project = "project-309310695"; String region = "region-934795532"; Address addressResource = Address.newBuilder().build(); - Operation actualResponse = client.insert(project, region, addressResource); + com.google.cloud.compute.v1.Operation actualResponse = + client.insertAsync(project, region, addressResource).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockService.getRequestPaths(); @@ -261,10 +277,9 @@ public void insertExceptionTest() throws Exception { String project = "project-309310695"; String region = "region-934795532"; Address addressResource = Address.newBuilder().build(); - client.insert(project, region, addressResource); + client.insertAsync(project, region, addressResource).get(); Assert.fail("No exception raised"); - } catch (InvalidArgumentException e) { - // Expected exception. + } catch (ExecutionException e) { } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesSettings.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesSettings.java index d2dc359f73..58fbc804d6 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesSettings.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesSettings.java @@ -27,6 +27,7 @@ import com.google.api.gax.rpc.ApiClientHeaderProvider; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.ClientSettings; +import com.google.api.gax.rpc.OperationCallSettings; import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.StubSettings; import com.google.api.gax.rpc.TransportChannelProvider; @@ -51,15 +52,15 @@ *

    The builder of this class is recursive, so contained classes are themselves builders. When * build() is called, the tree of builders is called to create the complete settings object. * - *

    For example, to set the total timeout of delete to 30 seconds: + *

    For example, to set the total timeout of aggregatedList to 30 seconds: * *

    {@code
      * AddressesSettings.Builder addressesSettingsBuilder = AddressesSettings.newBuilder();
      * addressesSettingsBuilder
    - *     .deleteSettings()
    + *     .aggregatedListSettings()
      *     .setRetrySettings(
      *         addressesSettingsBuilder
    - *             .deleteSettings()
    + *             .aggregatedListSettings()
      *             .getRetrySettings()
      *             .toBuilder()
      *             .setTotalTimeout(Duration.ofSeconds(30))
    @@ -82,11 +83,23 @@ public UnaryCallSettings deleteSettings() {
         return ((AddressesStubSettings) getStubSettings()).deleteSettings();
       }
     
    +  /** Returns the object with the settings used for calls to delete. */
    +  public OperationCallSettings
    +      deleteOperationSettings() {
    +    return ((AddressesStubSettings) getStubSettings()).deleteOperationSettings();
    +  }
    +
       /** Returns the object with the settings used for calls to insert. */
       public UnaryCallSettings insertSettings() {
         return ((AddressesStubSettings) getStubSettings()).insertSettings();
       }
     
    +  /** Returns the object with the settings used for calls to insert. */
    +  public OperationCallSettings
    +      insertOperationSettings() {
    +    return ((AddressesStubSettings) getStubSettings()).insertOperationSettings();
    +  }
    +
       /** Returns the object with the settings used for calls to list. */
       public PagedCallSettings listSettings() {
         return ((AddressesStubSettings) getStubSettings()).listSettings();
    @@ -201,11 +214,23 @@ public UnaryCallSettings.Builder deleteSettings
           return getStubSettingsBuilder().deleteSettings();
         }
     
    +    /** Returns the builder for the settings used for calls to delete. */
    +    public OperationCallSettings.Builder
    +        deleteOperationSettings() {
    +      return getStubSettingsBuilder().deleteOperationSettings();
    +    }
    +
         /** Returns the builder for the settings used for calls to insert. */
         public UnaryCallSettings.Builder insertSettings() {
           return getStubSettingsBuilder().insertSettings();
         }
     
    +    /** Returns the builder for the settings used for calls to insert. */
    +    public OperationCallSettings.Builder
    +        insertOperationSettings() {
    +      return getStubSettingsBuilder().insertOperationSettings();
    +    }
    +
         /** Returns the builder for the settings used for calls to list. */
         public PagedCallSettings.Builder
             listSettings() {
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json b/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json
    index 14eb0320fd..d2f2df6b3d 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json
    @@ -14,10 +14,10 @@
                   "methods": ["aggregatedList", "aggregatedList", "aggregatedListPagedCallable", "aggregatedListCallable"]
                 },
                 "Delete": {
    -              "methods": ["delete", "delete", "deleteCallable"]
    +              "methods": ["deleteAsync", "deleteAsync", "deleteOperationCallable", "deleteCallable"]
                 },
                 "Insert": {
    -              "methods": ["insert", "insert", "insertCallable"]
    +              "methods": ["insertAsync", "insertAsync", "insertOperationCallable", "insertCallable"]
                 },
                 "List": {
                   "methods": ["list", "list", "listPagedCallable", "listCallable"]
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/package-info.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/package-info.java
    index 941f3ab751..e525d9c7df 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/package-info.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/package-info.java
    @@ -28,9 +28,10 @@
      * 
    {@code
      * try (AddressesClient addressesClient = AddressesClient.create()) {
      *   String project = "project-309310695";
    - *   String region = "region-934795532";
    - *   String address = "address-1147692044";
    - *   Operation response = addressesClient.delete(project, region, address);
    + *   for (Map.Entry element :
    + *       addressesClient.aggregatedList(project).iterateAll()) {
    + *     // doThingsWith(element);
    + *   }
      * }
      * }
    * diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java index b7d7f6e590..551b0ec0eb 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java @@ -20,6 +20,7 @@ import static com.google.cloud.compute.v1.AddressesClient.ListPagedResponse; import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.UnaryCallable; import com.google.cloud.compute.v1.AddressAggregatedList; import com.google.cloud.compute.v1.AddressList; @@ -39,6 +40,10 @@ @Generated("by gapic-generator-java") public abstract class AddressesStub implements BackgroundResource { + public RegionOperationsStub getOperationsStub() { + throw new UnsupportedOperationException("Not implemented: getOperationsStub()"); + } + public UnaryCallable aggregatedListPagedCallable() { throw new UnsupportedOperationException("Not implemented: aggregatedListPagedCallable()"); @@ -49,10 +54,18 @@ public abstract class AddressesStub implements BackgroundResource { throw new UnsupportedOperationException("Not implemented: aggregatedListCallable()"); } + public OperationCallable deleteOperationCallable() { + throw new UnsupportedOperationException("Not implemented: deleteOperationCallable()"); + } + public UnaryCallable deleteCallable() { throw new UnsupportedOperationException("Not implemented: deleteCallable()"); } + public OperationCallable insertOperationCallable() { + throw new UnsupportedOperationException("Not implemented: insertOperationCallable()"); + } + public UnaryCallable insertCallable() { throw new UnsupportedOperationException("Not implemented: insertCallable()"); } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java index 69e3c4d6c0..55866e3401 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java @@ -25,13 +25,17 @@ import com.google.api.gax.core.GaxProperties; import com.google.api.gax.core.GoogleCredentialsProvider; import com.google.api.gax.core.InstantiatingExecutorProvider; +import com.google.api.gax.grpc.ProtoOperationTransformers; import com.google.api.gax.httpjson.GaxHttpJsonProperties; import com.google.api.gax.httpjson.HttpJsonTransportChannel; import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider; +import com.google.api.gax.longrunning.OperationSnapshot; +import com.google.api.gax.longrunning.OperationTimedPollAlgorithm; import com.google.api.gax.retrying.RetrySettings; import com.google.api.gax.rpc.ApiCallContext; import com.google.api.gax.rpc.ApiClientHeaderProvider; import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.rpc.OperationCallSettings; import com.google.api.gax.rpc.PageContext; import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.PagedListDescriptor; @@ -76,15 +80,15 @@ *

    The builder of this class is recursive, so contained classes are themselves builders. When * build() is called, the tree of builders is called to create the complete settings object. * - *

    For example, to set the total timeout of delete to 30 seconds: + *

    For example, to set the total timeout of aggregatedList to 30 seconds: * *

    {@code
      * AddressesStubSettings.Builder addressesSettingsBuilder = AddressesStubSettings.newBuilder();
      * addressesSettingsBuilder
    - *     .deleteSettings()
    + *     .aggregatedListSettings()
      *     .setRetrySettings(
      *         addressesSettingsBuilder
    - *             .deleteSettings()
    + *             .aggregatedListSettings()
      *             .getRetrySettings()
      *             .toBuilder()
      *             .setTotalTimeout(Duration.ofSeconds(30))
    @@ -105,7 +109,11 @@ public class AddressesStubSettings extends StubSettings {
               AggregatedListAddressesRequest, AddressAggregatedList, AggregatedListPagedResponse>
           aggregatedListSettings;
       private final UnaryCallSettings deleteSettings;
    +  private final OperationCallSettings
    +      deleteOperationSettings;
       private final UnaryCallSettings insertSettings;
    +  private final OperationCallSettings
    +      insertOperationSettings;
       private final PagedCallSettings
           listSettings;
     
    @@ -243,11 +251,23 @@ public UnaryCallSettings deleteSettings() {
         return deleteSettings;
       }
     
    +  /** Returns the object with the settings used for calls to delete. */
    +  public OperationCallSettings
    +      deleteOperationSettings() {
    +    return deleteOperationSettings;
    +  }
    +
       /** Returns the object with the settings used for calls to insert. */
       public UnaryCallSettings insertSettings() {
         return insertSettings;
       }
     
    +  /** Returns the object with the settings used for calls to insert. */
    +  public OperationCallSettings
    +      insertOperationSettings() {
    +    return insertOperationSettings;
    +  }
    +
       /** Returns the object with the settings used for calls to list. */
       public PagedCallSettings listSettings() {
         return listSettings;
    @@ -329,7 +349,9 @@ protected AddressesStubSettings(Builder settingsBuilder) throws IOException {
     
         aggregatedListSettings = settingsBuilder.aggregatedListSettings().build();
         deleteSettings = settingsBuilder.deleteSettings().build();
    +    deleteOperationSettings = settingsBuilder.deleteOperationSettings().build();
         insertSettings = settingsBuilder.insertSettings().build();
    +    insertOperationSettings = settingsBuilder.insertOperationSettings().build();
         listSettings = settingsBuilder.listSettings().build();
       }
     
    @@ -340,7 +362,11 @@ public static class Builder extends StubSettings.Builder
             aggregatedListSettings;
         private final UnaryCallSettings.Builder deleteSettings;
    +    private final OperationCallSettings.Builder
    +        deleteOperationSettings;
         private final UnaryCallSettings.Builder insertSettings;
    +    private final OperationCallSettings.Builder
    +        insertOperationSettings;
         private final PagedCallSettings.Builder
             listSettings;
         private static final ImmutableMap>
    @@ -395,7 +421,9 @@ protected Builder(ClientContext clientContext) {
     
           aggregatedListSettings = PagedCallSettings.newBuilder(AGGREGATED_LIST_PAGE_STR_FACT);
           deleteSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
    +      deleteOperationSettings = OperationCallSettings.newBuilder();
           insertSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
    +      insertOperationSettings = OperationCallSettings.newBuilder();
           listSettings = PagedCallSettings.newBuilder(LIST_PAGE_STR_FACT);
     
           unaryMethodSettingsBuilders =
    @@ -409,7 +437,9 @@ protected Builder(AddressesStubSettings settings) {
     
           aggregatedListSettings = settings.aggregatedListSettings.toBuilder();
           deleteSettings = settings.deleteSettings.toBuilder();
    +      deleteOperationSettings = settings.deleteOperationSettings.toBuilder();
           insertSettings = settings.insertSettings.toBuilder();
    +      insertOperationSettings = settings.insertOperationSettings.toBuilder();
           listSettings = settings.listSettings.toBuilder();
     
           unaryMethodSettingsBuilders =
    @@ -451,6 +481,54 @@ private static Builder initDefaults(Builder builder) {
               .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_0_codes"))
               .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_0_params"));
     
    +      builder
    +          .deleteOperationSettings()
    +          .setInitialCallSettings(
    +              UnaryCallSettings
    +                  .newUnaryCallSettingsBuilder()
    +                  .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes"))
    +                  .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params"))
    +                  .build())
    +          .setResponseTransformer(
    +              ProtoOperationTransformers.ResponseTransformer.create(Operation.class))
    +          .setMetadataTransformer(
    +              ProtoOperationTransformers.MetadataTransformer.create(Operation.class))
    +          .setPollingAlgorithm(
    +              OperationTimedPollAlgorithm.create(
    +                  RetrySettings.newBuilder()
    +                      .setInitialRetryDelay(Duration.ofMillis(5000L))
    +                      .setRetryDelayMultiplier(1.5)
    +                      .setMaxRetryDelay(Duration.ofMillis(45000L))
    +                      .setInitialRpcTimeout(Duration.ZERO)
    +                      .setRpcTimeoutMultiplier(1.0)
    +                      .setMaxRpcTimeout(Duration.ZERO)
    +                      .setTotalTimeout(Duration.ofMillis(300000L))
    +                      .build()));
    +
    +      builder
    +          .insertOperationSettings()
    +          .setInitialCallSettings(
    +              UnaryCallSettings
    +                  .newUnaryCallSettingsBuilder()
    +                  .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_1_codes"))
    +                  .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_1_params"))
    +                  .build())
    +          .setResponseTransformer(
    +              ProtoOperationTransformers.ResponseTransformer.create(Operation.class))
    +          .setMetadataTransformer(
    +              ProtoOperationTransformers.MetadataTransformer.create(Operation.class))
    +          .setPollingAlgorithm(
    +              OperationTimedPollAlgorithm.create(
    +                  RetrySettings.newBuilder()
    +                      .setInitialRetryDelay(Duration.ofMillis(5000L))
    +                      .setRetryDelayMultiplier(1.5)
    +                      .setMaxRetryDelay(Duration.ofMillis(45000L))
    +                      .setInitialRpcTimeout(Duration.ZERO)
    +                      .setRpcTimeoutMultiplier(1.0)
    +                      .setMaxRpcTimeout(Duration.ZERO)
    +                      .setTotalTimeout(Duration.ofMillis(300000L))
    +                      .build()));
    +
           return builder;
         }
     
    @@ -481,11 +559,27 @@ public UnaryCallSettings.Builder deleteSettings
           return deleteSettings;
         }
     
    +    /** Returns the builder for the settings used for calls to delete. */
    +    @BetaApi(
    +        "The surface for use by generated code is not stable yet and may change in the future.")
    +    public OperationCallSettings.Builder
    +        deleteOperationSettings() {
    +      return deleteOperationSettings;
    +    }
    +
         /** Returns the builder for the settings used for calls to insert. */
         public UnaryCallSettings.Builder insertSettings() {
           return insertSettings;
         }
     
    +    /** Returns the builder for the settings used for calls to insert. */
    +    @BetaApi(
    +        "The surface for use by generated code is not stable yet and may change in the future.")
    +    public OperationCallSettings.Builder
    +        insertOperationSettings() {
    +      return insertOperationSettings;
    +    }
    +
         /** Returns the builder for the settings used for calls to list. */
         public PagedCallSettings.Builder
             listSettings() {
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java
    index b9e0385e12..2290fc6952 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesCallableFactory.java
    @@ -17,7 +17,6 @@
     package com.google.cloud.compute.v1.stub;
     
     import com.google.api.core.BetaApi;
    -import com.google.api.gax.core.BackgroundResource;
     import com.google.api.gax.httpjson.HttpJsonCallSettings;
     import com.google.api.gax.httpjson.HttpJsonCallableFactory;
     import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable;
    @@ -29,7 +28,7 @@
     import com.google.api.gax.rpc.PagedCallSettings;
     import com.google.api.gax.rpc.UnaryCallSettings;
     import com.google.api.gax.rpc.UnaryCallable;
    -import com.google.longrunning.Operation;
    +import com.google.cloud.compute.v1.Operation;
     import javax.annotation.Generated;
     
     // AUTO-GENERATED DOCUMENTATION AND CLASS.
    @@ -41,7 +40,7 @@
     @Generated("by gapic-generator-java")
     @BetaApi
     public class HttpJsonAddressesCallableFactory
    -    implements HttpJsonStubCallableFactory {
    +    implements HttpJsonStubCallableFactory {
     
       @Override
       public  UnaryCallable createUnaryCallable(
    @@ -79,7 +78,7 @@ OperationCallable createOperationCallable(
               HttpJsonCallSettings httpJsonCallSettings,
               OperationCallSettings callSettings,
               ClientContext clientContext,
    -          BackgroundResource operationsStub) {
    +          RegionOperationsStub operationsStub) {
         UnaryCallable innerCallable =
             HttpJsonCallableFactory.createBaseUnaryCallable(
                 httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext);
    diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java
    index d79d2cc64a..943580e59b 100644
    --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java
    +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java
    @@ -33,6 +33,7 @@
     import com.google.api.gax.httpjson.ProtoRestSerializer;
     import com.google.api.gax.longrunning.OperationSnapshot;
     import com.google.api.gax.rpc.ClientContext;
    +import com.google.api.gax.rpc.OperationCallable;
     import com.google.api.gax.rpc.UnaryCallable;
     import com.google.cloud.compute.v1.AddressAggregatedList;
     import com.google.cloud.compute.v1.AddressList;
    @@ -251,11 +252,16 @@ public class HttpJsonAddressesStub extends AddressesStub {
       private final UnaryCallable
           aggregatedListPagedCallable;
       private final UnaryCallable deleteCallable;
    +  private final OperationCallable
    +      deleteOperationCallable;
       private final UnaryCallable insertCallable;
    +  private final OperationCallable
    +      insertOperationCallable;
       private final UnaryCallable listCallable;
       private final UnaryCallable listPagedCallable;
     
       private final BackgroundResource backgroundResources;
    +  private final HttpJsonRegionOperationsStub operationsStub;
       private final HttpJsonStubCallableFactory callableFactory;
     
       public static final HttpJsonAddressesStub create(AddressesStubSettings settings)
    @@ -294,6 +300,7 @@ protected HttpJsonAddressesStub(
           HttpJsonStubCallableFactory callableFactory)
           throws IOException {
         this.callableFactory = callableFactory;
    +    this.operationsStub = HttpJsonRegionOperationsStub.create(clientContext, callableFactory);
     
         HttpJsonCallSettings
             aggregatedListTransportSettings =
    @@ -322,9 +329,21 @@ protected HttpJsonAddressesStub(
         this.deleteCallable =
             callableFactory.createUnaryCallable(
                 deleteTransportSettings, settings.deleteSettings(), clientContext);
    +    this.deleteOperationCallable =
    +        callableFactory.createOperationCallable(
    +            deleteTransportSettings,
    +            settings.deleteOperationSettings(),
    +            clientContext,
    +            operationsStub);
         this.insertCallable =
             callableFactory.createUnaryCallable(
                 insertTransportSettings, settings.insertSettings(), clientContext);
    +    this.insertOperationCallable =
    +        callableFactory.createOperationCallable(
    +            insertTransportSettings,
    +            settings.insertOperationSettings(),
    +            clientContext,
    +            operationsStub);
         this.listCallable =
             callableFactory.createUnaryCallable(
                 listTransportSettings, settings.listSettings(), clientContext);
    @@ -363,11 +382,21 @@ public UnaryCallable deleteCallable() {
         return deleteCallable;
       }
     
    +  @Override
    +  public OperationCallable deleteOperationCallable() {
    +    return deleteOperationCallable;
    +  }
    +
       @Override
       public UnaryCallable insertCallable() {
         return insertCallable;
       }
     
    +  @Override
    +  public OperationCallable insertOperationCallable() {
    +    return insertOperationCallable;
    +  }
    +
       @Override
       public UnaryCallable listCallable() {
         return listCallable;
    
    From 200fce7eb91db005524d722a09656fccb7a040cd Mon Sep 17 00:00:00 2001
    From: Vadym Matsishevskyi <25311427+vam-google@users.noreply.github.com>
    Date: Tue, 7 Sep 2021 00:30:29 -0700
    Subject: [PATCH 5/9] chore: Merge multitransport client and fixes (#836)
    
    * feat: enable self signed jwt for gapic clients (#794)
    
    * feat: enable self signed jwt for gapic clients
    
    * resolve comments
    
    * update gax version
    
    * update goldens
    
    * update golden files
    
    * chore: release 2.1.0 (#827)
    
    Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
    
    * feat: REGAPIC initial implementation (#824)
    
    This includes:
    1) Proper GRPC transcoding
    2) Mimimal REST Operations (go make it compilable)
    3) Rely on resource names for tests values generation (to not fail http url path validation)
    4) Empty Server Streaming method implementation
    
    * feat: REGAPIC Multitransport implementation (grpc+rest) (#833)
    
    1) Fully backward compatible with grpc-only GAPIC
    2) Strictly speaking not fully backward compatible with rest-only REGAPIC (but is compatible for practical cases). See below for details.
    3) Introduces the concept of default transport (is necessary to preserve backward-compabitility). The default behavior assumes grpc transport.
    
    Needed to unblock DIREGAPIC LRO. To be reviewed after submission
    
    * chore: merge DIREGAPIC LRO with multitransport changes from master
    
    * fix: fix Stub.longRunningClient() issues for DIREGAPIC LRO
    
    * fix: [bazel] fix rest transport handling in assembly rule (#835)
    
    Co-authored-by: arithmetic1728 <58957152+arithmetic1728@users.noreply.github.com>
    Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
    ---
     WORKSPACE                                     |    2 +-
     repositories.bzl                              |    4 +-
     rules_java_gapic/java_gapic.bzl               |   30 +-
     rules_java_gapic/java_gapic_pkg.bzl           |    8 +-
     .../resources/gradle/assembly.gradle.tmpl     |    4 +-
     .../resources/gradle/client_grpc.gradle.tmpl  |    4 +-
     .../gradle/client_grpcrest.gradle.tmpl        |   63 +
     .../resources/gradle/client_rest.gradle.tmpl  |    4 +-
     .../resources/gradle/grpc.gradle.tmpl         |    4 +-
     .../resources/gradle/proto.gradle.tmpl        |    4 +-
     .../google/api/generator/gapic/BUILD.bazel    |    1 +
     .../api/generator/gapic/composer/BUILD.bazel  |    1 +
     .../generator/gapic/composer/Composer.java    |   94 +-
     ...ctServiceCallableFactoryClassComposer.java |    2 +-
     ...> AbstractServiceClientClassComposer.java} |  146 ++-
     ...bstractServiceClientTestClassComposer.java |   19 +-
     .../AbstractServiceSettingsClassComposer.java |   76 +-
     .../AbstractServiceStubClassComposer.java     | 1058 +++-------------
     ...tractServiceStubSettingsClassComposer.java |  288 ++++-
     ...ractTransportServiceStubClassComposer.java | 1077 +++++++++++++++++
     .../common/RetrySettingsComposer.java         |   14 +-
     .../common/ServiceStubClassComposer.java      |  283 -----
     .../composer/common/TransportContext.java     |   68 +-
     .../defaultvalue/DefaultValueComposer.java    |   26 +-
     .../gapic/composer/grpc/GrpcContext.java      |   30 +-
     .../grpc/GrpcServiceStubClassComposer.java    |   17 +-
     .../grpc/ServiceClientClassComposer.java      |   30 +
     .../grpc/ServiceClientTestClassComposer.java  |    9 +-
     .../grpc/ServiceStubClassComposer.java        |   30 +
     .../ServiceStubSettingsClassComposer.java     |  117 +-
     .../gapic/composer/grpcrest/BUILD.bazel       |   55 +
     .../composer/grpcrest/GrpcRestContext.java    |   95 ++
     ...ttpJsonServiceClientTestClassComposer.java |   57 +
     .../HttpJsonServiceStubClassComposer.java     |   40 +
     .../grpcrest/ServiceClientClassComposer.java  |   29 +
     .../ServiceSettingsClassComposer.java         |   68 ++
     .../grpcrest/ServiceStubClassComposer.java    |   47 +
     .../ServiceStubSettingsClassComposer.java     |  200 +++
     ...onServiceCallableFactoryClassComposer.java |   16 +-
     .../HttpJsonServiceStubClassComposer.java     |  268 ++--
     .../gapic/composer/rest/RestContext.java      |   33 +-
     .../rest/ServiceClientClassComposer.java      |   30 +
     .../rest/ServiceClientTestClassComposer.java  |   27 +-
     .../rest/ServiceStubClassComposer.java        |   30 +
     .../ServiceStubSettingsClassComposer.java     |  107 +-
     .../ServiceClientSampleCodeComposer.java      |    2 +-
     .../gapic/composer/utils/ClassNames.java      |   53 +-
     .../generator/gapic/model/HttpBindings.java   |    4 +
     .../api/generator/gapic/model/Service.java    |   18 +
     .../api/generator/gapic/model/Transport.java  |    2 -
     .../gapic/protoparser/HttpRuleParser.java     |    1 +
     .../google/api/generator/gapic/BUILD.bazel    |    1 +
     .../gapic/composer/common/BUILD.bazel         |    2 -
     .../common/RetrySettingsComposerTest.java     |    5 +-
     .../generator/gapic/composer/grpc/BUILD.bazel |    2 +
     .../ServiceClientClassComposerTest.java       |   10 +-
     .../ServiceStubClassComposerTest.java         |    3 +-
     .../goldens/BookshopClient.golden             |    0
     .../goldens/DeprecatedServiceClient.golden    |    0
     .../goldens/DeprecatedServiceStub.golden      |    0
     .../goldens/EchoClient.golden                 |    0
     .../{common => grpc}/goldens/EchoStub.golden  |    0
     .../goldens/IdentityClient.golden             |    0
     .../ServiceStubSettingsClassComposerTest.java |    2 +-
     .../goldens/ComplianceStubSettings.golden     |  531 ++------
     .../HttpJsonComplianceCallableFactory.golden  |   16 +-
     .../goldens/HttpJsonComplianceStub.golden     |    3 +-
     .../cloud/compute/v1/AddressesClient.java     |    4 +
     .../compute/v1/RegionOperationsClient.java    |  106 ++
     .../v1/RegionOperationsClientTest.java        |   69 ++
     .../compute/v1/RegionOperationsSettings.java  |   10 +
     .../cloud/compute/v1/gapic_metadata.json      |    3 +
     .../cloud/compute/v1/stub/AddressesStub.java  |    4 -
     .../v1/stub/AddressesStubSettings.java        |    2 +-
     .../v1/stub/HttpJsonAddressesStub.java        |    9 +-
     ...tpJsonRegionOperationsCallableFactory.java |   16 +-
     .../v1/stub/HttpJsonRegionOperationsStub.java |   48 +
     .../compute/v1/stub/RegionOperationsStub.java |   12 +
     .../v1/stub/RegionOperationsStubSettings.java |   30 +-
     79 files changed, 3410 insertions(+), 2173 deletions(-)
     create mode 100644 rules_java_gapic/resources/gradle/client_grpcrest.gradle.tmpl
     rename src/main/java/com/google/api/generator/gapic/composer/common/{ServiceClientClassComposer.java => AbstractServiceClientClassComposer.java} (94%)
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java
     delete mode 100644 src/main/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpcrest/BUILD.bazel
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpcrest/HttpJsonServiceClientTestClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpcrest/HttpJsonServiceStubClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceClientClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceSettingsClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubSettingsClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/rest/ServiceClientClassComposer.java
     create mode 100644 src/main/java/com/google/api/generator/gapic/composer/rest/ServiceStubClassComposer.java
     rename src/test/java/com/google/api/generator/gapic/composer/{common => grpc}/ServiceClientClassComposerTest.java (89%)
     rename src/test/java/com/google/api/generator/gapic/composer/{common => grpc}/ServiceStubClassComposerTest.java (94%)
     rename src/test/java/com/google/api/generator/gapic/composer/{common => grpc}/goldens/BookshopClient.golden (100%)
     rename src/test/java/com/google/api/generator/gapic/composer/{common => grpc}/goldens/DeprecatedServiceClient.golden (100%)
     rename src/test/java/com/google/api/generator/gapic/composer/{common => grpc}/goldens/DeprecatedServiceStub.golden (100%)
     rename src/test/java/com/google/api/generator/gapic/composer/{common => grpc}/goldens/EchoClient.golden (100%)
     rename src/test/java/com/google/api/generator/gapic/composer/{common => grpc}/goldens/EchoStub.golden (100%)
     rename src/test/java/com/google/api/generator/gapic/composer/{common => grpc}/goldens/IdentityClient.golden (100%)
    
    diff --git a/WORKSPACE b/WORKSPACE
    index cc406611a9..50cac18478 100644
    --- a/WORKSPACE
    +++ b/WORKSPACE
    @@ -33,7 +33,7 @@ jvm_maven_import_external(
     # which in its turn, prioritizes actual generated clients runtime dependencies
     # over the generator dependencies.
     
    -_gax_java_version = "2.3.0"
    +_gax_java_version = "2.4.0"
     
     http_archive(
         name = "com_google_api_gax_java",
    diff --git a/repositories.bzl b/repositories.bzl
    index f2074f578d..6091b21171 100644
    --- a/repositories.bzl
    +++ b/repositories.bzl
    @@ -70,9 +70,9 @@ def gapic_generator_java_repositories():
         _maybe(
             http_archive,
             name = "com_google_googleapis_discovery",
    -        strip_prefix = "googleapis-discovery-2872d382ff767518e63d59ececf5d6f9224b21b4",
    +        strip_prefix = "googleapis-discovery-bb8a053b93ef8698297c41634aa9201f7e075277",
             urls = [
    -            "https://github.com/vam-google/googleapis-discovery/archive/2872d382ff767518e63d59ececf5d6f9224b21b4.zip",
    +            "https://github.com/vam-google/googleapis-discovery/archive/bb8a053b93ef8698297c41634aa9201f7e075277.zip",
             ],
         )
     
    diff --git a/rules_java_gapic/java_gapic.bzl b/rules_java_gapic/java_gapic.bzl
    index 65cb3617f7..91eb4ddb56 100644
    --- a/rules_java_gapic/java_gapic.bzl
    +++ b/rules_java_gapic/java_gapic.bzl
    @@ -135,7 +135,7 @@ def _java_gapic_srcjar(
     
         if grpc_service_config:
             file_args_dict[grpc_service_config] = "grpc-service-config"
    -    elif transport != "rest":
    +    elif not transport or transport == "grpc":
             for keyword in NO_GRPC_CONFIG_ALLOWLIST:
                 if keyword not in name:
                     fail("Missing a gRPC service config file")
    @@ -230,16 +230,25 @@ def java_gapic_library(
             "@javax_annotation_javax_annotation_api//jar",
         ]
     
    -    if transport == "rest":
    +    if not transport or transport == "grpc":
    +        actual_deps += [
    +            "@com_google_api_gax_java//gax-grpc:gax_grpc",
    +            "@io_grpc_grpc_java//core:core",
    +            "@io_grpc_grpc_java//protobuf:protobuf",
    +        ]
    +    elif transport == "rest":
             actual_deps += [
                 "@com_google_api_gax_java//gax-httpjson:gax_httpjson",
             ]
    -    else:
    +    elif transport == "grpc+rest":
             actual_deps += [
                 "@com_google_api_gax_java//gax-grpc:gax_grpc",
                 "@io_grpc_grpc_java//core:core",
                 "@io_grpc_grpc_java//protobuf:protobuf",
    +            "@com_google_api_gax_java//gax-httpjson:gax_httpjson",
             ]
    +    else:
    +        fail("Unknown transport: %s" % transport)
     
         native.java_library(
             name = name,
    @@ -256,18 +265,29 @@ def java_gapic_library(
             "@junit_junit//jar",
         ]
     
    -    if transport == "rest":
    +    if not transport or transport == "grpc":
    +        actual_test_deps += [
    +            "@com_google_api_gax_java//gax-grpc:gax_grpc_testlib",
    +            "@io_grpc_grpc_java//auth:auth",
    +            "@io_grpc_grpc_netty_shaded//jar",
    +            "@io_grpc_grpc_java//stub:stub",
    +            "@io_opencensus_opencensus_contrib_grpc_metrics//jar",
    +        ]
    +    elif transport == "rest":
             actual_test_deps += [
                 "@com_google_api_gax_java//gax-httpjson:gax_httpjson_testlib",
             ]
    -    else:
    +    elif transport == "grpc+rest":
             actual_test_deps += [
                 "@com_google_api_gax_java//gax-grpc:gax_grpc_testlib",
                 "@io_grpc_grpc_java//auth:auth",
                 "@io_grpc_grpc_netty_shaded//jar",
                 "@io_grpc_grpc_java//stub:stub",
                 "@io_opencensus_opencensus_contrib_grpc_metrics//jar",
    +            "@com_google_api_gax_java//gax-httpjson:gax_httpjson_testlib",
             ]
    +    else:
    +        fail("Unknown transport: %s" % transport)
     
         _append_dep_without_duplicates(actual_test_deps, test_deps)
         _append_dep_without_duplicates(actual_test_deps, actual_deps)
    diff --git a/rules_java_gapic/java_gapic_pkg.bzl b/rules_java_gapic/java_gapic_pkg.bzl
    index a6bca826d2..eb109db524 100644
    --- a/rules_java_gapic/java_gapic_pkg.bzl
    +++ b/rules_java_gapic/java_gapic_pkg.bzl
    @@ -351,10 +351,12 @@ def java_gapic_assembly_gradle_pkg(
             grpc_target_dep = ["%s" % grpc_target]
     
         if client_deps:
    -        if transport == "rest":
    -            template_label = Label("//rules_java_gapic:resources/gradle/client_rest.gradle.tmpl")
    -        else:
    +        if not transport or transport == "grpc":
                 template_label = Label("//rules_java_gapic:resources/gradle/client_grpc.gradle.tmpl")
    +        elif transport == "rest":
    +            template_label = Label("//rules_java_gapic:resources/gradle/client_rest.gradle.tmpl")
    +        elif transport == "grpc+rest":
    +            template_label = Label("//rules_java_gapic:resources/gradle/client_grpcrest.gradle.tmpl")
     
             _java_gapic_gradle_pkg(
                 name = client_target,
    diff --git a/rules_java_gapic/resources/gradle/assembly.gradle.tmpl b/rules_java_gapic/resources/gradle/assembly.gradle.tmpl
    index 3c0e59ee69..336a7a5c05 100644
    --- a/rules_java_gapic/resources/gradle/assembly.gradle.tmpl
    +++ b/rules_java_gapic/resources/gradle/assembly.gradle.tmpl
    @@ -12,8 +12,8 @@ subprojects {
       apply plugin: 'java'
       apply plugin: 'maven'
     
    -  sourceCompatibility = 1.7
    -  targetCompatibility = 1.7
    +  sourceCompatibility = 1.8
    +  targetCompatibility = 1.8
     
       test {
         testLogging {
    diff --git a/rules_java_gapic/resources/gradle/client_grpc.gradle.tmpl b/rules_java_gapic/resources/gradle/client_grpc.gradle.tmpl
    index 137f38d6f2..5ed53f6401 100644
    --- a/rules_java_gapic/resources/gradle/client_grpc.gradle.tmpl
    +++ b/rules_java_gapic/resources/gradle/client_grpc.gradle.tmpl
    @@ -9,8 +9,8 @@ apply plugin: 'java'
     description = 'GAPIC library for {{name}}'
     group = 'com.google.cloud'
     version = (findProperty('version') == 'unspecified') ? '0.0.0-SNAPSHOT' : version
    -sourceCompatibility = 1.7
    -targetCompatibility = 1.7
    +sourceCompatibility = 1.8
    +targetCompatibility = 1.8
     
     repositories {
       mavenCentral()
    diff --git a/rules_java_gapic/resources/gradle/client_grpcrest.gradle.tmpl b/rules_java_gapic/resources/gradle/client_grpcrest.gradle.tmpl
    new file mode 100644
    index 0000000000..fe5aa44622
    --- /dev/null
    +++ b/rules_java_gapic/resources/gradle/client_grpcrest.gradle.tmpl
    @@ -0,0 +1,63 @@
    +buildscript {
    +  repositories {
    +    mavenCentral()
    +  }
    +}
    +
    +apply plugin: 'java'
    +
    +description = 'GAPIC library for {{name}}'
    +group = 'com.google.cloud'
    +version = (findProperty('version') == 'unspecified') ? '0.0.0-SNAPSHOT' : version
    +sourceCompatibility = 1.8
    +targetCompatibility = 1.8
    +
    +repositories {
    +  mavenCentral()
    +  mavenLocal()
    +}
    +
    +compileJava.options.encoding = 'UTF-8'
    +javadoc.options.encoding = 'UTF-8'
    +
    +dependencies {
    +  compile 'com.google.api:gax:{{version.gax}}'
    +  testCompile 'com.google.api:gax:{{version.gax}}:testlib'
    +  compile 'com.google.api:gax-grpc:{{version.gax_grpc}}'
    +  testCompile 'com.google.api:gax-grpc:{{version.gax_grpc}}:testlib'
    +  compile 'com.google.api:gax-httpjson:{{version.gax_httpjson}}'
    +  testCompile 'com.google.api:gax-httpjson:{{version.gax_httpjson}}:testlib'
    +  testCompile 'io.grpc:grpc-netty-shaded:{{version.io_grpc}}'
    +  testCompile '{{maven.junit_junit}}'
    +  {{extra_deps}}
    +}
    +
    +task smokeTest(type: Test) {
    +  filter {
    +    includeTestsMatching "*SmokeTest"
    +    setFailOnNoMatchingTests false
    +  }
    +}
    +
    +test {
    +  exclude "**/*SmokeTest*"
    +}
    +
    +sourceSets {
    +  main {
    +    java {
    +      srcDir 'src/main/java'
    +    }
    +  }
    +}
    +
    +clean {
    +  delete 'all-jars'
    +}
    +
    +task allJars(type: Copy) {
    +  dependsOn test, jar
    +  into 'all-jars'
    +  // Replace with `from configurations.testRuntime, jar` to include test dependencies
    +  from configurations.runtime, jar
    +}
    diff --git a/rules_java_gapic/resources/gradle/client_rest.gradle.tmpl b/rules_java_gapic/resources/gradle/client_rest.gradle.tmpl
    index ef16323736..20fab62963 100644
    --- a/rules_java_gapic/resources/gradle/client_rest.gradle.tmpl
    +++ b/rules_java_gapic/resources/gradle/client_rest.gradle.tmpl
    @@ -9,8 +9,8 @@ apply plugin: 'java'
     description = 'GAPIC library for {{name}}'
     group = 'com.google.cloud'
     version = (findProperty('version') == 'unspecified') ? '0.0.0-SNAPSHOT' : version
    -sourceCompatibility = 1.7
    -targetCompatibility = 1.7
    +sourceCompatibility = 1.8
    +targetCompatibility = 1.8
     
     repositories {
       mavenCentral()
    diff --git a/rules_java_gapic/resources/gradle/grpc.gradle.tmpl b/rules_java_gapic/resources/gradle/grpc.gradle.tmpl
    index d5dfa3f3de..fbae0add76 100644
    --- a/rules_java_gapic/resources/gradle/grpc.gradle.tmpl
    +++ b/rules_java_gapic/resources/gradle/grpc.gradle.tmpl
    @@ -9,8 +9,8 @@ apply plugin: 'java'
     description = 'GRPC library for {{name}}'
     group = 'com.google.api.grpc'
     version = (findProperty('version') == 'unspecified') ? '0.0.0-SNAPSHOT' : version
    -sourceCompatibility = 1.7
    -targetCompatibility = 1.7
    +sourceCompatibility = 1.8
    +targetCompatibility = 1.8
     
     repositories {
       mavenCentral()
    diff --git a/rules_java_gapic/resources/gradle/proto.gradle.tmpl b/rules_java_gapic/resources/gradle/proto.gradle.tmpl
    index ad5e20fc33..27f0bf8448 100644
    --- a/rules_java_gapic/resources/gradle/proto.gradle.tmpl
    +++ b/rules_java_gapic/resources/gradle/proto.gradle.tmpl
    @@ -9,8 +9,8 @@ apply plugin: 'java'
     description = 'PROTO library for {{name}}'
     group = 'com.google.api.grpc'
     version = (findProperty('version') == 'unspecified') ? '0.0.0-SNAPSHOT' : version
    -sourceCompatibility = 1.7
    -targetCompatibility = 1.7
    +sourceCompatibility = 1.8
    +targetCompatibility = 1.8
     
     repositories {
       mavenCentral()
    diff --git a/src/main/java/com/google/api/generator/gapic/BUILD.bazel b/src/main/java/com/google/api/generator/gapic/BUILD.bazel
    index 9f6eb8954e..60cbc46d03 100644
    --- a/src/main/java/com/google/api/generator/gapic/BUILD.bazel
    +++ b/src/main/java/com/google/api/generator/gapic/BUILD.bazel
    @@ -9,6 +9,7 @@ filegroup(
             "//src/main/java/com/google/api/generator/gapic/composer/comment:comment_files",
             "//src/main/java/com/google/api/generator/gapic/composer/defaultvalue:defaultvalue_files",
             "//src/main/java/com/google/api/generator/gapic/composer/grpc:grpc_files",
    +        "//src/main/java/com/google/api/generator/gapic/composer/grpcrest:grpcrest_files",
             "//src/main/java/com/google/api/generator/gapic/composer/resourcename:resourcename_files",
             "//src/main/java/com/google/api/generator/gapic/composer/rest:rest_files",
             "//src/main/java/com/google/api/generator/gapic/composer/samplecode:samplecode_files",
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/BUILD.bazel b/src/main/java/com/google/api/generator/gapic/composer/BUILD.bazel
    index 3cfcae2c62..0f09405d04 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/BUILD.bazel
    +++ b/src/main/java/com/google/api/generator/gapic/composer/BUILD.bazel
    @@ -21,6 +21,7 @@ java_library(
             "//src/main/java/com/google/api/generator/gapic/composer/common",
             "//src/main/java/com/google/api/generator/gapic/composer/defaultvalue",
             "//src/main/java/com/google/api/generator/gapic/composer/grpc",
    +        "//src/main/java/com/google/api/generator/gapic/composer/grpcrest",
             "//src/main/java/com/google/api/generator/gapic/composer/resourcename",
             "//src/main/java/com/google/api/generator/gapic/composer/rest",
             "//src/main/java/com/google/api/generator/gapic/composer/samplecode",
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/Composer.java b/src/main/java/com/google/api/generator/gapic/composer/Composer.java
    index 5c191b0a27..4eefc2845a 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/Composer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/Composer.java
    @@ -15,22 +15,21 @@
     package com.google.api.generator.gapic.composer;
     
     import com.google.api.generator.engine.ast.ClassDefinition;
    -import com.google.api.generator.engine.ast.ScopeNode;
     import com.google.api.generator.gapic.composer.comment.CommentComposer;
    -import com.google.api.generator.gapic.composer.common.ServiceClientClassComposer;
    -import com.google.api.generator.gapic.composer.common.ServiceStubClassComposer;
     import com.google.api.generator.gapic.composer.grpc.GrpcServiceCallableFactoryClassComposer;
     import com.google.api.generator.gapic.composer.grpc.GrpcServiceStubClassComposer;
     import com.google.api.generator.gapic.composer.grpc.MockServiceClassComposer;
     import com.google.api.generator.gapic.composer.grpc.MockServiceImplClassComposer;
    +import com.google.api.generator.gapic.composer.grpc.ServiceClientClassComposer;
     import com.google.api.generator.gapic.composer.grpc.ServiceClientTestClassComposer;
     import com.google.api.generator.gapic.composer.grpc.ServiceSettingsClassComposer;
    +import com.google.api.generator.gapic.composer.grpc.ServiceStubClassComposer;
     import com.google.api.generator.gapic.composer.grpc.ServiceStubSettingsClassComposer;
    +import com.google.api.generator.gapic.composer.grpcrest.HttpJsonServiceClientTestClassComposer;
     import com.google.api.generator.gapic.composer.resourcename.ResourceNameHelperClassComposer;
     import com.google.api.generator.gapic.composer.rest.HttpJsonServiceCallableFactoryClassComposer;
     import com.google.api.generator.gapic.composer.rest.HttpJsonServiceStubClassComposer;
     import com.google.api.generator.gapic.model.GapicClass;
    -import com.google.api.generator.gapic.model.GapicClass.Kind;
     import com.google.api.generator.gapic.model.GapicContext;
     import com.google.api.generator.gapic.model.GapicPackageInfo;
     import com.google.api.generator.gapic.model.Service;
    @@ -76,8 +75,10 @@ public static List generateStubClasses(GapicContext context) {
             .services()
             .forEach(
                 s -> {
    -              clazzes.add(ServiceStubClassComposer.instance().generate(context, s));
                   if (context.transport() == Transport.REST) {
    +                clazzes.add(
    +                    com.google.api.generator.gapic.composer.rest.ServiceStubClassComposer.instance()
    +                        .generate(context, s));
                     clazzes.add(
                         com.google.api.generator.gapic.composer.rest.ServiceStubSettingsClassComposer
                             .instance()
    @@ -85,11 +86,30 @@ public static List generateStubClasses(GapicContext context) {
                     clazzes.add(
                         HttpJsonServiceCallableFactoryClassComposer.instance().generate(context, s));
                     clazzes.add(HttpJsonServiceStubClassComposer.instance().generate(context, s));
    -              } else {
    +              } else if (context.transport() == Transport.GRPC) {
    +                clazzes.add(ServiceStubClassComposer.instance().generate(context, s));
                     clazzes.add(ServiceStubSettingsClassComposer.instance().generate(context, s));
                     clazzes.add(
                         GrpcServiceCallableFactoryClassComposer.instance().generate(context, s));
                     clazzes.add(GrpcServiceStubClassComposer.instance().generate(context, s));
    +              } else if (context.transport() == Transport.GRPC_REST) {
    +                clazzes.add(
    +                    com.google.api.generator.gapic.composer.grpcrest.ServiceStubClassComposer
    +                        .instance()
    +                        .generate(context, s));
    +                clazzes.add(
    +                    com.google.api.generator.gapic.composer.grpcrest
    +                        .ServiceStubSettingsClassComposer.instance()
    +                        .generate(context, s));
    +                clazzes.add(
    +                    GrpcServiceCallableFactoryClassComposer.instance().generate(context, s));
    +                clazzes.add(GrpcServiceStubClassComposer.instance().generate(context, s));
    +                clazzes.add(
    +                    HttpJsonServiceCallableFactoryClassComposer.instance().generate(context, s));
    +                clazzes.add(
    +                    com.google.api.generator.gapic.composer.grpcrest
    +                        .HttpJsonServiceStubClassComposer.instance()
    +                        .generate(context, s));
                   }
                 });
         return clazzes;
    @@ -101,14 +121,27 @@ public static List generateClientSettingsClasses(GapicContext contex
             .services()
             .forEach(
                 s -> {
    -              clazzes.add(ServiceClientClassComposer.instance().generate(context, s));
                   if (context.transport() == Transport.REST) {
    +                clazzes.add(
    +                    com.google.api.generator.gapic.composer.rest.ServiceClientClassComposer
    +                        .instance()
    +                        .generate(context, s));
                     clazzes.add(
                         com.google.api.generator.gapic.composer.rest.ServiceSettingsClassComposer
                             .instance()
                             .generate(context, s));
    -              } else {
    +              } else if (context.transport() == Transport.GRPC) {
    +                clazzes.add(ServiceClientClassComposer.instance().generate(context, s));
                     clazzes.add(ServiceSettingsClassComposer.instance().generate(context, s));
    +              } else if (context.transport() == Transport.GRPC_REST) {
    +                clazzes.add(
    +                    com.google.api.generator.gapic.composer.grpcrest.ServiceClientClassComposer
    +                        .instance()
    +                        .generate(context, s));
    +                clazzes.add(
    +                    com.google.api.generator.gapic.composer.grpcrest.ServiceSettingsClassComposer
    +                        .instance()
    +                        .generate(context, s));
                   }
                 });
         return clazzes;
    @@ -120,7 +153,10 @@ public static List generateMockClasses(GapicContext context, List {
               if (context.transport() == Transport.REST) {
                 // REST transport tests donot not use mock services.
    -          } else {
    +          } else if (context.transport() == Transport.GRPC) {
    +            clazzes.add(MockServiceClassComposer.instance().generate(context, s));
    +            clazzes.add(MockServiceImplClassComposer.instance().generate(context, s));
    +          } else if (context.transport() == Transport.GRPC_REST) {
                 clazzes.add(MockServiceClassComposer.instance().generate(context, s));
                 clazzes.add(MockServiceImplClassComposer.instance().generate(context, s));
               }
    @@ -129,35 +165,25 @@ public static List generateMockClasses(GapicContext context, List generateTestClasses(GapicContext context) {
    -    return context.services().stream()
    -        .map(
    +    List clazzes = new ArrayList<>();
    +    context
    +        .services()
    +        .forEach(
                 s -> {
                   if (context.transport() == Transport.REST) {
    -                return com.google.api.generator.gapic.composer.rest.ServiceClientTestClassComposer
    -                    .instance()
    -                    .generate(context, s);
    -              } else {
    -                return ServiceClientTestClassComposer.instance().generate(context, s);
    +                clazzes.add(
    +                    com.google.api.generator.gapic.composer.rest.ServiceClientTestClassComposer
    +                        .instance()
    +                        .generate(context, s));
    +              } else if (context.transport() == Transport.GRPC) {
    +                clazzes.add(ServiceClientTestClassComposer.instance().generate(context, s));
    +              } else if (context.transport() == Transport.GRPC_REST) {
    +                clazzes.add(ServiceClientTestClassComposer.instance().generate(context, s));
    +                clazzes.add(HttpJsonServiceClientTestClassComposer.instance().generate(context, s));
                   }
    -            })
    -        .collect(Collectors.toList());
    -  }
    -
    -  /** ====================== HELPERS ==================== */
    -  // TODO(miraleung): Add method list.
    -  private static GapicClass generateGenericClass(Kind kind, String name, Service service) {
    -    String pakkage = service.pakkage();
    -    if (kind.equals(Kind.STUB)) {
    -      pakkage += ".stub";
    -    }
    +            });
     
    -    ClassDefinition classDef =
    -        ClassDefinition.builder()
    -            .setPackageString(pakkage)
    -            .setName(name)
    -            .setScope(ScopeNode.PUBLIC)
    -            .build();
    -    return GapicClass.create(kind, classDef);
    +    return clazzes;
       }
     
       @VisibleForTesting
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java
    index ea3898051c..f4e31a962e 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java
    @@ -299,7 +299,7 @@ protected MethodDefinition createGenericCallableMethod(
       protected TypeNode getOperationsStubType(Service service) {
         TypeNode opeationsStubType = service.operationServiceStubType();
         if (opeationsStubType == null) {
    -      opeationsStubType = getTransportContext().operationsStubType();
    +      opeationsStubType = getTransportContext().operationsStubTypes().get(0);
         }
         return opeationsStubType;
       }
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java
    similarity index 94%
    rename from src/main/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposer.java
    rename to src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java
    index 4f804822f1..6a9ec1b17a 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java
    @@ -85,19 +85,21 @@
     import java.util.Arrays;
     import java.util.Collections;
     import java.util.HashMap;
    +import java.util.HashSet;
    +import java.util.Iterator;
     import java.util.LinkedHashMap;
     import java.util.List;
     import java.util.Map;
     import java.util.Objects;
     import java.util.Optional;
    +import java.util.Set;
     import java.util.concurrent.TimeUnit;
     import java.util.function.BiFunction;
     import java.util.function.Function;
     import java.util.stream.Collectors;
     import javax.annotation.Generated;
     
    -public class ServiceClientClassComposer implements ClassComposer {
    -  private static final ServiceClientClassComposer INSTANCE = new ServiceClientClassComposer();
    +public abstract class AbstractServiceClientClassComposer implements ClassComposer {
       private static final String PAGED_RESPONSE_TYPE_NAME_PATTERN = "%sPagedResponse";
       private static final String CALLABLE_NAME_PATTERN = "%sCallable";
       private static final String PAGED_CALLABLE_NAME_PATTERN = "%sPagedCallable";
    @@ -115,10 +117,14 @@ private enum CallableMethodKind {
         PAGED,
       }
     
    -  private ServiceClientClassComposer() {}
    +  private final TransportContext transportContext;
     
    -  public static ServiceClientClassComposer instance() {
    -    return INSTANCE;
    +  protected AbstractServiceClientClassComposer(TransportContext transportContext) {
    +    this.transportContext = transportContext;
    +  }
    +
    +  protected TransportContext getTransportContext() {
    +    return transportContext;
       }
     
       @Override
    @@ -129,7 +135,7 @@ public GapicClass generate(GapicContext context, Service service) {
         String className = ClassNames.getServiceClientClassName(service);
         GapicClass.Kind kind = Kind.MAIN;
         String pakkage = service.pakkage();
    -    boolean hasLroClient = exposeOperationsClient(service);
    +    boolean hasLroClient = service.hasStandardLroMethods();
     
         Map> grpcRpcsToJavaMethodNames = new HashMap<>();
     
    @@ -198,7 +204,7 @@ private static List createClassHeaderComments(
             service, classMethodSampleCode, credentialsSampleCode, endpointSampleCode);
       }
     
    -  private static List createClassMethods(
    +  private List createClassMethods(
           Service service,
           Map messageTypes,
           TypeStore typeStore,
    @@ -216,23 +222,19 @@ private static List createClassMethods(
         return methods;
       }
     
    -  private static boolean exposeOperationsClient(Service service) {
    -    for (Method method : service.methods()) {
    -      if (method.hasLro() && method.lro().operationServiceStubType() == null) {
    -        return true;
    -      }
    -    }
    -    return false;
    -  }
    -
    -  private static List createFieldDeclarations(
    +  private List createFieldDeclarations(
           Service service, TypeStore typeStore, boolean hasLroClient) {
         Map fieldNameToTypes = new HashMap<>();
         fieldNameToTypes.put(
             "settings", typeStore.get(ClassNames.getServiceSettingsClassName(service)));
         fieldNameToTypes.put("stub", typeStore.get(ClassNames.getServiceStubClassName(service)));
         if (hasLroClient) {
    -      fieldNameToTypes.put("operationsClient", typeStore.get("OperationsClient"));
    +      Iterator opClientName = getTransportContext().operationsClientNames().iterator();
    +      Iterator opClientType = getTransportContext().operationsClientTypes().iterator();
    +
    +      while (opClientName.hasNext() && opClientType.hasNext()) {
    +        fieldNameToTypes.put(opClientName.next(), opClientType.next());
    +      }
         }
     
         return fieldNameToTypes.entrySet().stream()
    @@ -352,14 +354,13 @@ private static List createStaticCreatorMethods(
         return methods;
       }
     
    -  private static List createConstructorMethods(
    +  private List createConstructorMethods(
           Service service, TypeStore typeStore, boolean hasLroClient) {
         List methods = new ArrayList<>();
         String thisClientName = ClassNames.getServiceClientClassName(service);
         String settingsName = ClassNames.getServiceSettingsClassName(service);
         TypeNode thisClassType = typeStore.get(thisClientName);
         TypeNode stubSettingsType = typeStore.get(ClassNames.getServiceStubSettingsClassName(service));
    -    TypeNode operationsClientType = typeStore.get("OperationsClient");
         TypeNode exceptionType = typeStore.get("IOException");
     
         TypeNode settingsType = typeStore.get(settingsName);
    @@ -372,9 +373,6 @@ private static List createConstructorMethods(
                     .setType(typeStore.get(ClassNames.getServiceStubClassName(service)))
                     .setName("stub")
                     .build());
    -    VariableExpr operationsClientVarExpr =
    -        VariableExpr.withVariable(
    -            Variable.builder().setType(operationsClientType).setName("operationsClient").build());
     
         // Create the ServiceClient(ServiceSettings settings) ctor.
         List ctorAssignmentExprs = new ArrayList<>();
    @@ -404,25 +402,10 @@ private static List createConstructorMethods(
                         .build())
                 .build());
     
    -    Expr clientArgExpr =
    -        MethodInvocationExpr.builder()
    -            .setExprReferenceExpr(stubVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    -            .setMethodName("getOperationsStub")
    -            .build();
    -    AssignmentExpr operationsClientAssignExpr =
    -        AssignmentExpr.builder()
    -            .setVariableExpr(
    -                operationsClientVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    -            .setValueExpr(
    -                MethodInvocationExpr.builder()
    -                    .setStaticReferenceType(operationsClientType)
    -                    .setMethodName("create")
    -                    .setArguments(clientArgExpr)
    -                    .setReturnType(operationsClientVarExpr.type())
    -                    .build())
    -            .build();
    +    List operationsClientAssignExprs =
    +        createOperationsClientAssignExprs(thisExpr, stubVarExpr);
         if (hasLroClient) {
    -      ctorAssignmentExprs.add(operationsClientAssignExpr);
    +      ctorAssignmentExprs.addAll(operationsClientAssignExprs);
         }
     
         methods.add(
    @@ -453,7 +436,7 @@ private static List createConstructorMethods(
                 .setValueExpr(stubVarExpr)
                 .build());
         if (hasLroClient) {
    -      ctorAssignmentExprs.add(operationsClientAssignExpr);
    +      ctorAssignmentExprs.addAll(operationsClientAssignExprs);
         }
         AnnotationNode betaAnnotation =
             AnnotationNode.builder()
    @@ -476,15 +459,70 @@ private static List createConstructorMethods(
         return methods;
       }
     
    -  private static List createGetterMethods(
    +  private List createOperationsClientAssignExprs(
    +      Expr thisExpr, VariableExpr stubVarExpr) {
    +    List operationsClientAssignExprs = new ArrayList<>();
    +
    +    Iterator opClientTypesIt = getTransportContext().operationsClientTypes().iterator();
    +    Iterator opClientNamesIt = getTransportContext().operationsClientNames().iterator();
    +    Iterator opStubNamesIt =
    +        getTransportContext().transportOperationsStubNames().iterator();
    +
    +    while (opClientTypesIt.hasNext() && opClientNamesIt.hasNext() && opStubNamesIt.hasNext()) {
    +      TypeNode operationsClientType = opClientTypesIt.next();
    +      String opClientName = opClientNamesIt.next();
    +      String opStubName = opStubNamesIt.next();
    +
    +      VariableExpr operationsClientVarExpr =
    +          VariableExpr.withVariable(
    +              Variable.builder().setType(operationsClientType).setName(opClientName).build());
    +
    +      String operationsStubGetterName =
    +          String.format("get%s", JavaStyle.toUpperCamelCase(opStubName));
    +
    +      Expr clientArgExpr =
    +          MethodInvocationExpr.builder()
    +              .setExprReferenceExpr(stubVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    +              .setMethodName(operationsStubGetterName)
    +              .build();
    +
    +      AssignmentExpr operationsClientAssignExpr =
    +          AssignmentExpr.builder()
    +              .setVariableExpr(
    +                  operationsClientVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    +              .setValueExpr(
    +                  MethodInvocationExpr.builder()
    +                      .setStaticReferenceType(operationsClientType)
    +                      .setMethodName("create")
    +                      .setArguments(clientArgExpr)
    +                      .setReturnType(operationsClientVarExpr.type())
    +                      .build())
    +              .build();
    +      operationsClientAssignExprs.add(operationsClientAssignExpr);
    +    }
    +
    +    return operationsClientAssignExprs;
    +  }
    +
    +  private List createGetterMethods(
           Service service, TypeStore typeStore, boolean hasLroClient) {
         Map methodNameToTypes = new LinkedHashMap<>();
         methodNameToTypes.put(
             "getSettings", typeStore.get(ClassNames.getServiceSettingsClassName(service)));
         methodNameToTypes.put("getStub", typeStore.get(ClassNames.getServiceStubClassName(service)));
    -    String getOperationsClientMethodName = "getOperationsClient";
    +
    +    Set getOperationsClientMethodNames = new HashSet<>();
    +
         if (hasLroClient) {
    -      methodNameToTypes.put(getOperationsClientMethodName, typeStore.get("OperationsClient"));
    +      Iterator opClientNamesIt = getTransportContext().operationsClientNames().iterator();
    +      Iterator opClientTypesIt = getTransportContext().operationsClientTypes().iterator();
    +
    +      while (opClientNamesIt.hasNext() && opClientTypesIt.hasNext()) {
    +        String opClientMethodName =
    +            String.format("get%s", JavaStyle.toUpperCamelCase(opClientNamesIt.next()));
    +        getOperationsClientMethodNames.add(opClientMethodName);
    +        methodNameToTypes.put(opClientMethodName, opClientTypesIt.next());
    +      }
         }
         AnnotationNode betaStubAnnotation =
             AnnotationNode.builder()
    @@ -500,7 +538,7 @@ private static List createGetterMethods(
                   TypeNode methodReturnType = e.getValue();
                   String returnVariableName = JavaStyle.toLowerCamelCase(methodName.substring(3));
                   MethodDefinition.Builder methodBuilder = MethodDefinition.builder();
    -              if (methodName.equals(getOperationsClientMethodName)) {
    +              if (getOperationsClientMethodNames.contains(methodName)) {
                     methodBuilder =
                         methodBuilder.setHeaderCommentStatements(
                             ServiceClientCommentComposer.GET_OPERATIONS_CLIENT_METHOD_COMMENT);
    @@ -708,6 +746,7 @@ private static MethodDefinition createMethodDefaultMethod(
             method.isPaged()
                 ? typeStore.get(String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, method.name()))
                 : method.outputType();
    +    List annotations = new ArrayList<>();
         if (method.hasLro()) {
           LongrunningOperation lro = method.lro();
           methodOutputType =
    @@ -718,6 +757,13 @@ private static MethodDefinition createMethodDefaultMethod(
                       .copyAndSetGenerics(
                           Arrays.asList(
                               lro.responseType().reference(), lro.metadataType().reference())));
    +      if (method.hasLro() && method.lro().operationServiceStubType() != null) {
    +        annotations.add(
    +            AnnotationNode.withTypeAndDescription(
    +                typeStore.get("BetaApi"),
    +                "The surface for long-running operations is not stable yet and may change in the"
    +                    + " future."));
    +      }
         }
     
         // Construct the method that accepts a request proto.
    @@ -759,8 +805,7 @@ private static MethodDefinition createMethodDefaultMethod(
                 .setArguments(Arrays.asList(requestArgVarExpr));
     
         if (method.isDeprecated()) {
    -      methodBuilder =
    -          methodBuilder.setAnnotations(Arrays.asList(AnnotationNode.withType(TypeNode.DEPRECATED)));
    +      annotations.add(AnnotationNode.withType(TypeNode.DEPRECATED));
         }
     
         if (isProtoEmptyType(methodOutputType)) {
    @@ -772,6 +817,9 @@ private static MethodDefinition createMethodDefaultMethod(
           methodBuilder =
               methodBuilder.setReturnExpr(callableMethodExpr).setReturnType(methodOutputType);
         }
    +
    +    methodBuilder.setAnnotations(annotations);
    +
         return methodBuilder.build();
       }
     
    @@ -1681,8 +1729,6 @@ private static void createVaporTypes(Service service, TypeStore typeStore) {
               ClassNames.getServiceClientClassName(service));
         }
     
    -    // LRO Gapic-generated types.
    -    typeStore.put("com.google.longrunning", "OperationsClient");
         // Pagination types.
         typeStore.putAll(
             service.pakkage(),
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java
    index 7d01cfbca3..364dd183b3 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java
    @@ -109,12 +109,14 @@ public TransportContext getTransportContext() {
     
       @Override
       public GapicClass generate(GapicContext context, Service service) {
    +    return generate(ClassNames.getServiceClientTestClassName(service), context, service);
    +  }
    +
    +  protected GapicClass generate(String className, GapicContext context, Service service) {
         Map resourceNames = context.helperResourceNames();
    -    Map messageTypes = context.messages();
         String pakkage = service.pakkage();
         TypeStore typeStore = new TypeStore();
         addDynamicTypes(context, service, typeStore);
    -    String className = ClassNames.getServiceClientTestClassName(service);
         GapicClass.Kind kind = Kind.MAIN;
     
         Map classMemberVarExprs =
    @@ -196,7 +198,8 @@ private List createTestAdminMethods(
           TypeStore typeStore) {
         List javaMethods = new ArrayList<>();
         javaMethods.add(
    -        createStartStaticServerMethod(service, context, classMemberVarExprs, typeStore));
    +        createStartStaticServerMethod(
    +            service, context, classMemberVarExprs, typeStore, "newBuilder"));
         javaMethods.add(createStopServerMethod(service, classMemberVarExprs));
         javaMethods.add(createSetUpMethod(service, classMemberVarExprs, typeStore));
         javaMethods.add(createTearDownMethod(service, classMemberVarExprs));
    @@ -207,7 +210,8 @@ protected abstract MethodDefinition createStartStaticServerMethod(
           Service service,
           GapicContext context,
           Map classMemberVarExprs,
    -      TypeStore typeStore);
    +      TypeStore typeStore,
    +      String newBuilderMethod);
     
       protected abstract MethodDefinition createStopServerMethod(
           Service service, Map classMemberVarExprs);
    @@ -470,7 +474,7 @@ private MethodDefinition createRpcTestMethod(
                 VariableExpr.withVariable(
                     Variable.builder().setType(methodArg.type()).setName(methodArgName).build());
             argExprs.add(varExpr);
    -        Expr valExpr = DefaultValueComposer.createDefaultValue(methodArg, resourceNames);
    +        Expr valExpr = createDefaultValue(methodArg, resourceNames);
             methodExprs.add(
                 AssignmentExpr.builder()
                     .setVariableExpr(varExpr.toBuilder().setIsDecl(true).build())
    @@ -735,6 +739,9 @@ protected abstract List createStreamingRpcExceptionTestStatements(
           Map resourceNames,
           Map messageTypes);
     
    +  protected abstract Expr createDefaultValue(
    +      MethodArgument methodArg, Map resourceNames);
    +
       protected List createRpcExceptionTestStatements(
           Method method,
           List methodSignature,
    @@ -766,7 +773,7 @@ protected List createRpcExceptionTestStatements(
                 VariableExpr.withVariable(
                     Variable.builder().setType(methodArg.type()).setName(methodArgName).build());
             argVarExprs.add(varExpr);
    -        Expr valExpr = DefaultValueComposer.createDefaultValue(methodArg, resourceNames);
    +        Expr valExpr = createDefaultValue(methodArg, resourceNames);
             tryBodyExprs.add(
                 AssignmentExpr.builder()
                     .setVariableExpr(varExpr.toBuilder().setIsDecl(true).build())
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceSettingsClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceSettingsClassComposer.java
    index e59e689bb2..cd4f89cbb9 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceSettingsClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceSettingsClassComposer.java
    @@ -62,11 +62,13 @@
     import com.google.api.generator.gapic.model.Service;
     import com.google.api.generator.gapic.utils.JavaStyle;
     import com.google.common.base.Preconditions;
    +import com.google.common.collect.ImmutableList;
     import com.google.longrunning.Operation;
     import java.io.IOException;
     import java.util.ArrayList;
     import java.util.Arrays;
     import java.util.Collections;
    +import java.util.Iterator;
     import java.util.List;
     import java.util.Optional;
     import java.util.function.BiFunction;
    @@ -172,6 +174,7 @@ private List createClassMethods(Service service, TypeStore typ
         javaMethods.addAll(createSettingsGetterMethods(service, typeStore));
         javaMethods.add(createCreatorMethod(service, typeStore));
         javaMethods.addAll(createDefaultGetterMethods(service, typeStore));
    +    javaMethods.addAll(createNewBuilderMethods(service, typeStore, "newBuilder", "createDefault"));
         javaMethods.addAll(createBuilderHelperMethods(service, typeStore));
         javaMethods.add(createConstructorMethod(service, typeStore));
         return javaMethods;
    @@ -351,12 +354,19 @@ private List createDefaultGetterMethods(Service service, TypeS
                     "defaultCredentialsProviderBuilder",
                     typeMakerFn.apply(GoogleCredentialsProvider.Builder.class)),
                 SettingsCommentComposer.DEFAULT_CREDENTIALS_PROVIDER_BUILDER_METHOD_COMMENT));
    -    javaMethods.add(
    -        methodMakerFn.apply(
    -            methodStarterFn.apply(
    -                getTransportContext().defaultTransportProviderBuilderName(),
    -                typeMakerFn.apply(getTransportContext().instantiatingChannelProviderClass())),
    -            SettingsCommentComposer.DEFAULT_TRANSPORT_PROVIDER_BUILDER_METHOD_COMMENT));
    +
    +    Iterator providerBuilderNamesIt =
    +        getTransportContext().defaultTransportProviderBuilderNames().iterator();
    +    Iterator> channelProviderClassesIt =
    +        getTransportContext().instantiatingChannelProviderBuilderClasses().iterator();
    +    while (providerBuilderNamesIt.hasNext() && channelProviderClassesIt.hasNext()) {
    +      javaMethods.add(
    +          methodMakerFn.apply(
    +              methodStarterFn.apply(
    +                  providerBuilderNamesIt.next(),
    +                  typeMakerFn.apply(channelProviderClassesIt.next())),
    +              SettingsCommentComposer.DEFAULT_TRANSPORT_PROVIDER_BUILDER_METHOD_COMMENT));
    +    }
     
         javaMethods.add(
             methodStarterFn
    @@ -383,23 +393,31 @@ private List createDefaultGetterMethods(Service service, TypeS
         return javaMethods;
       }
     
    -  private static List createBuilderHelperMethods(
    -      Service service, TypeStore typeStore) {
    +  protected List createNewBuilderMethods(
    +      Service service,
    +      TypeStore typeStore,
    +      String newBuilderMethodName,
    +      String createDefaultMethodName) {
         TypeNode builderType = typeStore.get(BUILDER_CLASS_NAME);
    -    MethodDefinition newBuilderMethodOne =
    +    return ImmutableList.of(
             MethodDefinition.builder()
                 .setHeaderCommentStatements(SettingsCommentComposer.NEW_BUILDER_METHOD_COMMENT)
                 .setScope(ScopeNode.PUBLIC)
                 .setIsStatic(true)
                 .setReturnType(builderType)
    -            .setName("newBuilder")
    +            .setName(newBuilderMethodName)
                 .setReturnExpr(
                     MethodInvocationExpr.builder()
                         .setStaticReferenceType(builderType)
    -                    .setMethodName("createDefault")
    +                    .setMethodName(createDefaultMethodName)
                         .setReturnType(builderType)
                         .build())
    -            .build();
    +            .build());
    +  }
    +
    +  private static List createBuilderHelperMethods(
    +      Service service, TypeStore typeStore) {
    +    TypeNode builderType = typeStore.get(BUILDER_CLASS_NAME);
     
         VariableExpr clientContextVarExpr =
             VariableExpr.withVariable(
    @@ -439,10 +457,10 @@ private static List createBuilderHelperMethods(
                         .build())
                 .build();
     
    -    return Arrays.asList(newBuilderMethodOne, newBuilderMethodTwo, toBuilderMethod);
    +    return Arrays.asList(newBuilderMethodTwo, toBuilderMethod);
       }
     
    -  private static ClassDefinition createNestedBuilderClass(Service service, TypeStore typeStore) {
    +  private ClassDefinition createNestedBuilderClass(Service service, TypeStore typeStore) {
         return ClassDefinition.builder()
             .setHeaderCommentStatements(
                 SettingsCommentComposer.createBuilderClassComment(
    @@ -466,11 +484,12 @@ private static ClassDefinition createNestedBuilderClass(Service service, TypeSto
             .build();
       }
     
    -  private static List createNestedBuilderClassMethods(
    +  private List createNestedBuilderClassMethods(
           Service service, TypeStore typeStore) {
         List javaMethods = new ArrayList<>();
         javaMethods.addAll(createNestedBuilderConstructorMethods(service, typeStore));
    -    javaMethods.add(createNestedBuilderCreatorMethod(service, typeStore));
    +    javaMethods.addAll(
    +        createNestedBuilderCreatorMethods(service, typeStore, "newBuilder", "createDefault"));
         javaMethods.add(createNestedBuilderStubSettingsBuilderMethod(service, typeStore));
         javaMethods.add(createNestedBuilderApplyToAllUnaryMethod(service, typeStore));
         javaMethods.addAll(createNestedBuilderSettingsGetterMethods(service, typeStore));
    @@ -557,23 +576,28 @@ private static List createNestedBuilderConstructorMethods(
         return Arrays.asList(noArgCtor, clientContextCtor, settingsCtor, stubSettingsCtor);
       }
     
    -  private static MethodDefinition createNestedBuilderCreatorMethod(
    -      Service service, TypeStore typeStore) {
    +  protected List createNestedBuilderCreatorMethods(
    +      Service service,
    +      TypeStore typeStore,
    +      String newBuilderMethodName,
    +      String createDefaultMethodName) {
         MethodInvocationExpr ctorArg =
             MethodInvocationExpr.builder()
                 .setStaticReferenceType(
                     typeStore.get(ClassNames.getServiceStubSettingsClassName(service)))
    -            .setMethodName("newBuilder")
    +            .setMethodName(newBuilderMethodName)
                 .build();
     
         TypeNode builderType = typeStore.get(BUILDER_CLASS_NAME);
    -    return MethodDefinition.builder()
    -        .setScope(ScopeNode.PRIVATE)
    -        .setIsStatic(true)
    -        .setReturnType(builderType)
    -        .setName("createDefault")
    -        .setReturnExpr(NewObjectExpr.builder().setType(builderType).setArguments(ctorArg).build())
    -        .build();
    +    return ImmutableList.of(
    +        MethodDefinition.builder()
    +            .setScope(ScopeNode.PRIVATE)
    +            .setIsStatic(true)
    +            .setReturnType(builderType)
    +            .setName(createDefaultMethodName)
    +            .setReturnExpr(
    +                NewObjectExpr.builder().setType(builderType).setArguments(ctorArg).build())
    +            .build());
       }
     
       private static MethodDefinition createNestedBuilderStubSettingsBuilderMethod(
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java
    index 8935e0b00c..c54ccbde39 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java
    @@ -16,39 +16,27 @@
     
     import com.google.api.core.BetaApi;
     import com.google.api.gax.core.BackgroundResource;
    -import com.google.api.gax.core.BackgroundResourceAggregation;
     import com.google.api.gax.rpc.BidiStreamingCallable;
    -import com.google.api.gax.rpc.ClientContext;
     import com.google.api.gax.rpc.ClientStreamingCallable;
    +import com.google.api.gax.rpc.LongRunningClient;
     import com.google.api.gax.rpc.OperationCallable;
    -import com.google.api.gax.rpc.RequestParamsExtractor;
     import com.google.api.gax.rpc.ServerStreamingCallable;
     import com.google.api.gax.rpc.UnaryCallable;
     import com.google.api.generator.engine.ast.AnnotationNode;
    -import com.google.api.generator.engine.ast.AssignmentExpr;
     import com.google.api.generator.engine.ast.ClassDefinition;
    -import com.google.api.generator.engine.ast.CommentStatement;
     import com.google.api.generator.engine.ast.ConcreteReference;
    -import com.google.api.generator.engine.ast.EmptyLineStatement;
    -import com.google.api.generator.engine.ast.Expr;
     import com.google.api.generator.engine.ast.ExprStatement;
    -import com.google.api.generator.engine.ast.JavaDocComment;
     import com.google.api.generator.engine.ast.MethodDefinition;
    -import com.google.api.generator.engine.ast.MethodInvocationExpr;
    -import com.google.api.generator.engine.ast.NewObjectExpr;
    -import com.google.api.generator.engine.ast.ReferenceConstructorExpr;
    +import com.google.api.generator.engine.ast.Reference;
     import com.google.api.generator.engine.ast.ScopeNode;
     import com.google.api.generator.engine.ast.Statement;
    -import com.google.api.generator.engine.ast.ThisObjectValue;
     import com.google.api.generator.engine.ast.ThrowExpr;
    -import com.google.api.generator.engine.ast.TryCatchStatement;
     import com.google.api.generator.engine.ast.TypeNode;
    -import com.google.api.generator.engine.ast.ValueExpr;
    -import com.google.api.generator.engine.ast.VaporReference;
     import com.google.api.generator.engine.ast.Variable;
     import com.google.api.generator.engine.ast.VariableExpr;
     import com.google.api.generator.gapic.composer.comment.StubCommentComposer;
     import com.google.api.generator.gapic.composer.store.TypeStore;
    +import com.google.api.generator.gapic.composer.utils.ClassNames;
     import com.google.api.generator.gapic.composer.utils.PackageChecker;
     import com.google.api.generator.gapic.model.GapicClass;
     import com.google.api.generator.gapic.model.GapicClass.Kind;
    @@ -57,40 +45,20 @@
     import com.google.api.generator.gapic.model.Method;
     import com.google.api.generator.gapic.model.Service;
     import com.google.api.generator.gapic.utils.JavaStyle;
    -import com.google.common.base.Preconditions;
     import com.google.common.collect.ImmutableList;
    -import com.google.common.collect.ImmutableMap;
     import com.google.longrunning.Operation;
    -import java.io.IOException;
     import java.util.ArrayList;
     import java.util.Arrays;
     import java.util.Collections;
    -import java.util.LinkedHashMap;
    +import java.util.Iterator;
     import java.util.List;
     import java.util.Map;
    -import java.util.concurrent.TimeUnit;
    -import java.util.function.BiFunction;
    -import java.util.function.Function;
     import java.util.stream.Collectors;
     import javax.annotation.Generated;
     
     public abstract class AbstractServiceStubClassComposer implements ClassComposer {
    -  private static final Statement EMPTY_LINE_STATEMENT = EmptyLineStatement.create();
    -
    -  private static final String METHOD_DESCRIPTOR_NAME_PATTERN = "%sMethodDescriptor";
    +  private static final String DOT = ".";
       private static final String PAGED_RESPONSE_TYPE_NAME_PATTERN = "%sPagedResponse";
    -  private static final String PAGED_CALLABLE_CLASS_MEMBER_PATTERN = "%sPagedCallable";
    -
    -  private static final String BACKGROUND_RESOURCES_MEMBER_NAME = "backgroundResources";
    -  private static final String CALLABLE_NAME = "Callable";
    -  private static final String CALLABLE_FACTORY_MEMBER_NAME = "callableFactory";
    -  private static final String CALLABLE_CLASS_MEMBER_PATTERN = "%sCallable";
    -  private static final String OPERATION_CALLABLE_CLASS_MEMBER_PATTERN = "%sOperationCallable";
    -  private static final String OPERATION_CALLABLE_NAME = "OperationCallable";
    -  private static final String OPERATIONS_STUB_MEMBER_NAME = "operationsStub";
    -  private static final String PAGED_CALLABLE_NAME = "PagedCallable";
    -
    -  protected static final TypeStore FIXED_TYPESTORE = createStaticTypes();
     
       private final TransportContext transportContext;
     
    @@ -98,271 +66,38 @@ protected AbstractServiceStubClassComposer(TransportContext transportContext) {
         this.transportContext = transportContext;
       }
     
    -  public TransportContext getTransportContext() {
    +  protected TransportContext getTransportContext() {
         return transportContext;
       }
     
    -  private static TypeStore createStaticTypes() {
    -    List concreteClazzes =
    -        Arrays.asList(
    -            BackgroundResource.class,
    -            BackgroundResourceAggregation.class,
    -            BetaApi.class,
    -            BidiStreamingCallable.class,
    -            ClientContext.class,
    -            ClientStreamingCallable.class,
    -            Generated.class,
    -            ImmutableMap.class,
    -            InterruptedException.class,
    -            IOException.class,
    -            Operation.class,
    -            OperationCallable.class,
    -            RequestParamsExtractor.class,
    -            ServerStreamingCallable.class,
    -            TimeUnit.class,
    -            UnaryCallable.class);
    -    return new TypeStore(concreteClazzes);
    -  }
    -
       @Override
       public GapicClass generate(GapicContext context, Service service) {
    -    String pakkage = service.pakkage() + ".stub";
    -    TypeStore typeStore = createDynamicTypes(service, pakkage);
    -    String className = getTransportContext().classNames().getTransportServiceStubClassName(service);
    -    GapicClass.Kind kind = Kind.STUB;
    -
    -    Map protoMethodNameToDescriptorVarExprs =
    -        createProtoMethodNameToDescriptorClassMembers(
    -            service, getTransportContext().methodDescriptorClass());
    -
    -    Map callableClassMemberVarExprs =
    -        createCallableClassMembers(service, typeStore);
    -
    -    Map classMemberVarExprs = new LinkedHashMap<>();
    -    classMemberVarExprs.put(
    -        BACKGROUND_RESOURCES_MEMBER_NAME,
    -        VariableExpr.withVariable(
    -            Variable.builder()
    -                .setName(BACKGROUND_RESOURCES_MEMBER_NAME)
    -                .setType(FIXED_TYPESTORE.get("BackgroundResource"))
    -                .build()));
    -
    -
    -    TypeNode opeationsStubType = getTransportOperationsStubType(service);
    -    if (opeationsStubType != null) {
    -      classMemberVarExprs.put(
    -          OPERATIONS_STUB_MEMBER_NAME,
    -          VariableExpr.withVariable(
    -              Variable.builder()
    -                  .setName(OPERATIONS_STUB_MEMBER_NAME)
    -                  .setType(opeationsStubType)
    -                  .build()));
    -    }
    -
    -    boolean operationPollingMethod = checkOperationPollingMethod(service);
    -    if(operationPollingMethod) {
    -      VariableExpr longRunningVarExpr = declareLongRunningClient();
    -      if (longRunningVarExpr != null) {
    -        classMemberVarExprs.put("longRunningClient", longRunningVarExpr);
    -      }
    -    }
    -
    -    classMemberVarExprs.put(
    -        CALLABLE_FACTORY_MEMBER_NAME,
    -        VariableExpr.withVariable(
    -            Variable.builder()
    -                .setName(CALLABLE_FACTORY_MEMBER_NAME)
    -                .setType(getTransportContext().stubCallableFactoryType())
    -                .build()));
    -
         Map messageTypes = context.messages();
    -    List classStatements =
    -        createClassStatements(
    -            service,
    -            protoMethodNameToDescriptorVarExprs,
    -            callableClassMemberVarExprs,
    -            classMemberVarExprs,
    -            messageTypes);
    -
    -    StubCommentComposer commentComposer =
    -        new StubCommentComposer(getTransportContext().transportName());
    +    TypeStore typeStore = createTypes(service, messageTypes);
    +    String className = ClassNames.getServiceStubClassName(service);
    +    GapicClass.Kind kind = Kind.STUB;
    +    String pakkage = String.format("%s.stub", service.pakkage());
     
         ClassDefinition classDef =
             ClassDefinition.builder()
                 .setPackageString(pakkage)
                 .setHeaderCommentStatements(
    -                commentComposer.createTransportServiceStubClassHeaderComments(
    +                StubCommentComposer.createServiceStubClassHeaderComments(
                         service.name(), service.isDeprecated()))
    -            .setAnnotations(createClassAnnotations(service))
    -            .setScope(ScopeNode.PUBLIC)
    +            .setAnnotations(createClassAnnotations(service, typeStore))
    +            .setIsAbstract(true)
    +            .setImplementsTypes(createClassImplements(typeStore))
                 .setName(className)
    -            .setExtendsType(
    -                typeStore.get(getTransportContext().classNames().getServiceStubClassName(service)))
    -            .setStatements(classStatements)
    -            .setMethods(
    -                createClassMethods(
    -                    service,
    -                    typeStore,
    -                    classMemberVarExprs,
    -                    callableClassMemberVarExprs,
    -                    protoMethodNameToDescriptorVarExprs))
    +            .setMethods(createClassMethods(service, messageTypes, typeStore))
    +            .setScope(ScopeNode.PUBLIC)
                 .build();
         return GapicClass.create(kind, classDef);
       }
     
    -  protected abstract Statement createMethodDescriptorVariableDecl(
    -      Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr, Map messageTypes);
    -
    -  protected abstract List createOperationsStubGetterMethod(
    -      VariableExpr operationsStubVarExpr);
    -
    -  protected abstract Expr createTransportSettingsInitExpr(
    -      Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr);
    -
    -  protected List createGetMethodDescriptorsMethod(
    -      Service service,
    -      TypeStore typeStore,
    -      Map protoMethodNameToDescriptorVarExprs) {
    -    return Arrays.asList();
    -  }
    -
    -  protected List createClassStatements(
    -      Service service,
    -      Map protoMethodNameToDescriptorVarExprs,
    -      Map callableClassMemberVarExprs,
    -      Map classMemberVarExprs,
    -      Map messageTypes) {
    -    List classStatements = new ArrayList<>();
    -    for (Statement statement :
    -        createMethodDescriptorVariableDecls(service, protoMethodNameToDescriptorVarExprs, messageTypes)) {
    -      classStatements.add(statement);
    -      classStatements.add(EMPTY_LINE_STATEMENT);
    -    }
    -
    -    classStatements.addAll(createClassMemberFieldDeclarations(callableClassMemberVarExprs));
    -    classStatements.add(EMPTY_LINE_STATEMENT);
    -
    -    classStatements.addAll(createClassMemberFieldDeclarations(classMemberVarExprs));
    -    return classStatements;
    -  }
    -
    -  protected List createMethodDescriptorVariableDecls(
    -      Service service, Map protoMethodNameToDescriptorVarExprs, Map messageTypes) {
    -    return service.methods().stream()
    -        .map(
    -            m ->
    -                createMethodDescriptorVariableDecl(
    -                    service, m, protoMethodNameToDescriptorVarExprs.get(m.name()), messageTypes))
    -        .collect(Collectors.toList());
    -  }
    -
    -  private static List createClassMemberFieldDeclarations(
    -      Map fieldNameToVarExprs) {
    -    return fieldNameToVarExprs.values().stream()
    -        .map(
    -            v ->
    -                ExprStatement.withExpr(
    -                    v.toBuilder()
    -                        .setIsDecl(true)
    -                        .setScope(ScopeNode.PRIVATE)
    -                        .setIsFinal(true)
    -                        .build()))
    -        .collect(Collectors.toList());
    -  }
    -
    -  protected Map createProtoMethodNameToDescriptorClassMembers(
    -      Service service, Class descriptorClass) {
    -    return service.methods().stream()
    -        .collect(
    -            Collectors.toMap(
    -                Method::name,
    -                m ->
    -                    VariableExpr.withVariable(
    -                        Variable.builder()
    -                            .setName(
    -                                String.format(
    -                                    METHOD_DESCRIPTOR_NAME_PATTERN,
    -                                    JavaStyle.toLowerCamelCase(m.name())))
    -                            .setType(
    -                                TypeNode.withReference(
    -                                    ConcreteReference.builder()
    -                                        .setClazz(descriptorClass)
    -                                        .setGenerics(
    -                                            Arrays.asList(
    -                                                m.inputType().reference(),
    -                                                m.outputType().reference()))
    -                                        .build()))
    -                            .build()),
    -                (u, v) -> {
    -                  throw new IllegalStateException();
    -                },
    -                LinkedHashMap::new));
    -  }
    -
    -  private Map createCallableClassMembers(
    -      Service service, TypeStore typeStore) {
    -    Map callableClassMembers = new LinkedHashMap<>();
    -    // Using a for-loop because the output cardinality is not a 1:1 mapping to the input set.
    -    for (Method protoMethod : service.methods()) {
    -      String javaStyleProtoMethodName = JavaStyle.toLowerCamelCase(protoMethod.name());
    -      String callableName = String.format(CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName);
    -      callableClassMembers.put(
    -          callableName,
    -          VariableExpr.withVariable(
    -              Variable.builder()
    -                  .setName(callableName)
    -                  .setType(getCallableType(protoMethod))
    -                  .build()));
    -      if (protoMethod.hasLro()) {
    -        callableName =
    -            String.format(OPERATION_CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName);
    -        callableClassMembers.put(
    -            callableName,
    -            VariableExpr.withVariable(
    -                Variable.builder()
    -                    .setName(callableName)
    -                    .setType(
    -                        TypeNode.withReference(
    -                            ConcreteReference.builder()
    -                                .setClazz(OperationCallable.class)
    -                                .setGenerics(
    -                                    Arrays.asList(
    -                                        protoMethod.inputType().reference(),
    -                                        protoMethod.lro().responseType().reference(),
    -                                        protoMethod.lro().metadataType().reference()))
    -                                .build()))
    -                    .build()));
    -      }
    -      if (protoMethod.isPaged()) {
    -        callableName = String.format(PAGED_CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName);
    -        callableClassMembers.put(
    -            callableName,
    -            VariableExpr.withVariable(
    -                Variable.builder()
    -                    .setName(callableName)
    -                    .setType(
    -                        TypeNode.withReference(
    -                            getCallableType(protoMethod)
    -                                .reference()
    -                                .copyAndSetGenerics(
    -                                    Arrays.asList(
    -                                        protoMethod.inputType().reference(),
    -                                        typeStore
    -                                            .get(
    -                                                String.format(
    -                                                    PAGED_RESPONSE_TYPE_NAME_PATTERN,
    -                                                    protoMethod.name()))
    -                                            .reference()))))
    -                    .build()));
    -      }
    -    }
    -    return callableClassMembers;
    -  }
    -
    -  protected List createClassAnnotations(Service service) {
    +  private static List createClassAnnotations(Service service, TypeStore typeStore) {
         List annotations = new ArrayList<>();
         if (!PackageChecker.isGaApi(service.pakkage())) {
    -      annotations.add(AnnotationNode.withType(FIXED_TYPESTORE.get("BetaApi")));
    +      annotations.add(AnnotationNode.withType(typeStore.get("BetaApi")));
         }
     
         if (service.isDeprecated()) {
    @@ -371,589 +106,169 @@ protected List createClassAnnotations(Service service) {
     
         annotations.add(
             AnnotationNode.builder()
    -            .setType(FIXED_TYPESTORE.get("Generated"))
    +            .setType(typeStore.get("Generated"))
                 .setDescription("by gapic-generator-java")
                 .build());
         return annotations;
       }
     
    -  protected List createClassMethods(
    -      Service service,
    -      TypeStore typeStore,
    -      Map classMemberVarExprs,
    -      Map callableClassMemberVarExprs,
    -      Map protoMethodNameToDescriptorVarExprs) {
    -    List javaMethods = new ArrayList<>();
    -    javaMethods.addAll(createStaticCreatorMethods(service, typeStore));
    -    javaMethods.addAll(
    -        createConstructorMethods(
    -            service,
    -            typeStore,
    -            classMemberVarExprs,
    -            callableClassMemberVarExprs,
    -            protoMethodNameToDescriptorVarExprs));
    -    javaMethods.addAll(
    -        createGetMethodDescriptorsMethod(service, typeStore, protoMethodNameToDescriptorVarExprs));
    -    javaMethods.addAll(
    -        createOperationsStubGetterMethod(classMemberVarExprs.get(OPERATIONS_STUB_MEMBER_NAME)));
    -    javaMethods.addAll(createCallableGetterMethods(callableClassMemberVarExprs));
    -    javaMethods.addAll(
    -        createStubOverrideMethods(classMemberVarExprs.get(BACKGROUND_RESOURCES_MEMBER_NAME), service));
    -    return javaMethods;
    +  private static List createClassImplements(TypeStore typeStore) {
    +    return Arrays.asList(typeStore.get("BackgroundResource"));
       }
     
    -  private List createStaticCreatorMethods(Service service, TypeStore typeStore) {
    -    TypeNode creatorMethodReturnType =
    -        typeStore.get(getTransportContext().classNames().getTransportServiceStubClassName(service));
    -    Function, MethodDefinition.Builder> creatorMethodStarterFn =
    -        argList ->
    -            MethodDefinition.builder()
    -                .setScope(ScopeNode.PUBLIC)
    -                .setIsStatic(true)
    -                .setIsFinal(true)
    -                .setReturnType(creatorMethodReturnType)
    -                .setName("create")
    -                .setArguments(
    -                    argList.stream()
    -                        .map(v -> v.toBuilder().setIsDecl(true).build())
    -                        .collect(Collectors.toList()))
    -                .setThrowsExceptions(
    -                    Arrays.asList(
    -                        TypeNode.withReference(ConcreteReference.withClazz(IOException.class))));
    -
    -    Function, Expr> instantiatorExprFn =
    -        argList ->
    -            NewObjectExpr.builder().setType(creatorMethodReturnType).setArguments(argList).build();
    -
    -    TypeNode stubSettingsType =
    -        typeStore.get(getTransportContext().classNames().getServiceStubSettingsClassName(service));
    -    VariableExpr settingsVarExpr =
    -        VariableExpr.withVariable(
    -            Variable.builder().setName("settings").setType(stubSettingsType).build());
    -
    -    TypeNode clientContextType = FIXED_TYPESTORE.get("ClientContext");
    -    VariableExpr clientContextVarExpr =
    -        VariableExpr.withVariable(
    -            Variable.builder().setName("clientContext").setType(clientContextType).build());
    -
    -    VariableExpr callableFactoryVarExpr =
    -        VariableExpr.withVariable(
    -            Variable.builder()
    -                .setName("callableFactory")
    -                .setType(getTransportContext().stubCallableFactoryType())
    -                .build());
    -
    -    MethodInvocationExpr clientContextCreateMethodExpr =
    -        MethodInvocationExpr.builder()
    -            .setMethodName("create")
    -            .setStaticReferenceType(clientContextType)
    -            .setArguments(Arrays.asList(settingsVarExpr))
    -            .build();
    -    MethodInvocationExpr settingsBuilderMethodExpr =
    -        MethodInvocationExpr.builder()
    -            .setMethodName("newBuilder")
    -            .setStaticReferenceType(stubSettingsType)
    -            .build();
    -    settingsBuilderMethodExpr =
    -        MethodInvocationExpr.builder()
    -            .setMethodName("build")
    -            .setExprReferenceExpr(settingsBuilderMethodExpr)
    -            .build();
    +  private List createClassMethods(
    +      Service service, Map messageTypes, TypeStore typeStore) {
    +    List methods = new ArrayList<>();
    +    if (service.hasStandardLroMethods()) {
    +      TypeNode operationsStubType = service.operationServiceStubType();
    +      methods.addAll(createOperationsStubGetters(typeStore, operationsStubType));
    +    }
     
    -    return Arrays.asList(
    -        creatorMethodStarterFn
    -            .apply(Arrays.asList(settingsVarExpr))
    -            .setReturnExpr(
    -                instantiatorExprFn.apply(
    -                    Arrays.asList(settingsVarExpr, clientContextCreateMethodExpr)))
    -            .build(),
    -        creatorMethodStarterFn
    -            .apply(Arrays.asList(clientContextVarExpr))
    -            .setReturnExpr(
    -                instantiatorExprFn.apply(
    -                    Arrays.asList(settingsBuilderMethodExpr, clientContextVarExpr)))
    -            .build(),
    -        creatorMethodStarterFn
    -            .apply(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr))
    -            .setReturnExpr(
    -                instantiatorExprFn.apply(
    -                    Arrays.asList(
    -                        settingsBuilderMethodExpr, clientContextVarExpr, callableFactoryVarExpr)))
    -            .build());
    +    if (service.operationPollingMethod() != null) {
    +      methods.addAll(createLongRunningClientGetters(typeStore));
    +     }
    +    methods.addAll(createCallableGetters(service, messageTypes, typeStore));
    +    methods.addAll(createBackgroundResourceMethodOverrides());
    +    return methods;
       }
     
    -  protected List createConstructorMethods(
    -      Service service,
    -      TypeStore typeStore,
    -      Map classMemberVarExprs,
    -      Map callableClassMemberVarExprs,
    -      Map protoMethodNameToDescriptorVarExprs) {
    -    TypeNode stubSettingsType =
    -        typeStore.get(getTransportContext().classNames().getServiceStubSettingsClassName(service));
    -    VariableExpr settingsVarExpr =
    -        VariableExpr.withVariable(
    -            Variable.builder().setName("settings").setType(stubSettingsType).build());
    -
    -    TypeNode clientContextType = FIXED_TYPESTORE.get("ClientContext");
    -    VariableExpr clientContextVarExpr =
    -        VariableExpr.withVariable(
    -            Variable.builder().setName("clientContext").setType(clientContextType).build());
    -
    -    VariableExpr callableFactoryVarExpr =
    -        VariableExpr.withVariable(
    -            Variable.builder()
    -                .setName("callableFactory")
    -                .setType(getTransportContext().stubCallableFactoryType())
    -                .build());
    -
    -    TypeNode thisClassType =
    -        typeStore.get(getTransportContext().classNames().getTransportServiceStubClassName(service));
    -    TypeNode ioExceptionType =
    -        TypeNode.withReference(ConcreteReference.withClazz(IOException.class));
    -
    -    BiFunction, List, MethodDefinition> ctorMakerFn =
    -        (args, body) ->
    -            MethodDefinition.constructorBuilder()
    -                .setScope(ScopeNode.PROTECTED)
    -                .setReturnType(thisClassType)
    -                .setHeaderCommentStatements(Arrays.asList(createProtectedCtorComment(service)))
    -                .setArguments(
    -                    args.stream()
    -                        .map(v -> v.toBuilder().setIsDecl(true).build())
    -                        .collect(Collectors.toList()))
    -                .setThrowsExceptions(Arrays.asList(ioExceptionType))
    -                .setBody(body)
    -                .build();
    -
    -    // First constructor method.
    -    MethodDefinition firstCtor =
    -        ctorMakerFn.apply(
    -            Arrays.asList(settingsVarExpr, clientContextVarExpr),
    -            Arrays.asList(
    -                ExprStatement.withExpr(
    -                    ReferenceConstructorExpr.thisBuilder()
    -                        .setType(thisClassType)
    -                        .setArguments(
    -                            settingsVarExpr,
    -                            clientContextVarExpr,
    -                            NewObjectExpr.builder()
    -                                .setType(
    -                                    typeStore.get(
    -                                        getTransportContext()
    -                                            .classNames()
    -                                            .getTransportServiceCallableFactoryClassName(service)))
    -                                .build())
    -                        .build())));
    -
    -    Expr thisExpr =
    -        ValueExpr.withValue(
    -            ThisObjectValue.withType(
    -                typeStore.get(
    -                    getTransportContext().classNames().getTransportServiceStubClassName(service))));
    -    // Body of the second constructor method.
    -    List secondCtorStatements = new ArrayList<>();
    -    List secondCtorExprs = new ArrayList<>();
    -    secondCtorExprs.add(
    -        AssignmentExpr.builder()
    -            .setVariableExpr(
    -                classMemberVarExprs.get("callableFactory").toBuilder()
    -                    .setExprReferenceExpr(thisExpr)
    -                    .build())
    -            .setValueExpr(callableFactoryVarExpr)
    -            .build());
    -    VariableExpr operationsStubClassVarExpr = classMemberVarExprs.get(OPERATIONS_STUB_MEMBER_NAME);
    -
    -    TypeNode opeationsStubType = getTransportOperationsStubType(service);
    -    if (opeationsStubType != null) {
    -      secondCtorExprs.add(
    -          AssignmentExpr.builder()
    -              .setVariableExpr(
    -                  operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    -              .setValueExpr(
    -                  MethodInvocationExpr.builder()
    -                      .setStaticReferenceType(opeationsStubType)
    -                      .setMethodName("create")
    -                      .setArguments(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr))
    -                      .setReturnType(operationsStubClassVarExpr.type())
    -                      .build())
    -              .build());
    +  private List createCallableGetters(
    +      Service service, Map messageTypes, TypeStore typeStore) {
    +    // Use a traditional for-loop since the output cardinality is not necessarily 1:1 with that of
    +    // service.methods().
    +    List javaMethods = new ArrayList<>();
    +    for (Method method : service.methods()) {
    +      if (method.hasLro()) {
    +        javaMethods.add(createOperationCallableGetter(method, typeStore));
    +      }
    +      if (method.isPaged()) {
    +        javaMethods.add(createPagedCallableGetter(method, typeStore));
    +      }
    +      javaMethods.add(createCallableGetter(method, typeStore));
         }
    -    secondCtorStatements.addAll(
    -        secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()));
    -    secondCtorExprs.clear();
    -    secondCtorStatements.add(EMPTY_LINE_STATEMENT);
    -
    -    // Transport settings local variables.
    -    Map javaStyleMethodNameToTransportSettingsVarExprs =
    -        service.methods().stream()
    -            .collect(
    -                Collectors.toMap(
    -                    m -> JavaStyle.toLowerCamelCase(m.name()),
    -                    m ->
    -                        VariableExpr.withVariable(
    -                            Variable.builder()
    -                                .setName(
    -                                    String.format(
    -                                        "%sTransportSettings",
    -                                        JavaStyle.toLowerCamelCase(m.name())))
    -                                .setType(
    -                                    TypeNode.withReference(
    -                                        ConcreteReference.builder()
    -                                            .setClazz(getTransportContext().callSettingsClass())
    -                                            .setGenerics(
    -                                                Arrays.asList(
    -                                                    m.inputType().reference(),
    -                                                    m.outputType().reference()))
    -                                            .build()))
    -                                .build())));
    -
    -    secondCtorExprs.addAll(
    -        service.methods().stream()
    -            .map(
    -                m ->
    -                    createTransportSettingsInitExpr(
    -                        m,
    -                        javaStyleMethodNameToTransportSettingsVarExprs.get(
    -                            JavaStyle.toLowerCamelCase(m.name())),
    -                        protoMethodNameToDescriptorVarExprs.get(m.name())))
    -            .collect(Collectors.toList()));
    -    secondCtorStatements.addAll(
    -        secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()));
    -    secondCtorExprs.clear();
    -    secondCtorStatements.add(EMPTY_LINE_STATEMENT);
    -
    -    // Initialize Callable variables.
    -    secondCtorExprs.addAll(
    -        callableClassMemberVarExprs.entrySet().stream()
    -            .map(
    -                e ->
    -                    createCallableInitExpr(
    -                        e.getKey(),
    -                        e.getValue(),
    -                        callableFactoryVarExpr,
    -                        settingsVarExpr,
    -                        clientContextVarExpr,
    -                        operationsStubClassVarExpr,
    -                        thisExpr,
    -                        javaStyleMethodNameToTransportSettingsVarExprs))
    -            .collect(Collectors.toList()));
    -    secondCtorStatements.addAll(
    -        secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()));
    -    secondCtorExprs.clear();
    -    secondCtorStatements.add(EMPTY_LINE_STATEMENT);
    -
    -
    -    secondCtorStatements.addAll(createLongRunningClient(service, typeStore));
    -
    -    // Instantiate backgroundResources.
    -    MethodInvocationExpr getBackgroundResourcesMethodExpr =
    -        MethodInvocationExpr.builder()
    -            .setExprReferenceExpr(clientContextVarExpr)
    -            .setMethodName("getBackgroundResources")
    -            .build();
    -
    -    VariableExpr backgroundResourcesVarExpr = classMemberVarExprs.get("backgroundResources");
    -    secondCtorExprs.add(
    -        AssignmentExpr.builder()
    -            .setVariableExpr(
    -                backgroundResourcesVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    -            .setValueExpr(
    -                NewObjectExpr.builder()
    -                    .setType(FIXED_TYPESTORE.get("BackgroundResourceAggregation"))
    -                    .setArguments(Arrays.asList(getBackgroundResourcesMethodExpr))
    -                    .build())
    -            .build());
    -    secondCtorStatements.addAll(
    -        secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()));
    -    secondCtorExprs.clear();
    -
    -    // Second constructor method.
    -    MethodDefinition secondCtor =
    -        ctorMakerFn.apply(
    -            Arrays.asList(settingsVarExpr, clientContextVarExpr, callableFactoryVarExpr),
    -            secondCtorStatements);
    +    return javaMethods;
    +  }
     
    -    return Arrays.asList(firstCtor, secondCtor);
    +  private MethodDefinition createOperationCallableGetter(
    +      Method method, TypeStore typeStore) {
    +    return createCallableGetterHelper(method, typeStore, true, false);
       }
     
    -  protected List createLongRunningClient(Service service, TypeStore typeStore) {
    -    return ImmutableList.of();
    +  private MethodDefinition createPagedCallableGetter(Method method, TypeStore typeStore) {
    +    return createCallableGetterHelper(method, typeStore, false, true);
       }
     
    -  protected VariableExpr declareLongRunningClient() {
    -    return null;
    +  private MethodDefinition createCallableGetter(Method method, TypeStore typeStore) {
    +    return createCallableGetterHelper(method, typeStore, false, false);
       }
     
    -  private static Expr createCallableInitExpr(
    -      String callableVarName,
    -      VariableExpr callableVarExpr,
    -      VariableExpr callableFactoryVarExpr,
    -      VariableExpr settingsVarExpr,
    -      VariableExpr clientContextVarExpr,
    -      VariableExpr operationsStubClassVarExpr,
    -      Expr thisExpr,
    -      Map javaStyleMethodNameToTransportSettingsVarExprs) {
    -    boolean isOperation = callableVarName.endsWith(OPERATION_CALLABLE_NAME);
    -    boolean isPaged = callableVarName.endsWith(PAGED_CALLABLE_NAME);
    -    int sublength = 0;
    -    if (isOperation) {
    -      sublength = OPERATION_CALLABLE_NAME.length();
    -    } else if (isPaged) {
    -      sublength = PAGED_CALLABLE_NAME.length();
    -    } else {
    -      sublength = CALLABLE_NAME.length();
    -    }
    -    String javaStyleMethodName = callableVarName.substring(0, callableVarName.length() - sublength);
    -    List creatorMethodArgVarExprs = null;
    -    Expr transportSettingsVarExpr =
    -        javaStyleMethodNameToTransportSettingsVarExprs.get(javaStyleMethodName);
    -    if (transportSettingsVarExpr == null && isOperation) {
    -      // Try again, in case the name dtection above was inaccurate.
    -      isOperation = false;
    -      sublength = CALLABLE_NAME.length();
    -      javaStyleMethodName = callableVarName.substring(0, callableVarName.length() - sublength);
    -      transportSettingsVarExpr =
    -          javaStyleMethodNameToTransportSettingsVarExprs.get(javaStyleMethodName);
    +  private MethodDefinition createCallableGetterHelper(
    +      Method method, TypeStore typeStore, boolean isLroCallable, boolean isPaged) {
    +    TypeNode returnType;
    +    switch (method.stream()) {
    +      case CLIENT:
    +        returnType = typeStore.get("ClientStreamingCallable");
    +        break;
    +      case SERVER:
    +        returnType = typeStore.get("ServerStreamingCallable");
    +        break;
    +      case BIDI:
    +        returnType = typeStore.get("BidiStreamingCallable");
    +        break;
    +      case NONE:
    +        // Fall through.
    +      default:
    +        returnType = typeStore.get(isLroCallable ? "OperationCallable" : "UnaryCallable");
         }
    -    Preconditions.checkNotNull(
    -        transportSettingsVarExpr,
    +
    +    String methodName =
             String.format(
    -            "No transport settings variable found for method name %s", javaStyleMethodName));
    -    if (isOperation) {
    -      creatorMethodArgVarExprs =
    -          Arrays.asList(
    -              transportSettingsVarExpr,
    -              MethodInvocationExpr.builder()
    -                  .setExprReferenceExpr(settingsVarExpr)
    -                  .setMethodName(String.format("%sOperationSettings", javaStyleMethodName))
    -                  .build(),
    -              clientContextVarExpr,
    -              operationsStubClassVarExpr);
    +            "%s%sCallable",
    +            JavaStyle.toLowerCamelCase(method.name()),
    +            (isLroCallable ? "Operation" : isPaged ? "Paged" : ""));
    +    List genericRefs = new ArrayList<>();
    +    genericRefs.add(method.inputType().reference());
    +    if (method.hasLro() && isLroCallable) {
    +      genericRefs.add(method.lro().responseType().reference());
    +      genericRefs.add(method.lro().metadataType().reference());
    +    } else if (isPaged) {
    +      genericRefs.add(
    +          typeStore
    +              .get(String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, method.name()))
    +              .reference());
         } else {
    -      creatorMethodArgVarExprs =
    -          Arrays.asList(
    -              transportSettingsVarExpr,
    -              MethodInvocationExpr.builder()
    -                  .setExprReferenceExpr(settingsVarExpr)
    -                  .setMethodName(String.format("%sSettings", javaStyleMethodName))
    -                  .build(),
    -              clientContextVarExpr);
    +      genericRefs.add(method.outputType().reference());
         }
     
    -    String callableCreatorMethodName = getCallableCreatorMethodName(callableVarExpr.type());
    -    return AssignmentExpr.builder()
    -        .setVariableExpr(callableVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    -        .setValueExpr(
    -            MethodInvocationExpr.builder()
    -                .setExprReferenceExpr(callableFactoryVarExpr)
    -                .setMethodName(callableCreatorMethodName)
    -                .setArguments(creatorMethodArgVarExprs)
    -                .setReturnType(callableVarExpr.type())
    -                .build())
    -        .build();
    -  }
    -
    -  private static String getCallableCreatorMethodName(TypeNode callableVarExprType) {
    -    final String typeName = callableVarExprType.reference().name();
    -    String streamName = "Unary";
    +    List annotations =
    +        method.isDeprecated()
    +            ? Arrays.asList(AnnotationNode.withType(TypeNode.DEPRECATED))
    +            : Collections.emptyList();
     
    -    // Special handling for pagination methods.
    -    if (callableVarExprType.reference().generics().size() == 2
    -        && callableVarExprType.reference().generics().get(1).name().endsWith("PagedResponse")) {
    -      streamName = "Paged";
    -    } else {
    -      if (typeName.startsWith("Client")) {
    -        streamName = "ClientStreaming";
    -      } else if (typeName.startsWith("Server")) {
    -        streamName = "ServerStreaming";
    -      } else if (typeName.startsWith("Bidi")) {
    -        streamName = "BidiStreaming";
    -      } else if (typeName.startsWith("Operation")) {
    -        streamName = "Operation";
    -      }
    -    }
    -    return String.format("create%sCallable", streamName);
    -  }
    +    returnType = TypeNode.withReference(returnType.reference().copyAndSetGenerics(genericRefs));
     
    -  private static List createCallableGetterMethods(
    -      Map callableClassMemberVarExprs) {
    -    return callableClassMemberVarExprs.entrySet().stream()
    -        .map(
    -            e ->
    -                MethodDefinition.builder()
    -                    .setIsOverride(true)
    -                    .setScope(ScopeNode.PUBLIC)
    -                    .setReturnType(e.getValue().type())
    -                    .setName(e.getKey())
    -                    .setReturnExpr(e.getValue())
    -                    .build())
    -        .collect(Collectors.toList());
    +    return createCallableGetterMethodDefinition(returnType, methodName, annotations, typeStore);
       }
     
    -  private List createStubOverrideMethods(
    -      VariableExpr backgroundResourcesVarExpr, Service service) {
    -    Function methodMakerStarterFn =
    -        methodName ->
    -            MethodDefinition.builder()
    -                .setIsOverride(true)
    -                .setScope(ScopeNode.PUBLIC)
    -                .setName(methodName);
    -
    -    Function voidMethodMakerFn =
    -        methodName ->
    -            methodMakerStarterFn
    -                .apply(methodName)
    -                .setReturnType(TypeNode.VOID)
    -                .setBody(
    -                    Arrays.asList(
    -                        ExprStatement.withExpr(
    -                            MethodInvocationExpr.builder()
    -                                .setExprReferenceExpr(backgroundResourcesVarExpr)
    -                                .setMethodName(methodName)
    -                                .build())))
    -                .build();
    +  private List createOperationsStubGetters(TypeStore typeStore, TypeNode operationsStubType) {
    +    List getters = new ArrayList<>();
     
    -    Function booleanMethodMakerFn =
    -        methodName ->
    -            methodMakerStarterFn
    -                .apply(methodName)
    -                .setReturnType(TypeNode.BOOLEAN)
    -                .setReturnExpr(
    -                    MethodInvocationExpr.builder()
    -                        .setExprReferenceExpr(backgroundResourcesVarExpr)
    -                        .setMethodName(methodName)
    -                        .setReturnType(TypeNode.BOOLEAN)
    -                        .build())
    -                .build();
    +    Iterator operationStubNameIt =
    +        getTransportContext().transportOperationsStubNames().iterator();
    +    Iterator operationStubTypeIt = getTransportContext().operationsStubTypes().iterator();
     
    -    // Generate the close() method:
    -    //   @Override
    -    //   public final void close() {
    -    //     try {
    -    //       backgroundResources.close();
    -    //     } catch (RuntimeException e) {
    -    //       throw e;
    -    //     } catch (Exception e) {
    -    //       throw new IllegalStateException("Failed to close resource", e);
    -    //     }
    -    //  }
    +    while (operationStubNameIt.hasNext() && operationStubTypeIt.hasNext()) {
    +      String methodName =
    +          String.format("get%s", JavaStyle.toUpperCamelCase(operationStubNameIt.next()));
    +      //TODO: refactor this
    +      TypeNode actualOperationsStubType = operationStubTypeIt.next();
    +      if (operationsStubType != null) {
    +        actualOperationsStubType = operationsStubType;
    +      }
     
    -    VariableExpr catchRuntimeExceptionVarExpr =
    -        VariableExpr.builder()
    -            .setVariable(
    -                Variable.builder()
    -                    .setType(TypeNode.withExceptionClazz(RuntimeException.class))
    -                    .setName("e")
    -                    .build())
    -            .build();
    -    VariableExpr catchExceptionVarExpr =
    -        VariableExpr.builder()
    -            .setVariable(
    -                Variable.builder()
    -                    .setType(TypeNode.withExceptionClazz(Exception.class))
    -                    .setName("e")
    -                    .build())
    -            .build();
    -    List javaMethods = new ArrayList<>();
    -    if (service.operationPollingMethod() != null) {
    -      javaMethods.addAll(createLongRunningClientGetter());
    +      getters.add(createOperationsStubGetterMethodDefinition(actualOperationsStubType, methodName, typeStore));
         }
    -    javaMethods.add(
    -        methodMakerStarterFn
    -            .apply("close")
    -            .setIsFinal(true)
    -            .setReturnType(TypeNode.VOID)
    -            .setBody(
    -                Arrays.asList(
    -                    TryCatchStatement.builder()
    -                        .setTryBody(
    -                            Arrays.asList(
    -                                ExprStatement.withExpr(
    -                                    MethodInvocationExpr.builder()
    -                                        .setExprReferenceExpr(backgroundResourcesVarExpr)
    -                                        .setMethodName("close")
    -                                        .build())))
    -                        .addCatch(
    -                            catchRuntimeExceptionVarExpr.toBuilder().setIsDecl(true).build(),
    -                            Arrays.asList(
    -                                ExprStatement.withExpr(
    -                                    ThrowExpr.builder()
    -                                        .setThrowExpr(catchRuntimeExceptionVarExpr)
    -                                        .build())))
    -                        .addCatch(
    -                            catchExceptionVarExpr.toBuilder().setIsDecl(true).build(),
    -                            Arrays.asList(
    -                                ExprStatement.withExpr(
    -                                    ThrowExpr.builder()
    -                                        .setType(
    -                                            TypeNode.withExceptionClazz(
    -                                                IllegalStateException.class))
    -                                        .setMessageExpr(String.format("Failed to close resource"))
    -                                        .setCauseExpr(catchExceptionVarExpr)
    -                                        .build())))
    -                        .build()))
    -            .build());
    -    javaMethods.add(voidMethodMakerFn.apply("shutdown"));
    -    javaMethods.add(booleanMethodMakerFn.apply("isShutdown"));
    -    javaMethods.add(booleanMethodMakerFn.apply("isTerminated"));
    -    javaMethods.add(voidMethodMakerFn.apply("shutdownNow"));
     
    -    List awaitTerminationArgs =
    -        Arrays.asList(
    -            VariableExpr.withVariable(
    -                Variable.builder().setName("duration").setType(TypeNode.LONG).build()),
    -            VariableExpr.withVariable(
    -                Variable.builder()
    -                    .setName("unit")
    -                    .setType(FIXED_TYPESTORE.get("TimeUnit"))
    -                    .build()));
    -    javaMethods.add(
    -        methodMakerStarterFn
    -            .apply("awaitTermination")
    -            .setReturnType(TypeNode.BOOLEAN)
    -            .setArguments(
    -                awaitTerminationArgs.stream()
    -                    .map(v -> v.toBuilder().setIsDecl(true).build())
    -                    .collect(Collectors.toList()))
    -            .setThrowsExceptions(Arrays.asList(FIXED_TYPESTORE.get("InterruptedException")))
    -            .setReturnExpr(
    -                MethodInvocationExpr.builder()
    -                    .setExprReferenceExpr(backgroundResourcesVarExpr)
    -                    .setMethodName("awaitTermination")
    -                    .setArguments(
    -                        awaitTerminationArgs.stream()
    -                            .map(v -> (Expr) v)
    -                            .collect(Collectors.toList()))
    -                    .setReturnType(TypeNode.BOOLEAN)
    -                    .build())
    -            .build());
    -    return javaMethods;
    +    return getters;
       }
     
    -  private boolean checkOperationPollingMethod(Service service) {
    -    for(Method method : service.methods()) {
    -      if(method.isOperationPollingMethod()) {
    -        return true;
    -      }
    -    }
    -    return false;
    +  private List createLongRunningClientGetters(TypeStore typeStore) {
    +    return ImmutableList.of(createCallableGetterMethodDefinition(
    +        TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class)),
    +        "longRunningClient",
    +        ImmutableList.of(AnnotationNode.withType(typeStore.get("BetaApi"))),
    +        typeStore));
       }
     
    -  protected List createLongRunningClientGetter() {
    -    return Collections.emptyList();
    +  private static List createBackgroundResourceMethodOverrides() {
    +    MethodDefinition closeMethod =
    +        MethodDefinition.builder()
    +            .setIsOverride(true)
    +            .setScope(ScopeNode.PUBLIC)
    +            .setIsAbstract(true)
    +            .setReturnType(TypeNode.VOID)
    +            .setName("close")
    +            .build();
    +    return Arrays.asList(closeMethod);
       }
     
    -  private TypeStore createDynamicTypes(Service service, String stubPakkage) {
    -    TypeStore typeStore = new TypeStore();
    -    typeStore.putAll(
    -        stubPakkage,
    +  private static TypeStore createTypes(Service service, Map messageTypes) {
    +    List concreteClazzes =
             Arrays.asList(
    -            getTransportContext().classNames().getTransportServiceStubClassName(service),
    -            getTransportContext().classNames().getServiceStubSettingsClassName(service),
    -            getTransportContext().classNames().getServiceStubClassName(service),
    -            getTransportContext()
    -                .classNames()
    -                .getTransportServiceCallableFactoryClassName(service)));
    +            BackgroundResource.class,
    +            BetaApi.class,
    +            BidiStreamingCallable.class,
    +            ClientStreamingCallable.class,
    +            Generated.class,
    +            Operation.class,
    +            OperationCallable.class,
    +            ServerStreamingCallable.class,
    +            UnaryCallable.class,
    +            UnsupportedOperationException.class);
    +    TypeStore typeStore = new TypeStore(concreteClazzes);
    +
    +    typeStore.put("com.google.longrunning.stub", "OperationsStub");
    +
         // Pagination types.
         typeStore.putAll(
             service.pakkage(),
    @@ -962,68 +277,45 @@ private TypeStore createDynamicTypes(Service service, String stubPakkage) {
                 .map(m -> String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, m.name()))
                 .collect(Collectors.toList()),
             true,
    -        getTransportContext().classNames().getServiceClientClassName(service));
    -    return typeStore;
    -  }
    +        ClassNames.getServiceClientClassName(service));
     
    -  private static TypeNode getCallableType(Method protoMethod) {
    -    TypeNode callableType = FIXED_TYPESTORE.get("UnaryCallable");
    -    switch (protoMethod.stream()) {
    -      case CLIENT:
    -        callableType = FIXED_TYPESTORE.get("ClientStreamingCallable");
    -        break;
    -      case SERVER:
    -        callableType = FIXED_TYPESTORE.get("ServerStreamingCallable");
    -        break;
    -      case BIDI:
    -        callableType = FIXED_TYPESTORE.get("BidiStreamingCallable");
    -        break;
    -      case NONE:
    -        // Fall through
    -      default:
    -        // Fall through
    -    }
    -
    -    return TypeNode.withReference(
    -        callableType
    -            .reference()
    -            .copyAndSetGenerics(
    -                Arrays.asList(
    -                    protoMethod.inputType().reference(), protoMethod.outputType().reference())));
    +    return typeStore;
       }
     
    -  private CommentStatement createProtectedCtorComment(Service service) {
    -    return CommentStatement.withComment(
    -        JavaDocComment.withComment(
    -            String.format(
    -                "Constructs an instance of %s, using the given settings. This is protected so that"
    -                    + " it is easy to make a subclass, but otherwise, the static factory methods"
    -                    + " should be  preferred.",
    -                getTransportContext().classNames().getTransportServiceStubClassName(service))));
    +  protected MethodDefinition createCallableGetterMethodDefinition(
    +      TypeNode returnType, String methodName, List annotations, TypeStore typeStore) {
    +    return MethodDefinition.builder()
    +        .setScope(ScopeNode.PUBLIC)
    +        .setAnnotations(annotations)
    +        .setName(methodName)
    +        .setReturnType(returnType)
    +        .setBody(
    +            Arrays.asList(
    +                ExprStatement.withExpr(
    +                    ThrowExpr.builder()
    +                        .setType(typeStore.get("UnsupportedOperationException"))
    +                        .setMessageExpr(String.format("Not implemented: %s()", methodName))
    +                        .build())))
    +        .build();
       }
     
    -  protected String getProtoRpcFullMethodName(Service protoService, Method protoMethod) {
    -    if (protoMethod.isMixin()) {
    -      return String.format("%s/%s", protoMethod.mixedInApiName(), protoMethod.name());
    -    }
    -
    -    return String.format(
    -        "%s.%s/%s", protoService.protoPakkage(), protoService.name(), protoMethod.name());
    +  protected MethodDefinition createOperationsStubGetterMethodDefinition(
    +      TypeNode returnType, String methodName, TypeStore typeStore) {
    +    return MethodDefinition.builder()
    +        .setScope(ScopeNode.PUBLIC)
    +        .setReturnType(returnType)
    +        .setName(methodName)
    +        .setBody(
    +            Arrays.asList(
    +                ExprStatement.withExpr(
    +                    ThrowExpr.builder()
    +                        .setType(typeStore.get("UnsupportedOperationException"))
    +                        .setMessageExpr(String.format("Not implemented: %s()", methodName))
    +                        .build())))
    +        .build();
       }
     
    -  protected TypeNode getTransportOperationsStubType(Service service) {
    -    TypeNode transportOpeationsStubType = service.operationServiceStubType();
    -    if (transportOpeationsStubType == null) {
    -      transportOpeationsStubType = getTransportContext().transportOperationsStubType();
    -    }
    -    else {
    -      transportOpeationsStubType = TypeNode.withReference(
    -          VaporReference.builder()
    -              .setName("HttpJson" + transportOpeationsStubType.reference().simpleName())
    -              .setPakkage(transportOpeationsStubType.reference().pakkage())
    -              .build());
    -    }
    -
    -    return transportOpeationsStubType;
    +  private static String getClientClassName(Service service) {
    +    return String.format("%sClient", service.overriddenName());
       }
     }
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java
    index c999fccb9d..d61456e1ad 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubSettingsClassComposer.java
    @@ -105,6 +105,7 @@
     import java.util.Arrays;
     import java.util.Collections;
     import java.util.HashSet;
    +import java.util.Iterator;
     import java.util.LinkedHashMap;
     import java.util.List;
     import java.util.Map;
    @@ -225,11 +226,125 @@ protected MethodDefinition createDefaultCredentialsProviderBuilderMethod() {
             .build();
       }
     
    -  protected abstract MethodDefinition createDefaultTransportTransportProviderBuilderMethod();
    +  protected List createDefaultTransportTransportProviderBuilderMethods() {
    +    // Create the defaultGrpcTransportProviderBuilder method.
    +    Iterator> providerClassIt =
    +        getTransportContext().instantiatingChannelProviderClasses().iterator();
    +    Iterator> providerBuilderClassIt =
    +        getTransportContext().instantiatingChannelProviderBuilderClasses().iterator();
    +    Iterator builderNamesIt =
    +        getTransportContext().defaultTransportProviderBuilderNames().iterator();
    +
    +    List methods = new ArrayList<>();
    +
    +    while (providerClassIt.hasNext()
    +        && providerBuilderClassIt.hasNext()
    +        && builderNamesIt.hasNext()) {
    +      TypeNode returnType =
    +          TypeNode.withReference(ConcreteReference.withClazz(providerBuilderClassIt.next()));
    +      TypeNode channelProviderType =
    +          TypeNode.withReference(ConcreteReference.withClazz(providerClassIt.next()));
    +
    +      MethodInvocationExpr transportChannelProviderBuilderExpr =
    +          MethodInvocationExpr.builder()
    +              .setStaticReferenceType(channelProviderType)
    +              .setMethodName("newBuilder")
    +              .setReturnType(returnType)
    +              .build();
    +      Expr returnExpr =
    +          initializeTransportProviderBuilder(transportChannelProviderBuilderExpr, returnType);
     
    -  protected abstract MethodDefinition createDefaultApiClientHeaderProviderBuilderMethod(
    +      MethodDefinition method =
    +          MethodDefinition.builder()
    +              .setHeaderCommentStatements(
    +                  SettingsCommentComposer.DEFAULT_TRANSPORT_PROVIDER_BUILDER_METHOD_COMMENT)
    +              .setScope(ScopeNode.PUBLIC)
    +              .setIsStatic(true)
    +              .setReturnType(returnType)
    +              .setName(builderNamesIt.next())
    +              .setReturnExpr(returnExpr)
    +              .build();
    +      methods.add(method);
    +    }
    +
    +    return methods;
    +  }
    +
    +  protected Expr initializeTransportProviderBuilder(
    +      MethodInvocationExpr transportChannelProviderBuilderExpr, TypeNode returnType) {
    +    return transportChannelProviderBuilderExpr;
    +  }
    +
    +  protected abstract List createApiClientHeaderProviderBuilderMethods(
           Service service, TypeStore typeStore);
     
    +  protected MethodDefinition createApiClientHeaderProviderBuilderMethod(
    +      Service service,
    +      TypeStore typeStore,
    +      String methodName,
    +      TypeNode gaxPropertiesType,
    +      String getTokenMethodName,
    +      String getVersionMethodName) {
    +    TypeNode returnType =
    +        TypeNode.withReference(ConcreteReference.withClazz(ApiClientHeaderProvider.Builder.class));
    +    MethodInvocationExpr returnExpr =
    +        MethodInvocationExpr.builder()
    +            .setStaticReferenceType(FIXED_TYPESTORE.get("ApiClientHeaderProvider"))
    +            .setMethodName("newBuilder")
    +            .build();
    +
    +    MethodInvocationExpr versionArgExpr =
    +        MethodInvocationExpr.builder()
    +            .setStaticReferenceType(FIXED_TYPESTORE.get("GaxProperties"))
    +            .setMethodName("getLibraryVersion")
    +            .setArguments(
    +                VariableExpr.builder()
    +                    .setVariable(
    +                        Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build())
    +                    .setStaticReferenceType(
    +                        typeStore.get(ClassNames.getServiceStubSettingsClassName(service)))
    +                    .build())
    +            .build();
    +
    +    returnExpr =
    +        MethodInvocationExpr.builder()
    +            .setExprReferenceExpr(returnExpr)
    +            .setMethodName("setGeneratedLibToken")
    +            .setArguments(ValueExpr.withValue(StringObjectValue.withValue("gapic")), versionArgExpr)
    +            .build();
    +    returnExpr =
    +        MethodInvocationExpr.builder()
    +            .setExprReferenceExpr(returnExpr)
    +            .setMethodName("setTransportToken")
    +            .setArguments(
    +                MethodInvocationExpr.builder()
    +                    .setStaticReferenceType(gaxPropertiesType)
    +                    .setMethodName(getTokenMethodName)
    +                    .build(),
    +                MethodInvocationExpr.builder()
    +                    .setStaticReferenceType(gaxPropertiesType)
    +                    .setMethodName(getVersionMethodName)
    +                    .build())
    +            .setReturnType(returnType)
    +            .build();
    +
    +    AnnotationNode annotation =
    +        AnnotationNode.builder()
    +            .setType(FIXED_TYPESTORE.get("BetaApi"))
    +            .setDescription(
    +                "The surface for customizing headers is not stable yet and may change in the"
    +                    + " future.")
    +            .build();
    +    return MethodDefinition.builder()
    +        .setAnnotations(Arrays.asList(annotation))
    +        .setScope(ScopeNode.PUBLIC)
    +        .setIsStatic(true)
    +        .setReturnType(returnType)
    +        .setName(methodName)
    +        .setReturnExpr(returnExpr)
    +        .build();
    +  }
    +
       public abstract MethodDefinition createDefaultTransportChannelProviderMethod();
     
       private List createClassAnnotations(Service service) {
    @@ -843,6 +958,7 @@ private List createClassMethods(
             createMethodSettingsGetterMethods(methodSettingsMemberVarExprs, deprecatedSettingVarNames));
         javaMethods.add(createCreateStubMethod(service, typeStore));
         javaMethods.addAll(createDefaultHelperAndGetterMethods(service, typeStore));
    +    javaMethods.addAll(createNewBuilderMethods(service, typeStore, "newBuilder", "createDefault"));
         javaMethods.addAll(createBuilderHelperMethods(service, typeStore));
         javaMethods.add(createClassConstructor(service, methodSettingsMemberVarExprs, typeStore));
         return javaMethods;
    @@ -875,11 +991,7 @@ private static List createMethodSettingsGetterMethods(
     
       private MethodDefinition createCreateStubMethod(Service service, TypeStore typeStore) {
         // Set up the if-statement.
    -    Expr tRansportNameExpr =
    -        MethodInvocationExpr.builder()
    -            .setStaticReferenceType(getTransportContext().transportChannelType())
    -            .setMethodName(getTransportContext().transportGetterName())
    -            .build();
    +    List bodyStatements = new ArrayList<>();
     
         Expr getTransportNameExpr =
             MethodInvocationExpr.builder().setMethodName("getTransportChannelProvider").build();
    @@ -889,31 +1001,48 @@ private MethodDefinition createCreateStubMethod(Service service, TypeStore typeS
                 .setMethodName("getTransportName")
                 .build();
     
    -    Expr ifConditionExpr =
    -        MethodInvocationExpr.builder()
    -            .setExprReferenceExpr(getTransportNameExpr)
    -            .setMethodName("equals")
    -            .setArguments(tRansportNameExpr)
    -            .setReturnType(TypeNode.BOOLEAN)
    -            .build();
    +    Iterator channelTypesIt = getTransportContext().transportChannelTypes().iterator();
    +    Iterator getterNameIt = getTransportContext().transportGetterNames().iterator();
    +    Iterator serivceStubClassNameIt =
    +        getTransportContext().classNames().getTransportServiceStubClassNames(service).iterator();
     
    -    Expr createExpr =
    -        MethodInvocationExpr.builder()
    -            .setStaticReferenceType(
    -                typeStore.get(
    -                    getTransportContext().classNames().getTransportServiceStubClassName(service)))
    -            .setMethodName("create")
    -            .setArguments(
    -                ValueExpr.withValue(
    -                    ThisObjectValue.withType(
    -                        typeStore.get(ClassNames.getServiceStubSettingsClassName(service)))))
    -            .build();
    +    while (channelTypesIt.hasNext() && getterNameIt.hasNext()) {
    +      TypeNode channelType = channelTypesIt.next();
    +      String getterName = getterNameIt.next();
    +      String serivceStubClassName = serivceStubClassNameIt.next();
     
    -    IfStatement ifStatement =
    -        IfStatement.builder()
    -            .setConditionExpr(ifConditionExpr)
    -            .setBody(Arrays.asList(ExprStatement.withExpr(ReturnExpr.withExpr(createExpr))))
    -            .build();
    +      Expr tRansportNameExpr =
    +          MethodInvocationExpr.builder()
    +              .setStaticReferenceType(channelType)
    +              .setMethodName(getterName)
    +              .build();
    +
    +      Expr ifConditionExpr =
    +          MethodInvocationExpr.builder()
    +              .setExprReferenceExpr(getTransportNameExpr)
    +              .setMethodName("equals")
    +              .setArguments(tRansportNameExpr)
    +              .setReturnType(TypeNode.BOOLEAN)
    +              .build();
    +
    +      Expr createExpr =
    +          MethodInvocationExpr.builder()
    +              .setStaticReferenceType(typeStore.get(serivceStubClassName))
    +              .setMethodName("create")
    +              .setArguments(
    +                  ValueExpr.withValue(
    +                      ThisObjectValue.withType(
    +                          typeStore.get(ClassNames.getServiceStubSettingsClassName(service)))))
    +              .build();
    +
    +      IfStatement ifStatement =
    +          IfStatement.builder()
    +              .setConditionExpr(ifConditionExpr)
    +              .setBody(Arrays.asList(ExprStatement.withExpr(ReturnExpr.withExpr(createExpr))))
    +              .build();
    +
    +      bodyStatements.add(ifStatement);
    +    }
     
         // Set up exception throwing.
         Expr errorMessageExpr =
    @@ -930,6 +1059,8 @@ private MethodDefinition createCreateStubMethod(Service service, TypeStore typeS
             ExprStatement.withExpr(
                 ThrowExpr.builder().setType(exceptionType).setMessageExpr(errorMessageExpr).build());
     
    +    bodyStatements.add(throwStatement);
    +
         // Put the method together.
         TypeNode returnType = typeStore.get(ClassNames.getServiceStubClassName(service));
         AnnotationNode annotation =
    @@ -945,7 +1076,7 @@ private MethodDefinition createCreateStubMethod(Service service, TypeStore typeS
             .setReturnType(returnType)
             .setName("createStub")
             .setThrowsExceptions(Arrays.asList(TypeNode.withExceptionClazz(IOException.class)))
    -        .setBody(Arrays.asList(ifStatement, throwStatement))
    +        .setBody(bodyStatements)
             .build();
       }
     
    @@ -1021,33 +1152,40 @@ private List createDefaultHelperAndGetterMethods(
                 .build());
     
         javaMethods.add(createDefaultCredentialsProviderBuilderMethod());
    -    javaMethods.add(createDefaultTransportTransportProviderBuilderMethod());
    +    javaMethods.addAll(createDefaultTransportTransportProviderBuilderMethods());
         javaMethods.add(createDefaultTransportChannelProviderMethod());
    -    javaMethods.add(createDefaultApiClientHeaderProviderBuilderMethod(service, typeStore));
    +    javaMethods.addAll(createApiClientHeaderProviderBuilderMethods(service, typeStore));
     
         return javaMethods;
       }
     
    -  private static List createBuilderHelperMethods(
    -      Service service, TypeStore typeStore) {
    -    List javaMethods = new ArrayList<>();
    +  protected List createNewBuilderMethods(
    +      Service service,
    +      TypeStore typeStore,
    +      String newBuilderMethodName,
    +      String createDefaultMethodName) {
         // Create the newBuilder() method.
         final TypeNode builderReturnType = typeStore.get(NESTED_BUILDER_CLASS_NAME);
    -    javaMethods.add(
    +    return ImmutableList.of(
             MethodDefinition.builder()
                 .setHeaderCommentStatements(SettingsCommentComposer.NEW_BUILDER_METHOD_COMMENT)
                 .setScope(ScopeNode.PUBLIC)
                 .setIsStatic(true)
                 .setReturnType(builderReturnType)
    -            .setName("newBuilder")
    +            .setName(newBuilderMethodName)
                 .setReturnExpr(
                     MethodInvocationExpr.builder()
                         .setStaticReferenceType(builderReturnType)
    -                    .setMethodName("createDefault")
    +                    .setMethodName(createDefaultMethodName)
                         .setReturnType(builderReturnType)
                         .build())
                 .build());
    +  }
     
    +  protected List createBuilderHelperMethods(
    +      Service service, TypeStore typeStore) {
    +    List javaMethods = new ArrayList<>();
    +    final TypeNode builderReturnType = typeStore.get(NESTED_BUILDER_CLASS_NAME);
         // Create the newBuilder(ClientContext) method.
         Function newBuilderFn =
             argExpr -> NewObjectExpr.builder().setType(builderReturnType).setArguments(argExpr).build();
    @@ -1136,7 +1274,7 @@ private static MethodDefinition createClassConstructor(
             .build();
       }
     
    -  private static ClassDefinition createNestedBuilderClass(
    +  private ClassDefinition createNestedBuilderClass(
           Service service, @Nullable GapicServiceConfig serviceConfig, TypeStore typeStore) {
         // TODO(miraleung): Robustify this against a null serviceConfig.
         String thisClassName = ClassNames.getServiceStubSettingsClassName(service);
    @@ -1236,7 +1374,7 @@ private static List createNestedClassStatements(
         return statements;
       }
     
    -  private static List createNestedClassMethods(
    +  private List createNestedClassMethods(
           Service service,
           GapicServiceConfig serviceConfig,
           TypeNode superType,
    @@ -1247,7 +1385,7 @@ private static List createNestedClassMethods(
         nestedClassMethods.addAll(
             createNestedClassConstructorMethods(
                 service, serviceConfig, nestedMethodSettingsMemberVarExprs, typeStore));
    -    nestedClassMethods.add(createNestedClassCreateDefaultMethod(typeStore));
    +    nestedClassMethods.addAll(createNestedClassCreateDefaultMethods(typeStore));
         nestedClassMethods.add(createNestedClassInitDefaultsMethod(service, serviceConfig, typeStore));
         nestedClassMethods.add(createNestedClassApplyToAllUnaryMethodsMethod(superType, typeStore));
         nestedClassMethods.add(createNestedClassUnaryMethodSettingsBuilderGetterMethod());
    @@ -1258,7 +1396,7 @@ private static List createNestedClassMethods(
         return nestedClassMethods;
       }
     
    -  private static MethodDefinition createNestedClassInitDefaultsMethod(
    +  private MethodDefinition createNestedClassInitDefaultsMethod(
           Service service, @Nullable GapicServiceConfig serviceConfig, TypeStore typeStore) {
         // TODO(miraleung): Robustify this against a null serviceConfig.
         TypeNode builderType = typeStore.get(NESTED_BUILDER_CLASS_NAME);
    @@ -1313,7 +1451,9 @@ private static MethodDefinition createNestedClassInitDefaultsMethod(
                       method,
                       builderVarExpr,
                       NESTED_RETRYABLE_CODE_DEFINITIONS_VAR_EXPR,
    -                  NESTED_RETRY_PARAM_DEFINITIONS_VAR_EXPR)));
    +                  NESTED_RETRY_PARAM_DEFINITIONS_VAR_EXPR,
    +                  getTransportContext().operationResponseTransformerType(),
    +                  getTransportContext().operationMetadataTransformerType())));
           bodyStatements.add(EMPTY_LINE_STATEMENT);
         }
     
    @@ -1583,7 +1723,22 @@ private static List createNestedClassConstructorMethods(
         return ctorMethods;
       }
     
    -  private static MethodDefinition createNestedClassCreateDefaultMethod(TypeStore typeStore) {
    +  protected List createNestedClassCreateDefaultMethods(TypeStore typeStore) {
    +    return Collections.singletonList(
    +        createNestedClassCreateDefaultMethod(
    +            typeStore,
    +            "createDefault",
    +            "defaultTransportChannelProvider",
    +            null,
    +            "defaultApiClientHeaderProviderBuilder"));
    +  }
    +
    +  protected MethodDefinition createNestedClassCreateDefaultMethod(
    +      TypeStore typeStore,
    +      String methodName,
    +      String defaultTransportChannelProvider,
    +      String defaultTransportChannelProviderBuilder,
    +      String defaultApiClientHeaderProviderBuilder) {
         List bodyStatements = new ArrayList<>();
     
         // Initialize the builder: Builder builder = new Builder((ClientContext) null);
    @@ -1608,15 +1763,32 @@ private static MethodDefinition createNestedClassCreateDefaultMethod(TypeStore t
         bodyStatements.add(EMPTY_LINE_STATEMENT);
     
         List bodyExprs = new ArrayList<>();
    -    bodyExprs.add(
    -        MethodInvocationExpr.builder()
    -            .setExprReferenceExpr(builderVarExpr)
    -            .setMethodName("setTransportChannelProvider")
    -            .setArguments(
    -                MethodInvocationExpr.builder()
    -                    .setMethodName("defaultTransportChannelProvider")
    -                    .build())
    -            .build());
    +
    +    if (defaultTransportChannelProvider != null) {
    +      bodyExprs.add(
    +          MethodInvocationExpr.builder()
    +              .setExprReferenceExpr(builderVarExpr)
    +              .setMethodName("setTransportChannelProvider")
    +              .setArguments(
    +                  MethodInvocationExpr.builder()
    +                      .setMethodName(defaultTransportChannelProvider)
    +                      .build())
    +              .build());
    +    } else {
    +      bodyExprs.add(
    +          MethodInvocationExpr.builder()
    +              .setExprReferenceExpr(builderVarExpr)
    +              .setMethodName("setTransportChannelProvider")
    +              .setArguments(
    +                  MethodInvocationExpr.builder()
    +                      .setExprReferenceExpr(
    +                          MethodInvocationExpr.builder()
    +                              .setMethodName(defaultTransportChannelProviderBuilder)
    +                              .build())
    +                      .setMethodName("build")
    +                      .build())
    +              .build());
    +    }
     
         bodyExprs.add(
             MethodInvocationExpr.builder()
    @@ -1640,7 +1812,7 @@ private static MethodDefinition createNestedClassCreateDefaultMethod(TypeStore t
                     MethodInvocationExpr.builder()
                         .setExprReferenceExpr(
                             MethodInvocationExpr.builder()
    -                            .setMethodName("defaultApiClientHeaderProviderBuilder")
    +                            .setMethodName(defaultApiClientHeaderProviderBuilder)
                                 .build())
                         .setMethodName("build")
                         .build())
    @@ -1683,7 +1855,7 @@ private static MethodDefinition createNestedClassCreateDefaultMethod(TypeStore t
             .setScope(ScopeNode.PRIVATE)
             .setIsStatic(true)
             .setReturnType(builderType)
    -        .setName("createDefault")
    +        .setName(methodName)
             .setBody(bodyStatements)
             .setReturnExpr(returnExpr)
             .build();
    @@ -1867,10 +2039,12 @@ private TypeStore createDynamicTypes(Service service, String pakkage) {
             pakkage,
             Arrays.asList(
                 thisClassName,
    -            getTransportContext().classNames().getTransportServiceStubClassName(service),
                 ClassNames.getServiceStubSettingsClassName(service),
                 ClassNames.getServiceStubClassName(service)));
     
    +    typeStore.putAll(
    +        pakkage, getTransportContext().classNames().getTransportServiceStubClassNames(service));
    +
         // Nested builder class.
         typeStore.put(pakkage, NESTED_BUILDER_CLASS_NAME, true, thisClassName);
     
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java
    new file mode 100644
    index 0000000000..3aa79a452f
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java
    @@ -0,0 +1,1077 @@
    +// Copyright 2020 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//      http://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +package com.google.api.generator.gapic.composer.common;
    +
    +import com.google.api.core.BetaApi;
    +import com.google.api.gax.core.BackgroundResource;
    +import com.google.api.gax.core.BackgroundResourceAggregation;
    +import com.google.api.gax.rpc.BidiStreamingCallable;
    +import com.google.api.gax.rpc.ClientContext;
    +import com.google.api.gax.rpc.ClientStreamingCallable;
    +import com.google.api.gax.rpc.LongRunningClient;
    +import com.google.api.gax.rpc.OperationCallable;
    +import com.google.api.gax.rpc.RequestParamsExtractor;
    +import com.google.api.gax.rpc.ServerStreamingCallable;
    +import com.google.api.gax.rpc.UnaryCallable;
    +import com.google.api.generator.engine.ast.AnnotationNode;
    +import com.google.api.generator.engine.ast.AssignmentExpr;
    +import com.google.api.generator.engine.ast.ClassDefinition;
    +import com.google.api.generator.engine.ast.CommentStatement;
    +import com.google.api.generator.engine.ast.ConcreteReference;
    +import com.google.api.generator.engine.ast.EmptyLineStatement;
    +import com.google.api.generator.engine.ast.Expr;
    +import com.google.api.generator.engine.ast.ExprStatement;
    +import com.google.api.generator.engine.ast.JavaDocComment;
    +import com.google.api.generator.engine.ast.MethodDefinition;
    +import com.google.api.generator.engine.ast.MethodInvocationExpr;
    +import com.google.api.generator.engine.ast.NewObjectExpr;
    +import com.google.api.generator.engine.ast.ReferenceConstructorExpr;
    +import com.google.api.generator.engine.ast.ScopeNode;
    +import com.google.api.generator.engine.ast.Statement;
    +import com.google.api.generator.engine.ast.ThisObjectValue;
    +import com.google.api.generator.engine.ast.ThrowExpr;
    +import com.google.api.generator.engine.ast.TryCatchStatement;
    +import com.google.api.generator.engine.ast.TypeNode;
    +import com.google.api.generator.engine.ast.ValueExpr;
    +import com.google.api.generator.engine.ast.VaporReference;
    +import com.google.api.generator.engine.ast.Variable;
    +import com.google.api.generator.engine.ast.VariableExpr;
    +import com.google.api.generator.gapic.composer.comment.StubCommentComposer;
    +import com.google.api.generator.gapic.composer.store.TypeStore;
    +import com.google.api.generator.gapic.composer.utils.PackageChecker;
    +import com.google.api.generator.gapic.model.GapicClass;
    +import com.google.api.generator.gapic.model.GapicClass.Kind;
    +import com.google.api.generator.gapic.model.GapicContext;
    +import com.google.api.generator.gapic.model.Message;
    +import com.google.api.generator.gapic.model.Method;
    +import com.google.api.generator.gapic.model.Service;
    +import com.google.api.generator.gapic.utils.JavaStyle;
    +import com.google.common.base.Preconditions;
    +import com.google.common.collect.ImmutableList;
    +import com.google.common.collect.ImmutableMap;
    +import com.google.longrunning.Operation;
    +import java.io.IOException;
    +import java.util.ArrayList;
    +import java.util.Arrays;
    +import java.util.Collections;
    +import java.util.LinkedHashMap;
    +import java.util.List;
    +import java.util.Map;
    +import java.util.Optional;
    +import java.util.concurrent.TimeUnit;
    +import java.util.function.BiFunction;
    +import java.util.function.Function;
    +import java.util.stream.Collectors;
    +import javax.annotation.Generated;
    +
    +public abstract class AbstractTransportServiceStubClassComposer implements ClassComposer {
    +  private static final Statement EMPTY_LINE_STATEMENT = EmptyLineStatement.create();
    +
    +  private static final String METHOD_DESCRIPTOR_NAME_PATTERN = "%sMethodDescriptor";
    +  private static final String PAGED_RESPONSE_TYPE_NAME_PATTERN = "%sPagedResponse";
    +  private static final String PAGED_CALLABLE_CLASS_MEMBER_PATTERN = "%sPagedCallable";
    +
    +  private static final String BACKGROUND_RESOURCES_MEMBER_NAME = "backgroundResources";
    +  private static final String CALLABLE_NAME = "Callable";
    +  private static final String CALLABLE_FACTORY_MEMBER_NAME = "callableFactory";
    +  private static final String CALLABLE_CLASS_MEMBER_PATTERN = "%sCallable";
    +  private static final String OPERATION_CALLABLE_CLASS_MEMBER_PATTERN = "%sOperationCallable";
    +  private static final String OPERATION_CALLABLE_NAME = "OperationCallable";
    +  // private static final String OPERATIONS_STUB_MEMBER_NAME = "operationsStub";
    +  private static final String PAGED_CALLABLE_NAME = "PagedCallable";
    +
    +  protected static final TypeStore FIXED_TYPESTORE = createStaticTypes();
    +
    +  private final TransportContext transportContext;
    +
    +  protected AbstractTransportServiceStubClassComposer(TransportContext transportContext) {
    +    this.transportContext = transportContext;
    +  }
    +
    +  public TransportContext getTransportContext() {
    +    return transportContext;
    +  }
    +
    +  private static TypeStore createStaticTypes() {
    +    List concreteClazzes =
    +        Arrays.asList(
    +            BackgroundResource.class,
    +            BackgroundResourceAggregation.class,
    +            BetaApi.class,
    +            BidiStreamingCallable.class,
    +            ClientContext.class,
    +            ClientStreamingCallable.class,
    +            Generated.class,
    +            ImmutableMap.class,
    +            InterruptedException.class,
    +            IOException.class,
    +            Operation.class,
    +            OperationCallable.class,
    +            RequestParamsExtractor.class,
    +            ServerStreamingCallable.class,
    +            TimeUnit.class,
    +            UnaryCallable.class);
    +    return new TypeStore(concreteClazzes);
    +  }
    +
    +  @Override
    +  public GapicClass generate(GapicContext context, Service service) {
    +    String pakkage = service.pakkage() + ".stub";
    +    TypeStore typeStore = createDynamicTypes(service, pakkage);
    +    String className = getTransportContext().classNames().getTransportServiceStubClassName(service);
    +    GapicClass.Kind kind = Kind.STUB;
    +
    +    Map protoMethodNameToDescriptorVarExprs =
    +        createProtoMethodNameToDescriptorClassMembers(
    +            service, getTransportContext().methodDescriptorClass());
    +
    +    Map callableClassMemberVarExprs =
    +        createCallableClassMembers(service, typeStore);
    +
    +    Map classMemberVarExprs = new LinkedHashMap<>();
    +    classMemberVarExprs.put(
    +        BACKGROUND_RESOURCES_MEMBER_NAME,
    +        VariableExpr.withVariable(
    +            Variable.builder()
    +                .setName(BACKGROUND_RESOURCES_MEMBER_NAME)
    +                .setType(FIXED_TYPESTORE.get("BackgroundResource"))
    +                .build()));
    +    if (generateOperationsStubLogic(service)) {
    +      // Transport-specific service stub may have only one element of the following, thus get(0).
    +      TypeNode opeationsStubType = getTransportOperationsStubType(service);
    +      classMemberVarExprs.put(
    +          getTransportContext().transportOperationsStubNames().get(0),
    +          VariableExpr.withVariable(
    +              Variable.builder()
    +                  .setName(getTransportContext().transportOperationsStubNames().get(0))
    +                  .setType(opeationsStubType)
    +                  .build()));
    +    }
    +
    +    boolean operationPollingMethod = checkOperationPollingMethod(service);
    +    if(operationPollingMethod) {
    +      VariableExpr longRunningVarExpr = declareLongRunningClient();
    +      if (longRunningVarExpr != null) {
    +        classMemberVarExprs.put("longRunningClient", longRunningVarExpr);
    +      }
    +    }
    +
    +    classMemberVarExprs.put(
    +        CALLABLE_FACTORY_MEMBER_NAME,
    +        VariableExpr.withVariable(
    +            Variable.builder()
    +                .setName(CALLABLE_FACTORY_MEMBER_NAME)
    +                .setType(getTransportContext().stubCallableFactoryType())
    +                .build()));
    +
    +    Map messageTypes = context.messages();
    +    List classStatements =
    +        createClassStatements(
    +            service,
    +            protoMethodNameToDescriptorVarExprs,
    +            callableClassMemberVarExprs,
    +            classMemberVarExprs,
    +            messageTypes);
    +
    +    StubCommentComposer commentComposer =
    +        new StubCommentComposer(getTransportContext().transportName());
    +
    +    ClassDefinition classDef =
    +        ClassDefinition.builder()
    +            .setPackageString(pakkage)
    +            .setHeaderCommentStatements(
    +                commentComposer.createTransportServiceStubClassHeaderComments(
    +                    service.name(), service.isDeprecated()))
    +            .setAnnotations(createClassAnnotations(service))
    +            .setScope(ScopeNode.PUBLIC)
    +            .setName(className)
    +            .setExtendsType(
    +                typeStore.get(getTransportContext().classNames().getServiceStubClassName(service)))
    +            .setStatements(classStatements)
    +            .setMethods(
    +                createClassMethods(
    +                    service,
    +                    typeStore,
    +                    classMemberVarExprs,
    +                    callableClassMemberVarExprs,
    +                    protoMethodNameToDescriptorVarExprs))
    +            .build();
    +    return GapicClass.create(kind, classDef);
    +  }
    +
    +  protected abstract Statement createMethodDescriptorVariableDecl(
    +      Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr, Map messageTypes);
    +
    +  protected boolean generateOperationsStubLogic(Service service) {
    +    return true;
    +  }
    +
    +  protected List createOperationsStubGetterMethod(
    +      Service service, VariableExpr operationsStubVarExpr) {
    +    if (!generateOperationsStubLogic(service)) {
    +      return Collections.emptyList();
    +    }
    +
    +    String methodName =
    +        String.format(
    +            "get%s",
    +            JavaStyle.toUpperCamelCase(getTransportContext().transportOperationsStubNames().get(0)));
    +
    +    return Arrays.asList(
    +        MethodDefinition.builder()
    +            .setScope(ScopeNode.PUBLIC)
    +            .setReturnType(operationsStubVarExpr.type())
    +            .setName(methodName)
    +            .setReturnExpr(operationsStubVarExpr)
    +            .build());
    +  }
    +
    +  protected abstract Expr createTransportSettingsInitExpr(
    +      Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr);
    +
    +  protected List createGetMethodDescriptorsMethod(
    +      Service service,
    +      TypeStore typeStore,
    +      Map protoMethodNameToDescriptorVarExprs) {
    +    return Arrays.asList();
    +  }
    +
    +  protected List createClassStatements(
    +      Service service,
    +      Map protoMethodNameToDescriptorVarExprs,
    +      Map callableClassMemberVarExprs,
    +      Map classMemberVarExprs,
    +      Map messageTypes) {
    +    List classStatements = new ArrayList<>();
    +    for (Statement statement :
    +        createMethodDescriptorVariableDecls(service, protoMethodNameToDescriptorVarExprs, messageTypes)) {
    +      classStatements.add(statement);
    +      classStatements.add(EMPTY_LINE_STATEMENT);
    +    }
    +
    +    classStatements.addAll(createClassMemberFieldDeclarations(callableClassMemberVarExprs));
    +    classStatements.add(EMPTY_LINE_STATEMENT);
    +
    +    classStatements.addAll(createClassMemberFieldDeclarations(classMemberVarExprs));
    +    return classStatements;
    +  }
    +
    +  protected List createMethodDescriptorVariableDecls(
    +      Service service, Map protoMethodNameToDescriptorVarExprs, Map messageTypes) {
    +    return service.methods().stream()
    +        .map(
    +            m ->
    +                createMethodDescriptorVariableDecl(
    +                    service, m, protoMethodNameToDescriptorVarExprs.get(m.name()), messageTypes))
    +        .collect(Collectors.toList());
    +  }
    +
    +  private static List createClassMemberFieldDeclarations(
    +      Map fieldNameToVarExprs) {
    +    return fieldNameToVarExprs.values().stream()
    +        .map(
    +            v ->
    +                ExprStatement.withExpr(
    +                    v.toBuilder()
    +                        .setIsDecl(true)
    +                        .setScope(ScopeNode.PRIVATE)
    +                        .setIsFinal(true)
    +                        .build()))
    +        .collect(Collectors.toList());
    +  }
    +
    +  protected Map createProtoMethodNameToDescriptorClassMembers(
    +      Service service, Class descriptorClass) {
    +    return service.methods().stream()
    +        .collect(
    +            Collectors.toMap(
    +                Method::name,
    +                m ->
    +                    VariableExpr.withVariable(
    +                        Variable.builder()
    +                            .setName(
    +                                String.format(
    +                                    METHOD_DESCRIPTOR_NAME_PATTERN,
    +                                    JavaStyle.toLowerCamelCase(m.name())))
    +                            .setType(
    +                                TypeNode.withReference(
    +                                    ConcreteReference.builder()
    +                                        .setClazz(descriptorClass)
    +                                        .setGenerics(
    +                                            Arrays.asList(
    +                                                m.inputType().reference(),
    +                                                m.outputType().reference()))
    +                                        .build()))
    +                            .build()),
    +                (u, v) -> {
    +                  throw new IllegalStateException();
    +                },
    +                LinkedHashMap::new));
    +  }
    +
    +  private Map createCallableClassMembers(
    +      Service service, TypeStore typeStore) {
    +    Map callableClassMembers = new LinkedHashMap<>();
    +    // Using a for-loop because the output cardinality is not a 1:1 mapping to the input set.
    +    for (Method protoMethod : service.methods()) {
    +      String javaStyleProtoMethodName = JavaStyle.toLowerCamelCase(protoMethod.name());
    +      String callableName = String.format(CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName);
    +      callableClassMembers.put(
    +          callableName,
    +          VariableExpr.withVariable(
    +              Variable.builder()
    +                  .setName(callableName)
    +                  .setType(getCallableType(protoMethod))
    +                  .build()));
    +      if (protoMethod.hasLro()) {
    +        callableName =
    +            String.format(OPERATION_CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName);
    +        callableClassMembers.put(
    +            callableName,
    +            VariableExpr.withVariable(
    +                Variable.builder()
    +                    .setName(callableName)
    +                    .setType(
    +                        TypeNode.withReference(
    +                            ConcreteReference.builder()
    +                                .setClazz(OperationCallable.class)
    +                                .setGenerics(
    +                                    Arrays.asList(
    +                                        protoMethod.inputType().reference(),
    +                                        protoMethod.lro().responseType().reference(),
    +                                        protoMethod.lro().metadataType().reference()))
    +                                .build()))
    +                    .build()));
    +      }
    +      if (protoMethod.isPaged()) {
    +        callableName = String.format(PAGED_CALLABLE_CLASS_MEMBER_PATTERN, javaStyleProtoMethodName);
    +        callableClassMembers.put(
    +            callableName,
    +            VariableExpr.withVariable(
    +                Variable.builder()
    +                    .setName(callableName)
    +                    .setType(
    +                        TypeNode.withReference(
    +                            getCallableType(protoMethod)
    +                                .reference()
    +                                .copyAndSetGenerics(
    +                                    Arrays.asList(
    +                                        protoMethod.inputType().reference(),
    +                                        typeStore
    +                                            .get(
    +                                                String.format(
    +                                                    PAGED_RESPONSE_TYPE_NAME_PATTERN,
    +                                                    protoMethod.name()))
    +                                            .reference()))))
    +                    .build()));
    +      }
    +    }
    +    return callableClassMembers;
    +  }
    +
    +  protected List createClassAnnotations(Service service) {
    +    List annotations = new ArrayList<>();
    +    if (!PackageChecker.isGaApi(service.pakkage())) {
    +      annotations.add(AnnotationNode.withType(FIXED_TYPESTORE.get("BetaApi")));
    +    }
    +
    +    if (service.isDeprecated()) {
    +      annotations.add(AnnotationNode.withType(TypeNode.DEPRECATED));
    +    }
    +
    +    annotations.add(
    +        AnnotationNode.builder()
    +            .setType(FIXED_TYPESTORE.get("Generated"))
    +            .setDescription("by gapic-generator-java")
    +            .build());
    +    return annotations;
    +  }
    +
    +  protected List createClassMethods(
    +      Service service,
    +      TypeStore typeStore,
    +      Map classMemberVarExprs,
    +      Map callableClassMemberVarExprs,
    +      Map protoMethodNameToDescriptorVarExprs) {
    +    List javaMethods = new ArrayList<>();
    +    javaMethods.addAll(createStaticCreatorMethods(service, typeStore, "newBuilder"));
    +    javaMethods.addAll(
    +        createConstructorMethods(
    +            service,
    +            typeStore,
    +            classMemberVarExprs,
    +            callableClassMemberVarExprs,
    +            protoMethodNameToDescriptorVarExprs));
    +    javaMethods.addAll(
    +        createGetMethodDescriptorsMethod(service, typeStore, protoMethodNameToDescriptorVarExprs));
    +    javaMethods.addAll(
    +        createOperationsStubGetterMethod(
    +            service, classMemberVarExprs.get(getTransportContext().transportOperationsStubNames().get(0))));
    +    javaMethods.addAll(createCallableGetterMethods(callableClassMemberVarExprs));
    +    javaMethods.addAll(
    +        createStubOverrideMethods(classMemberVarExprs.get(BACKGROUND_RESOURCES_MEMBER_NAME), service));
    +    return javaMethods;
    +  }
    +
    +  protected List createStaticCreatorMethods(Service service, TypeStore typeStore, String newBuilderMethod) {
    +    TypeNode creatorMethodReturnType =
    +        typeStore.get(getTransportContext().classNames().getTransportServiceStubClassName(service));
    +    Function, MethodDefinition.Builder> creatorMethodStarterFn =
    +        argList ->
    +            MethodDefinition.builder()
    +                .setScope(ScopeNode.PUBLIC)
    +                .setIsStatic(true)
    +                .setIsFinal(true)
    +                .setReturnType(creatorMethodReturnType)
    +                .setName("create")
    +                .setArguments(
    +                    argList.stream()
    +                        .map(v -> v.toBuilder().setIsDecl(true).build())
    +                        .collect(Collectors.toList()))
    +                .setThrowsExceptions(
    +                    Arrays.asList(
    +                        TypeNode.withReference(ConcreteReference.withClazz(IOException.class))));
    +
    +    Function, Expr> instantiatorExprFn =
    +        argList ->
    +            NewObjectExpr.builder().setType(creatorMethodReturnType).setArguments(argList).build();
    +
    +    TypeNode stubSettingsType =
    +        typeStore.get(getTransportContext().classNames().getServiceStubSettingsClassName(service));
    +    VariableExpr settingsVarExpr =
    +        VariableExpr.withVariable(
    +            Variable.builder().setName("settings").setType(stubSettingsType).build());
    +
    +    TypeNode clientContextType = FIXED_TYPESTORE.get("ClientContext");
    +    VariableExpr clientContextVarExpr =
    +        VariableExpr.withVariable(
    +            Variable.builder().setName("clientContext").setType(clientContextType).build());
    +
    +    VariableExpr callableFactoryVarExpr =
    +        VariableExpr.withVariable(
    +            Variable.builder()
    +                .setName("callableFactory")
    +                .setType(getTransportContext().stubCallableFactoryType())
    +                .build());
    +
    +    MethodInvocationExpr clientContextCreateMethodExpr =
    +        MethodInvocationExpr.builder()
    +            .setMethodName("create")
    +            .setStaticReferenceType(clientContextType)
    +            .setArguments(Arrays.asList(settingsVarExpr))
    +            .build();
    +    MethodInvocationExpr settingsBuilderMethodExpr =
    +        MethodInvocationExpr.builder()
    +            .setMethodName(newBuilderMethod)
    +            .setStaticReferenceType(stubSettingsType)
    +            .build();
    +    settingsBuilderMethodExpr =
    +        MethodInvocationExpr.builder()
    +            .setMethodName("build")
    +            .setExprReferenceExpr(settingsBuilderMethodExpr)
    +            .build();
    +
    +    return Arrays.asList(
    +        creatorMethodStarterFn
    +            .apply(Arrays.asList(settingsVarExpr))
    +            .setReturnExpr(
    +                instantiatorExprFn.apply(
    +                    Arrays.asList(settingsVarExpr, clientContextCreateMethodExpr)))
    +            .build(),
    +        creatorMethodStarterFn
    +            .apply(Arrays.asList(clientContextVarExpr))
    +            .setReturnExpr(
    +                instantiatorExprFn.apply(
    +                    Arrays.asList(settingsBuilderMethodExpr, clientContextVarExpr)))
    +            .build(),
    +        creatorMethodStarterFn
    +            .apply(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr))
    +            .setReturnExpr(
    +                instantiatorExprFn.apply(
    +                    Arrays.asList(
    +                        settingsBuilderMethodExpr, clientContextVarExpr, callableFactoryVarExpr)))
    +            .build());
    +  }
    +
    +  protected List createConstructorMethods(
    +      Service service,
    +      TypeStore typeStore,
    +      Map classMemberVarExprs,
    +      Map callableClassMemberVarExprs,
    +      Map protoMethodNameToDescriptorVarExprs) {
    +    TypeNode stubSettingsType =
    +        typeStore.get(getTransportContext().classNames().getServiceStubSettingsClassName(service));
    +    VariableExpr settingsVarExpr =
    +        VariableExpr.withVariable(
    +            Variable.builder().setName("settings").setType(stubSettingsType).build());
    +
    +    TypeNode clientContextType = FIXED_TYPESTORE.get("ClientContext");
    +    VariableExpr clientContextVarExpr =
    +        VariableExpr.withVariable(
    +            Variable.builder().setName("clientContext").setType(clientContextType).build());
    +
    +    VariableExpr callableFactoryVarExpr =
    +        VariableExpr.withVariable(
    +            Variable.builder()
    +                .setName("callableFactory")
    +                .setType(getTransportContext().stubCallableFactoryType())
    +                .build());
    +
    +    TypeNode thisClassType =
    +        typeStore.get(getTransportContext().classNames().getTransportServiceStubClassName(service));
    +    TypeNode ioExceptionType =
    +        TypeNode.withReference(ConcreteReference.withClazz(IOException.class));
    +
    +    BiFunction, List, MethodDefinition> ctorMakerFn =
    +        (args, body) ->
    +            MethodDefinition.constructorBuilder()
    +                .setScope(ScopeNode.PROTECTED)
    +                .setReturnType(thisClassType)
    +                .setHeaderCommentStatements(Arrays.asList(createProtectedCtorComment(service)))
    +                .setArguments(
    +                    args.stream()
    +                        .map(v -> v.toBuilder().setIsDecl(true).build())
    +                        .collect(Collectors.toList()))
    +                .setThrowsExceptions(Arrays.asList(ioExceptionType))
    +                .setBody(body)
    +                .build();
    +
    +    // First constructor method.
    +    MethodDefinition firstCtor =
    +        ctorMakerFn.apply(
    +            Arrays.asList(settingsVarExpr, clientContextVarExpr),
    +            Arrays.asList(
    +                ExprStatement.withExpr(
    +                    ReferenceConstructorExpr.thisBuilder()
    +                        .setType(thisClassType)
    +                        .setArguments(
    +                            settingsVarExpr,
    +                            clientContextVarExpr,
    +                            NewObjectExpr.builder()
    +                                .setType(
    +                                    typeStore.get(
    +                                        getTransportContext()
    +                                            .classNames()
    +                                            .getTransportServiceCallableFactoryClassName(service)))
    +                                .build())
    +                        .build())));
    +
    +    Expr thisExpr =
    +        ValueExpr.withValue(
    +            ThisObjectValue.withType(
    +                typeStore.get(
    +                    getTransportContext().classNames().getTransportServiceStubClassName(service))));
    +    // Body of the second constructor method.
    +    List secondCtorStatements = new ArrayList<>();
    +    List secondCtorExprs = new ArrayList<>();
    +    secondCtorExprs.add(
    +        AssignmentExpr.builder()
    +            .setVariableExpr(
    +                classMemberVarExprs.get("callableFactory").toBuilder()
    +                    .setExprReferenceExpr(thisExpr)
    +                    .build())
    +            .setValueExpr(callableFactoryVarExpr)
    +            .build());
    +    VariableExpr operationsStubClassVarExpr = classMemberVarExprs.get(getTransportContext().transportOperationsStubNames().get(0));
    +    //TODO: refactor this
    +    if (generateOperationsStubLogic(service)) {
    +      TypeNode opeationsStubType = getTransportOperationsStubType(service);
    +      secondCtorExprs.add(
    +          AssignmentExpr.builder()
    +              .setVariableExpr(
    +                  operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    +              .setValueExpr(
    +                  MethodInvocationExpr.builder()
    +                      .setStaticReferenceType(opeationsStubType)
    +                      .setMethodName("create")
    +                      .setArguments(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr))
    +                      .setReturnType(operationsStubClassVarExpr.type())
    +                      .build())
    +              .build());
    +    }
    +    secondCtorStatements.addAll(
    +        secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()));
    +    secondCtorExprs.clear();
    +    secondCtorStatements.add(EMPTY_LINE_STATEMENT);
    +
    +    // Transport settings local variables.
    +    Map javaStyleMethodNameToTransportSettingsVarExprs =
    +        service.methods().stream()
    +            .collect(
    +                Collectors.toMap(
    +                    m -> JavaStyle.toLowerCamelCase(m.name()),
    +                    m ->
    +                        VariableExpr.withVariable(
    +                            Variable.builder()
    +                                .setName(
    +                                    String.format(
    +                                        "%sTransportSettings",
    +                                        JavaStyle.toLowerCamelCase(m.name())))
    +                                .setType(
    +                                    TypeNode.withReference(
    +                                        ConcreteReference.builder()
    +                                            .setClazz(getTransportContext().callSettingsClass())
    +                                            .setGenerics(
    +                                                Arrays.asList(
    +                                                    m.inputType().reference(),
    +                                                    m.outputType().reference()))
    +                                            .build()))
    +                                .build())));
    +
    +    secondCtorExprs.addAll(
    +        service.methods().stream()
    +            .map(
    +                m ->
    +                    createTransportSettingsInitExpr(
    +                        m,
    +                        javaStyleMethodNameToTransportSettingsVarExprs.get(
    +                            JavaStyle.toLowerCamelCase(m.name())),
    +                        protoMethodNameToDescriptorVarExprs.get(m.name())))
    +            .collect(Collectors.toList()));
    +    secondCtorStatements.addAll(
    +        secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()));
    +    secondCtorExprs.clear();
    +    secondCtorStatements.add(EMPTY_LINE_STATEMENT);
    +
    +    // Initialize Callable variables.
    +    secondCtorExprs.addAll(
    +        callableClassMemberVarExprs.entrySet().stream()
    +            .map(
    +                e ->
    +                    createCallableInitExpr(
    +                        e.getKey(),
    +                        e.getValue(),
    +                        callableFactoryVarExpr,
    +                        settingsVarExpr,
    +                        clientContextVarExpr,
    +                        operationsStubClassVarExpr,
    +                        thisExpr,
    +                        javaStyleMethodNameToTransportSettingsVarExprs))
    +            .collect(Collectors.toList()));
    +    secondCtorStatements.addAll(
    +        secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()));
    +    secondCtorExprs.clear();
    +    secondCtorStatements.add(EMPTY_LINE_STATEMENT);
    +
    +
    +    secondCtorStatements.addAll(createLongRunningClient(service, typeStore));
    +
    +    // Instantiate backgroundResources.
    +    MethodInvocationExpr getBackgroundResourcesMethodExpr =
    +        MethodInvocationExpr.builder()
    +            .setExprReferenceExpr(clientContextVarExpr)
    +            .setMethodName("getBackgroundResources")
    +            .build();
    +
    +    VariableExpr backgroundResourcesVarExpr = classMemberVarExprs.get("backgroundResources");
    +    secondCtorExprs.add(
    +        AssignmentExpr.builder()
    +            .setVariableExpr(
    +                backgroundResourcesVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    +            .setValueExpr(
    +                NewObjectExpr.builder()
    +                    .setType(FIXED_TYPESTORE.get("BackgroundResourceAggregation"))
    +                    .setArguments(Arrays.asList(getBackgroundResourcesMethodExpr))
    +                    .build())
    +            .build());
    +    secondCtorStatements.addAll(
    +        secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()));
    +    secondCtorExprs.clear();
    +
    +    // Second constructor method.
    +    MethodDefinition secondCtor =
    +        ctorMakerFn.apply(
    +            Arrays.asList(settingsVarExpr, clientContextVarExpr, callableFactoryVarExpr),
    +            secondCtorStatements);
    +
    +    return Arrays.asList(firstCtor, secondCtor);
    +  }
    +
    +  protected List createLongRunningClient(Service service, TypeStore typeStore) {
    +    return ImmutableList.of();
    +  }
    +
    +  protected VariableExpr declareLongRunningClient() {
    +    return null;
    +  }
    +
    +  private Expr createCallableInitExpr(
    +      String callableVarName,
    +      VariableExpr callableVarExpr,
    +      VariableExpr callableFactoryVarExpr,
    +      VariableExpr settingsVarExpr,
    +      VariableExpr clientContextVarExpr,
    +      VariableExpr operationsStubClassVarExpr,
    +      Expr thisExpr,
    +      Map javaStyleMethodNameToTransportSettingsVarExprs) {
    +    boolean isOperation = callableVarName.endsWith(OPERATION_CALLABLE_NAME);
    +    boolean isPaged = callableVarName.endsWith(PAGED_CALLABLE_NAME);
    +    int sublength = 0;
    +    if (isOperation) {
    +      sublength = OPERATION_CALLABLE_NAME.length();
    +    } else if (isPaged) {
    +      sublength = PAGED_CALLABLE_NAME.length();
    +    } else {
    +      sublength = CALLABLE_NAME.length();
    +    }
    +    String javaStyleMethodName = callableVarName.substring(0, callableVarName.length() - sublength);
    +    List creatorMethodArgVarExprs = null;
    +    Expr transportSettingsVarExpr =
    +        javaStyleMethodNameToTransportSettingsVarExprs.get(javaStyleMethodName);
    +    if (transportSettingsVarExpr == null && isOperation) {
    +      // Try again, in case the name dtection above was inaccurate.
    +      isOperation = false;
    +      sublength = CALLABLE_NAME.length();
    +      javaStyleMethodName = callableVarName.substring(0, callableVarName.length() - sublength);
    +      transportSettingsVarExpr =
    +          javaStyleMethodNameToTransportSettingsVarExprs.get(javaStyleMethodName);
    +    }
    +    Preconditions.checkNotNull(
    +        transportSettingsVarExpr,
    +        String.format(
    +            "No transport settings variable found for method name %s", javaStyleMethodName));
    +    if (isOperation) {
    +      creatorMethodArgVarExprs =
    +          Arrays.asList(
    +              transportSettingsVarExpr,
    +              MethodInvocationExpr.builder()
    +                  .setExprReferenceExpr(settingsVarExpr)
    +                  .setMethodName(String.format("%sOperationSettings", javaStyleMethodName))
    +                  .build(),
    +              clientContextVarExpr,
    +              operationsStubClassVarExpr);
    +    } else {
    +      creatorMethodArgVarExprs =
    +          Arrays.asList(
    +              transportSettingsVarExpr,
    +              MethodInvocationExpr.builder()
    +                  .setExprReferenceExpr(settingsVarExpr)
    +                  .setMethodName(String.format("%sSettings", javaStyleMethodName))
    +                  .build(),
    +              clientContextVarExpr);
    +    }
    +
    +    Optional callableCreatorMethodName =
    +        getCallableCreatorMethodName(callableVarExpr.type());
    +
    +    Expr initExpr;
    +    if (callableCreatorMethodName.isPresent()) {
    +      initExpr =
    +          MethodInvocationExpr.builder()
    +              .setExprReferenceExpr(callableFactoryVarExpr)
    +              .setMethodName(callableCreatorMethodName.get())
    +              .setArguments(creatorMethodArgVarExprs)
    +              .setReturnType(callableVarExpr.type())
    +              .build();
    +    } else {
    +      initExpr = ValueExpr.createNullExpr();
    +    }
    +
    +    return AssignmentExpr.builder()
    +        .setVariableExpr(callableVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build())
    +        .setValueExpr(initExpr)
    +        .build();
    +  }
    +
    +  protected Optional getCallableCreatorMethodName(TypeNode callableVarExprType) {
    +    final String typeName = callableVarExprType.reference().name();
    +    String streamName = "Unary";
    +
    +    // Special handling for pagination methods.
    +    if (callableVarExprType.reference().generics().size() == 2
    +        && callableVarExprType.reference().generics().get(1).name().endsWith("PagedResponse")) {
    +      streamName = "Paged";
    +    } else {
    +      if (typeName.startsWith("Client")) {
    +        streamName = "ClientStreaming";
    +      } else if (typeName.startsWith("Server")) {
    +        streamName = "ServerStreaming";
    +      } else if (typeName.startsWith("Bidi")) {
    +        streamName = "BidiStreaming";
    +      } else if (typeName.startsWith("Operation")) {
    +        streamName = "Operation";
    +      }
    +    }
    +    return Optional.of(String.format("create%sCallable", streamName));
    +  }
    +
    +  private static List createCallableGetterMethods(
    +      Map callableClassMemberVarExprs) {
    +    return callableClassMemberVarExprs.entrySet().stream()
    +        .map(
    +            e ->
    +                MethodDefinition.builder()
    +                    .setIsOverride(true)
    +                    .setScope(ScopeNode.PUBLIC)
    +                    .setReturnType(e.getValue().type())
    +                    .setName(e.getKey())
    +                    .setReturnExpr(e.getValue())
    +                    .build())
    +        .collect(Collectors.toList());
    +  }
    +
    +  private List createStubOverrideMethods(
    +      VariableExpr backgroundResourcesVarExpr, Service service) {
    +    Function methodMakerStarterFn =
    +        methodName ->
    +            MethodDefinition.builder()
    +                .setIsOverride(true)
    +                .setScope(ScopeNode.PUBLIC)
    +                .setName(methodName);
    +
    +    Function voidMethodMakerFn =
    +        methodName ->
    +            methodMakerStarterFn
    +                .apply(methodName)
    +                .setReturnType(TypeNode.VOID)
    +                .setBody(
    +                    Arrays.asList(
    +                        ExprStatement.withExpr(
    +                            MethodInvocationExpr.builder()
    +                                .setExprReferenceExpr(backgroundResourcesVarExpr)
    +                                .setMethodName(methodName)
    +                                .build())))
    +                .build();
    +
    +    Function booleanMethodMakerFn =
    +        methodName ->
    +            methodMakerStarterFn
    +                .apply(methodName)
    +                .setReturnType(TypeNode.BOOLEAN)
    +                .setReturnExpr(
    +                    MethodInvocationExpr.builder()
    +                        .setExprReferenceExpr(backgroundResourcesVarExpr)
    +                        .setMethodName(methodName)
    +                        .setReturnType(TypeNode.BOOLEAN)
    +                        .build())
    +                .build();
    +
    +    // Generate the close() method:
    +    //   @Override
    +    //   public final void close() {
    +    //     try {
    +    //       backgroundResources.close();
    +    //     } catch (RuntimeException e) {
    +    //       throw e;
    +    //     } catch (Exception e) {
    +    //       throw new IllegalStateException("Failed to close resource", e);
    +    //     }
    +    //  }
    +
    +    VariableExpr catchRuntimeExceptionVarExpr =
    +        VariableExpr.builder()
    +            .setVariable(
    +                Variable.builder()
    +                    .setType(TypeNode.withExceptionClazz(RuntimeException.class))
    +                    .setName("e")
    +                    .build())
    +            .build();
    +    VariableExpr catchExceptionVarExpr =
    +        VariableExpr.builder()
    +            .setVariable(
    +                Variable.builder()
    +                    .setType(TypeNode.withExceptionClazz(Exception.class))
    +                    .setName("e")
    +                    .build())
    +            .build();
    +    List javaMethods = new ArrayList<>();
    +    if (service.operationPollingMethod() != null) {
    +      javaMethods.addAll(createLongRunningClientGetters());
    +    }
    +    javaMethods.add(
    +        methodMakerStarterFn
    +            .apply("close")
    +            .setIsFinal(true)
    +            .setReturnType(TypeNode.VOID)
    +            .setBody(
    +                Arrays.asList(
    +                    TryCatchStatement.builder()
    +                        .setTryBody(
    +                            Arrays.asList(
    +                                ExprStatement.withExpr(
    +                                    MethodInvocationExpr.builder()
    +                                        .setExprReferenceExpr(backgroundResourcesVarExpr)
    +                                        .setMethodName("close")
    +                                        .build())))
    +                        .addCatch(
    +                            catchRuntimeExceptionVarExpr.toBuilder().setIsDecl(true).build(),
    +                            Arrays.asList(
    +                                ExprStatement.withExpr(
    +                                    ThrowExpr.builder()
    +                                        .setThrowExpr(catchRuntimeExceptionVarExpr)
    +                                        .build())))
    +                        .addCatch(
    +                            catchExceptionVarExpr.toBuilder().setIsDecl(true).build(),
    +                            Arrays.asList(
    +                                ExprStatement.withExpr(
    +                                    ThrowExpr.builder()
    +                                        .setType(
    +                                            TypeNode.withExceptionClazz(
    +                                                IllegalStateException.class))
    +                                        .setMessageExpr(String.format("Failed to close resource"))
    +                                        .setCauseExpr(catchExceptionVarExpr)
    +                                        .build())))
    +                        .build()))
    +            .build());
    +    javaMethods.add(voidMethodMakerFn.apply("shutdown"));
    +    javaMethods.add(booleanMethodMakerFn.apply("isShutdown"));
    +    javaMethods.add(booleanMethodMakerFn.apply("isTerminated"));
    +    javaMethods.add(voidMethodMakerFn.apply("shutdownNow"));
    +
    +    List awaitTerminationArgs =
    +        Arrays.asList(
    +            VariableExpr.withVariable(
    +                Variable.builder().setName("duration").setType(TypeNode.LONG).build()),
    +            VariableExpr.withVariable(
    +                Variable.builder()
    +                    .setName("unit")
    +                    .setType(FIXED_TYPESTORE.get("TimeUnit"))
    +                    .build()));
    +    javaMethods.add(
    +        methodMakerStarterFn
    +            .apply("awaitTermination")
    +            .setReturnType(TypeNode.BOOLEAN)
    +            .setArguments(
    +                awaitTerminationArgs.stream()
    +                    .map(v -> v.toBuilder().setIsDecl(true).build())
    +                    .collect(Collectors.toList()))
    +            .setThrowsExceptions(Arrays.asList(FIXED_TYPESTORE.get("InterruptedException")))
    +            .setReturnExpr(
    +                MethodInvocationExpr.builder()
    +                    .setExprReferenceExpr(backgroundResourcesVarExpr)
    +                    .setMethodName("awaitTermination")
    +                    .setArguments(
    +                        awaitTerminationArgs.stream()
    +                            .map(v -> (Expr) v)
    +                            .collect(Collectors.toList()))
    +                    .setReturnType(TypeNode.BOOLEAN)
    +                    .build())
    +            .build());
    +    return javaMethods;
    +  }
    +
    +  private boolean checkOperationPollingMethod(Service service) {
    +    for(Method method : service.methods()) {
    +      if(method.isOperationPollingMethod()) {
    +        return true;
    +      }
    +    }
    +    return false;
    +  }
    +
    +  protected List createLongRunningClientGetters() {
    +    VariableExpr longRunningClient =
    +        VariableExpr.withVariable(
    +            Variable.builder()
    +                .setName("longRunningClient")
    +                .setType(
    +                    TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class)))
    +                .build());
    +
    +    return ImmutableList.of(
    +        MethodDefinition.builder()
    +            .setName("longRunningClient")
    +            .setScope(ScopeNode.PUBLIC)
    +            .setIsOverride(true)
    +            .setReturnType(
    +                TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class)))
    +            .setReturnExpr(longRunningClient)
    +            .build());
    +  }
    +
    +  private TypeStore createDynamicTypes(Service service, String stubPakkage) {
    +    TypeStore typeStore = new TypeStore();
    +    typeStore.putAll(
    +        stubPakkage,
    +        Arrays.asList(
    +            getTransportContext().classNames().getTransportServiceStubClassName(service),
    +            getTransportContext().classNames().getServiceStubSettingsClassName(service),
    +            getTransportContext().classNames().getServiceStubClassName(service),
    +            getTransportContext()
    +                .classNames()
    +                .getTransportServiceCallableFactoryClassName(service)));
    +    // Pagination types.
    +    typeStore.putAll(
    +        service.pakkage(),
    +        service.methods().stream()
    +            .filter(m -> m.isPaged())
    +            .map(m -> String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, m.name()))
    +            .collect(Collectors.toList()),
    +        true,
    +        getTransportContext().classNames().getServiceClientClassName(service));
    +    return typeStore;
    +  }
    +
    +  private static TypeNode getCallableType(Method protoMethod) {
    +    TypeNode callableType = FIXED_TYPESTORE.get("UnaryCallable");
    +    switch (protoMethod.stream()) {
    +      case CLIENT:
    +        callableType = FIXED_TYPESTORE.get("ClientStreamingCallable");
    +        break;
    +      case SERVER:
    +        callableType = FIXED_TYPESTORE.get("ServerStreamingCallable");
    +        break;
    +      case BIDI:
    +        callableType = FIXED_TYPESTORE.get("BidiStreamingCallable");
    +        break;
    +      case NONE:
    +        // Fall through
    +      default:
    +        // Fall through
    +    }
    +
    +    return TypeNode.withReference(
    +        callableType
    +            .reference()
    +            .copyAndSetGenerics(
    +                Arrays.asList(
    +                    protoMethod.inputType().reference(), protoMethod.outputType().reference())));
    +  }
    +
    +  private CommentStatement createProtectedCtorComment(Service service) {
    +    return CommentStatement.withComment(
    +        JavaDocComment.withComment(
    +            String.format(
    +                "Constructs an instance of %s, using the given settings. This is protected so that"
    +                    + " it is easy to make a subclass, but otherwise, the static factory methods"
    +                    + " should be  preferred.",
    +                getTransportContext().classNames().getTransportServiceStubClassName(service))));
    +  }
    +
    +  protected String getProtoRpcFullMethodName(Service protoService, Method protoMethod) {
    +    if (protoMethod.isMixin()) {
    +      return String.format("%s/%s", protoMethod.mixedInApiName(), protoMethod.name());
    +    }
    +
    +    return String.format(
    +        "%s.%s/%s", protoService.protoPakkage(), protoService.name(), protoMethod.name());
    +  }
    +
    +  protected TypeNode getTransportOperationsStubType(Service service) {
    +    TypeNode transportOpeationsStubType = service.operationServiceStubType();
    +    if (transportOpeationsStubType == null) {
    +      transportOpeationsStubType = getTransportContext().transportOperationsStubTypes().get(0);
    +    }
    +    else {
    +      transportOpeationsStubType = TypeNode.withReference(
    +          VaporReference.builder()
    +              .setName("HttpJson" + transportOpeationsStubType.reference().simpleName())
    +              .setPakkage(transportOpeationsStubType.reference().pakkage())
    +              .build());
    +    }
    +
    +    return transportOpeationsStubType;
    +  }
    +}
    \ No newline at end of file
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposer.java
    index 4a20961399..4497495d67 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposer.java
    @@ -248,7 +248,9 @@ public static Expr createLroSettingsBuilderExpr(
           Method method,
           VariableExpr builderVarExpr,
           VariableExpr retryableCodeDefsVarExpr,
    -      VariableExpr retryParamDefsVarExpr) {
    +      VariableExpr retryParamDefsVarExpr,
    +      TypeNode operationResponseTransformer,
    +      TypeNode operationMetadataTransformer) {
         Preconditions.checkState(
             method.hasLro(),
             String.format(
    @@ -325,10 +327,7 @@ public static Expr createLroSettingsBuilderExpr(
                 .setMethodName("setResponseTransformer")
                 .setArguments(
                     MethodInvocationExpr.builder()
    -                    .setStaticReferenceType(
    -                        TypeNode.withReference(
    -                            ConcreteReference.withClazz(
    -                                ProtoOperationTransformers.ResponseTransformer.class)))
    +                    .setStaticReferenceType(operationResponseTransformer)
                         .setMethodName("create")
                         .setArguments(classFieldRefFn.apply(method.lro().responseType()))
                         .build())
    @@ -339,10 +338,7 @@ public static Expr createLroSettingsBuilderExpr(
                 .setMethodName("setMetadataTransformer")
                 .setArguments(
                     MethodInvocationExpr.builder()
    -                    .setStaticReferenceType(
    -                        TypeNode.withReference(
    -                            ConcreteReference.withClazz(
    -                                ProtoOperationTransformers.MetadataTransformer.class)))
    +                    .setStaticReferenceType(operationMetadataTransformer)
                         .setMethodName("create")
                         .setArguments(classFieldRefFn.apply(method.lro().metadataType()))
                         .build())
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposer.java
    deleted file mode 100644
    index 1c8bed3ccb..0000000000
    --- a/src/main/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposer.java
    +++ /dev/null
    @@ -1,283 +0,0 @@
    -// Copyright 2020 Google LLC
    -//
    -// Licensed under the Apache License, Version 2.0 (the "License");
    -// you may not use this file except in compliance with the License.
    -// You may obtain a copy of the License at
    -//
    -//      http://www.apache.org/licenses/LICENSE-2.0
    -//
    -// Unless required by applicable law or agreed to in writing, software
    -// distributed under the License is distributed on an "AS IS" BASIS,
    -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -// See the License for the specific language governing permissions and
    -// limitations under the License.
    -
    -package com.google.api.generator.gapic.composer.common;
    -
    -import com.google.api.core.BetaApi;
    -import com.google.api.gax.core.BackgroundResource;
    -import com.google.api.gax.rpc.BidiStreamingCallable;
    -import com.google.api.gax.rpc.ClientStreamingCallable;
    -import com.google.api.gax.rpc.OperationCallable;
    -import com.google.api.gax.rpc.ServerStreamingCallable;
    -import com.google.api.gax.rpc.UnaryCallable;
    -import com.google.api.generator.engine.ast.AnnotationNode;
    -import com.google.api.generator.engine.ast.ClassDefinition;
    -import com.google.api.generator.engine.ast.ExprStatement;
    -import com.google.api.generator.engine.ast.MethodDefinition;
    -import com.google.api.generator.engine.ast.Reference;
    -import com.google.api.generator.engine.ast.ScopeNode;
    -import com.google.api.generator.engine.ast.Statement;
    -import com.google.api.generator.engine.ast.ThrowExpr;
    -import com.google.api.generator.engine.ast.TypeNode;
    -import com.google.api.generator.gapic.composer.comment.StubCommentComposer;
    -import com.google.api.generator.gapic.composer.store.TypeStore;
    -import com.google.api.generator.gapic.composer.utils.ClassNames;
    -import com.google.api.generator.gapic.composer.utils.PackageChecker;
    -import com.google.api.generator.gapic.model.GapicClass;
    -import com.google.api.generator.gapic.model.GapicClass.Kind;
    -import com.google.api.generator.gapic.model.GapicContext;
    -import com.google.api.generator.gapic.model.Message;
    -import com.google.api.generator.gapic.model.Method;
    -import com.google.api.generator.gapic.model.Service;
    -import com.google.api.generator.gapic.utils.JavaStyle;
    -import com.google.longrunning.Operation;
    -import java.util.ArrayList;
    -import java.util.Arrays;
    -import java.util.Collections;
    -import java.util.List;
    -import java.util.Map;
    -import java.util.stream.Collectors;
    -import javax.annotation.Generated;
    -
    -public class ServiceStubClassComposer implements ClassComposer {
    -  private static final ServiceStubClassComposer INSTANCE = new ServiceStubClassComposer();
    -  private static final String DOT = ".";
    -  private static final String PAGED_RESPONSE_TYPE_NAME_PATTERN = "%sPagedResponse";
    -
    -  private ServiceStubClassComposer() {}
    -
    -  public static ServiceStubClassComposer instance() {
    -    return INSTANCE;
    -  }
    -
    -  @Override
    -  public GapicClass generate(GapicContext context, Service service) {
    -    Map messageTypes = context.messages();
    -    TypeStore typeStore = createTypes(service, messageTypes);
    -    String className = ClassNames.getServiceStubClassName(service);
    -    GapicClass.Kind kind = Kind.STUB;
    -    String pakkage = String.format("%s.stub", service.pakkage());
    -
    -    ClassDefinition classDef =
    -        ClassDefinition.builder()
    -            .setPackageString(pakkage)
    -            .setHeaderCommentStatements(
    -                StubCommentComposer.createServiceStubClassHeaderComments(
    -                    service.name(), service.isDeprecated()))
    -            .setAnnotations(createClassAnnotations(service, typeStore))
    -            .setIsAbstract(true)
    -            .setImplementsTypes(createClassImplements(typeStore))
    -            .setName(className)
    -            .setMethods(createClassMethods(service, messageTypes, typeStore))
    -            .setScope(ScopeNode.PUBLIC)
    -            .build();
    -    return GapicClass.create(kind, classDef);
    -  }
    -
    -  private static List createClassAnnotations(Service service, TypeStore typeStore) {
    -    List annotations = new ArrayList<>();
    -    if (!PackageChecker.isGaApi(service.pakkage())) {
    -      annotations.add(AnnotationNode.withType(typeStore.get("BetaApi")));
    -    }
    -
    -    if (service.isDeprecated()) {
    -      annotations.add(AnnotationNode.withType(TypeNode.DEPRECATED));
    -    }
    -
    -    annotations.add(
    -        AnnotationNode.builder()
    -            .setType(typeStore.get("Generated"))
    -            .setDescription("by gapic-generator-java")
    -            .build());
    -    return annotations;
    -  }
    -
    -  private static List createClassImplements(TypeStore typeStore) {
    -    return Arrays.asList(typeStore.get("BackgroundResource"));
    -  }
    -
    -  private static List createClassMethods(
    -      Service service, Map messageTypes, TypeStore typeStore) {
    -    boolean hasLroClient = hasLroMethods(service);
    -    List methods = new ArrayList<>();
    -    if (hasLroClient) {
    -      TypeNode operationsStubType = service.operationServiceStubType();
    -      if (operationsStubType == null) {
    -        operationsStubType = typeStore.get("OperationsStub");
    -      }
    -      methods.add(createOperationsStubGetter(typeStore, operationsStubType));
    -    }
    -    methods.addAll(createCallableGetters(service, messageTypes, typeStore));
    -    methods.addAll(createBackgroundResourceMethodOverrides());
    -    return methods;
    -  }
    -
    -  private static List createCallableGetters(
    -      Service service, Map messageTypes, TypeStore typeStore) {
    -    // Use a traditional for-loop since the output cardinality is not necessarily 1:1 with that of
    -    // service.methods().
    -    List javaMethods = new ArrayList<>();
    -    for (Method method : service.methods()) {
    -      if (method.hasLro()) {
    -        javaMethods.add(createOperationCallableGetter(method, typeStore));
    -      }
    -      if (method.isPaged()) {
    -        javaMethods.add(createPagedCallableGetter(method, typeStore));
    -      }
    -      javaMethods.add(createCallableGetter(method, typeStore));
    -    }
    -    return javaMethods;
    -  }
    -
    -  private static MethodDefinition createOperationCallableGetter(
    -      Method method, TypeStore typeStore) {
    -    return createCallableGetterHelper(method, typeStore, true, false);
    -  }
    -
    -  private static MethodDefinition createPagedCallableGetter(Method method, TypeStore typeStore) {
    -    return createCallableGetterHelper(method, typeStore, false, true);
    -  }
    -
    -  private static MethodDefinition createCallableGetter(Method method, TypeStore typeStore) {
    -    return createCallableGetterHelper(method, typeStore, false, false);
    -  }
    -
    -  private static MethodDefinition createCallableGetterHelper(
    -      Method method, TypeStore typeStore, boolean isLroCallable, boolean isPaged) {
    -    TypeNode returnType;
    -    switch (method.stream()) {
    -      case CLIENT:
    -        returnType = typeStore.get("ClientStreamingCallable");
    -        break;
    -      case SERVER:
    -        returnType = typeStore.get("ServerStreamingCallable");
    -        break;
    -      case BIDI:
    -        returnType = typeStore.get("BidiStreamingCallable");
    -        break;
    -      case NONE:
    -        // Fall through.
    -      default:
    -        returnType = typeStore.get(isLroCallable ? "OperationCallable" : "UnaryCallable");
    -    }
    -
    -    String methodName =
    -        String.format(
    -            "%s%sCallable",
    -            JavaStyle.toLowerCamelCase(method.name()),
    -            (isLroCallable ? "Operation" : isPaged ? "Paged" : ""));
    -    List genericRefs = new ArrayList<>();
    -    genericRefs.add(method.inputType().reference());
    -    if (method.hasLro() && isLroCallable) {
    -      genericRefs.add(method.lro().responseType().reference());
    -      genericRefs.add(method.lro().metadataType().reference());
    -    } else if (isPaged) {
    -      genericRefs.add(
    -          typeStore
    -              .get(String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, method.name()))
    -              .reference());
    -    } else {
    -      genericRefs.add(method.outputType().reference());
    -    }
    -
    -    List annotations =
    -        method.isDeprecated()
    -            ? Arrays.asList(AnnotationNode.withType(TypeNode.DEPRECATED))
    -            : Collections.emptyList();
    -
    -    returnType = TypeNode.withReference(returnType.reference().copyAndSetGenerics(genericRefs));
    -
    -    return MethodDefinition.builder()
    -        .setAnnotations(annotations)
    -        .setScope(ScopeNode.PUBLIC)
    -        .setReturnType(returnType)
    -        .setName(methodName)
    -        .setBody(createThrowUOEBody(methodName, typeStore))
    -        .build();
    -  }
    -
    -  private static MethodDefinition createOperationsStubGetter(TypeStore typeStore, TypeNode operationsStubType) {
    -    String methodName = "getOperationsStub";
    -    return MethodDefinition.builder()
    -        .setScope(ScopeNode.PUBLIC)
    -        .setReturnType(operationsStubType)
    -        .setName(methodName)
    -        .setBody(createThrowUOEBody(methodName, typeStore))
    -        .build();
    -  }
    -
    -  private static List createBackgroundResourceMethodOverrides() {
    -    MethodDefinition closeMethod =
    -        MethodDefinition.builder()
    -            .setIsOverride(true)
    -            .setScope(ScopeNode.PUBLIC)
    -            .setIsAbstract(true)
    -            .setReturnType(TypeNode.VOID)
    -            .setName("close")
    -            .build();
    -    return Arrays.asList(closeMethod);
    -  }
    -
    -  private static boolean hasLroMethods(Service service) {
    -    for (Method method : service.methods()) {
    -      if (method.hasLro()) {
    -        return true;
    -      }
    -    }
    -    return false;
    -  }
    -
    -  private static TypeStore createTypes(Service service, Map messageTypes) {
    -    List concreteClazzes =
    -        Arrays.asList(
    -            BackgroundResource.class,
    -            BetaApi.class,
    -            BidiStreamingCallable.class,
    -            ClientStreamingCallable.class,
    -            Generated.class,
    -            Operation.class,
    -            OperationCallable.class,
    -            ServerStreamingCallable.class,
    -            UnaryCallable.class,
    -            UnsupportedOperationException.class);
    -    TypeStore typeStore = new TypeStore(concreteClazzes);
    -
    -    typeStore.put("com.google.longrunning.stub", "OperationsStub");
    -
    -    // Pagination types.
    -    typeStore.putAll(
    -        service.pakkage(),
    -        service.methods().stream()
    -            .filter(m -> m.isPaged())
    -            .map(m -> String.format(PAGED_RESPONSE_TYPE_NAME_PATTERN, m.name()))
    -            .collect(Collectors.toList()),
    -        true,
    -        ClassNames.getServiceClientClassName(service));
    -
    -    return typeStore;
    -  }
    -
    -  private static List createThrowUOEBody(String methodName, TypeStore typeStore) {
    -    return Arrays.asList(
    -        ExprStatement.withExpr(
    -            ThrowExpr.builder()
    -                .setType(typeStore.get("UnsupportedOperationException"))
    -                .setMessageExpr(String.format("Not implemented: %s()", methodName))
    -                .build()));
    -  }
    -
    -  private static String getClientClassName(Service service) {
    -    return String.format("%sClient", service.overriddenName());
    -  }
    -}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/TransportContext.java b/src/main/java/com/google/api/generator/gapic/composer/common/TransportContext.java
    index 4058fbafbf..507ff662ca 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/common/TransportContext.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/common/TransportContext.java
    @@ -19,6 +19,7 @@
     import com.google.api.generator.gapic.composer.utils.ClassNames;
     import com.google.api.generator.gapic.model.Transport;
     import com.google.auto.value.AutoValue;
    +import java.util.List;
     import javax.annotation.Nullable;
     
     @AutoValue
    @@ -29,36 +30,57 @@ public abstract class TransportContext {
       // For AbstractServiceStubClassComposer
       public abstract Transport transport();
     
    +  @Nullable
       public abstract String transportName();
     
    +  @Nullable
       public abstract Class callSettingsClass();
     
    +  @Nullable
       public abstract TypeNode stubCallableFactoryType();
     
    +  @Nullable
       public abstract Class methodDescriptorClass();
     
    -  @Nullable
    -  public abstract TypeNode transportOperationsStubType();
    +  public abstract List transportOperationsStubTypes();
    +
    +  public abstract List transportOperationsStubNames();
     
       // For AbstractServiceSettingsClassComposer
    -  public abstract Class instantiatingChannelProviderClass();
    +  public abstract List> instantiatingChannelProviderClasses();
     
    -  public abstract String defaultTransportProviderBuilderName();
    +  public abstract List> instantiatingChannelProviderBuilderClasses();
    +
    +  public abstract List defaultTransportProviderBuilderNames();
    +
    +  public abstract List transportApiClientHeaderProviderBuilderNames();
     
       // For AbstractServiceStubSettingsClassComposer
    -  public abstract TypeNode transportChannelType();
    +  public abstract List transportChannelTypes();
     
    -  public abstract String transportGetterName();
    +  public abstract List transportGetterNames();
     
       // For AbstractServiceCallableFactoryClassComposer
    +  @Nullable
       public abstract TypeNode transportCallSettingsType();
     
    +  @Nullable
       public abstract TypeNode transportCallableFactoryType();
     
    -  public abstract TypeNode operationsStubType();
    +  public abstract List operationsStubTypes();
     
    +  @Nullable
       public abstract String transportCallSettingsName();
     
    +  // For RetrySettingsComposer
    +  public abstract TypeNode operationResponseTransformerType();
    +
    +  public abstract TypeNode operationMetadataTransformerType();
    +
    +  public abstract List operationsClientTypes();
    +
    +  public abstract List operationsClientNames();
    +
       protected static TypeNode classToType(Class clazz) {
         return TypeNode.withReference(ConcreteReference.withClazz(clazz));
       }
    @@ -82,15 +104,21 @@ public abstract static class Builder {
     
         public abstract Builder setMethodDescriptorClass(Class methodDescriptorClass);
     
    -    public abstract Builder setInstantiatingChannelProviderClass(
    -        Class instantiatingChannelProviderClass);
    +    public abstract Builder setInstantiatingChannelProviderClasses(
    +        List> instantiatingChannelProviderClasses);
    +
    +    public abstract Builder setInstantiatingChannelProviderBuilderClasses(
    +        List> instantiatingChannelProviderBuilderClasses);
    +
    +    public abstract Builder setDefaultTransportProviderBuilderNames(
    +        List defaultTransportProviderBuilderNames);
     
    -    public abstract Builder setDefaultTransportProviderBuilderName(
    -        String defaultTransportProviderBuilderName);
    +    public abstract Builder setTransportApiClientHeaderProviderBuilderNames(
    +        List transportApiClientHeaderProviderBuilderNames);
     
    -    public abstract Builder setTransportChannelType(TypeNode transportChannelType);
    +    public abstract Builder setTransportChannelTypes(List transportChannelTypes);
     
    -    public abstract Builder setTransportGetterName(String transportGetterName);
    +    public abstract Builder setTransportGetterNames(List transportGetterNames);
     
         public abstract Builder setTransportCallSettingsType(TypeNode transportCallSettingsType);
     
    @@ -98,9 +126,19 @@ public abstract Builder setDefaultTransportProviderBuilderName(
     
         public abstract Builder setTransportCallSettingsName(String transportCallSettingsName);
     
    -    public abstract Builder setTransportOperationsStubType(TypeNode transportOperationsStubType);
    +    public abstract Builder setTransportOperationsStubTypes(List transportOperationsStubTypes);
    +
    +    public abstract Builder setTransportOperationsStubNames(List transportOperationsStubNames);
    +
    +    public abstract Builder setOperationsStubTypes(List operationsStubType);
    +
    +    public abstract Builder setOperationResponseTransformerType(TypeNode operationResponseTransformerType);
    +
    +    public abstract Builder setOperationMetadataTransformerType(TypeNode operationMetadataTransformerType);
    +
    +    public abstract Builder setOperationsClientTypes(List operationsClientTypes);
     
    -    public abstract Builder setOperationsStubType(TypeNode operationsStubType);
    +    public abstract Builder setOperationsClientNames(List operationsClientNames);
     
         public abstract TransportContext build();
       }
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java
    index 75562d680c..5af2722fd7 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java
    @@ -58,8 +58,11 @@ public class DefaultValueComposer {
           TypeNode.withReference(ConcreteReference.withClazz(ByteString.class));
     
       public static Expr createDefaultValue(
    -      MethodArgument methodArg, Map resourceNames) {
    -    if (methodArg.isResourceNameHelper()) {
    +      MethodArgument methodArg,
    +      Map resourceNames,
    +      boolean forceResourceNameInitializer) {
    +    if (methodArg.isResourceNameHelper()
    +        || (forceResourceNameInitializer && methodArg.field().hasResourceReference())) {
           Preconditions.checkState(
               methodArg.field().hasResourceReference(),
               String.format(
    @@ -72,10 +75,21 @@ public static Expr createDefaultValue(
               String.format(
                   "No resource name found for reference %s",
                   methodArg.field().resourceReference().resourceTypeString()));
    -      return createDefaultValue(
    -          resourceName,
    -          resourceNames.values().stream().collect(Collectors.toList()),
    -          methodArg.field().name());
    +      Expr defValue =
    +          createDefaultValue(
    +              resourceName,
    +              resourceNames.values().stream().collect(Collectors.toList()),
    +              methodArg.field().name());
    +
    +      if (!methodArg.isResourceNameHelper() && methodArg.field().hasResourceReference()) {
    +        defValue =
    +            MethodInvocationExpr.builder()
    +                .setExprReferenceExpr(defValue)
    +                .setMethodName("toString")
    +                .setReturnType(TypeNode.STRING)
    +                .build();
    +      }
    +      return defValue;
         }
     
         if (methodArg.type().equals(methodArg.field().type())) {
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcContext.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcContext.java
    index 9a291669e2..5f9b27963e 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcContext.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcContext.java
    @@ -19,9 +19,12 @@
     import com.google.api.gax.grpc.GrpcStubCallableFactory;
     import com.google.api.gax.grpc.GrpcTransportChannel;
     import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
    +import com.google.api.gax.grpc.ProtoOperationTransformers;
     import com.google.api.generator.gapic.composer.common.TransportContext;
     import com.google.api.generator.gapic.composer.utils.ClassNames;
     import com.google.api.generator.gapic.model.Transport;
    +import com.google.common.collect.ImmutableList;
    +import com.google.longrunning.OperationsClient;
     import com.google.longrunning.stub.GrpcOperationsStub;
     import com.google.longrunning.stub.OperationsStub;
     import io.grpc.MethodDescriptor;
    @@ -36,18 +39,33 @@ public abstract class GrpcContext extends TransportContext {
               .setCallSettingsClass(GrpcCallSettings.class)
               .setStubCallableFactoryType(classToType(GrpcStubCallableFactory.class))
               .setMethodDescriptorClass(MethodDescriptor.class)
    -          .setTransportOperationsStubType(classToType(GrpcOperationsStub.class))
    +          .setTransportOperationsStubTypes(ImmutableList.of(classToType(GrpcOperationsStub.class)))
    +          .setTransportOperationsStubNames(ImmutableList.of("operationsStub"))
               // For grpc.ServiceSettingsClassComposer
    -          .setInstantiatingChannelProviderClass(InstantiatingGrpcChannelProvider.Builder.class)
    -          .setDefaultTransportProviderBuilderName("defaultGrpcTransportProviderBuilder")
    +          .setInstantiatingChannelProviderClasses(
    +              ImmutableList.of(InstantiatingGrpcChannelProvider.class))
    +          .setInstantiatingChannelProviderBuilderClasses(
    +              ImmutableList.of(InstantiatingGrpcChannelProvider.Builder.class))
    +          .setDefaultTransportProviderBuilderNames(
    +              ImmutableList.of("defaultGrpcTransportProviderBuilder"))
    +          .setTransportApiClientHeaderProviderBuilderNames(
    +              ImmutableList.of("defaultGrpcApiClientHeaderProviderBuilder"))
               // For grpc.ServiceStubSettingsClassComposer
    -          .setTransportChannelType(classToType(GrpcTransportChannel.class))
    -          .setTransportGetterName("getGrpcTransportName")
    +          .setTransportChannelTypes(ImmutableList.of(classToType(GrpcTransportChannel.class)))
    +          .setTransportGetterNames(ImmutableList.of("getGrpcTransportName"))
               // For grpc.GrpcServiceCallableFactoryClassComposer
               .setTransportCallSettingsType(classToType(GrpcCallSettings.class))
               .setTransportCallableFactoryType(classToType(GrpcCallableFactory.class))
    -          .setOperationsStubType(classToType(OperationsStub.class))
    +          .setOperationsStubTypes(ImmutableList.of(classToType(OperationsStub.class)))
               .setTransportCallSettingsName("grpcCallSettings")
    +          // For RetrySettingsComposer
    +          .setOperationResponseTransformerType(
    +              classToType(ProtoOperationTransformers.ResponseTransformer.class))
    +          .setOperationMetadataTransformerType(
    +              classToType(ProtoOperationTransformers.MetadataTransformer.class))
    +          // For ServiceClientClassComposer
    +          .setOperationsClientTypes(ImmutableList.of(classToType(OperationsClient.class)))
    +          .setOperationsClientNames(ImmutableList.of("operationsClient"))
               .build();
     
       public static TransportContext instance() {
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java
    index 3fc25a95b2..f3ad194c51 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java
    @@ -22,7 +22,6 @@
     import com.google.api.generator.engine.ast.Expr;
     import com.google.api.generator.engine.ast.ExprStatement;
     import com.google.api.generator.engine.ast.LambdaExpr;
    -import com.google.api.generator.engine.ast.MethodDefinition;
     import com.google.api.generator.engine.ast.MethodInvocationExpr;
     import com.google.api.generator.engine.ast.ScopeNode;
     import com.google.api.generator.engine.ast.Statement;
    @@ -31,7 +30,7 @@
     import com.google.api.generator.engine.ast.ValueExpr;
     import com.google.api.generator.engine.ast.Variable;
     import com.google.api.generator.engine.ast.VariableExpr;
    -import com.google.api.generator.gapic.composer.common.AbstractServiceStubClassComposer;
    +import com.google.api.generator.gapic.composer.common.AbstractTransportServiceStubClassComposer;
     import com.google.api.generator.gapic.composer.store.TypeStore;
     import com.google.api.generator.gapic.model.HttpBindings.HttpBinding;
     import com.google.api.generator.gapic.model.Message;
    @@ -53,7 +52,7 @@
     import java.util.function.Function;
     import java.util.stream.Collectors;
     
    -public class GrpcServiceStubClassComposer extends AbstractServiceStubClassComposer {
    +public class GrpcServiceStubClassComposer extends AbstractTransportServiceStubClassComposer {
       private static final GrpcServiceStubClassComposer INSTANCE = new GrpcServiceStubClassComposer();
     
       // Legacy support for the original reroute_to_grpc_interface option in gapic.yaml. These two APIs
    @@ -193,18 +192,6 @@ protected EnumRefExpr getMethodDescriptorMethodTypeExpr(Method protoMethod) {
             .build();
       }
     
    -  @Override
    -  protected List createOperationsStubGetterMethod(
    -      VariableExpr operationsStubVarExpr) {
    -    return Arrays.asList(
    -        MethodDefinition.builder()
    -            .setScope(ScopeNode.PUBLIC)
    -            .setReturnType(operationsStubVarExpr.type())
    -            .setName("getOperationsStub")
    -            .setReturnExpr(operationsStubVarExpr)
    -            .build());
    -  }
    -
       @Override
       protected Expr createTransportSettingsInitExpr(
           Method method, VariableExpr transportSettingsVarExpr, VariableExpr methodDescriptorVarExpr) {
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposer.java
    new file mode 100644
    index 0000000000..9b95e9c280
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposer.java
    @@ -0,0 +1,30 @@
    +/*
    + * Copyright 2021 Google LLC
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + *     https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package com.google.api.generator.gapic.composer.grpc;
    +
    +import com.google.api.generator.gapic.composer.common.AbstractServiceClientClassComposer;
    +
    +public class ServiceClientClassComposer extends AbstractServiceClientClassComposer {
    +  private static final ServiceClientClassComposer INSTANCE = new ServiceClientClassComposer();
    +
    +  protected ServiceClientClassComposer() {
    +    super(GrpcContext.instance());
    +  }
    +
    +  public static ServiceClientClassComposer instance() {
    +    return INSTANCE;
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientTestClassComposer.java
    index 15b05ee765..75bd4c0133 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientTestClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceClientTestClassComposer.java
    @@ -143,7 +143,8 @@ protected MethodDefinition createStartStaticServerMethod(
           Service service,
           GapicContext context,
           Map classMemberVarExprs,
    -      TypeStore typeStore) {
    +      TypeStore typeStore,
    +      String newBuilderMethod) {
         VariableExpr serviceHelperVarExpr = classMemberVarExprs.get(SERVICE_HELPER_VAR_NAME);
         Function serviceToVarExprFn =
             s -> classMemberVarExprs.get(getMockServiceVarName(s));
    @@ -1055,6 +1056,12 @@ protected List createStreamingRpcExceptionTestStatements(
         return statements;
       }
     
    +  @Override
    +  protected Expr createDefaultValue(
    +      MethodArgument methodArg, Map resourceNames) {
    +    return DefaultValueComposer.createDefaultValue(methodArg, resourceNames, false);
    +  }
    +
       @Override
       protected List createRpcLroExceptionTestCatchBody(
           VariableExpr exceptionExpr, boolean isStreaming) {
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposer.java
    new file mode 100644
    index 0000000000..1e11c5087d
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposer.java
    @@ -0,0 +1,30 @@
    +/*
    + * Copyright 2021 Google LLC
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + *     https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package com.google.api.generator.gapic.composer.grpc;
    +
    +import com.google.api.generator.gapic.composer.common.AbstractServiceStubClassComposer;
    +
    +public class ServiceStubClassComposer extends AbstractServiceStubClassComposer {
    +  private static final ServiceStubClassComposer INSTANCE = new ServiceStubClassComposer();
    +
    +  protected ServiceStubClassComposer() {
    +    super(GrpcContext.instance());
    +  }
    +
    +  public static ServiceStubClassComposer instance() {
    +    return INSTANCE;
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposer.java
    index 6d0b8e221d..a80feffcd5 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposer.java
    @@ -18,14 +18,12 @@
     import com.google.api.gax.grpc.GaxGrpcProperties;
     import com.google.api.gax.grpc.GrpcTransportChannel;
     import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
    -import com.google.api.gax.rpc.ApiClientHeaderProvider;
    -import com.google.api.generator.engine.ast.AnnotationNode;
     import com.google.api.generator.engine.ast.ConcreteReference;
    +import com.google.api.generator.engine.ast.Expr;
     import com.google.api.generator.engine.ast.MethodDefinition;
     import com.google.api.generator.engine.ast.MethodInvocationExpr;
     import com.google.api.generator.engine.ast.PrimitiveValue;
     import com.google.api.generator.engine.ast.ScopeNode;
    -import com.google.api.generator.engine.ast.StringObjectValue;
     import com.google.api.generator.engine.ast.TypeNode;
     import com.google.api.generator.engine.ast.ValueExpr;
     import com.google.api.generator.engine.ast.Variable;
    @@ -33,9 +31,9 @@
     import com.google.api.generator.gapic.composer.comment.SettingsCommentComposer;
     import com.google.api.generator.gapic.composer.common.AbstractServiceStubSettingsClassComposer;
     import com.google.api.generator.gapic.composer.store.TypeStore;
    -import com.google.api.generator.gapic.composer.utils.ClassNames;
     import com.google.api.generator.gapic.model.Service;
     import java.util.Arrays;
    +import java.util.Collections;
     import java.util.List;
     
     public class ServiceStubSettingsClassComposer extends AbstractServiceStubSettingsClassComposer {
    @@ -62,37 +60,17 @@ private static TypeStore createStaticTypes() {
       }
     
       @Override
    -  protected MethodDefinition createDefaultTransportTransportProviderBuilderMethod() {
    -    // Create the defaultGrpcTransportProviderBuilder method.
    -    TypeNode returnType =
    -        TypeNode.withReference(
    -            ConcreteReference.withClazz(InstantiatingGrpcChannelProvider.Builder.class));
    -    MethodInvocationExpr transportChannelProviderBuilderExpr =
    -        MethodInvocationExpr.builder()
    -            .setStaticReferenceType(
    -                FIXED_GRPC_TYPESTORE.get(InstantiatingGrpcChannelProvider.class.getSimpleName()))
    -            .setMethodName("newBuilder")
    -            .build();
    -    transportChannelProviderBuilderExpr =
    -        MethodInvocationExpr.builder()
    -            .setExprReferenceExpr(transportChannelProviderBuilderExpr)
    -            .setMethodName("setMaxInboundMessageSize")
    -            .setArguments(
    -                VariableExpr.builder()
    -                    .setVariable(
    -                        Variable.builder().setType(TypeNode.INT).setName("MAX_VALUE").build())
    -                    .setStaticReferenceType(TypeNode.INT_OBJECT)
    -                    .build())
    -            .setReturnType(returnType)
    -            .build();
    -    return MethodDefinition.builder()
    -        .setHeaderCommentStatements(
    -            SettingsCommentComposer.DEFAULT_TRANSPORT_PROVIDER_BUILDER_METHOD_COMMENT)
    -        .setScope(ScopeNode.PUBLIC)
    -        .setIsStatic(true)
    +  protected Expr initializeTransportProviderBuilder(
    +      MethodInvocationExpr transportChannelProviderBuilderExpr, TypeNode returnType) {
    +    return MethodInvocationExpr.builder()
    +        .setExprReferenceExpr(transportChannelProviderBuilderExpr)
    +        .setMethodName("setMaxInboundMessageSize")
    +        .setArguments(
    +            VariableExpr.builder()
    +                .setVariable(Variable.builder().setType(TypeNode.INT).setName("MAX_VALUE").build())
    +                .setStaticReferenceType(TypeNode.INT_OBJECT)
    +                .build())
             .setReturnType(returnType)
    -        .setName("defaultGrpcTransportProviderBuilder")
    -        .setReturnExpr(transportChannelProviderBuilderExpr)
             .build();
       }
     
    @@ -138,69 +116,16 @@ protected MethodDefinition createDefaultCredentialsProviderBuilderMethod() {
       }
     
       @Override
    -  protected MethodDefinition createDefaultApiClientHeaderProviderBuilderMethod(
    +  protected List createApiClientHeaderProviderBuilderMethods(
           Service service, TypeStore typeStore) {
    -    // Create the defaultApiClientHeaderProviderBuilder method.
    -    TypeNode returnType =
    -        TypeNode.withReference(ConcreteReference.withClazz(ApiClientHeaderProvider.Builder.class));
    -    MethodInvocationExpr returnExpr =
    -        MethodInvocationExpr.builder()
    -            .setStaticReferenceType(FIXED_TYPESTORE.get("ApiClientHeaderProvider"))
    -            .setMethodName("newBuilder")
    -            .build();
    -
    -    MethodInvocationExpr versionArgExpr =
    -        MethodInvocationExpr.builder()
    -            .setStaticReferenceType(FIXED_TYPESTORE.get("GaxProperties"))
    -            .setMethodName("getLibraryVersion")
    -            .setArguments(
    -                VariableExpr.builder()
    -                    .setVariable(
    -                        Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build())
    -                    .setStaticReferenceType(
    -                        typeStore.get(ClassNames.getServiceStubSettingsClassName(service)))
    -                    .build())
    -            .build();
    -
    -    returnExpr =
    -        MethodInvocationExpr.builder()
    -            .setExprReferenceExpr(returnExpr)
    -            .setMethodName("setGeneratedLibToken")
    -            .setArguments(ValueExpr.withValue(StringObjectValue.withValue("gapic")), versionArgExpr)
    -            .build();
    -    returnExpr =
    -        MethodInvocationExpr.builder()
    -            .setExprReferenceExpr(returnExpr)
    -            .setMethodName("setTransportToken")
    -            .setArguments(
    -                MethodInvocationExpr.builder()
    -                    .setStaticReferenceType(
    -                        FIXED_GRPC_TYPESTORE.get(GaxGrpcProperties.class.getSimpleName()))
    -                    .setMethodName("getGrpcTokenName")
    -                    .build(),
    -                MethodInvocationExpr.builder()
    -                    .setStaticReferenceType(
    -                        FIXED_GRPC_TYPESTORE.get(GaxGrpcProperties.class.getSimpleName()))
    -                    .setMethodName("getGrpcVersion")
    -                    .build())
    -            .setReturnType(returnType)
    -            .build();
    -
    -    AnnotationNode annotation =
    -        AnnotationNode.builder()
    -            .setType(FIXED_TYPESTORE.get("BetaApi"))
    -            .setDescription(
    -                "The surface for customizing headers is not stable yet and may change in the"
    -                    + " future.")
    -            .build();
    -    return MethodDefinition.builder()
    -        .setAnnotations(Arrays.asList(annotation))
    -        .setScope(ScopeNode.PUBLIC)
    -        .setIsStatic(true)
    -        .setReturnType(returnType)
    -        .setName("defaultApiClientHeaderProviderBuilder")
    -        .setReturnExpr(returnExpr)
    -        .build();
    +    return Collections.singletonList(
    +        createApiClientHeaderProviderBuilderMethod(
    +            service,
    +            typeStore,
    +            "defaultApiClientHeaderProviderBuilder",
    +            FIXED_GRPC_TYPESTORE.get(GaxGrpcProperties.class.getSimpleName()),
    +            "getGrpcTokenName",
    +            "getGrpcVersion"));
       }
     
       @Override
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/BUILD.bazel b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/BUILD.bazel
    new file mode 100644
    index 0000000000..ea77aab100
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/BUILD.bazel
    @@ -0,0 +1,55 @@
    +load("@rules_java//java:defs.bzl", "java_library")
    +
    +package(default_visibility = ["//visibility:public"])
    +
    +filegroup(
    +    name = "grpcrest_files",
    +    srcs = glob(["*.java"]),
    +)
    +
    +java_library(
    +    name = "grpcrest",
    +    srcs = [
    +        ":grpcrest_files",
    +    ],
    +    deps = [
    +        "//:service_config_java_proto",
    +        "//src/main/java/com/google/api/generator/engine/ast",
    +        "//src/main/java/com/google/api/generator/engine/writer",
    +        "//src/main/java/com/google/api/generator/gapic:status_java_proto",
    +        "//src/main/java/com/google/api/generator/gapic/composer/comment",
    +        "//src/main/java/com/google/api/generator/gapic/composer/common",
    +        "//src/main/java/com/google/api/generator/gapic/composer/defaultvalue",
    +        "//src/main/java/com/google/api/generator/gapic/composer/resourcename",
    +        "//src/main/java/com/google/api/generator/gapic/composer/rest",
    +        "//src/main/java/com/google/api/generator/gapic/composer/samplecode",
    +        "//src/main/java/com/google/api/generator/gapic/composer/store",
    +        "//src/main/java/com/google/api/generator/gapic/composer/utils",
    +        "//src/main/java/com/google/api/generator/gapic/model",
    +        "//src/main/java/com/google/api/generator/gapic/utils",
    +        "//src/main/java/com/google/api/generator/util",
    +        "@com_google_api_api_common//jar",
    +        "@com_google_api_gax_java//gax",
    +        "@com_google_api_gax_java//gax:gax_testlib",
    +        "@com_google_api_gax_java//gax-grpc:gax_grpc",
    +        "@com_google_api_gax_java//gax-grpc:gax_grpc_testlib",
    +        "@com_google_api_gax_java//gax-httpjson:gax_httpjson",
    +        "@com_google_api_gax_java//gax-httpjson:gax_httpjson_testlib",
    +        "@com_google_code_findbugs_jsr305//jar",
    +        "@com_google_googleapis//gapic/metadata:metadata_java_proto",
    +        "@com_google_googleapis//google/api:api_java_proto",
    +        "@com_google_googleapis//google/longrunning:longrunning_java_proto",
    +        "@com_google_googleapis//google/rpc:rpc_java_proto",
    +        "@com_google_guava_guava//jar",
    +        "@com_google_http_client_google_http_client//jar",
    +        "@com_google_protobuf//:protobuf_java",
    +        "@com_google_protobuf//:protobuf_java_util",
    +        "@com_google_protobuf//java/core",
    +        "@io_grpc_grpc_java//api",
    +        "@io_grpc_grpc_java//protobuf",
    +        "@io_grpc_grpc_java//stub",
    +        "@javax_annotation_javax_annotation_api//jar",
    +        "@junit_junit//jar",
    +        "@org_threeten_threetenbp//jar",
    +    ],
    +)
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java
    new file mode 100644
    index 0000000000..3f84bf3c97
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java
    @@ -0,0 +1,95 @@
    +// Copyright 2021 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//      http://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +package com.google.api.generator.gapic.composer.grpcrest;
    +
    +import com.google.api.gax.core.BackgroundResource;
    +import com.google.api.gax.grpc.GrpcTransportChannel;
    +import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
    +import com.google.api.gax.grpc.ProtoOperationTransformers;
    +import com.google.api.gax.httpjson.HttpJsonTransportChannel;
    +import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider;
    +import com.google.api.gax.httpjson.longrunning.stub.HttpJsonOperationsStub;
    +import com.google.api.generator.gapic.composer.common.TransportContext;
    +import com.google.api.generator.gapic.composer.utils.ClassNames;
    +import com.google.api.generator.gapic.model.Transport;
    +import com.google.common.collect.ImmutableList;
    +import com.google.longrunning.OperationsClient;
    +import com.google.longrunning.stub.GrpcOperationsStub;
    +import com.google.longrunning.stub.OperationsStub;
    +
    +public abstract class GrpcRestContext extends TransportContext {
    +  private static final TransportContext INSTANCE =
    +      GrpcRestContext.builder()
    +          .setClassNames(new ClassNames("Grpc", "HttpJson"))
    +          .setTransport(Transport.GRPC_REST)
    +          .setTransportName(null)
    +          // For grpcrest.GrpcServiceStubClassComposer
    +          .setCallSettingsClass(null)
    +          .setStubCallableFactoryType(null)
    +          .setMethodDescriptorClass(null)
    +          .setTransportOperationsStubTypes(
    +              ImmutableList.of(
    +                  classToType(GrpcOperationsStub.class), classToType(HttpJsonOperationsStub.class)))
    +          .setTransportOperationsStubNames(
    +              ImmutableList.of("operationsStub", "httpJsonOperationsStub"))
    +          // For grpcrest.ServiceSettingsClassComposer
    +          .setInstantiatingChannelProviderClasses(
    +              ImmutableList.of(
    +                  InstantiatingGrpcChannelProvider.class,
    +                  InstantiatingHttpJsonChannelProvider.class))
    +          .setInstantiatingChannelProviderBuilderClasses(
    +              ImmutableList.of(
    +                  InstantiatingGrpcChannelProvider.Builder.class,
    +                  InstantiatingHttpJsonChannelProvider.Builder.class))
    +          .setDefaultTransportProviderBuilderNames(
    +              ImmutableList.of(
    +                  "defaultGrpcTransportProviderBuilder", "defaultHttpJsonTransportProviderBuilder"))
    +          .setTransportApiClientHeaderProviderBuilderNames(
    +              ImmutableList.of(
    +                  "defaultGrpcApiClientHeaderProviderBuilder",
    +                  "defaultHttpJsonApiClientHeaderProviderBuilder"))
    +          // For grpcrest.ServiceStubSettingsClassComposer
    +          .setTransportChannelTypes(
    +              ImmutableList.of(
    +                  classToType(GrpcTransportChannel.class),
    +                  classToType(HttpJsonTransportChannel.class)))
    +          .setTransportGetterNames(
    +              ImmutableList.of("getGrpcTransportName", "getHttpJsonTransportName"))
    +          // For grpcrest.GrpcServiceCallableFactoryClassComposer
    +          .setTransportCallSettingsType(null)
    +          .setTransportCallableFactoryType(null)
    +          .setOperationsStubTypes(
    +              ImmutableList.of(
    +                  classToType(OperationsStub.class), classToType(BackgroundResource.class)))
    +          .setTransportCallSettingsName(null)
    +          // For RetrySettingsComposer
    +          // TODO: fix when LRO for REST RE FIXED
    +          .setOperationResponseTransformerType(
    +              classToType(ProtoOperationTransformers.ResponseTransformer.class))
    +          .setOperationMetadataTransformerType(
    +              classToType(ProtoOperationTransformers.MetadataTransformer.class))
    +          // For ServiceClientClassComposer
    +          .setOperationsClientTypes(
    +              ImmutableList.of(
    +                  classToType(OperationsClient.class),
    +                  classToType(com.google.api.gax.httpjson.longrunning.OperationsClient.class)))
    +          .setOperationsClientNames(
    +              ImmutableList.of("operationsClient", "httpJsonOperationsClient"))
    +          .build();
    +
    +  public static TransportContext instance() {
    +    return INSTANCE;
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/HttpJsonServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/HttpJsonServiceClientTestClassComposer.java
    new file mode 100644
    index 0000000000..9f9bbafc05
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/HttpJsonServiceClientTestClassComposer.java
    @@ -0,0 +1,57 @@
    +// Copyright 2021 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//      http://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +package com.google.api.generator.gapic.composer.grpcrest;
    +
    +import com.google.api.generator.engine.ast.MethodDefinition;
    +import com.google.api.generator.engine.ast.VariableExpr;
    +import com.google.api.generator.gapic.composer.common.AbstractServiceClientTestClassComposer;
    +import com.google.api.generator.gapic.composer.rest.ServiceClientTestClassComposer;
    +import com.google.api.generator.gapic.composer.store.TypeStore;
    +import com.google.api.generator.gapic.model.GapicClass;
    +import com.google.api.generator.gapic.model.GapicContext;
    +import com.google.api.generator.gapic.model.Service;
    +import java.util.Map;
    +
    +public class HttpJsonServiceClientTestClassComposer extends ServiceClientTestClassComposer {
    +  private static final HttpJsonServiceClientTestClassComposer INSTANCE =
    +      new HttpJsonServiceClientTestClassComposer();
    +
    +  protected HttpJsonServiceClientTestClassComposer() {
    +    super();
    +  }
    +
    +  public static AbstractServiceClientTestClassComposer instance() {
    +    return INSTANCE;
    +  }
    +
    +  @Override
    +  protected GapicClass generate(String className, GapicContext context, Service service) {
    +    return super.generate(
    +        getTransportContext().classNames().getServiceClientTestClassNames(service).get(0),
    +        context,
    +        service);
    +  }
    +
    +  @Override
    +  protected MethodDefinition createStartStaticServerMethod(
    +      Service service,
    +      GapicContext context,
    +      Map classMemberVarExprs,
    +      TypeStore typeStore,
    +      String newBuilderMethod) {
    +    return super.createStartStaticServerMethod(
    +        service, context, classMemberVarExprs, typeStore, "newHttpJsonBuilder");
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/HttpJsonServiceStubClassComposer.java
    new file mode 100644
    index 0000000000..7f99c81287
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/HttpJsonServiceStubClassComposer.java
    @@ -0,0 +1,40 @@
    +// Copyright 2021 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//      http://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +package com.google.api.generator.gapic.composer.grpcrest;
    +
    +import com.google.api.generator.engine.ast.MethodDefinition;
    +import com.google.api.generator.gapic.composer.store.TypeStore;
    +import com.google.api.generator.gapic.model.Service;
    +import java.util.List;
    +
    +public class HttpJsonServiceStubClassComposer
    +    extends com.google.api.generator.gapic.composer.rest.HttpJsonServiceStubClassComposer {
    +  private static final HttpJsonServiceStubClassComposer INSTANCE =
    +      new HttpJsonServiceStubClassComposer();
    +
    +  protected HttpJsonServiceStubClassComposer() {
    +    super();
    +  }
    +
    +  public static HttpJsonServiceStubClassComposer instance() {
    +    return INSTANCE;
    +  }
    +
    +  @Override
    +  protected List createStaticCreatorMethods(
    +      Service service, TypeStore typeStore, String newBuilderMethod) {
    +    return super.createStaticCreatorMethods(service, typeStore, "newHttpJsonBuilder");
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceClientClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceClientClassComposer.java
    new file mode 100644
    index 0000000000..7529b002cf
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceClientClassComposer.java
    @@ -0,0 +1,29 @@
    +// Copyright 2021 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//      http://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +package com.google.api.generator.gapic.composer.grpcrest;
    +
    +import com.google.api.generator.gapic.composer.common.AbstractServiceClientClassComposer;
    +
    +public class ServiceClientClassComposer extends AbstractServiceClientClassComposer {
    +  private static final ServiceClientClassComposer INSTANCE = new ServiceClientClassComposer();
    +
    +  protected ServiceClientClassComposer() {
    +    super(GrpcRestContext.instance());
    +  }
    +
    +  public static ServiceClientClassComposer instance() {
    +    return INSTANCE;
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceSettingsClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceSettingsClassComposer.java
    new file mode 100644
    index 0000000000..03ff5dc54a
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceSettingsClassComposer.java
    @@ -0,0 +1,68 @@
    +// Copyright 2021 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//      http://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +package com.google.api.generator.gapic.composer.grpcrest;
    +
    +import com.google.api.generator.engine.ast.MethodDefinition;
    +import com.google.api.generator.gapic.composer.common.AbstractServiceSettingsClassComposer;
    +import com.google.api.generator.gapic.composer.store.TypeStore;
    +import com.google.api.generator.gapic.model.Service;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +public class ServiceSettingsClassComposer extends AbstractServiceSettingsClassComposer {
    +  private static final ServiceSettingsClassComposer INSTANCE = new ServiceSettingsClassComposer();
    +
    +  protected ServiceSettingsClassComposer() {
    +    super(GrpcRestContext.instance());
    +  }
    +
    +  public static ServiceSettingsClassComposer instance() {
    +    return INSTANCE;
    +  }
    +
    +  @Override
    +  protected List createNestedBuilderCreatorMethods(
    +      Service service,
    +      TypeStore typeStore,
    +      String newBuilderMethodName,
    +      String createDefaultMethodName) {
    +    List methods = new ArrayList<>();
    +
    +    methods.addAll(
    +        super.createNestedBuilderCreatorMethods(service, typeStore, "newBuilder", "createDefault"));
    +    methods.addAll(
    +        super.createNestedBuilderCreatorMethods(
    +            service, typeStore, "newHttpJsonBuilder", "createHttpJsonDefault"));
    +
    +    return methods;
    +  }
    +
    +  @Override
    +  protected List createNewBuilderMethods(
    +      Service service,
    +      TypeStore typeStore,
    +      String newBuilderMethodName,
    +      String createDefaultMethodName) {
    +    List methods = new ArrayList<>();
    +
    +    methods.addAll(
    +        super.createNewBuilderMethods(service, typeStore, "newBuilder", "createDefault"));
    +    methods.addAll(
    +        super.createNewBuilderMethods(
    +            service, typeStore, "newHttpJsonBuilder", "createHttpJsonDefault"));
    +
    +    return methods;
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubClassComposer.java
    new file mode 100644
    index 0000000000..6be0ef7ac2
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubClassComposer.java
    @@ -0,0 +1,47 @@
    +/*
    + * Copyright 2021 Google LLC
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + *     https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package com.google.api.generator.gapic.composer.grpcrest;
    +
    +import com.google.api.generator.engine.ast.MethodDefinition;
    +import com.google.api.generator.engine.ast.ReturnExpr;
    +import com.google.api.generator.engine.ast.ScopeNode;
    +import com.google.api.generator.engine.ast.TypeNode;
    +import com.google.api.generator.engine.ast.ValueExpr;
    +import com.google.api.generator.gapic.composer.common.AbstractServiceStubClassComposer;
    +import com.google.api.generator.gapic.composer.store.TypeStore;
    +
    +public class ServiceStubClassComposer extends AbstractServiceStubClassComposer {
    +  private static final ServiceStubClassComposer INSTANCE = new ServiceStubClassComposer();
    +
    +  protected ServiceStubClassComposer() {
    +    super(GrpcRestContext.instance());
    +  }
    +
    +  public static ServiceStubClassComposer instance() {
    +    return INSTANCE;
    +  }
    +
    +  @Override
    +  protected MethodDefinition createOperationsStubGetterMethodDefinition(
    +      TypeNode returnType, String methodName, TypeStore typeStore) {
    +    return MethodDefinition.builder()
    +        .setScope(ScopeNode.PUBLIC)
    +        .setReturnType(returnType)
    +        .setName(methodName)
    +        .setReturnExpr(ReturnExpr.withExpr(ValueExpr.createNullExpr()))
    +        .build();
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubSettingsClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubSettingsClassComposer.java
    new file mode 100644
    index 0000000000..6f65ced39c
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubSettingsClassComposer.java
    @@ -0,0 +1,200 @@
    +// Copyright 2021 Google LLC
    +//
    +// Licensed under the Apache License, Version 2.0 (the "License");
    +// you may not use this file except in compliance with the License.
    +// You may obtain a copy of the License at
    +//
    +//      http://www.apache.org/licenses/LICENSE-2.0
    +//
    +// Unless required by applicable law or agreed to in writing, software
    +// distributed under the License is distributed on an "AS IS" BASIS,
    +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +// See the License for the specific language governing permissions and
    +// limitations under the License.
    +
    +package com.google.api.generator.gapic.composer.grpcrest;
    +
    +import com.google.api.gax.core.GoogleCredentialsProvider;
    +import com.google.api.gax.grpc.GaxGrpcProperties;
    +import com.google.api.gax.httpjson.GaxHttpJsonProperties;
    +import com.google.api.gax.rpc.ApiClientHeaderProvider;
    +import com.google.api.generator.engine.ast.ConcreteReference;
    +import com.google.api.generator.engine.ast.Expr;
    +import com.google.api.generator.engine.ast.MethodDefinition;
    +import com.google.api.generator.engine.ast.MethodInvocationExpr;
    +import com.google.api.generator.engine.ast.PrimitiveValue;
    +import com.google.api.generator.engine.ast.ScopeNode;
    +import com.google.api.generator.engine.ast.TypeNode;
    +import com.google.api.generator.engine.ast.ValueExpr;
    +import com.google.api.generator.engine.ast.Variable;
    +import com.google.api.generator.engine.ast.VariableExpr;
    +import com.google.api.generator.gapic.composer.comment.SettingsCommentComposer;
    +import com.google.api.generator.gapic.composer.common.AbstractServiceStubSettingsClassComposer;
    +import com.google.api.generator.gapic.composer.store.TypeStore;
    +import com.google.api.generator.gapic.composer.utils.ClassNames;
    +import com.google.api.generator.gapic.model.Service;
    +import com.google.common.collect.ImmutableList;
    +import java.util.ArrayList;
    +import java.util.List;
    +
    +public class ServiceStubSettingsClassComposer extends AbstractServiceStubSettingsClassComposer {
    +  private static final ServiceStubSettingsClassComposer INSTANCE =
    +      new ServiceStubSettingsClassComposer();
    +
    +  public static ServiceStubSettingsClassComposer instance() {
    +    return INSTANCE;
    +  }
    +
    +  protected ServiceStubSettingsClassComposer() {
    +    super(GrpcRestContext.instance());
    +  }
    +
    +  @Override
    +  protected Expr initializeTransportProviderBuilder(
    +      MethodInvocationExpr transportChannelProviderBuilderExpr, TypeNode returnType) {
    +    if (!returnType.reference().isFromPackage("com.google.api.gax.grpc")) {
    +      return transportChannelProviderBuilderExpr;
    +    }
    +
    +    return MethodInvocationExpr.builder()
    +        .setExprReferenceExpr(transportChannelProviderBuilderExpr)
    +        .setMethodName("setMaxInboundMessageSize")
    +        .setArguments(
    +            VariableExpr.builder()
    +                .setVariable(Variable.builder().setType(TypeNode.INT).setName("MAX_VALUE").build())
    +                .setStaticReferenceType(TypeNode.INT_OBJECT)
    +                .build())
    +        .setReturnType(returnType)
    +        .build();
    +  }
    +
    +  @Override
    +  protected MethodDefinition createDefaultCredentialsProviderBuilderMethod() {
    +    TypeNode returnType =
    +        TypeNode.withReference(
    +            ConcreteReference.withClazz(GoogleCredentialsProvider.Builder.class));
    +    MethodInvocationExpr credsProviderBuilderExpr =
    +        MethodInvocationExpr.builder()
    +            .setStaticReferenceType(FIXED_TYPESTORE.get("GoogleCredentialsProvider"))
    +            .setMethodName("newBuilder")
    +            .build();
    +    credsProviderBuilderExpr =
    +        MethodInvocationExpr.builder()
    +            .setExprReferenceExpr(credsProviderBuilderExpr)
    +            .setMethodName("setScopesToApply")
    +            .setArguments(DEFAULT_SERVICE_SCOPES_VAR_EXPR)
    +            .setReturnType(returnType)
    +            .build();
    +
    +    // This section is specific to GAPIC clients. It sets UseJwtAccessWithScope value to true to
    +    // enable self signed JWT feature.
    +    credsProviderBuilderExpr =
    +        MethodInvocationExpr.builder()
    +            .setExprReferenceExpr(credsProviderBuilderExpr)
    +            .setMethodName("setUseJwtAccessWithScope")
    +            .setArguments(
    +                ValueExpr.withValue(
    +                    PrimitiveValue.builder().setType(TypeNode.BOOLEAN).setValue("true").build()))
    +            .setReturnType(returnType)
    +            .build();
    +
    +    return MethodDefinition.builder()
    +        .setHeaderCommentStatements(
    +            SettingsCommentComposer.DEFAULT_CREDENTIALS_PROVIDER_BUILDER_METHOD_COMMENT)
    +        .setScope(ScopeNode.PUBLIC)
    +        .setIsStatic(true)
    +        .setReturnType(returnType)
    +        .setName("defaultCredentialsProviderBuilder")
    +        .setReturnExpr(credsProviderBuilderExpr)
    +        .build();
    +  }
    +
    +  @Override
    +  protected List createApiClientHeaderProviderBuilderMethods(
    +      Service service, TypeStore typeStore) {
    +
    +    TypeNode returnType =
    +        TypeNode.withReference(ConcreteReference.withClazz(ApiClientHeaderProvider.Builder.class));
    +
    +    return ImmutableList.of(
    +        createApiClientHeaderProviderBuilderMethod(
    +            service,
    +            typeStore,
    +            "defaultGrpcApiClientHeaderProviderBuilder",
    +            TypeNode.withReference(ConcreteReference.withClazz(GaxGrpcProperties.class)),
    +            "getGrpcTokenName",
    +            "getGrpcVersion"),
    +        createApiClientHeaderProviderBuilderMethod(
    +            service,
    +            typeStore,
    +            "defaultHttpJsonApiClientHeaderProviderBuilder",
    +            TypeNode.withReference(ConcreteReference.withClazz(GaxHttpJsonProperties.class)),
    +            "getHttpJsonTokenName",
    +            "getHttpJsonVersion"),
    +        MethodDefinition.builder()
    +            .setScope(ScopeNode.PUBLIC)
    +            .setIsStatic(true)
    +            .setReturnType(returnType)
    +            .setName("defaultApiClientHeaderProviderBuilder")
    +            .setReturnExpr(
    +                MethodInvocationExpr.builder()
    +                    .setStaticReferenceType(
    +                        typeStore.get(ClassNames.getServiceStubSettingsClassName(service)))
    +                    .setMethodName("defaultGrpcApiClientHeaderProviderBuilder")
    +                    .setReturnType(returnType)
    +                    .build())
    +            .build());
    +  }
    +
    +  @Override
    +  public MethodDefinition createDefaultTransportChannelProviderMethod() {
    +    TypeNode returnType = FIXED_TYPESTORE.get("TransportChannelProvider");
    +    MethodInvocationExpr transportProviderBuilderExpr =
    +        MethodInvocationExpr.builder().setMethodName("defaultGrpcTransportProviderBuilder").build();
    +    transportProviderBuilderExpr =
    +        MethodInvocationExpr.builder()
    +            .setExprReferenceExpr(transportProviderBuilderExpr)
    +            .setMethodName("build")
    +            .setReturnType(returnType)
    +            .build();
    +    return MethodDefinition.builder()
    +        .setScope(ScopeNode.PUBLIC)
    +        .setIsStatic(true)
    +        .setReturnType(returnType)
    +        .setName("defaultTransportChannelProvider")
    +        .setReturnExpr(transportProviderBuilderExpr)
    +        .build();
    +  }
    +
    +  @Override
    +  protected List createNestedClassCreateDefaultMethods(TypeStore typeStore) {
    +    return ImmutableList.of(
    +        createNestedClassCreateDefaultMethod(
    +            typeStore,
    +            "createDefault",
    +            "defaultTransportChannelProvider",
    +            null,
    +            "defaultApiClientHeaderProviderBuilder"),
    +        createNestedClassCreateDefaultMethod(
    +            typeStore,
    +            "createHttpJsonDefault",
    +            null,
    +            "defaultHttpJsonTransportProviderBuilder",
    +            "defaultHttpJsonApiClientHeaderProviderBuilder"));
    +  }
    +
    +  @Override
    +  protected List createNewBuilderMethods(
    +      Service service,
    +      TypeStore typeStore,
    +      String newBuilderMethodName,
    +      String createDefaultMethodName) {
    +    List methods = new ArrayList<>();
    +    methods.addAll(
    +        super.createNewBuilderMethods(service, typeStore, "newBuilder", "createDefault"));
    +    methods.addAll(
    +        super.createNewBuilderMethods(
    +            service, typeStore, "newHttpJsonBuilder", "createHttpJsonDefault"));
    +    return methods;
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java
    index 7f8a966859..a7b525239e 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java
    @@ -27,13 +27,14 @@
     import com.google.api.generator.engine.ast.NewObjectExpr;
     import com.google.api.generator.engine.ast.Statement;
     import com.google.api.generator.engine.ast.TypeNode;
    +import com.google.api.generator.engine.ast.ValueExpr;
     import com.google.api.generator.engine.ast.VaporReference;
     import com.google.api.generator.engine.ast.Variable;
     import com.google.api.generator.engine.ast.VariableExpr;
     import com.google.api.generator.gapic.composer.common.AbstractServiceCallableFactoryClassComposer;
     import com.google.api.generator.gapic.composer.store.TypeStore;
     import com.google.api.generator.gapic.model.Service;
    -import com.google.longrunning.Operation;
    +import com.google.common.collect.ImmutableList;
     import java.util.ArrayList;
     import java.util.Arrays;
     import java.util.List;
    @@ -45,7 +46,7 @@ public class HttpJsonServiceCallableFactoryClassComposer
           new HttpJsonServiceCallableFactoryClassComposer();
     
       private static final TypeNode DEFAULT_OPERATION_TYPE =
    -      TypeNode.withReference(ConcreteReference.withClazz(Operation.class));
    +      TypeNode.withReference(ConcreteReference.withClazz(Object.class));
     
       private HttpJsonServiceCallableFactoryClassComposer() {
         super(RestContext.instance());
    @@ -127,7 +128,16 @@ protected MethodDefinition createOperationCallableMethod(Service service, TypeSt
                     .collect(Collectors.toList()),
                 Arrays.asList(betaAnnotation));
     
    -    List createOperationCallableBody = new ArrayList(2);
    +    List createOperationCallableBody = new ArrayList<>();
    +    if (service.operationServiceStubType() == null) {
    +      // It is an Operation polling service, it cannot contain LRO methods
    +      return method
    +          .toBuilder()
    +          .setBody(ImmutableList.of())
    +          .setReturnExpr(ValueExpr.createNullExpr())
    +          .build();
    +    }
    +
         List arguments = new ArrayList<>(method.arguments());
     
         Variable httpJsonCallSettingsVar = arguments.get(0).variable();
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java
    index 39974fe44a..fb45703936 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java
    @@ -49,8 +49,7 @@
     import com.google.api.generator.engine.ast.VaporReference;
     import com.google.api.generator.engine.ast.Variable;
     import com.google.api.generator.engine.ast.VariableExpr;
    -import com.google.api.generator.gapic.composer.common.AbstractServiceStubClassComposer;
    -import com.google.api.generator.gapic.composer.common.TransportContext;
    +import com.google.api.generator.gapic.composer.common.AbstractTransportServiceStubClassComposer;
     import com.google.api.generator.gapic.composer.store.TypeStore;
     import com.google.api.generator.gapic.model.HttpBindings.HttpBinding;
     import com.google.api.generator.gapic.model.Message;
    @@ -66,12 +65,13 @@
     import java.util.HashMap;
     import java.util.List;
     import java.util.Map;
    +import java.util.Optional;
     import java.util.Set;
     import java.util.function.BiFunction;
     import java.util.function.Function;
     import java.util.stream.Collectors;
     
    -public class HttpJsonServiceStubClassComposer extends AbstractServiceStubClassComposer {
    +public class HttpJsonServiceStubClassComposer extends AbstractTransportServiceStubClassComposer {
       private static final HttpJsonServiceStubClassComposer INSTANCE =
           new HttpJsonServiceStubClassComposer();
     
    @@ -101,6 +101,11 @@ private static TypeStore createStaticTypes() {
                 ProtoRestSerializer.class));
       }
     
    +  @Override
    +  protected boolean generateOperationsStubLogic(Service service) {
    +    return service.hasLroMethods();
    +  }
    +
       @Override
       protected Statement createMethodDescriptorVariableDecl(
           Service service,
    @@ -172,12 +177,11 @@ protected Statement createMethodDescriptorVariableDecl(
     
       @Override
       protected List createOperationsStubGetterMethod(
    -      VariableExpr operationsStubVarExpr) {
    -    return Collections.emptyList();
    -  }
    -
    -  public HttpJsonServiceStubClassComposer(TransportContext transportContext) {
    -    super(transportContext);
    +      Service service, VariableExpr operationsStubVarExpr) {
    +    if (!service.hasStandardLroMethods()) {
    +      return Collections.emptyList();
    +    }
    +    return super.createOperationsStubGetterMethod(service, operationsStubVarExpr);
       }
     
       @Override
    @@ -348,16 +352,20 @@ private List getRequestFormatterExpr(Method protoMethod) {
                 .apply(expr);
     
         extractorVarType = TypeNode.STRING;
    +    boolean asteriskBody = protoMethod.httpBindings().isAsteriskBody();
         expr =
             methodMaker
                 .apply(
                     "setRequestBodyExtractor",
                     Arrays.asList(
    -                    createFieldsExtractorClassInstance(
    +                    createBodyFieldsExtractorClassInstance(
                             protoMethod,
                             extractorVarType,
    -                        protoMethod.httpBindings().bodyParameters(),
    -                        "toBody")))
    +                        asteriskBody
    +                            ? protoMethod.httpBindings().pathParameters()
    +                            : protoMethod.httpBindings().bodyParameters(),
    +                        "toBody",
    +                        asteriskBody)))
                 .apply(expr);
         expr = methodMaker.apply("build", Collections.emptyList()).apply(expr);
     
    @@ -699,71 +707,148 @@ private List setPollingRequestFactoryExpr(
                 .build());
       }
     
    -  private Expr createFieldsExtractorClassInstance(
    +  private Expr createBodyFieldsExtractorClassInstance(
           Method method,
           TypeNode extractorReturnType,
           Set httpBindingFieldNames,
    -      String serializerMethodName) {
    +      String serializerMethodName,
    +      boolean asteriskBody) {
         List bodyStatements = new ArrayList<>();
     
         Expr returnExpr = null;
    -    VariableExpr fieldsVarExpr = null;
    -    Expr serializerExpr = null;
    -    if (extractorReturnType.isProtoPrimitiveType()) {
    -      serializerExpr =
    +    Expr serializerExpr =
    +        MethodInvocationExpr.builder()
    +            .setMethodName("create")
    +            .setStaticReferenceType(
    +                FIXED_REST_TYPESTORE.get(ProtoRestSerializer.class.getSimpleName()))
    +            .build();
    +
    +    VariableExpr requestVarExpr =
    +        VariableExpr.withVariable(
    +            Variable.builder().setType(method.inputType()).setName("request").build());
    +    Expr bodyRequestExpr = requestVarExpr;
    +    String requestMethodPrefix = "get";
    +    String bodyParamName = null;
    +
    +    if (asteriskBody) {
    +      bodyRequestExpr =
               MethodInvocationExpr.builder()
    -              .setMethodName("create")
    -              .setStaticReferenceType(
    -                  FIXED_REST_TYPESTORE.get(ProtoRestSerializer.class.getSimpleName()))
    +              .setExprReferenceExpr(requestVarExpr)
    +              .setMethodName("toBuilder")
                   .build();
    -      if (httpBindingFieldNames.isEmpty()) {
    -        returnExpr = ValueExpr.createNullExpr();
    +      // In case of `body: "*"` case we send the whole request message as a body, minus the fields
    +      // in the path, therefore the "clear" prefix here.
    +      requestMethodPrefix = "clear";
    +    }
    +
    +    Expr prevExpr = bodyRequestExpr;
    +    for (HttpBinding httpBindingFieldName : httpBindingFieldNames) {
    +      // Handle foo.bar cases by descending into the subfields.
    +      MethodInvocationExpr.Builder requestFieldMethodExprBuilder =
    +          MethodInvocationExpr.builder().setExprReferenceExpr(prevExpr);
    +      bodyParamName = JavaStyle.toLowerCamelCase(httpBindingFieldName.name());
    +      String[] descendantFields = httpBindingFieldName.name().split("\\.");
    +      if (asteriskBody && descendantFields.length > 1) {
    +        // This is the `body: "*"` case, do not clean nested body fields as it a very rare, not
    +        // well-defined case, and it is generally safer to send more than less in such case.
    +        continue;
           }
     
    +      for (int i = 0; i < descendantFields.length; i++) {
    +        String currFieldName = descendantFields[i];
    +        String bindingFieldMethodName =
    +            String.format("%s%s", requestMethodPrefix, JavaStyle.toUpperCamelCase(currFieldName));
    +        requestFieldMethodExprBuilder =
    +            requestFieldMethodExprBuilder.setMethodName(bindingFieldMethodName);
    +
    +        if (i < descendantFields.length - 1) {
    +          requestFieldMethodExprBuilder =
    +              MethodInvocationExpr.builder()
    +                  .setExprReferenceExpr(requestFieldMethodExprBuilder.build());
    +        }
    +      }
    +      prevExpr = requestFieldMethodExprBuilder.build();
    +    }
    +
    +    if (httpBindingFieldNames.isEmpty() && !asteriskBody) {
    +      returnExpr = ValueExpr.createNullExpr();
         } else {
    -      fieldsVarExpr =
    -          VariableExpr.withVariable(
    -              Variable.builder().setName("fields").setType(extractorReturnType).build());
    -      Expr fieldsAssignExpr =
    -          AssignmentExpr.builder()
    -              .setVariableExpr(fieldsVarExpr.toBuilder().setIsDecl(true).build())
    -              .setValueExpr(
    -                  NewObjectExpr.builder()
    -                      .setType(FIXED_REST_TYPESTORE.get(HashMap.class.getSimpleName()))
    -                      .setIsGeneric(true)
    -                      .build())
    +      ImmutableList.Builder paramsPutArgs = ImmutableList.builder();
    +      if (asteriskBody) {
    +        prevExpr =
    +            MethodInvocationExpr.builder()
    +                .setExprReferenceExpr(prevExpr)
    +                .setMethodName("build")
    +                .build();
    +        bodyParamName = "*";
    +      }
    +      paramsPutArgs.add(ValueExpr.withValue(StringObjectValue.withValue(bodyParamName)));
    +      paramsPutArgs.add(prevExpr);
    +
    +      returnExpr =
    +          MethodInvocationExpr.builder()
    +              .setExprReferenceExpr(serializerExpr)
    +              .setMethodName(serializerMethodName)
    +              .setArguments(paramsPutArgs.build())
    +              .setReturnType(extractorReturnType)
                   .build();
    +    }
    +
    +    // Overrides FieldsExtractor
    +    // (https://github.com/googleapis/gax-java/blob/12b18ee255d3fabe13bb3969df40753b29f830d5/gax-httpjson/src/main/java/com/google/api/gax/httpjson/FieldsExtractor.java).
    +    return LambdaExpr.builder()
    +        .setArguments(requestVarExpr.toBuilder().setIsDecl(true).build())
    +        .setBody(bodyStatements)
    +        .setReturnExpr(returnExpr)
    +        .build();
    +  }
     
    -      bodyStatements.add(ExprStatement.withExpr(fieldsAssignExpr));
    -      returnExpr = fieldsVarExpr;
    +  private Expr createFieldsExtractorClassInstance(
    +      Method method,
    +      TypeNode extractorReturnType,
    +      Set httpBindingFieldNames,
    +      String serializerMethodName) {
    +    List bodyStatements = new ArrayList<>();
     
    -      TypeNode serializerVarType =
    -          TypeNode.withReference(
    -              ConcreteReference.builder()
    -                  .setClazz(ProtoRestSerializer.class)
    -                  .setGenerics(method.inputType().reference())
    -                  .build());
    +    VariableExpr fieldsVarExpr =
    +        VariableExpr.withVariable(
    +            Variable.builder().setName("fields").setType(extractorReturnType).build());
    +    Expr fieldsAssignExpr =
    +        AssignmentExpr.builder()
    +            .setVariableExpr(fieldsVarExpr.toBuilder().setIsDecl(true).build())
    +            .setValueExpr(
    +                NewObjectExpr.builder()
    +                    .setType(FIXED_REST_TYPESTORE.get(HashMap.class.getSimpleName()))
    +                    .setIsGeneric(true)
    +                    .build())
    +            .build();
     
    -      VariableExpr serializerVarExpr =
    -          VariableExpr.withVariable(
    -              Variable.builder().setName("serializer").setType(serializerVarType).build());
    +    bodyStatements.add(ExprStatement.withExpr(fieldsAssignExpr));
     
    -      Expr serializerAssignExpr =
    -          AssignmentExpr.builder()
    -              .setVariableExpr(serializerVarExpr.toBuilder().setIsDecl(true).build())
    -              .setValueExpr(
    -                  MethodInvocationExpr.builder()
    -                      .setStaticReferenceType(
    -                          FIXED_REST_TYPESTORE.get(ProtoRestSerializer.class.getSimpleName()))
    -                      .setMethodName("create")
    -                      .setReturnType(serializerVarType)
    -                      .build())
    -              .build();
    +    TypeNode serializerVarType =
    +        TypeNode.withReference(
    +            ConcreteReference.builder()
    +                .setClazz(ProtoRestSerializer.class)
    +                .setGenerics(method.inputType().reference())
    +                .build());
     
    -      serializerExpr = serializerVarExpr;
    +    VariableExpr serializerVarExpr =
    +        VariableExpr.withVariable(
    +            Variable.builder().setName("serializer").setType(serializerVarType).build());
     
    -      bodyStatements.add(ExprStatement.withExpr(serializerAssignExpr));
    -    }
    +    Expr serializerAssignExpr =
    +        AssignmentExpr.builder()
    +            .setVariableExpr(serializerVarExpr.toBuilder().setIsDecl(true).build())
    +            .setValueExpr(
    +                MethodInvocationExpr.builder()
    +                    .setStaticReferenceType(
    +                        FIXED_REST_TYPESTORE.get(ProtoRestSerializer.class.getSimpleName()))
    +                    .setMethodName("create")
    +                    .setReturnType(serializerVarType)
    +                    .build())
    +            .build();
    +
    +    bodyStatements.add(ExprStatement.withExpr(serializerAssignExpr));
     
         VariableExpr requestVarExpr =
             VariableExpr.withVariable(
    @@ -806,9 +891,9 @@ private Expr createFieldsExtractorClassInstance(
           MethodInvocationExpr requestHasExpr = requestFieldHasExprBuilder.build();
     
           ImmutableList.Builder paramsPutArgs = ImmutableList.builder();
    -      if (fieldsVarExpr != null) {
    -        paramsPutArgs.add(fieldsVarExpr);
    -      }
    +
    +      paramsPutArgs.add(fieldsVarExpr);
    +
           paramsPutArgs.add(
               ValueExpr.withValue(
                   StringObjectValue.withValue(
    @@ -817,24 +902,20 @@ private Expr createFieldsExtractorClassInstance(
     
           Expr paramsPutExpr =
               MethodInvocationExpr.builder()
    -              .setExprReferenceExpr(serializerExpr)
    +              .setExprReferenceExpr(serializerVarExpr)
                   .setMethodName(serializerMethodName)
                   .setArguments(paramsPutArgs.build())
                   .setReturnType(extractorReturnType)
                   .build();
     
    -      if (fieldsVarExpr == null) {
    -        returnExpr = paramsPutExpr;
    +      if (httpBindingFieldName.isOptional()) {
    +        bodyStatements.add(
    +            IfStatement.builder()
    +                .setConditionExpr(requestHasExpr)
    +                .setBody(Arrays.asList(ExprStatement.withExpr(paramsPutExpr)))
    +                .build());
           } else {
    -        if (httpBindingFieldName.isOptional()) {
    -          bodyStatements.add(
    -              IfStatement.builder()
    -                  .setConditionExpr(requestHasExpr)
    -                  .setBody(Arrays.asList(ExprStatement.withExpr(paramsPutExpr)))
    -                  .build());
    -        } else {
    -          bodyStatements.add(ExprStatement.withExpr(paramsPutExpr));
    -        }
    +        bodyStatements.add(ExprStatement.withExpr(paramsPutExpr));
           }
         }
     
    @@ -843,7 +924,7 @@ private Expr createFieldsExtractorClassInstance(
         return LambdaExpr.builder()
             .setArguments(requestVarExpr.toBuilder().setIsDecl(true).build())
             .setBody(bodyStatements)
    -        .setReturnExpr(returnExpr)
    +        .setReturnExpr(fieldsVarExpr)
             .build();
       }
     
    @@ -942,24 +1023,25 @@ protected VariableExpr declareLongRunningClient() {
                 .build());
       }
     
    -  @Override
    -  protected List createLongRunningClientGetter() {
    -    VariableExpr longRunningClient =
    -        VariableExpr.withVariable(
    -            Variable.builder()
    -                .setName("longRunningClient")
    -                .setType(
    -                    TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class)))
    -                .build());
    +  protected Optional getCallableCreatorMethodName(TypeNode callableVarExprType) {
    +    final String typeName = callableVarExprType.reference().name();
    +    String streamName = "Unary";
     
    -    return ImmutableList.of(
    -        MethodDefinition.builder()
    -            .setName("longRunningClient")
    -            .setScope(ScopeNode.PUBLIC)
    -            .setIsOverride(true)
    -            .setReturnType(
    -                TypeNode.withReference(ConcreteReference.withClazz(LongRunningClient.class)))
    -            .setReturnExpr(longRunningClient)
    -            .build());
    +    // Special handling for pagination methods.
    +    if (callableVarExprType.reference().generics().size() == 2
    +        && callableVarExprType.reference().generics().get(1).name().endsWith("PagedResponse")) {
    +      streamName = "Paged";
    +    } else {
    +      if (typeName.startsWith("Client")) {
    +        return Optional.empty(); // not supported in REST transport
    +      } else if (typeName.startsWith("Server")) {
    +        return Optional.empty(); // not supported in REST transport (for now)
    +      } else if (typeName.startsWith("Bidi")) {
    +        return Optional.empty(); // not supported in REST transport
    +      } else if (typeName.startsWith("Operation")) {
    +        streamName = "Operation";
    +      }
    +    }
    +    return Optional.of(String.format("create%sCallable", streamName));
       }
     }
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java b/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java
    index fc5b385427..eab59215bf 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java
    @@ -21,9 +21,13 @@
     import com.google.api.gax.httpjson.HttpJsonStubCallableFactory;
     import com.google.api.gax.httpjson.HttpJsonTransportChannel;
     import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider;
    +import com.google.api.gax.httpjson.ProtoOperationTransformers;
    +import com.google.api.gax.httpjson.longrunning.OperationsClient;
    +import com.google.api.gax.httpjson.longrunning.stub.HttpJsonOperationsStub;
     import com.google.api.generator.gapic.composer.common.TransportContext;
     import com.google.api.generator.gapic.composer.utils.ClassNames;
     import com.google.api.generator.gapic.model.Transport;
    +import com.google.common.collect.ImmutableList;
     
     public abstract class RestContext extends TransportContext {
       private static final TransportContext INSTANCE =
    @@ -35,18 +39,35 @@ public abstract class RestContext extends TransportContext {
               .setCallSettingsClass(HttpJsonCallSettings.class)
               .setStubCallableFactoryType(classToType(HttpJsonStubCallableFactory.class))
               .setMethodDescriptorClass(ApiMethodDescriptor.class)
    -          .setTransportOperationsStubType(null)
    +          .setTransportOperationsStubTypes(
    +              ImmutableList.of(classToType(HttpJsonOperationsStub.class)))
    +          .setTransportOperationsStubNames(ImmutableList.of("httpJsonOperationsStub"))
               // For httpjson.ServiceSettingsClassComposer
    -          .setInstantiatingChannelProviderClass(InstantiatingHttpJsonChannelProvider.Builder.class)
    -          .setDefaultTransportProviderBuilderName("defaultHttpJsonTransportProviderBuilder")
    +          .setInstantiatingChannelProviderClasses(
    +              ImmutableList.of(InstantiatingHttpJsonChannelProvider.class))
    +          .setInstantiatingChannelProviderBuilderClasses(
    +              ImmutableList.of(InstantiatingHttpJsonChannelProvider.Builder.class))
    +          .setDefaultTransportProviderBuilderNames(
    +              ImmutableList.of("defaultHttpJsonTransportProviderBuilder"))
    +          .setTransportApiClientHeaderProviderBuilderNames(
    +              ImmutableList.of("defaultHttpJsonApiClientHeaderProviderBuilder"))
               // For httpjson.ServiceStubSettingsClassComposer
    -          .setTransportChannelType(classToType(HttpJsonTransportChannel.class))
    -          .setTransportGetterName("getHttpJsonTransportName")
    +          .setTransportChannelTypes(ImmutableList.of(classToType(HttpJsonTransportChannel.class)))
    +          .setTransportGetterNames(ImmutableList.of("getHttpJsonTransportName"))
               // For httpjson.HttpJsonServiceCallableFactoryClassComposer
               .setTransportCallSettingsType(classToType(HttpJsonCallSettings.class))
               .setTransportCallableFactoryType(classToType(HttpJsonCallableFactory.class))
    -          .setOperationsStubType(classToType(BackgroundResource.class))
    +          // TODO: set to com.google.api.gax.httpjson.longrunning.stub.OperationsStub.class
    +          .setOperationsStubTypes(ImmutableList.of(classToType(BackgroundResource.class)))
               .setTransportCallSettingsName("httpJsonCallSettings")
    +          // For RetrySettingsComposer
    +          .setOperationResponseTransformerType(
    +              classToType(ProtoOperationTransformers.ResponseTransformer.class))
    +          .setOperationMetadataTransformerType(
    +              classToType(ProtoOperationTransformers.MetadataTransformer.class))
    +          // For ServiceClientClassComposer
    +          .setOperationsClientTypes(ImmutableList.of(classToType(OperationsClient.class)))
    +          .setOperationsClientNames(ImmutableList.of("httpJsonOperationsClient"))
               .build();
     
       public static TransportContext instance() {
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceClientClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceClientClassComposer.java
    new file mode 100644
    index 0000000000..9b5f996db7
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceClientClassComposer.java
    @@ -0,0 +1,30 @@
    +/*
    + * Copyright 2021 Google LLC
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + *     https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package com.google.api.generator.gapic.composer.rest;
    +
    +import com.google.api.generator.gapic.composer.common.AbstractServiceClientClassComposer;
    +
    +public class ServiceClientClassComposer extends AbstractServiceClientClassComposer {
    +  private static final ServiceClientClassComposer INSTANCE = new ServiceClientClassComposer();
    +
    +  protected ServiceClientClassComposer() {
    +    super(RestContext.instance());
    +  }
    +
    +  public static ServiceClientClassComposer instance() {
    +    return INSTANCE;
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceClientTestClassComposer.java
    index 5eed17f8f2..893777e057 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceClientTestClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceClientTestClassComposer.java
    @@ -39,6 +39,7 @@
     import com.google.api.generator.engine.ast.Variable;
     import com.google.api.generator.engine.ast.VariableExpr;
     import com.google.api.generator.gapic.composer.common.AbstractServiceClientTestClassComposer;
    +import com.google.api.generator.gapic.composer.defaultvalue.DefaultValueComposer;
     import com.google.api.generator.gapic.composer.store.TypeStore;
     import com.google.api.generator.gapic.composer.utils.ClassNames;
     import com.google.api.generator.gapic.model.GapicContext;
    @@ -72,7 +73,7 @@ protected ServiceClientTestClassComposer() {
         super(RestContext.instance());
       }
     
    -  public static ServiceClientTestClassComposer instance() {
    +  public static AbstractServiceClientTestClassComposer instance() {
         return INSTANCE;
       }
     
    @@ -125,7 +126,8 @@ protected MethodDefinition createStartStaticServerMethod(
           Service service,
           GapicContext context,
           Map classMemberVarExprs,
    -      TypeStore typeStore) {
    +      TypeStore typeStore,
    +      String newBuilderMethod) {
     
         VariableExpr mockServiceVarExpr = classMemberVarExprs.get(MOCK_SERVICE_VAR_NAME);
         VariableExpr clientVarExpr = classMemberVarExprs.get(CLIENT_VAR_NAME);
    @@ -167,7 +169,7 @@ protected MethodDefinition createStartStaticServerMethod(
         Expr settingsBuilderExpr =
             MethodInvocationExpr.builder()
                 .setStaticReferenceType(settingsType)
    -            .setMethodName("newBuilder")
    +            .setMethodName(newBuilderMethod)
                 .build();
     
         Expr transportChannelProviderExpr =
    @@ -420,7 +422,18 @@ protected MethodDefinition createStreamingRpcTestMethod(
           Map classMemberVarExprs,
           Map resourceNames,
           Map messageTypes) {
    -    return null;
    +    // Add some actual statements once implemented
    +    List methodStatements = new ArrayList<>();
    +
    +    String testMethodName = String.format("%sTest", JavaStyle.toLowerCamelCase(method.name()));
    +    return MethodDefinition.builder()
    +        .setAnnotations(Arrays.asList(TEST_ANNOTATION))
    +        .setScope(ScopeNode.PUBLIC)
    +        .setReturnType(TypeNode.VOID)
    +        .setName(testMethodName)
    +        .setThrowsExceptions(Arrays.asList(TypeNode.withExceptionClazz(Exception.class)))
    +        .setBody(methodStatements)
    +        .build();
       }
     
       @Override
    @@ -513,6 +526,12 @@ protected List createStreamingRpcExceptionTestStatements(
         return Collections.emptyList();
       }
     
    +  @Override
    +  protected Expr createDefaultValue(
    +      MethodArgument methodArg, Map resourceNames) {
    +    return DefaultValueComposer.createDefaultValue(methodArg, resourceNames, true);
    +  }
    +
       @Override
       protected List createRpcLroExceptionTestCatchBody(
           VariableExpr exceptionExpr, boolean isStreaming) {
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceStubClassComposer.java
    new file mode 100644
    index 0000000000..704fac96b6
    --- /dev/null
    +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceStubClassComposer.java
    @@ -0,0 +1,30 @@
    +/*
    + * Copyright 2021 Google LLC
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + *     https://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +package com.google.api.generator.gapic.composer.rest;
    +
    +import com.google.api.generator.gapic.composer.common.AbstractServiceStubClassComposer;
    +
    +public class ServiceStubClassComposer extends AbstractServiceStubClassComposer {
    +  private static final ServiceStubClassComposer INSTANCE = new ServiceStubClassComposer();
    +
    +  protected ServiceStubClassComposer() {
    +    super(RestContext.instance());
    +  }
    +
    +  public static ServiceStubClassComposer instance() {
    +    return INSTANCE;
    +  }
    +}
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposer.java
    index 9375399546..b12528ec3f 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposer.java
    @@ -17,23 +17,16 @@
     import com.google.api.gax.httpjson.GaxHttpJsonProperties;
     import com.google.api.gax.httpjson.HttpJsonTransportChannel;
     import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider;
    -import com.google.api.gax.rpc.ApiClientHeaderProvider;
    -import com.google.api.generator.engine.ast.AnnotationNode;
    -import com.google.api.generator.engine.ast.ConcreteReference;
     import com.google.api.generator.engine.ast.MethodDefinition;
     import com.google.api.generator.engine.ast.MethodInvocationExpr;
     import com.google.api.generator.engine.ast.ScopeNode;
    -import com.google.api.generator.engine.ast.StringObjectValue;
     import com.google.api.generator.engine.ast.TypeNode;
    -import com.google.api.generator.engine.ast.ValueExpr;
    -import com.google.api.generator.engine.ast.Variable;
    -import com.google.api.generator.engine.ast.VariableExpr;
    -import com.google.api.generator.gapic.composer.comment.SettingsCommentComposer;
     import com.google.api.generator.gapic.composer.common.AbstractServiceStubSettingsClassComposer;
     import com.google.api.generator.gapic.composer.store.TypeStore;
    -import com.google.api.generator.gapic.composer.utils.ClassNames;
     import com.google.api.generator.gapic.model.Service;
     import java.util.Arrays;
    +import java.util.Collections;
    +import java.util.List;
     
     public class ServiceStubSettingsClassComposer extends AbstractServiceStubSettingsClassComposer {
       private static final ServiceStubSettingsClassComposer INSTANCE =
    @@ -58,94 +51,16 @@ private static TypeStore createStaticTypes() {
       }
     
       @Override
    -  protected MethodDefinition createDefaultTransportTransportProviderBuilderMethod() {
    -    // Create the defaultHttpJsonTransportProviderBuilder method.
    -    TypeNode returnType =
    -        TypeNode.withReference(
    -            ConcreteReference.withClazz(InstantiatingHttpJsonChannelProvider.Builder.class));
    -    MethodInvocationExpr transportChannelProviderBuilderExpr =
    -        MethodInvocationExpr.builder()
    -            .setStaticReferenceType(
    -                FIXED_REST_TYPESTORE.get(
    -                    InstantiatingHttpJsonChannelProvider.class.getSimpleName()))
    -            .setMethodName("newBuilder")
    -            .setReturnType(returnType)
    -            .build();
    -    return MethodDefinition.builder()
    -        .setHeaderCommentStatements(
    -            SettingsCommentComposer.DEFAULT_TRANSPORT_PROVIDER_BUILDER_METHOD_COMMENT)
    -        .setScope(ScopeNode.PUBLIC)
    -        .setIsStatic(true)
    -        .setReturnType(returnType)
    -        .setName("defaultHttpJsonTransportProviderBuilder")
    -        .setReturnExpr(transportChannelProviderBuilderExpr)
    -        .build();
    -  }
    -
    -  @Override
    -  protected MethodDefinition createDefaultApiClientHeaderProviderBuilderMethod(
    +  protected List createApiClientHeaderProviderBuilderMethods(
           Service service, TypeStore typeStore) {
    -    // Create the defaultApiClientHeaderProviderBuilder method.
    -    TypeNode returnType =
    -        TypeNode.withReference(ConcreteReference.withClazz(ApiClientHeaderProvider.Builder.class));
    -    MethodInvocationExpr returnExpr =
    -        MethodInvocationExpr.builder()
    -            .setStaticReferenceType(FIXED_TYPESTORE.get("ApiClientHeaderProvider"))
    -            .setMethodName("newBuilder")
    -            .build();
    -
    -    MethodInvocationExpr versionArgExpr =
    -        MethodInvocationExpr.builder()
    -            .setStaticReferenceType(FIXED_TYPESTORE.get("GaxProperties"))
    -            .setMethodName("getLibraryVersion")
    -            .setArguments(
    -                VariableExpr.builder()
    -                    .setVariable(
    -                        Variable.builder().setType(TypeNode.CLASS_OBJECT).setName("class").build())
    -                    .setStaticReferenceType(
    -                        typeStore.get(ClassNames.getServiceStubSettingsClassName(service)))
    -                    .build())
    -            .build();
    -
    -    returnExpr =
    -        MethodInvocationExpr.builder()
    -            .setExprReferenceExpr(returnExpr)
    -            .setMethodName("setGeneratedLibToken")
    -            .setArguments(ValueExpr.withValue(StringObjectValue.withValue("gapic")), versionArgExpr)
    -            .build();
    -    returnExpr =
    -        MethodInvocationExpr.builder()
    -            .setExprReferenceExpr(returnExpr)
    -            .setMethodName("setTransportToken")
    -            .setArguments(
    -                MethodInvocationExpr.builder()
    -                    .setStaticReferenceType(
    -                        FIXED_REST_TYPESTORE.get(GaxHttpJsonProperties.class.getSimpleName()))
    -                    .setMethodName("getHttpJsonTokenName")
    -                    .build(),
    -                MethodInvocationExpr.builder()
    -                    .setStaticReferenceType(
    -                        FIXED_REST_TYPESTORE.get(GaxHttpJsonProperties.class.getSimpleName()))
    -                    .setMethodName("getHttpJsonVersion")
    -                    .build())
    -            .setReturnType(returnType)
    -            .build();
    -
    -    AnnotationNode annotation =
    -        AnnotationNode.builder()
    -            .setType(FIXED_TYPESTORE.get("BetaApi"))
    -            .setDescription(
    -                "The surface for customizing headers is not stable yet and may change in the"
    -                    + " future.")
    -            .build();
    -    return MethodDefinition.builder()
    -        .setAnnotations(Arrays.asList(annotation))
    -        .setScope(ScopeNode.PUBLIC)
    -        .setIsStatic(true)
    -        .setReturnType(returnType)
    -        .setName("defaultApiClientHeaderProviderBuilder")
    -        .setReturnExpr(returnExpr)
    -        .build();
    +    return Collections.singletonList(
    +        createApiClientHeaderProviderBuilderMethod(
    +            service,
    +            typeStore,
    +            "defaultApiClientHeaderProviderBuilder",
    +            FIXED_REST_TYPESTORE.get(GaxHttpJsonProperties.class.getSimpleName()),
    +            "getHttpJsonTokenName",
    +            "getHttpJsonVersion"));
       }
     
       @Override
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposer.java b/src/main/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposer.java
    index ac8d805b59..5572bde8e3 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposer.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposer.java
    @@ -1310,7 +1310,7 @@ private static List createRpcMethodArgumentDefaultValueExprs(
             .map(
                 arg ->
                     !isStringTypedResourceName(arg, resourceNames)
    -                    ? DefaultValueComposer.createDefaultValue(arg, resourceNames)
    +                    ? DefaultValueComposer.createDefaultValue(arg, resourceNames, false)
                         : stringResourceNameDefaultValueExpr.apply(arg))
             .collect(Collectors.toList());
       }
    diff --git a/src/main/java/com/google/api/generator/gapic/composer/utils/ClassNames.java b/src/main/java/com/google/api/generator/gapic/composer/utils/ClassNames.java
    index f1abb45a4c..c0b717fc0a 100644
    --- a/src/main/java/com/google/api/generator/gapic/composer/utils/ClassNames.java
    +++ b/src/main/java/com/google/api/generator/gapic/composer/utils/ClassNames.java
    @@ -15,6 +15,9 @@
     package com.google.api.generator.gapic.composer.utils;
     
     import com.google.api.generator.gapic.model.Service;
    +import java.util.Arrays;
    +import java.util.List;
    +import java.util.stream.Collectors;
     
     /** Provides Gapic class names. */
     public class ClassNames {
    @@ -23,6 +26,7 @@ public class ClassNames {
       private static final String MOCK_SERVICE_IMPL_CLASS_NAME_PATTERN = "Mock%sImpl";
       private static final String SERVICE_CLIENT_CLASS_NAME_PATTERN = "%sClient";
       private static final String SERVICE_CLIENT_TEST_CLASS_NAME_PATTERN = "%sClientTest";
    +  private static final String SERVICE_CLIENT_TRANSPORT_TEST_CLASS_NAME_PATTERN = "%sClient%sTest";
       private static final String SERVICE_SETTINGS_CLASS_NAME_PATTERN = "%sSettings";
       private static final String SERVICE_STUB_SETTINGS_CLASS_NAME_PATTERN = "%sStubSettings";
       private static final String SERVICE_STUB_CLASS_NAME_PATTERN = "%sStub";
    @@ -30,10 +34,10 @@ public class ClassNames {
       private static final String TRANSPORT_SERVICE_CALLABLE_FACTORY_CLASS_NAME_PATTERN =
           "%s%sCallableFactory";
     
    -  private final String transportPrefix;
    +  private final List transportPrefixes;
     
    -  public ClassNames(String transportPrefix) {
    -    this.transportPrefix = transportPrefix;
    +  public ClassNames(String... transportPrefixes) {
    +    this.transportPrefixes = Arrays.asList(transportPrefixes);
       }
     
       public static String getServiceClientClassName(Service service) {
    @@ -59,23 +63,50 @@ public static String getServiceStubClassName(Service service) {
       }
     
       public String getTransportServiceCallableFactoryClassName(Service service) {
    -    return String.format(
    -        TRANSPORT_SERVICE_CALLABLE_FACTORY_CLASS_NAME_PATTERN,
    -        transportPrefix,
    -        monolithBackwardsCompatibleName(service.name()));
    +    return getTransportServiceCallableFactoryClassNames(service).get(0);
    +  }
    +
    +  public List getTransportServiceCallableFactoryClassNames(Service service) {
    +    return transportPrefixes.stream()
    +        .map(
    +            prefix ->
    +                String.format(
    +                    TRANSPORT_SERVICE_CALLABLE_FACTORY_CLASS_NAME_PATTERN,
    +                    prefix,
    +                    monolithBackwardsCompatibleName(service.name())))
    +        .collect(Collectors.toList());
       }
     
       public String getTransportServiceStubClassName(Service service) {
    -    return String.format(
    -        TRANSPORT_SERVICE_STUB_CLASS_NAME_PATTERN,
    -        transportPrefix,
    -        monolithBackwardsCompatibleName(service.name()));
    +    return getTransportServiceStubClassNames(service).get(0);
    +  }
    +
    +  public List getTransportServiceStubClassNames(Service service) {
    +    return transportPrefixes.stream()
    +        .map(
    +            prefix ->
    +                String.format(
    +                    TRANSPORT_SERVICE_STUB_CLASS_NAME_PATTERN,
    +                    prefix,
    +                    monolithBackwardsCompatibleName(service.name())))
    +        .collect(Collectors.toList());
       }
     
       public static String getServiceClientTestClassName(Service service) {
         return String.format(SERVICE_CLIENT_TEST_CLASS_NAME_PATTERN, service.overriddenName());
       }
     
    +  public List getServiceClientTestClassNames(Service service) {
    +    return transportPrefixes.stream()
    +        .map(
    +            prefix ->
    +                String.format(
    +                    SERVICE_CLIENT_TRANSPORT_TEST_CLASS_NAME_PATTERN,
    +                    service.overriddenName(),
    +                    prefix))
    +        .collect(Collectors.toList());
    +  }
    +
       public static String getMockServiceClassName(Service service) {
         return String.format(MOCK_SERVICE_CLASS_NAME_PATTERN, service.name());
       }
    diff --git a/src/main/java/com/google/api/generator/gapic/model/HttpBindings.java b/src/main/java/com/google/api/generator/gapic/model/HttpBindings.java
    index 9ca67cf4c7..171f6b1bf7 100644
    --- a/src/main/java/com/google/api/generator/gapic/model/HttpBindings.java
    +++ b/src/main/java/com/google/api/generator/gapic/model/HttpBindings.java
    @@ -57,6 +57,8 @@ public int compareTo(HttpBinding o) {
     
       public abstract Set bodyParameters();
     
    +  public abstract boolean isAsteriskBody();
    +
       public static HttpBindings.Builder builder() {
         return new AutoValue_HttpBindings.Builder()
             .setPathParameters(ImmutableSet.of())
    @@ -93,6 +95,8 @@ public abstract static class Builder {
     
         public abstract HttpBindings.Builder setBodyParameters(Set bodyParameters);
     
    +    public abstract HttpBindings.Builder setIsAsteriskBody(boolean asteriskBody);
    +
         public abstract HttpBindings autoBuild();
     
         public HttpBindings build() {
    diff --git a/src/main/java/com/google/api/generator/gapic/model/Service.java b/src/main/java/com/google/api/generator/gapic/model/Service.java
    index ace91051bc..34d3f97b25 100644
    --- a/src/main/java/com/google/api/generator/gapic/model/Service.java
    +++ b/src/main/java/com/google/api/generator/gapic/model/Service.java
    @@ -79,6 +79,24 @@ public TypeNode operationType() {
         return null;
       }
     
    +  public boolean hasLroMethods() {
    +    for (Method method : methods()) {
    +      if (method.hasLro()) {
    +        return true;
    +      }
    +    }
    +    return false;
    +  }
    +
    +  public boolean hasStandardLroMethods() {
    +    for (Method method : methods()) {
    +      if (method.hasLro() && method.lro().operationServiceStubType() == null) {
    +        return true;
    +      }
    +    }
    +    return false;
    +  }
    +
       public abstract Builder toBuilder();
     
       public static Builder builder() {
    diff --git a/src/main/java/com/google/api/generator/gapic/model/Transport.java b/src/main/java/com/google/api/generator/gapic/model/Transport.java
    index aeb7b9361c..ae7820c8ed 100644
    --- a/src/main/java/com/google/api/generator/gapic/model/Transport.java
    +++ b/src/main/java/com/google/api/generator/gapic/model/Transport.java
    @@ -17,8 +17,6 @@
     public enum Transport {
       REST,
       GRPC,
    -  // Never used in the context as is, must be split into two contexts (REST and GRPC respectively)
    -  // instead.
       GRPC_REST;
     
       /**
    diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/HttpRuleParser.java b/src/main/java/com/google/api/generator/gapic/protoparser/HttpRuleParser.java
    index 26629949ef..36828206d3 100644
    --- a/src/main/java/com/google/api/generator/gapic/protoparser/HttpRuleParser.java
    +++ b/src/main/java/com/google/api/generator/gapic/protoparser/HttpRuleParser.java
    @@ -104,6 +104,7 @@ private static HttpBindings parseHttpRuleHelper(
                 validateAndConstructHttpBindings(queryParamNames, message, messageTypes, false))
             .setBodyParameters(
                 validateAndConstructHttpBindings(bodyParamNames, message, messageTypes, false))
    +        .setIsAsteriskBody(body.equals(ASTERISK))
             .build();
       }
     
    diff --git a/src/test/java/com/google/api/generator/gapic/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/BUILD.bazel
    index 40de9b259f..5c5f8983ad 100644
    --- a/src/test/java/com/google/api/generator/gapic/BUILD.bazel
    +++ b/src/test/java/com/google/api/generator/gapic/BUILD.bazel
    @@ -6,6 +6,7 @@ filegroup(
             "//src/test/java/com/google/api/generator/gapic/composer:composer_files",
             "//src/test/java/com/google/api/generator/gapic/composer/defaultvalue:defaultvalue_files",
             "//src/test/java/com/google/api/generator/gapic/composer/grpc:grpc_files",
    +        #        "//src/test/java/com/google/api/generator/gapic/composer/grpcrest:grpcrest_files",
             "//src/test/java/com/google/api/generator/gapic/composer/resourcename:resourcename_files",
             "//src/test/java/com/google/api/generator/gapic/composer/rest:rest_files",
             "//src/test/java/com/google/api/generator/gapic/composer/samplecode:samplecode_files",
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/composer/common/BUILD.bazel
    index 159c97d9b1..28a4bfc8b4 100644
    --- a/src/test/java/com/google/api/generator/gapic/composer/common/BUILD.bazel
    +++ b/src/test/java/com/google/api/generator/gapic/composer/common/BUILD.bazel
    @@ -5,8 +5,6 @@ package(default_visibility = ["//visibility:public"])
     
     UPDATE_GOLDENS_TESTS = [
         "BatchingDescriptorComposerTest",
    -    "ServiceClientClassComposerTest",
    -    "ServiceStubClassComposerTest",
     ]
     
     TESTS = UPDATE_GOLDENS_TESTS + [
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposerTest.java
    index 09b1bf5b1c..d3fa5aa2e9 100644
    --- a/src/test/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposerTest.java
    +++ b/src/test/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposerTest.java
    @@ -27,6 +27,7 @@
     import com.google.api.generator.engine.ast.Variable;
     import com.google.api.generator.engine.ast.VariableExpr;
     import com.google.api.generator.engine.writer.JavaWriterVisitor;
    +import com.google.api.generator.gapic.composer.grpc.GrpcContext;
     import com.google.api.generator.gapic.model.GapicBatchingSettings;
     import com.google.api.generator.gapic.model.GapicContext;
     import com.google.api.generator.gapic.model.GapicServiceConfig;
    @@ -329,7 +330,9 @@ public void lroBuilderExpr() {
                 waitMethod,
                 builderVarExpr,
                 RETRY_CODES_DEFINITIONS_VAR_EXPR,
    -            RETRY_PARAM_DEFINITIONS_VAR_EXPR);
    +            RETRY_PARAM_DEFINITIONS_VAR_EXPR,
    +            GrpcContext.instance().operationResponseTransformerType(),
    +            GrpcContext.instance().operationMetadataTransformerType());
         builderExpr.accept(writerVisitor);
         String expected =
             LineFormatter.lines(
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/composer/grpc/BUILD.bazel
    index 14ac8deeba..825635a75e 100644
    --- a/src/test/java/com/google/api/generator/gapic/composer/grpc/BUILD.bazel
    +++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/BUILD.bazel
    @@ -8,8 +8,10 @@ TESTS = [
         "GrpcServiceStubClassComposerTest",
         "MockServiceClassComposerTest",
         "MockServiceImplClassComposerTest",
    +    "ServiceClientClassComposerTest",
         "ServiceClientTestClassComposerTest",
         "ServiceSettingsClassComposerTest",
    +    "ServiceStubClassComposerTest",
         "ServiceStubSettingsClassComposerTest",
     ]
     
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposerTest.java
    similarity index 89%
    rename from src/test/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposerTest.java
    rename to src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposerTest.java
    index b7767f41a6..331b94e484 100644
    --- a/src/test/java/com/google/api/generator/gapic/composer/common/ServiceClientClassComposerTest.java
    +++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceClientClassComposerTest.java
    @@ -12,7 +12,7 @@
     // See the License for the specific language governing permissions and
     // limitations under the License.
     
    -package com.google.api.generator.gapic.composer.common;
    +package com.google.api.generator.gapic.composer.grpc;
     
     import static com.google.api.generator.test.framework.Assert.assertCodeEquals;
     
    @@ -28,7 +28,7 @@
     public class ServiceClientClassComposerTest {
       @Test
       public void generateServiceClasses() {
    -    GapicContext context = TestProtoLoader.instance().parseShowcaseEcho();
    +    GapicContext context = GrpcTestProtoLoader.instance().parseShowcaseEcho();
         Service echoProtoService = context.services().get(0);
         GapicClass clazz = ServiceClientClassComposer.instance().generate(context, echoProtoService);
     
    @@ -41,7 +41,7 @@ public void generateServiceClasses() {
     
       @Test
       public void generateServiceClasses_deprecated() {
    -    GapicContext context = TestProtoLoader.instance().parseDeprecatedService();
    +    GapicContext context = GrpcTestProtoLoader.instance().parseDeprecatedService();
         Service protoService = context.services().get(0);
         GapicClass clazz = ServiceClientClassComposer.instance().generate(context, protoService);
     
    @@ -55,7 +55,7 @@ public void generateServiceClasses_deprecated() {
     
       @Test
       public void generateServiceClasses_methodSignatureHasNestedFields() {
    -    GapicContext context = TestProtoLoader.instance().parseShowcaseIdentity();
    +    GapicContext context = GrpcTestProtoLoader.instance().parseShowcaseIdentity();
         Service protoService = context.services().get(0);
         GapicClass clazz = ServiceClientClassComposer.instance().generate(context, protoService);
     
    @@ -68,7 +68,7 @@ public void generateServiceClasses_methodSignatureHasNestedFields() {
     
       @Test
       public void generateServiceClasses_bookshopNameConflicts() {
    -    GapicContext context = TestProtoLoader.instance().parseBookshopService();
    +    GapicContext context = GrpcTestProtoLoader.instance().parseBookshopService();
         Service protoService = context.services().get(0);
         GapicClass clazz = ServiceClientClassComposer.instance().generate(context, protoService);
     
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposerTest.java
    similarity index 94%
    rename from src/test/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposerTest.java
    rename to src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposerTest.java
    index b30ce3630c..bb411b9ad3 100644
    --- a/src/test/java/com/google/api/generator/gapic/composer/common/ServiceStubClassComposerTest.java
    +++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubClassComposerTest.java
    @@ -12,9 +12,10 @@
     // See the License for the specific language governing permissions and
     // limitations under the License.
     
    -package com.google.api.generator.gapic.composer.common;
    +package com.google.api.generator.gapic.composer.grpc;
     
     import com.google.api.generator.engine.writer.JavaWriterVisitor;
    +import com.google.api.generator.gapic.composer.common.TestProtoLoader;
     import com.google.api.generator.gapic.model.GapicClass;
     import com.google.api.generator.gapic.model.GapicContext;
     import com.google.api.generator.gapic.model.Service;
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/BookshopClient.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/BookshopClient.golden
    similarity index 100%
    rename from src/test/java/com/google/api/generator/gapic/composer/common/goldens/BookshopClient.golden
    rename to src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/BookshopClient.golden
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/DeprecatedServiceClient.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/DeprecatedServiceClient.golden
    similarity index 100%
    rename from src/test/java/com/google/api/generator/gapic/composer/common/goldens/DeprecatedServiceClient.golden
    rename to src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/DeprecatedServiceClient.golden
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/DeprecatedServiceStub.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/DeprecatedServiceStub.golden
    similarity index 100%
    rename from src/test/java/com/google/api/generator/gapic/composer/common/goldens/DeprecatedServiceStub.golden
    rename to src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/DeprecatedServiceStub.golden
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoClient.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoClient.golden
    similarity index 100%
    rename from src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoClient.golden
    rename to src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoClient.golden
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoStub.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoStub.golden
    similarity index 100%
    rename from src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoStub.golden
    rename to src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoStub.golden
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/IdentityClient.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/IdentityClient.golden
    similarity index 100%
    rename from src/test/java/com/google/api/generator/gapic/composer/common/goldens/IdentityClient.golden
    rename to src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/IdentityClient.golden
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposerTest.java
    index e3e5641f93..53392a549e 100644
    --- a/src/test/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposerTest.java
    +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/ServiceStubSettingsClassComposerTest.java
    @@ -27,7 +27,7 @@
     public class ServiceStubSettingsClassComposerTest {
       @Test
       public void generateServiceStubSettingsClasses_basic() {
    -    GapicContext context = RestTestProtoLoader.instance().parseShowcaseEcho();
    +    GapicContext context = RestTestProtoLoader.instance().parseCompliance();
         Service echoProtoService = context.services().get(0);
         GapicClass clazz =
             ServiceStubSettingsClassComposer.instance().generate(context, echoProtoService);
    diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/ComplianceStubSettings.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/ComplianceStubSettings.golden
    index 3535651104..a858c0123e 100644
    --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/ComplianceStubSettings.golden
    +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/ComplianceStubSettings.golden
    @@ -1,60 +1,33 @@
     package com.google.showcase.v1beta1.stub;
     
    -import static com.google.showcase.v1beta1.EchoClient.PagedExpandPagedResponse;
    -import static com.google.showcase.v1beta1.EchoClient.SimplePagedExpandPagedResponse;
    -
     import com.google.api.core.ApiFunction;
    -import com.google.api.core.ApiFuture;
     import com.google.api.core.BetaApi;
     import com.google.api.gax.core.GaxProperties;
     import com.google.api.gax.core.GoogleCredentialsProvider;
     import com.google.api.gax.core.InstantiatingExecutorProvider;
    -import com.google.api.gax.grpc.ProtoOperationTransformers;
     import com.google.api.gax.httpjson.GaxHttpJsonProperties;
     import com.google.api.gax.httpjson.HttpJsonTransportChannel;
     import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider;
    -import com.google.api.gax.longrunning.OperationSnapshot;
    -import com.google.api.gax.longrunning.OperationTimedPollAlgorithm;
     import com.google.api.gax.retrying.RetrySettings;
    -import com.google.api.gax.rpc.ApiCallContext;
     import com.google.api.gax.rpc.ApiClientHeaderProvider;
     import com.google.api.gax.rpc.ClientContext;
    -import com.google.api.gax.rpc.OperationCallSettings;
    -import com.google.api.gax.rpc.PageContext;
    -import com.google.api.gax.rpc.PagedCallSettings;
    -import com.google.api.gax.rpc.PagedListDescriptor;
    -import com.google.api.gax.rpc.PagedListResponseFactory;
    -import com.google.api.gax.rpc.ServerStreamingCallSettings;
     import com.google.api.gax.rpc.StatusCode;
    -import com.google.api.gax.rpc.StreamingCallSettings;
     import com.google.api.gax.rpc.StubSettings;
     import com.google.api.gax.rpc.TransportChannelProvider;
     import com.google.api.gax.rpc.UnaryCallSettings;
    -import com.google.api.gax.rpc.UnaryCallable;
     import com.google.common.collect.ImmutableList;
     import com.google.common.collect.ImmutableMap;
     import com.google.common.collect.ImmutableSet;
     import com.google.common.collect.Lists;
    -import com.google.longrunning.Operation;
    -import com.google.showcase.v1beta1.BlockRequest;
    -import com.google.showcase.v1beta1.BlockResponse;
    -import com.google.showcase.v1beta1.EchoRequest;
    -import com.google.showcase.v1beta1.EchoResponse;
    -import com.google.showcase.v1beta1.ExpandRequest;
    -import com.google.showcase.v1beta1.Object;
    -import com.google.showcase.v1beta1.PagedExpandRequest;
    -import com.google.showcase.v1beta1.PagedExpandResponse;
    -import com.google.showcase.v1beta1.WaitMetadata;
    -import com.google.showcase.v1beta1.WaitRequest;
    -import com.google.showcase.v1beta1.WaitResponse;
    +import com.google.showcase.v1beta1.RepeatRequest;
    +import com.google.showcase.v1beta1.RepeatResponse;
     import java.io.IOException;
     import java.util.List;
     import javax.annotation.Generated;
    -import org.threeten.bp.Duration;
     
     // AUTO-GENERATED DOCUMENTATION AND CLASS.
     /**
    - * Settings class to configure an instance of {@link EchoStub}.
    + * Settings class to configure an instance of {@link ComplianceStub}.
      *
      * 

    The default instance has everything set to sensible defaults: * @@ -67,214 +40,73 @@ import org.threeten.bp.Duration; *

    The builder of this class is recursive, so contained classes are themselves builders. When * build() is called, the tree of builders is called to create the complete settings object. * - *

    For example, to set the total timeout of echo to 30 seconds: + *

    For example, to set the total timeout of repeatDataBody to 30 seconds: * *

    {@code
    - * EchoStubSettings.Builder echoSettingsBuilder = EchoStubSettings.newBuilder();
    - * echoSettingsBuilder
    - *     .echoSettings()
    + * ComplianceStubSettings.Builder complianceSettingsBuilder = ComplianceStubSettings.newBuilder();
    + * complianceSettingsBuilder
    + *     .repeatDataBodySettings()
      *     .setRetrySettings(
    - *         echoSettingsBuilder
    - *             .echoSettings()
    + *         complianceSettingsBuilder
    + *             .repeatDataBodySettings()
      *             .getRetrySettings()
      *             .toBuilder()
      *             .setTotalTimeout(Duration.ofSeconds(30))
      *             .build());
    - * EchoStubSettings echoSettings = echoSettingsBuilder.build();
    + * ComplianceStubSettings complianceSettings = complianceSettingsBuilder.build();
      * }
    */ @BetaApi @Generated("by gapic-generator-java") -public class EchoStubSettings extends StubSettings { +public class ComplianceStubSettings extends StubSettings { /** The default scopes of the service. */ private static final ImmutableList DEFAULT_SERVICE_SCOPES = - ImmutableList.builder().add("https://www.googleapis.com/auth/cloud-platform").build(); - - private final UnaryCallSettings echoSettings; - private final ServerStreamingCallSettings expandSettings; - private final StreamingCallSettings collectSettings; - private final StreamingCallSettings chatSettings; - private final StreamingCallSettings chatAgainSettings; - private final PagedCallSettings - pagedExpandSettings; - private final PagedCallSettings< - PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse> - simplePagedExpandSettings; - private final UnaryCallSettings waitSettings; - private final OperationCallSettings - waitOperationSettings; - private final UnaryCallSettings blockSettings; - private final UnaryCallSettings collideNameSettings; - - private static final PagedListDescriptor - PAGED_EXPAND_PAGE_STR_DESC = - new PagedListDescriptor() { - @Override - public String emptyToken() { - return ""; - } - - @Override - public PagedExpandRequest injectToken(PagedExpandRequest payload, String token) { - return PagedExpandRequest.newBuilder(payload).setPageToken(token).build(); - } - - @Override - public PagedExpandRequest injectPageSize(PagedExpandRequest payload, int pageSize) { - return PagedExpandRequest.newBuilder(payload).setPageSize(pageSize).build(); - } - - @Override - public Integer extractPageSize(PagedExpandRequest payload) { - return payload.getPageSize(); - } - - @Override - public String extractNextToken(PagedExpandResponse payload) { - return payload.getNextPageToken(); - } - - @Override - public Iterable extractResources(PagedExpandResponse payload) { - return payload.getResponsesList() == null - ? ImmutableList.of() - : payload.getResponsesList(); - } - }; - - private static final PagedListDescriptor - SIMPLE_PAGED_EXPAND_PAGE_STR_DESC = - new PagedListDescriptor() { - @Override - public String emptyToken() { - return ""; - } - - @Override - public PagedExpandRequest injectToken(PagedExpandRequest payload, String token) { - return PagedExpandRequest.newBuilder(payload).setPageToken(token).build(); - } - - @Override - public PagedExpandRequest injectPageSize(PagedExpandRequest payload, int pageSize) { - return PagedExpandRequest.newBuilder(payload).setPageSize(pageSize).build(); - } - - @Override - public Integer extractPageSize(PagedExpandRequest payload) { - return payload.getPageSize(); - } - - @Override - public String extractNextToken(PagedExpandResponse payload) { - return payload.getNextPageToken(); - } - - @Override - public Iterable extractResources(PagedExpandResponse payload) { - return payload.getResponsesList() == null - ? ImmutableList.of() - : payload.getResponsesList(); - } - }; - - private static final PagedListResponseFactory< - PagedExpandRequest, PagedExpandResponse, PagedExpandPagedResponse> - PAGED_EXPAND_PAGE_STR_FACT = - new PagedListResponseFactory< - PagedExpandRequest, PagedExpandResponse, PagedExpandPagedResponse>() { - @Override - public ApiFuture getFuturePagedResponse( - UnaryCallable callable, - PagedExpandRequest request, - ApiCallContext context, - ApiFuture futureResponse) { - PageContext pageContext = - PageContext.create(callable, PAGED_EXPAND_PAGE_STR_DESC, request, context); - return PagedExpandPagedResponse.createAsync(pageContext, futureResponse); - } - }; - - private static final PagedListResponseFactory< - PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse> - SIMPLE_PAGED_EXPAND_PAGE_STR_FACT = - new PagedListResponseFactory< - PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse>() { - @Override - public ApiFuture getFuturePagedResponse( - UnaryCallable callable, - PagedExpandRequest request, - ApiCallContext context, - ApiFuture futureResponse) { - PageContext pageContext = - PageContext.create(callable, SIMPLE_PAGED_EXPAND_PAGE_STR_DESC, request, context); - return SimplePagedExpandPagedResponse.createAsync(pageContext, futureResponse); - } - }; - - /** Returns the object with the settings used for calls to echo. */ - public UnaryCallSettings echoSettings() { - return echoSettings; - } - - /** Returns the object with the settings used for calls to expand. */ - public ServerStreamingCallSettings expandSettings() { - return expandSettings; - } - - /** Returns the object with the settings used for calls to collect. */ - public StreamingCallSettings collectSettings() { - return collectSettings; - } - - /** Returns the object with the settings used for calls to chat. */ - public StreamingCallSettings chatSettings() { - return chatSettings; + ImmutableList.builder().build(); + + private final UnaryCallSettings repeatDataBodySettings; + private final UnaryCallSettings repeatDataBodyInfoSettings; + private final UnaryCallSettings repeatDataQuerySettings; + private final UnaryCallSettings repeatDataSimplePathSettings; + private final UnaryCallSettings repeatDataPathResourceSettings; + private final UnaryCallSettings + repeatDataPathTrailingResourceSettings; + + /** Returns the object with the settings used for calls to repeatDataBody. */ + public UnaryCallSettings repeatDataBodySettings() { + return repeatDataBodySettings; } - /** Returns the object with the settings used for calls to chatAgain. */ - public StreamingCallSettings chatAgainSettings() { - return chatAgainSettings; + /** Returns the object with the settings used for calls to repeatDataBodyInfo. */ + public UnaryCallSettings repeatDataBodyInfoSettings() { + return repeatDataBodyInfoSettings; } - /** Returns the object with the settings used for calls to pagedExpand. */ - public PagedCallSettings - pagedExpandSettings() { - return pagedExpandSettings; + /** Returns the object with the settings used for calls to repeatDataQuery. */ + public UnaryCallSettings repeatDataQuerySettings() { + return repeatDataQuerySettings; } - /** Returns the object with the settings used for calls to simplePagedExpand. */ - public PagedCallSettings - simplePagedExpandSettings() { - return simplePagedExpandSettings; + /** Returns the object with the settings used for calls to repeatDataSimplePath. */ + public UnaryCallSettings repeatDataSimplePathSettings() { + return repeatDataSimplePathSettings; } - /** Returns the object with the settings used for calls to wait. */ - public UnaryCallSettings waitSettings() { - return waitSettings; + /** Returns the object with the settings used for calls to repeatDataPathResource. */ + public UnaryCallSettings repeatDataPathResourceSettings() { + return repeatDataPathResourceSettings; } - /** Returns the object with the settings used for calls to wait. */ - public OperationCallSettings waitOperationSettings() { - return waitOperationSettings; - } - - /** Returns the object with the settings used for calls to block. */ - public UnaryCallSettings blockSettings() { - return blockSettings; - } - - /** Returns the object with the settings used for calls to collideName. */ - public UnaryCallSettings collideNameSettings() { - return collideNameSettings; + /** Returns the object with the settings used for calls to repeatDataPathTrailingResource. */ + public UnaryCallSettings repeatDataPathTrailingResourceSettings() { + return repeatDataPathTrailingResourceSettings; } @BetaApi("A restructuring of stub classes is planned, so this may break in the future") - public EchoStub createStub() throws IOException { + public ComplianceStub createStub() throws IOException { if (getTransportChannelProvider() .getTransportName() .equals(HttpJsonTransportChannel.getHttpJsonTransportName())) { - return HttpJsonEchoStub.create(this); + return HttpJsonComplianceStub.create(this); } throw new UnsupportedOperationException( String.format( @@ -319,7 +151,8 @@ public class EchoStubSettings extends StubSettings { @BetaApi("The surface for customizing headers is not stable yet and may change in the future.") public static ApiClientHeaderProvider.Builder defaultApiClientHeaderProviderBuilder() { return ApiClientHeaderProvider.newBuilder() - .setGeneratedLibToken("gapic", GaxProperties.getLibraryVersion(EchoStubSettings.class)) + .setGeneratedLibToken( + "gapic", GaxProperties.getLibraryVersion(ComplianceStubSettings.class)) .setTransportToken( GaxHttpJsonProperties.getHttpJsonTokenName(), GaxHttpJsonProperties.getHttpJsonVersion()); @@ -340,54 +173,38 @@ public class EchoStubSettings extends StubSettings { return new Builder(this); } - protected EchoStubSettings(Builder settingsBuilder) throws IOException { + protected ComplianceStubSettings(Builder settingsBuilder) throws IOException { super(settingsBuilder); - echoSettings = settingsBuilder.echoSettings().build(); - expandSettings = settingsBuilder.expandSettings().build(); - collectSettings = settingsBuilder.collectSettings().build(); - chatSettings = settingsBuilder.chatSettings().build(); - chatAgainSettings = settingsBuilder.chatAgainSettings().build(); - pagedExpandSettings = settingsBuilder.pagedExpandSettings().build(); - simplePagedExpandSettings = settingsBuilder.simplePagedExpandSettings().build(); - waitSettings = settingsBuilder.waitSettings().build(); - waitOperationSettings = settingsBuilder.waitOperationSettings().build(); - blockSettings = settingsBuilder.blockSettings().build(); - collideNameSettings = settingsBuilder.collideNameSettings().build(); + repeatDataBodySettings = settingsBuilder.repeatDataBodySettings().build(); + repeatDataBodyInfoSettings = settingsBuilder.repeatDataBodyInfoSettings().build(); + repeatDataQuerySettings = settingsBuilder.repeatDataQuerySettings().build(); + repeatDataSimplePathSettings = settingsBuilder.repeatDataSimplePathSettings().build(); + repeatDataPathResourceSettings = settingsBuilder.repeatDataPathResourceSettings().build(); + repeatDataPathTrailingResourceSettings = + settingsBuilder.repeatDataPathTrailingResourceSettings().build(); } - /** Builder for EchoStubSettings. */ - public static class Builder extends StubSettings.Builder { + /** Builder for ComplianceStubSettings. */ + public static class Builder extends StubSettings.Builder { private final ImmutableList> unaryMethodSettingsBuilders; - private final UnaryCallSettings.Builder echoSettings; - private final ServerStreamingCallSettings.Builder expandSettings; - private final StreamingCallSettings.Builder collectSettings; - private final StreamingCallSettings.Builder chatSettings; - private final StreamingCallSettings.Builder chatAgainSettings; - private final PagedCallSettings.Builder< - PagedExpandRequest, PagedExpandResponse, PagedExpandPagedResponse> - pagedExpandSettings; - private final PagedCallSettings.Builder< - PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse> - simplePagedExpandSettings; - private final UnaryCallSettings.Builder waitSettings; - private final OperationCallSettings.Builder - waitOperationSettings; - private final UnaryCallSettings.Builder blockSettings; - private final UnaryCallSettings.Builder collideNameSettings; + private final UnaryCallSettings.Builder repeatDataBodySettings; + private final UnaryCallSettings.Builder + repeatDataBodyInfoSettings; + private final UnaryCallSettings.Builder repeatDataQuerySettings; + private final UnaryCallSettings.Builder + repeatDataSimplePathSettings; + private final UnaryCallSettings.Builder + repeatDataPathResourceSettings; + private final UnaryCallSettings.Builder + repeatDataPathTrailingResourceSettings; private static final ImmutableMap> RETRYABLE_CODE_DEFINITIONS; static { ImmutableMap.Builder> definitions = ImmutableMap.builder(); - definitions.put( - "retry_policy_1_codes", - ImmutableSet.copyOf( - Lists.newArrayList( - StatusCode.Code.UNAVAILABLE, StatusCode.Code.UNKNOWN))); - definitions.put( - "no_retry_0_codes", ImmutableSet.copyOf(Lists.newArrayList())); + definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList())); RETRYABLE_CODE_DEFINITIONS = definitions.build(); } @@ -396,25 +213,8 @@ public class EchoStubSettings extends StubSettings { static { ImmutableMap.Builder definitions = ImmutableMap.builder(); RetrySettings settings = null; - settings = - RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.ofMillis(100L)) - .setRetryDelayMultiplier(2.0) - .setMaxRetryDelay(Duration.ofMillis(3000L)) - .setInitialRpcTimeout(Duration.ofMillis(10000L)) - .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ofMillis(10000L)) - .setTotalTimeout(Duration.ofMillis(10000L)) - .build(); - definitions.put("retry_policy_1_params", settings); - settings = - RetrySettings.newBuilder() - .setInitialRpcTimeout(Duration.ofMillis(5000L)) - .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ofMillis(5000L)) - .setTotalTimeout(Duration.ofMillis(5000L)) - .build(); - definitions.put("no_retry_0_params", settings); + settings = RetrySettings.newBuilder().setRpcTimeoutMultiplier(1.0).build(); + definitions.put("no_retry_params", settings); RETRY_PARAM_DEFINITIONS = definitions.build(); } @@ -425,52 +225,43 @@ public class EchoStubSettings extends StubSettings { protected Builder(ClientContext clientContext) { super(clientContext); - echoSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - expandSettings = ServerStreamingCallSettings.newBuilder(); - collectSettings = StreamingCallSettings.newBuilder(); - chatSettings = StreamingCallSettings.newBuilder(); - chatAgainSettings = StreamingCallSettings.newBuilder(); - pagedExpandSettings = PagedCallSettings.newBuilder(PAGED_EXPAND_PAGE_STR_FACT); - simplePagedExpandSettings = PagedCallSettings.newBuilder(SIMPLE_PAGED_EXPAND_PAGE_STR_FACT); - waitSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - waitOperationSettings = OperationCallSettings.newBuilder(); - blockSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); - collideNameSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + repeatDataBodySettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + repeatDataBodyInfoSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + repeatDataQuerySettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + repeatDataSimplePathSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + repeatDataPathResourceSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); + repeatDataPathTrailingResourceSettings = UnaryCallSettings.newUnaryCallSettingsBuilder(); unaryMethodSettingsBuilders = ImmutableList.>of( - echoSettings, - pagedExpandSettings, - simplePagedExpandSettings, - waitSettings, - blockSettings, - collideNameSettings); + repeatDataBodySettings, + repeatDataBodyInfoSettings, + repeatDataQuerySettings, + repeatDataSimplePathSettings, + repeatDataPathResourceSettings, + repeatDataPathTrailingResourceSettings); initDefaults(this); } - protected Builder(EchoStubSettings settings) { + protected Builder(ComplianceStubSettings settings) { super(settings); - echoSettings = settings.echoSettings.toBuilder(); - expandSettings = settings.expandSettings.toBuilder(); - collectSettings = settings.collectSettings.toBuilder(); - chatSettings = settings.chatSettings.toBuilder(); - chatAgainSettings = settings.chatAgainSettings.toBuilder(); - pagedExpandSettings = settings.pagedExpandSettings.toBuilder(); - simplePagedExpandSettings = settings.simplePagedExpandSettings.toBuilder(); - waitSettings = settings.waitSettings.toBuilder(); - waitOperationSettings = settings.waitOperationSettings.toBuilder(); - blockSettings = settings.blockSettings.toBuilder(); - collideNameSettings = settings.collideNameSettings.toBuilder(); + repeatDataBodySettings = settings.repeatDataBodySettings.toBuilder(); + repeatDataBodyInfoSettings = settings.repeatDataBodyInfoSettings.toBuilder(); + repeatDataQuerySettings = settings.repeatDataQuerySettings.toBuilder(); + repeatDataSimplePathSettings = settings.repeatDataSimplePathSettings.toBuilder(); + repeatDataPathResourceSettings = settings.repeatDataPathResourceSettings.toBuilder(); + repeatDataPathTrailingResourceSettings = + settings.repeatDataPathTrailingResourceSettings.toBuilder(); unaryMethodSettingsBuilders = ImmutableList.>of( - echoSettings, - pagedExpandSettings, - simplePagedExpandSettings, - waitSettings, - blockSettings, - collideNameSettings); + repeatDataBodySettings, + repeatDataBodyInfoSettings, + repeatDataQuerySettings, + repeatDataSimplePathSettings, + repeatDataPathResourceSettings, + repeatDataPathTrailingResourceSettings); } private static Builder createDefault() { @@ -488,62 +279,34 @@ public class EchoStubSettings extends StubSettings { private static Builder initDefaults(Builder builder) { builder - .echoSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); - - builder - .expandSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); + .repeatDataBodySettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); builder - .pagedExpandSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_1_codes")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_1_params")); + .repeatDataBodyInfoSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); builder - .simplePagedExpandSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); + .repeatDataQuerySettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); builder - .waitSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); + .repeatDataSimplePathSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); builder - .blockSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); + .repeatDataPathResourceSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); builder - .collideNameSettings() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")); - - builder - .waitOperationSettings() - .setInitialCallSettings( - UnaryCallSettings.newUnaryCallSettingsBuilder() - .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes")) - .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params")) - .build()) - .setResponseTransformer( - ProtoOperationTransformers.ResponseTransformer.create(WaitResponse.class)) - .setMetadataTransformer( - ProtoOperationTransformers.MetadataTransformer.create(WaitMetadata.class)) - .setPollingAlgorithm( - OperationTimedPollAlgorithm.create( - RetrySettings.newBuilder() - .setInitialRetryDelay(Duration.ofMillis(5000L)) - .setRetryDelayMultiplier(1.5) - .setMaxRetryDelay(Duration.ofMillis(45000L)) - .setInitialRpcTimeout(Duration.ZERO) - .setRpcTimeoutMultiplier(1.0) - .setMaxRpcTimeout(Duration.ZERO) - .setTotalTimeout(Duration.ofMillis(300000L)) - .build())); + .repeatDataPathTrailingResourceSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); return builder; } @@ -563,71 +326,41 @@ public class EchoStubSettings extends StubSettings { return unaryMethodSettingsBuilders; } - /** Returns the builder for the settings used for calls to echo. */ - public UnaryCallSettings.Builder echoSettings() { - return echoSettings; - } - - /** Returns the builder for the settings used for calls to expand. */ - public ServerStreamingCallSettings.Builder expandSettings() { - return expandSettings; - } - - /** Returns the builder for the settings used for calls to collect. */ - public StreamingCallSettings.Builder collectSettings() { - return collectSettings; - } - - /** Returns the builder for the settings used for calls to chat. */ - public StreamingCallSettings.Builder chatSettings() { - return chatSettings; - } - - /** Returns the builder for the settings used for calls to chatAgain. */ - public StreamingCallSettings.Builder chatAgainSettings() { - return chatAgainSettings; - } - - /** Returns the builder for the settings used for calls to pagedExpand. */ - public PagedCallSettings.Builder< - PagedExpandRequest, PagedExpandResponse, PagedExpandPagedResponse> - pagedExpandSettings() { - return pagedExpandSettings; + /** Returns the builder for the settings used for calls to repeatDataBody. */ + public UnaryCallSettings.Builder repeatDataBodySettings() { + return repeatDataBodySettings; } - /** Returns the builder for the settings used for calls to simplePagedExpand. */ - public PagedCallSettings.Builder< - PagedExpandRequest, PagedExpandResponse, SimplePagedExpandPagedResponse> - simplePagedExpandSettings() { - return simplePagedExpandSettings; + /** Returns the builder for the settings used for calls to repeatDataBodyInfo. */ + public UnaryCallSettings.Builder repeatDataBodyInfoSettings() { + return repeatDataBodyInfoSettings; } - /** Returns the builder for the settings used for calls to wait. */ - public UnaryCallSettings.Builder waitSettings() { - return waitSettings; + /** Returns the builder for the settings used for calls to repeatDataQuery. */ + public UnaryCallSettings.Builder repeatDataQuerySettings() { + return repeatDataQuerySettings; } - /** Returns the builder for the settings used for calls to wait. */ - @BetaApi( - "The surface for use by generated code is not stable yet and may change in the future.") - public OperationCallSettings.Builder - waitOperationSettings() { - return waitOperationSettings; + /** Returns the builder for the settings used for calls to repeatDataSimplePath. */ + public UnaryCallSettings.Builder repeatDataSimplePathSettings() { + return repeatDataSimplePathSettings; } - /** Returns the builder for the settings used for calls to block. */ - public UnaryCallSettings.Builder blockSettings() { - return blockSettings; + /** Returns the builder for the settings used for calls to repeatDataPathResource. */ + public UnaryCallSettings.Builder + repeatDataPathResourceSettings() { + return repeatDataPathResourceSettings; } - /** Returns the builder for the settings used for calls to collideName. */ - public UnaryCallSettings.Builder collideNameSettings() { - return collideNameSettings; + /** Returns the builder for the settings used for calls to repeatDataPathTrailingResource. */ + public UnaryCallSettings.Builder + repeatDataPathTrailingResourceSettings() { + return repeatDataPathTrailingResourceSettings; } @Override - public EchoStubSettings build() throws IOException { - return new EchoStubSettings(this); + public ComplianceStubSettings build() throws IOException { + return new ComplianceStubSettings(this); } } } diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden index 8db61290e0..ab84437e6e 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden @@ -4,7 +4,6 @@ import com.google.api.core.BetaApi; import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; -import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.rpc.BatchingCallSettings; import com.google.api.gax.rpc.ClientContext; @@ -13,7 +12,6 @@ import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; -import com.google.longrunning.Operation; import javax.annotation.Generated; // AUTO-GENERATED DOCUMENTATION AND CLASS. @@ -25,7 +23,7 @@ import javax.annotation.Generated; @BetaApi @Generated("by gapic-generator-java") public class HttpJsonComplianceCallableFactory - implements HttpJsonStubCallableFactory { + implements HttpJsonStubCallableFactory { @Override public UnaryCallable createUnaryCallable( @@ -60,18 +58,10 @@ public class HttpJsonComplianceCallableFactory @Override public OperationCallable createOperationCallable( - HttpJsonCallSettings httpJsonCallSettings, + HttpJsonCallSettings httpJsonCallSettings, OperationCallSettings callSettings, ClientContext clientContext, BackgroundResource operationsStub) { - UnaryCallable innerCallable = - HttpJsonCallableFactory.createBaseUnaryCallable( - httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); - HttpJsonOperationSnapshotCallable initialCallable = - new HttpJsonOperationSnapshotCallable( - innerCallable, - httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); - return HttpJsonCallableFactory.createOperationCallable( - callSettings, clientContext, operationsStub.longRunningClient(), initialCallable); + return null; } } diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden index 5324f21655..331e5bf961 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden @@ -57,8 +57,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { }) .setRequestBodyExtractor( request -> - ProtoRestSerializer.create() - .toBody("serverVerify", request.getServerVerify())) + ProtoRestSerializer.create().toBody("*", request.toBuilder().build())) .build()) .setResponseParser( ProtoMessageResponseParser.newBuilder() diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java index 7173f3bce5..f9039b41df 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClient.java @@ -329,6 +329,8 @@ public final OperationFuture deleteAsync( * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") public final OperationFuture deleteAsync(DeleteAddressRequest request) { return deleteOperationCallable().futureCall(request); } @@ -438,6 +440,8 @@ public final OperationFuture insertAsync( * @param request The request object containing all of the parameters for the API call. * @throws com.google.api.gax.rpc.ApiException if the remote call fails */ + @BetaApi( + "The surface for long-running operations is not stable yet and may change in the future.") public final OperationFuture insertAsync(InsertAddressRequest request) { return insertOperationCallable().futureCall(request); } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClient.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClient.java index fb6a5e296d..09fb0b090a 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClient.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClient.java @@ -222,6 +222,112 @@ public final UnaryCallable getCallable() { return stub.getCallable(); } + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Waits for the specified Operation resource to return as `DONE` or for the request to approach + * the 2 minute deadline, and retrieves the specified Operation resource. This method differs from + * the `GET` method in that it waits for no more than the default deadline (2 minutes) and then + * returns the current state of the operation, which might be `DONE` or still in progress. + * + *

    This method is called on a best-effort basis. Specifically: - In uncommon cases, when the + * server is overloaded, the request might return before the default deadline is reached, or might + * return after zero seconds. - If the default deadline is reached, there is no guarantee that the + * operation is actually done when the method returns. Be prepared to retry if the operation is + * not `DONE`. + * + *

    Sample code: + * + *

    {@code
    +   * try (RegionOperationsClient regionOperationsClient = RegionOperationsClient.create()) {
    +   *   String project = "project-309310695";
    +   *   String region = "region-934795532";
    +   *   String operation = "operation1662702951";
    +   *   Operation response = regionOperationsClient.wait(project, region, operation);
    +   * }
    +   * }
    + * + * @param project Project ID for this request. + * @param region Name of the region for this request. + * @param operation Name of the Operations resource to return. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Operation wait(String project, String region, String operation) { + WaitRegionOperationRequest request = + WaitRegionOperationRequest.newBuilder() + .setProject(project) + .setRegion(region) + .setOperation(operation) + .build(); + return wait(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Waits for the specified Operation resource to return as `DONE` or for the request to approach + * the 2 minute deadline, and retrieves the specified Operation resource. This method differs from + * the `GET` method in that it waits for no more than the default deadline (2 minutes) and then + * returns the current state of the operation, which might be `DONE` or still in progress. + * + *

    This method is called on a best-effort basis. Specifically: - In uncommon cases, when the + * server is overloaded, the request might return before the default deadline is reached, or might + * return after zero seconds. - If the default deadline is reached, there is no guarantee that the + * operation is actually done when the method returns. Be prepared to retry if the operation is + * not `DONE`. + * + *

    Sample code: + * + *

    {@code
    +   * try (RegionOperationsClient regionOperationsClient = RegionOperationsClient.create()) {
    +   *   WaitRegionOperationRequest request =
    +   *       WaitRegionOperationRequest.newBuilder()
    +   *           .setOperation("operation1662702951")
    +   *           .setProject("project-309310695")
    +   *           .setRegion("region-934795532")
    +   *           .build();
    +   *   Operation response = regionOperationsClient.wait(request);
    +   * }
    +   * }
    + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Operation wait(WaitRegionOperationRequest request) { + return waitCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Waits for the specified Operation resource to return as `DONE` or for the request to approach + * the 2 minute deadline, and retrieves the specified Operation resource. This method differs from + * the `GET` method in that it waits for no more than the default deadline (2 minutes) and then + * returns the current state of the operation, which might be `DONE` or still in progress. + * + *

    This method is called on a best-effort basis. Specifically: - In uncommon cases, when the + * server is overloaded, the request might return before the default deadline is reached, or might + * return after zero seconds. - If the default deadline is reached, there is no guarantee that the + * operation is actually done when the method returns. Be prepared to retry if the operation is + * not `DONE`. + * + *

    Sample code: + * + *

    {@code
    +   * try (RegionOperationsClient regionOperationsClient = RegionOperationsClient.create()) {
    +   *   WaitRegionOperationRequest request =
    +   *       WaitRegionOperationRequest.newBuilder()
    +   *           .setOperation("operation1662702951")
    +   *           .setProject("project-309310695")
    +   *           .setRegion("region-934795532")
    +   *           .build();
    +   *   ApiFuture future = regionOperationsClient.waitCallable().futureCall(request);
    +   *   // Do something.
    +   *   Operation response = future.get();
    +   * }
    +   * }
    + */ + public final UnaryCallable waitCallable() { + return stub.waitCallable(); + } + @Override public final void close() { stub.close(); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java index d41b1f5191..684c1312ab 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java @@ -140,4 +140,73 @@ public void getExceptionTest() throws Exception { // Expected exception. } } + + @Test + public void waitTest() throws Exception { + Operation expectedResponse = + Operation.newBuilder() + .setClientOperationId("clientOperationId-1230366697") + .setCreationTimestamp("creationTimestamp-370203401") + .setDescription("description-1724546052") + .setEndTime("endTime-1607243192") + .setError(Error.newBuilder().build()) + .setHttpErrorMessage("httpErrorMessage1577303431") + .setHttpErrorStatusCode(1386087020) + .setId(3355) + .setInsertTime("insertTime966165798") + .setKind("kind3292052") + .setName("name3373707") + .setOperationType("operationType91999553") + .setProgress(-1001078227) + .setRegion("region-934795532") + .setSelfLink("selfLink1191800166") + .setStartTime("startTime-2129294769") + .setStatusMessage("statusMessage-958704715") + .setTargetId(-815576439) + .setTargetLink("targetLink486368555") + .setUser("user3599307") + .addAllWarnings(new ArrayList()) + .setZone("zone3744684") + .build(); + mockService.addResponse(expectedResponse); + + String project = "project-309310695"; + String region = "region-934795532"; + String operation = "operation1662702951"; + + Operation actualResponse = client.wait(project, region, operation); + Assert.assertEquals(expectedResponse, actualResponse); + + List actualRequests = mockService.getRequestPaths(); + Assert.assertEquals(1, actualRequests.size()); + + String apiClientHeaderKey = + mockService + .getRequestHeaders() + .get(ApiClientHeaderProvider.getDefaultApiClientHeaderKey()) + .iterator() + .next(); + Assert.assertTrue( + GaxHttpJsonProperties.getDefaultApiClientHeaderPattern() + .matcher(apiClientHeaderKey) + .matches()); + } + + @Test + public void waitExceptionTest() throws Exception { + ApiException exception = + ApiExceptionFactory.createException( + new Exception(), FakeStatusCode.of(StatusCode.Code.INVALID_ARGUMENT), false); + mockService.addException(exception); + + try { + String project = "project-309310695"; + String region = "region-934795532"; + String operation = "operation1662702951"; + client.wait(project, region, operation); + Assert.fail("No exception raised"); + } catch (InvalidArgumentException e) { + // Expected exception. + } + } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsSettings.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsSettings.java index 4e0ffca9d4..91cabed69d 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsSettings.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsSettings.java @@ -72,6 +72,11 @@ public UnaryCallSettings getSettings() { return ((RegionOperationsStubSettings) getStubSettings()).getSettings(); } + /** Returns the object with the settings used for calls to wait. */ + public UnaryCallSettings waitSettings() { + return ((RegionOperationsStubSettings) getStubSettings()).waitSettings(); + } + public static final RegionOperationsSettings create(RegionOperationsStubSettings stub) throws IOException { return new RegionOperationsSettings.Builder(stub.toBuilder()).build(); @@ -175,6 +180,11 @@ public UnaryCallSettings.Builder getSettin return getStubSettingsBuilder().getSettings(); } + /** Returns the builder for the settings used for calls to wait. */ + public UnaryCallSettings.Builder waitSettings() { + return getStubSettingsBuilder().waitSettings(); + } + @Override public RegionOperationsSettings build() throws IOException { return new RegionOperationsSettings(this); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json b/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json index d2f2df6b3d..a56d0a2382 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/gapic_metadata.json @@ -33,6 +33,9 @@ "rpcs": { "Get": { "methods": ["get", "get", "getCallable"] + }, + "Wait": { + "methods": ["wait", "wait", "waitCallable"] } } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java index 551b0ec0eb..9ae394b7ca 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStub.java @@ -40,10 +40,6 @@ @Generated("by gapic-generator-java") public abstract class AddressesStub implements BackgroundResource { - public RegionOperationsStub getOperationsStub() { - throw new UnsupportedOperationException("Not implemented: getOperationsStub()"); - } - public UnaryCallable aggregatedListPagedCallable() { throw new UnsupportedOperationException("Not implemented: aggregatedListPagedCallable()"); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java index 55866e3401..517743de7d 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/AddressesStubSettings.java @@ -25,10 +25,10 @@ import com.google.api.gax.core.GaxProperties; import com.google.api.gax.core.GoogleCredentialsProvider; import com.google.api.gax.core.InstantiatingExecutorProvider; -import com.google.api.gax.grpc.ProtoOperationTransformers; import com.google.api.gax.httpjson.GaxHttpJsonProperties; import com.google.api.gax.httpjson.HttpJsonTransportChannel; import com.google.api.gax.httpjson.InstantiatingHttpJsonChannelProvider; +import com.google.api.gax.httpjson.ProtoOperationTransformers; import com.google.api.gax.longrunning.OperationSnapshot; import com.google.api.gax.longrunning.OperationTimedPollAlgorithm; import com.google.api.gax.retrying.RetrySettings; diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java index 943580e59b..9e5e90fbe1 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java @@ -261,7 +261,7 @@ public class HttpJsonAddressesStub extends AddressesStub { private final UnaryCallable listPagedCallable; private final BackgroundResource backgroundResources; - private final HttpJsonRegionOperationsStub operationsStub; + private final HttpJsonRegionOperationsStub httpJsonOperationsStub; private final HttpJsonStubCallableFactory callableFactory; public static final HttpJsonAddressesStub create(AddressesStubSettings settings) @@ -300,7 +300,8 @@ protected HttpJsonAddressesStub( HttpJsonStubCallableFactory callableFactory) throws IOException { this.callableFactory = callableFactory; - this.operationsStub = HttpJsonRegionOperationsStub.create(clientContext, callableFactory); + this.httpJsonOperationsStub = + HttpJsonRegionOperationsStub.create(clientContext, callableFactory); HttpJsonCallSettings aggregatedListTransportSettings = @@ -334,7 +335,7 @@ protected HttpJsonAddressesStub( deleteTransportSettings, settings.deleteOperationSettings(), clientContext, - operationsStub); + httpJsonOperationsStub); this.insertCallable = callableFactory.createUnaryCallable( insertTransportSettings, settings.insertSettings(), clientContext); @@ -343,7 +344,7 @@ protected HttpJsonAddressesStub( insertTransportSettings, settings.insertOperationSettings(), clientContext, - operationsStub); + httpJsonOperationsStub); this.listCallable = callableFactory.createUnaryCallable( listTransportSettings, settings.listSettings(), clientContext); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java index b775dbba59..24e9ad539a 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java @@ -20,7 +20,6 @@ import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; -import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; import com.google.api.gax.rpc.BatchingCallSettings; import com.google.api.gax.rpc.ClientContext; @@ -29,7 +28,6 @@ import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; -import com.google.longrunning.Operation; import javax.annotation.Generated; // AUTO-GENERATED DOCUMENTATION AND CLASS. @@ -41,7 +39,7 @@ @Generated("by gapic-generator-java") @BetaApi public class HttpJsonRegionOperationsCallableFactory - implements HttpJsonStubCallableFactory { + implements HttpJsonStubCallableFactory { @Override public UnaryCallable createUnaryCallable( @@ -76,18 +74,10 @@ public UnaryCallable createBatchingCa @Override public OperationCallable createOperationCallable( - HttpJsonCallSettings httpJsonCallSettings, + HttpJsonCallSettings httpJsonCallSettings, OperationCallSettings callSettings, ClientContext clientContext, BackgroundResource operationsStub) { - UnaryCallable innerCallable = - HttpJsonCallableFactory.createBaseUnaryCallable( - httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); - HttpJsonOperationSnapshotCallable initialCallable = - new HttpJsonOperationSnapshotCallable( - innerCallable, - httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); - return HttpJsonCallableFactory.createOperationCallable( - callSettings, clientContext, operationsStub.longRunningClient(), initialCallable); + return null; } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java index 1949dd2c60..c167489173 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java @@ -36,6 +36,7 @@ import com.google.cloud.compute.v1.GetRegionOperationRequest; import com.google.cloud.compute.v1.Operation; import com.google.cloud.compute.v1.Operation.Status; +import com.google.cloud.compute.v1.WaitRegionOperationRequest; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -107,7 +108,41 @@ public class HttpJsonRegionOperationsStub extends RegionOperationsStub { }) .build(); + private static final ApiMethodDescriptor + waitMethodDescriptor = + ApiMethodDescriptor.newBuilder() + .setFullMethodName("google.cloud.compute.v1.RegionOperations/Wait") + .setHttpMethod(HttpMethods.POST) + .setRequestFormatter( + ProtoMessageRequestFormatter.newBuilder() + .setPath( + "/compute/v1/projects/projects/{project}/regions/{region}/operations/{operation}/wait", + request -> { + Map fields = new HashMap<>(); + ProtoRestSerializer serializer = + ProtoRestSerializer.create(); + serializer.putPathParam(fields, "operation", request.getOperation()); + serializer.putPathParam(fields, "project", request.getProject()); + serializer.putPathParam(fields, "region", request.getRegion()); + return fields; + }) + .setQueryParamsExtractor( + request -> { + Map> fields = new HashMap<>(); + ProtoRestSerializer serializer = + ProtoRestSerializer.create(); + return fields; + }) + .setRequestBodyExtractor(request -> null) + .build()) + .setResponseParser( + ProtoMessageResponseParser.newBuilder() + .setDefaultInstance(Operation.getDefaultInstance()) + .build()) + .build(); + private final UnaryCallable getCallable; + private final UnaryCallable waitCallable; private final BackgroundResource backgroundResources; private final LongRunningClient longRunningClient; @@ -156,10 +191,17 @@ protected HttpJsonRegionOperationsStub( HttpJsonCallSettings.newBuilder() .setMethodDescriptor(getMethodDescriptor) .build(); + HttpJsonCallSettings waitTransportSettings = + HttpJsonCallSettings.newBuilder() + .setMethodDescriptor(waitMethodDescriptor) + .build(); this.getCallable = callableFactory.createUnaryCallable( getTransportSettings, settings.getSettings(), clientContext); + this.waitCallable = + callableFactory.createUnaryCallable( + waitTransportSettings, settings.waitSettings(), clientContext); this.longRunningClient = new HttpJsonLongRunningClient( @@ -174,6 +216,7 @@ protected HttpJsonRegionOperationsStub( public static List getMethodDescriptors() { List methodDescriptors = new ArrayList<>(); methodDescriptors.add(getMethodDescriptor); + methodDescriptors.add(waitMethodDescriptor); return methodDescriptors; } @@ -182,6 +225,11 @@ public UnaryCallable getCallable() { return getCallable; } + @Override + public UnaryCallable waitCallable() { + return waitCallable; + } + @Override public LongRunningClient longRunningClient() { return longRunningClient; diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStub.java index c3019038cb..2d40fa610a 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStub.java @@ -16,10 +16,13 @@ package com.google.cloud.compute.v1.stub; +import com.google.api.core.BetaApi; import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.rpc.LongRunningClient; import com.google.api.gax.rpc.UnaryCallable; import com.google.cloud.compute.v1.GetRegionOperationRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.WaitRegionOperationRequest; import javax.annotation.Generated; // AUTO-GENERATED DOCUMENTATION AND CLASS. @@ -31,10 +34,19 @@ @Generated("by gapic-generator-java") public abstract class RegionOperationsStub implements BackgroundResource { + @BetaApi + public LongRunningClient longRunningClient() { + throw new UnsupportedOperationException("Not implemented: longRunningClient()"); + } + public UnaryCallable getCallable() { throw new UnsupportedOperationException("Not implemented: getCallable()"); } + public UnaryCallable waitCallable() { + throw new UnsupportedOperationException("Not implemented: waitCallable()"); + } + @Override public abstract void close(); } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStubSettings.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStubSettings.java index ebcf98e4f7..3c57601386 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStubSettings.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/RegionOperationsStubSettings.java @@ -33,6 +33,7 @@ import com.google.api.gax.rpc.UnaryCallSettings; import com.google.cloud.compute.v1.GetRegionOperationRequest; import com.google.cloud.compute.v1.Operation; +import com.google.cloud.compute.v1.WaitRegionOperationRequest; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -85,12 +86,18 @@ public class RegionOperationsStubSettings extends StubSettings getSettings; + private final UnaryCallSettings waitSettings; /** Returns the object with the settings used for calls to get. */ public UnaryCallSettings getSettings() { return getSettings; } + /** Returns the object with the settings used for calls to wait. */ + public UnaryCallSettings waitSettings() { + return waitSettings; + } + @BetaApi("A restructuring of stub classes is planned, so this may break in the future") public RegionOperationsStub createStub() throws IOException { if (getTransportChannelProvider() @@ -167,12 +174,14 @@ protected RegionOperationsStubSettings(Builder settingsBuilder) throws IOExcepti super(settingsBuilder); getSettings = settingsBuilder.getSettings().build(); + waitSettings = settingsBuilder.waitSettings().build(); } /** Builder for RegionOperationsStubSettings. */ public static class Builder extends StubSettings.Builder { private final ImmutableList> unaryMethodSettingsBuilders; private final UnaryCallSettings.Builder getSettings; + private final UnaryCallSettings.Builder waitSettings; private static final ImmutableMap> RETRYABLE_CODE_DEFINITIONS; @@ -184,6 +193,7 @@ public static class Builder extends StubSettings.BuildernewArrayList( StatusCode.Code.DEADLINE_EXCEEDED, StatusCode.Code.UNAVAILABLE))); + definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.newArrayList())); RETRYABLE_CODE_DEFINITIONS = definitions.build(); } @@ -203,6 +213,8 @@ public static class Builder extends StubSettings.Builder>of(getSettings); + unaryMethodSettingsBuilders = + ImmutableList.>of(getSettings, waitSettings); initDefaults(this); } @@ -223,8 +237,10 @@ protected Builder(RegionOperationsStubSettings settings) { super(settings); getSettings = settings.getSettings.toBuilder(); + waitSettings = settings.waitSettings.toBuilder(); - unaryMethodSettingsBuilders = ImmutableList.>of(getSettings); + unaryMethodSettingsBuilders = + ImmutableList.>of(getSettings, waitSettings); } private static Builder createDefault() { @@ -246,6 +262,11 @@ private static Builder initDefaults(Builder builder) { .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("retry_policy_0_codes")) .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("retry_policy_0_params")); + builder + .waitSettings() + .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes")) + .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params")); + return builder; } @@ -269,6 +290,11 @@ public UnaryCallSettings.Builder getSettin return getSettings; } + /** Returns the builder for the settings used for calls to wait. */ + public UnaryCallSettings.Builder waitSettings() { + return waitSettings; + } + @Override public RegionOperationsStubSettings build() throws IOException { return new RegionOperationsStubSettings(this); From 8ae8e6f111d0f3849986cd0445d6003601ced148 Mon Sep 17 00:00:00 2001 From: Vadym Matsishevskyi <25311427+vam-google@users.noreply.github.com> Date: Thu, 9 Sep 2021 01:59:39 -0700 Subject: [PATCH 6/9] fix: DIREGAPIC LRO generated tests logic (#838) --- ...bstractServiceClientTestClassComposer.java | 24 +++--------- .../defaultvalue/DefaultValueComposer.java | 35 ++++++++++++++++- .../HttpJsonServiceStubClassComposer.java | 5 ++- .../api/generator/gapic/model/Message.java | 4 +- .../gapic/model/OperationResponse.java | 6 --- .../generator/gapic/protoparser/Parser.java | 7 +++- .../cloud/compute/v1/AddressesClientTest.java | 39 +++++++------------ .../v1/RegionOperationsClientTest.java | 7 +++- 8 files changed, 67 insertions(+), 60 deletions(-) diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java index 364dd183b3..8309679eae 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java @@ -59,6 +59,7 @@ import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.Method; import com.google.api.generator.gapic.model.MethodArgument; +import com.google.api.generator.gapic.model.OperationResponse; import com.google.api.generator.gapic.model.ResourceName; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; @@ -413,7 +414,10 @@ private MethodDefinition createRpcTestMethod( .setValueExpr(expectedResponseValExpr) .build()); - if (method.hasLro()) { + if (method.hasLro() + && (method.lro().operationServiceStubType() == null + || !method.lro().responseType().equals(method.outputType()))) { + VariableExpr resultOperationVarExpr = VariableExpr.withVariable( Variable.builder() @@ -910,24 +914,6 @@ private void addDynamicTypes(GapicContext context, Service service, TypeStore ty } } - private static TypeNode getOperationCallSettingsTypeHelper( - Method protoMethod, boolean isBuilder) { - Preconditions.checkState( - protoMethod.hasLro(), - String.format("Cannot get OperationCallSettings on non-LRO method %s", protoMethod.name())); - Class callSettingsClazz = - isBuilder ? OperationCallSettings.Builder.class : OperationCallSettings.class; - return TypeNode.withReference( - ConcreteReference.builder() - .setClazz(callSettingsClazz) - .setGenerics( - Arrays.asList( - protoMethod.inputType().reference(), - protoMethod.lro().responseType().reference(), - protoMethod.lro().metadataType().reference())) - .build()); - } - private static TypeNode getCallSettingsTypeHelper( Method protoMethod, TypeStore typeStore, boolean isBuilder) { Class callSettingsClazz = isBuilder ? UnaryCallSettings.Builder.class : UnaryCallSettings.class; diff --git a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java index 5af2722fd7..1b0ffc3c41 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java @@ -27,6 +27,7 @@ import com.google.api.generator.engine.ast.StringObjectValue; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; +import com.google.api.generator.engine.ast.VaporReference; import com.google.api.generator.engine.ast.Variable; import com.google.api.generator.engine.ast.VariableExpr; import com.google.api.generator.gapic.composer.resourcename.ResourceNameTokenizer; @@ -265,9 +266,12 @@ public static Expr createSimpleMessageBuilderExpr( .setStaticReferenceType(message.type()) .setMethodName("newBuilder") .build(); + for (Field field : message.fields()) { if (field.isContainedInOneof() // Avoid colliding fields. - || ((field.isMessage() || field.isEnum()) // Avoid importing unparsed messages. + || ((field.isMessage() + || (field.isEnum() + && message.operationResponse() == null)) // Avoid importing unparsed messages. && !field.isRepeated() && !messageTypes.containsKey(field.type().reference().fullName()))) { continue; @@ -292,7 +296,34 @@ public static Expr createSimpleMessageBuilderExpr( .setReturnType(TypeNode.STRING) .build(); } else { - defaultExpr = createDefaultValue(field, true); + if (message.operationResponse() != null) { + if (field.name().equals(message.operationResponse().statusFieldName())) { + String statusTypeName = message.operationResponse().statusFieldTypeName(); + String statusClassName = statusTypeName.substring(statusTypeName.lastIndexOf('.') + 1); + + TypeNode statusType = + TypeNode.withReference( + VaporReference.builder() + .setName(statusClassName) + .setPakkage(message.type().reference().fullName()) + .setIsStaticImport(false) + .build()); + defaultExpr = + VariableExpr.builder() + .setVariable(Variable.builder().setName("DONE").setType(statusType).build()) + .setStaticReferenceType(statusType) + .build(); + + } else if (field.name().equals(message.operationResponse().errorCodeFieldName())) { + defaultExpr = + ValueExpr.withValue( + PrimitiveValue.builder().setType(field.type()).setValue("0").build()); + } + } + + if (defaultExpr == null) { + defaultExpr = createDefaultValue(field, true); + } } builderExpr = MethodInvocationExpr.builder() diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java index fb45703936..59a05c0a62 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java @@ -511,11 +511,14 @@ private List setOperationSnapshotFactoryExpr( String statusTypeName = operationResponse.statusFieldTypeName(); String statusClassName = statusTypeName.substring(statusTypeName.lastIndexOf('.') + 1); + TypeNode opType = + protoMethod.hasLro() ? protoMethod.lro().responseType() : protoMethod.outputType(); + TypeNode statusType = TypeNode.withReference( VaporReference.builder() .setName(statusClassName) - .setPakkage(protoMethod.outputType().reference().fullName()) + .setPakkage(opType.reference().fullName()) .setIsStaticImport(false) .build()); VariableExpr statusDoneExpr = diff --git a/src/main/java/com/google/api/generator/gapic/model/Message.java b/src/main/java/com/google/api/generator/gapic/model/Message.java index 51245444fe..91a5388e37 100644 --- a/src/main/java/com/google/api/generator/gapic/model/Message.java +++ b/src/main/java/com/google/api/generator/gapic/model/Message.java @@ -53,6 +53,7 @@ public abstract class Message { public abstract ImmutableMap fieldMap(); + @Nullable public abstract OperationResponse operationResponse(); public abstract Map operationRequestFields(); @@ -113,8 +114,7 @@ public static Builder builder() { .setFieldMap(Collections.emptyMap()) .setEnumValues(Collections.emptyMap()) .setOperationResponseFields(HashBiMap.create()) - .setOperationRequestFields(Collections.emptyMap()) - .setOperationResponse(OperationResponse.builder().build()); + .setOperationRequestFields(Collections.emptyMap()); } @AutoValue.Builder diff --git a/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java b/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java index 20543d3fc8..9ad5ac385f 100644 --- a/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java +++ b/src/main/java/com/google/api/generator/gapic/model/OperationResponse.java @@ -16,23 +16,17 @@ package com.google.api.generator.gapic.model; import com.google.auto.value.AutoValue; -import javax.annotation.Nullable; @AutoValue public abstract class OperationResponse { - @Nullable public abstract String nameFieldName(); - @Nullable public abstract String statusFieldName(); - @Nullable public abstract String errorCodeFieldName(); - @Nullable public abstract String errorMessageFieldName(); - @Nullable public abstract String statusFieldTypeName(); public static Builder builder() { diff --git a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java index a5f227a3d7..1ccfc3d1eb 100644 --- a/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java +++ b/src/main/java/com/google/api/generator/gapic/protoparser/Parser.java @@ -564,7 +564,7 @@ private static Map parseMessages( List fields = messageDescriptor.getFields(); HashMap operationRequestFields = new HashMap(); BiMap operationResponseFields = HashBiMap.create(); - OperationResponse.Builder operationResponse = OperationResponse.builder(); + OperationResponse.Builder operationResponse = null; for (FieldDescriptor fd : fields) { if (fd.getOptions().hasExtension(ExtendedOperationsProto.operationRequestField)) { String orf = fd.getOptions().getExtension(ExtendedOperationsProto.operationRequestField); @@ -577,6 +577,9 @@ private static Map parseMessages( if (fd.getOptions().hasExtension(ExtendedOperationsProto.operationField)) { OperationResponseMapping orm = fd.getOptions().getExtension(ExtendedOperationsProto.operationField); + if (operationResponse == null) { + operationResponse = OperationResponse.builder(); + } if (orm.equals(OperationResponseMapping.NAME)) { operationResponse.setNameFieldName(fd.getName()); } else if (orm.equals(OperationResponseMapping.STATUS)) { @@ -599,7 +602,7 @@ private static Map parseMessages( .setOuterNestedTypes(outerNestedTypes) .setOperationRequestFields(operationRequestFields) .setOperationResponseFields(operationResponseFields) - .setOperationResponse(operationResponse.build()) + .setOperationResponse(operationResponse != null ? operationResponse.build() : null) .build()); return messages; } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java index 04f3ea46b9..ec3f75047c 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/AddressesClientTest.java @@ -28,10 +28,9 @@ import com.google.api.gax.rpc.InvalidArgumentException; import com.google.api.gax.rpc.StatusCode; import com.google.api.gax.rpc.testing.FakeStatusCode; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.stub.HttpJsonAddressesStub; import com.google.common.collect.Lists; -import com.google.longrunning.Operation; -import com.google.protobuf.Any; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -135,15 +134,15 @@ public void aggregatedListExceptionTest() throws Exception { @Test public void deleteTest() throws Exception { - com.google.cloud.compute.v1.Operation expectedResponse = - com.google.cloud.compute.v1.Operation.newBuilder() + Operation expectedResponse = + Operation.newBuilder() .setClientOperationId("clientOperationId-1230366697") .setCreationTimestamp("creationTimestamp-370203401") .setDescription("description-1724546052") .setEndTime("endTime-1607243192") .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") - .setHttpErrorStatusCode(1386087020) + .setHttpErrorStatusCode(0) .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") @@ -153,6 +152,7 @@ public void deleteTest() throws Exception { .setRegion("region-934795532") .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") + .setStatus(Status.DONE) .setStatusMessage("statusMessage-958704715") .setTargetId(-815576439) .setTargetLink("targetLink486368555") @@ -160,20 +160,13 @@ public void deleteTest() throws Exception { .addAllWarnings(new ArrayList()) .setZone("zone3744684") .build(); - Operation resultOperation = - Operation.newBuilder() - .setName("deleteTest") - .setDone(true) - .setResponse(Any.pack(expectedResponse)) - .build(); - mockService.addResponse(resultOperation); + mockService.addResponse(expectedResponse); String project = "project-309310695"; String region = "region-934795532"; String address = "address-1147692044"; - com.google.cloud.compute.v1.Operation actualResponse = - client.deleteAsync(project, region, address).get(); + Operation actualResponse = client.deleteAsync(project, region, address).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockService.getRequestPaths(); @@ -210,15 +203,15 @@ public void deleteExceptionTest() throws Exception { @Test public void insertTest() throws Exception { - com.google.cloud.compute.v1.Operation expectedResponse = - com.google.cloud.compute.v1.Operation.newBuilder() + Operation expectedResponse = + Operation.newBuilder() .setClientOperationId("clientOperationId-1230366697") .setCreationTimestamp("creationTimestamp-370203401") .setDescription("description-1724546052") .setEndTime("endTime-1607243192") .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") - .setHttpErrorStatusCode(1386087020) + .setHttpErrorStatusCode(0) .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") @@ -228,6 +221,7 @@ public void insertTest() throws Exception { .setRegion("region-934795532") .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") + .setStatus(Status.DONE) .setStatusMessage("statusMessage-958704715") .setTargetId(-815576439) .setTargetLink("targetLink486368555") @@ -235,20 +229,13 @@ public void insertTest() throws Exception { .addAllWarnings(new ArrayList()) .setZone("zone3744684") .build(); - Operation resultOperation = - Operation.newBuilder() - .setName("insertTest") - .setDone(true) - .setResponse(Any.pack(expectedResponse)) - .build(); - mockService.addResponse(resultOperation); + mockService.addResponse(expectedResponse); String project = "project-309310695"; String region = "region-934795532"; Address addressResource = Address.newBuilder().build(); - com.google.cloud.compute.v1.Operation actualResponse = - client.insertAsync(project, region, addressResource).get(); + Operation actualResponse = client.insertAsync(project, region, addressResource).get(); Assert.assertEquals(expectedResponse, actualResponse); List actualRequests = mockService.getRequestPaths(); diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java index 684c1312ab..c1a2c78519 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/RegionOperationsClientTest.java @@ -25,6 +25,7 @@ import com.google.api.gax.rpc.InvalidArgumentException; import com.google.api.gax.rpc.StatusCode; import com.google.api.gax.rpc.testing.FakeStatusCode; +import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.stub.HttpJsonRegionOperationsStub; import java.io.IOException; import java.util.ArrayList; @@ -82,7 +83,7 @@ public void getTest() throws Exception { .setEndTime("endTime-1607243192") .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") - .setHttpErrorStatusCode(1386087020) + .setHttpErrorStatusCode(0) .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") @@ -92,6 +93,7 @@ public void getTest() throws Exception { .setRegion("region-934795532") .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") + .setStatus(Status.DONE) .setStatusMessage("statusMessage-958704715") .setTargetId(-815576439) .setTargetLink("targetLink486368555") @@ -151,7 +153,7 @@ public void waitTest() throws Exception { .setEndTime("endTime-1607243192") .setError(Error.newBuilder().build()) .setHttpErrorMessage("httpErrorMessage1577303431") - .setHttpErrorStatusCode(1386087020) + .setHttpErrorStatusCode(0) .setId(3355) .setInsertTime("insertTime966165798") .setKind("kind3292052") @@ -161,6 +163,7 @@ public void waitTest() throws Exception { .setRegion("region-934795532") .setSelfLink("selfLink1191800166") .setStartTime("startTime-2129294769") + .setStatus(Status.DONE) .setStatusMessage("statusMessage-958704715") .setTargetId(-815576439) .setTargetLink("targetLink486368555") From cb1b534701b95781e5195e57eacf6d0abff252bf Mon Sep 17 00:00:00 2001 From: vam-google Date: Tue, 21 Sep 2021 03:31:40 -0700 Subject: [PATCH 7/9] feat: Add REST AIP-151 LRO suport Depends on https://github.com/googleapis/gax-java/pull/1484 --- ...ractTransportServiceStubClassComposer.java | 106 +++-- .../composer/grpcrest/GrpcRestContext.java | 4 +- ...onServiceCallableFactoryClassComposer.java | 14 +- .../HttpJsonServiceStubClassComposer.java | 365 ++++++++++++------ .../gapic/composer/rest/RestContext.java | 4 +- .../HttpJsonComplianceCallableFactory.golden | 20 +- .../goldens/HttpJsonComplianceStub.golden | 15 + .../v1/stub/HttpJsonAddressesStub.java | 12 + ...tpJsonRegionOperationsCallableFactory.java | 20 +- .../v1/stub/HttpJsonRegionOperationsStub.java | 7 + 10 files changed, 386 insertions(+), 181 deletions(-) diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java index 3aa79a452f..d3b9eae6f9 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java @@ -17,6 +17,7 @@ import com.google.api.core.BetaApi; import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.core.BackgroundResourceAggregation; +import com.google.api.gax.longrunning.OperationSnapshot; import com.google.api.gax.rpc.BidiStreamingCallable; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.ClientStreamingCallable; @@ -119,6 +120,7 @@ private static TypeStore createStaticTypes() { IOException.class, Operation.class, OperationCallable.class, + OperationSnapshot.class, RequestParamsExtractor.class, ServerStreamingCallable.class, TimeUnit.class, @@ -161,7 +163,7 @@ public GapicClass generate(GapicContext context, Service service) { } boolean operationPollingMethod = checkOperationPollingMethod(service); - if(operationPollingMethod) { + if (operationPollingMethod) { VariableExpr longRunningVarExpr = declareLongRunningClient(); if (longRunningVarExpr != null) { classMemberVarExprs.put("longRunningClient", longRunningVarExpr); @@ -212,7 +214,10 @@ public GapicClass generate(GapicContext context, Service service) { } protected abstract Statement createMethodDescriptorVariableDecl( - Service service, Method protoMethod, VariableExpr methodDescriptorVarExpr, Map messageTypes); + Service service, + Method protoMethod, + VariableExpr methodDescriptorVarExpr, + Map messageTypes); protected boolean generateOperationsStubLogic(Service service) { return true; @@ -227,7 +232,8 @@ protected List createOperationsStubGetterMethod( String methodName = String.format( "get%s", - JavaStyle.toUpperCamelCase(getTransportContext().transportOperationsStubNames().get(0))); + JavaStyle.toUpperCamelCase( + getTransportContext().transportOperationsStubNames().get(0))); return Arrays.asList( MethodDefinition.builder() @@ -248,6 +254,10 @@ protected List createGetMethodDescriptorsMethod( return Arrays.asList(); } + protected List createTypeRegistry(Service service) { + return Arrays.asList(); + } + protected List createClassStatements( Service service, Map protoMethodNameToDescriptorVarExprs, @@ -255,8 +265,15 @@ protected List createClassStatements( Map classMemberVarExprs, Map messageTypes) { List classStatements = new ArrayList<>(); + + classStatements.addAll(createTypeRegistry(service)); + if (!classStatements.isEmpty()) { + classStatements.add(EMPTY_LINE_STATEMENT); + } + for (Statement statement : - createMethodDescriptorVariableDecls(service, protoMethodNameToDescriptorVarExprs, messageTypes)) { + createMethodDescriptorVariableDecls( + service, protoMethodNameToDescriptorVarExprs, messageTypes)) { classStatements.add(statement); classStatements.add(EMPTY_LINE_STATEMENT); } @@ -265,11 +282,15 @@ protected List createClassStatements( classStatements.add(EMPTY_LINE_STATEMENT); classStatements.addAll(createClassMemberFieldDeclarations(classMemberVarExprs)); + classStatements.add(EMPTY_LINE_STATEMENT); + return classStatements; } protected List createMethodDescriptorVariableDecls( - Service service, Map protoMethodNameToDescriptorVarExprs, Map messageTypes) { + Service service, + Map protoMethodNameToDescriptorVarExprs, + Map messageTypes) { return service.methods().stream() .map( m -> @@ -418,14 +439,17 @@ protected List createClassMethods( createGetMethodDescriptorsMethod(service, typeStore, protoMethodNameToDescriptorVarExprs)); javaMethods.addAll( createOperationsStubGetterMethod( - service, classMemberVarExprs.get(getTransportContext().transportOperationsStubNames().get(0)))); + service, + classMemberVarExprs.get(getTransportContext().transportOperationsStubNames().get(0)))); javaMethods.addAll(createCallableGetterMethods(callableClassMemberVarExprs)); javaMethods.addAll( - createStubOverrideMethods(classMemberVarExprs.get(BACKGROUND_RESOURCES_MEMBER_NAME), service)); + createStubOverrideMethods( + classMemberVarExprs.get(BACKGROUND_RESOURCES_MEMBER_NAME), service)); return javaMethods; } - protected List createStaticCreatorMethods(Service service, TypeStore typeStore, String newBuilderMethod) { + protected List createStaticCreatorMethods( + Service service, TypeStore typeStore, String newBuilderMethod) { TypeNode creatorMethodReturnType = typeStore.get(getTransportContext().classNames().getTransportServiceStubClassName(service)); Function, MethodDefinition.Builder> creatorMethodStarterFn = @@ -584,22 +608,16 @@ protected List createConstructorMethods( .build()) .setValueExpr(callableFactoryVarExpr) .build()); - VariableExpr operationsStubClassVarExpr = classMemberVarExprs.get(getTransportContext().transportOperationsStubNames().get(0)); - //TODO: refactor this + VariableExpr operationsStubClassVarExpr = + classMemberVarExprs.get(getTransportContext().transportOperationsStubNames().get(0)); + // TODO: refactor this if (generateOperationsStubLogic(service)) { - TypeNode opeationsStubType = getTransportOperationsStubType(service); - secondCtorExprs.add( - AssignmentExpr.builder() - .setVariableExpr( - operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) - .setValueExpr( - MethodInvocationExpr.builder() - .setStaticReferenceType(opeationsStubType) - .setMethodName("create") - .setArguments(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr)) - .setReturnType(operationsStubClassVarExpr.type()) - .build()) - .build()); + secondCtorExprs.addAll(createOperationsStubInitExpr( + service, + thisExpr, + operationsStubClassVarExpr, + clientContextVarExpr, + callableFactoryVarExpr)); } secondCtorStatements.addAll( secondCtorExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList())); @@ -665,7 +683,6 @@ protected List createConstructorMethods( secondCtorExprs.clear(); secondCtorStatements.add(EMPTY_LINE_STATEMENT); - secondCtorStatements.addAll(createLongRunningClient(service, typeStore)); // Instantiate backgroundResources. @@ -699,6 +716,27 @@ protected List createConstructorMethods( return Arrays.asList(firstCtor, secondCtor); } + protected List createOperationsStubInitExpr( + Service service, + Expr thisExpr, + VariableExpr operationsStubClassVarExpr, + VariableExpr clientContextVarExpr, + VariableExpr callableFactoryVarExpr) { + TypeNode opeationsStubType = getTransportOperationsStubType(service); + return Collections.singletonList( + AssignmentExpr.builder() + .setVariableExpr( + operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) + .setValueExpr( + MethodInvocationExpr.builder() + .setStaticReferenceType(opeationsStubType) + .setMethodName("create") + .setArguments(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr)) + .setReturnType(operationsStubClassVarExpr.type()) + .build()) + .build()); + } + protected List createLongRunningClient(Service service, TypeStore typeStore) { return ImmutableList.of(); } @@ -963,8 +1001,8 @@ private List createStubOverrideMethods( } private boolean checkOperationPollingMethod(Service service) { - for(Method method : service.methods()) { - if(method.isOperationPollingMethod()) { + for (Method method : service.methods()) { + if (method.isOperationPollingMethod()) { return true; } } @@ -1063,15 +1101,15 @@ protected TypeNode getTransportOperationsStubType(Service service) { TypeNode transportOpeationsStubType = service.operationServiceStubType(); if (transportOpeationsStubType == null) { transportOpeationsStubType = getTransportContext().transportOperationsStubTypes().get(0); - } - else { - transportOpeationsStubType = TypeNode.withReference( - VaporReference.builder() - .setName("HttpJson" + transportOpeationsStubType.reference().simpleName()) - .setPakkage(transportOpeationsStubType.reference().pakkage()) - .build()); + } else { + transportOpeationsStubType = + TypeNode.withReference( + VaporReference.builder() + .setName("HttpJson" + transportOpeationsStubType.reference().simpleName()) + .setPakkage(transportOpeationsStubType.reference().pakkage()) + .build()); } return transportOpeationsStubType; } -} \ No newline at end of file +} diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java index 3f84bf3c97..59376001e2 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java @@ -14,7 +14,6 @@ package com.google.api.generator.gapic.composer.grpcrest; -import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.grpc.GrpcTransportChannel; import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider; import com.google.api.gax.grpc.ProtoOperationTransformers; @@ -72,7 +71,8 @@ public abstract class GrpcRestContext extends TransportContext { .setTransportCallableFactoryType(null) .setOperationsStubTypes( ImmutableList.of( - classToType(OperationsStub.class), classToType(BackgroundResource.class))) + classToType(OperationsStub.class), + classToType(com.google.api.gax.httpjson.longrunning.stub.OperationsStub.class))) .setTransportCallSettingsName(null) // For RetrySettingsComposer // TODO: fix when LRO for REST RE FIXED diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java index a7b525239e..b295cb8f83 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java @@ -27,14 +27,13 @@ import com.google.api.generator.engine.ast.NewObjectExpr; import com.google.api.generator.engine.ast.Statement; import com.google.api.generator.engine.ast.TypeNode; -import com.google.api.generator.engine.ast.ValueExpr; import com.google.api.generator.engine.ast.VaporReference; import com.google.api.generator.engine.ast.Variable; import com.google.api.generator.engine.ast.VariableExpr; import com.google.api.generator.gapic.composer.common.AbstractServiceCallableFactoryClassComposer; import com.google.api.generator.gapic.composer.store.TypeStore; import com.google.api.generator.gapic.model.Service; -import com.google.common.collect.ImmutableList; +import com.google.longrunning.Operation; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -46,7 +45,7 @@ public class HttpJsonServiceCallableFactoryClassComposer new HttpJsonServiceCallableFactoryClassComposer(); private static final TypeNode DEFAULT_OPERATION_TYPE = - TypeNode.withReference(ConcreteReference.withClazz(Object.class)); + TypeNode.withReference(ConcreteReference.withClazz(Operation.class)); private HttpJsonServiceCallableFactoryClassComposer() { super(RestContext.instance()); @@ -129,15 +128,6 @@ protected MethodDefinition createOperationCallableMethod(Service service, TypeSt Arrays.asList(betaAnnotation)); List createOperationCallableBody = new ArrayList<>(); - if (service.operationServiceStubType() == null) { - // It is an Operation polling service, it cannot contain LRO methods - return method - .toBuilder() - .setBody(ImmutableList.of()) - .setReturnExpr(ValueExpr.createNullExpr()) - .build(); - } - List arguments = new ArrayList<>(method.arguments()); Variable httpJsonCallSettingsVar = arguments.get(0).variable(); diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java index 59a05c0a62..172326176d 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java @@ -25,6 +25,7 @@ import com.google.api.gax.httpjson.ProtoMessageRequestFormatter; import com.google.api.gax.httpjson.ProtoMessageResponseParser; import com.google.api.gax.httpjson.ProtoRestSerializer; +import com.google.api.gax.httpjson.longrunning.stub.HttpJsonOperationsStub; import com.google.api.gax.longrunning.OperationSnapshot; import com.google.api.gax.rpc.LongRunningClient; import com.google.api.gax.rpc.UnaryCallable; @@ -59,6 +60,7 @@ import com.google.api.generator.gapic.utils.JavaStyle; import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableList; +import com.google.protobuf.TypeRegistry; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -76,6 +78,14 @@ public class HttpJsonServiceStubClassComposer extends AbstractTransportServiceSt new HttpJsonServiceStubClassComposer(); private static final TypeStore FIXED_REST_TYPESTORE = createStaticTypes(); + private static final VariableExpr TYPE_REGISTRY_VAR_EXPR = + VariableExpr.builder() + .setVariable( + Variable.builder() + .setName("typeRegistry") + .setType(FIXED_REST_TYPESTORE.get(TypeRegistry.class.getSimpleName())) + .build()) + .build(); protected HttpJsonServiceStubClassComposer() { super(RestContext.instance()); @@ -94,11 +104,13 @@ private static TypeStore createStaticTypes() { InternalApi.class, HashMap.class, HttpJsonCallSettings.class, + HttpJsonOperationSnapshot.class, HttpJsonStubCallableFactory.class, Map.class, ProtoMessageRequestFormatter.class, ProtoMessageResponseParser.class, - ProtoRestSerializer.class)); + ProtoRestSerializer.class, + TypeRegistry.class)); } @Override @@ -201,6 +213,13 @@ protected Expr createTransportSettingsInitExpr( .setArguments(Arrays.asList(methodDescriptorVarExpr)) .build(); + callSettingsBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(callSettingsBuilderExpr) + .setMethodName("setTypeRegistry") + .setArguments(Arrays.asList(TYPE_REGISTRY_VAR_EXPR)) + .build(); + callSettingsBuilderExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(callSettingsBuilderExpr) @@ -396,6 +415,11 @@ private List setResponseParserExpr(Method protoMethod) { .setReturnType(protoMethod.outputType()) .build())) .apply(expr); + + expr = + methodMaker + .apply("setDefaultTypeRegistry", Arrays.asList(TYPE_REGISTRY_VAR_EXPR)) + .apply(expr); expr = methodMaker.apply("build", Collections.emptyList()).apply(expr); return Collections.singletonList(expr); @@ -451,15 +475,6 @@ private MethodInvocationExpr getExpr(VariableExpr var, String num) { private List setOperationSnapshotFactoryExpr( Method protoMethod, Map messageTypes) { - Message inputOperationMessage = - messageTypes.get(protoMethod.inputType().reference().fullName()); - Message outputOperationMessage = - messageTypes.get(protoMethod.outputType().reference().fullName()); - OperationResponse operationResponse = outputOperationMessage.operationResponse(); - - BiFunction, Function> - methodMaker = getMethodMaker(); - // Generate input varibles for create() VariableExpr requestVarExpr = VariableExpr.withVariable( @@ -468,127 +483,148 @@ private List setOperationSnapshotFactoryExpr( VariableExpr.withVariable( Variable.builder().setType(protoMethod.outputType()).setName("response").build()); - List createBody = new ArrayList(4); + MethodInvocationExpr buildExpr; + List createBody = new ArrayList<>(4); - // Generate opName - TypeNode stringBuilderType = - TypeNode.withReference(ConcreteReference.withClazz(StringBuilder.class)); - VariableExpr opNameVarExpr = - VariableExpr.withVariable( - Variable.builder().setType(stringBuilderType).setName("opName").build()); - MethodInvocationExpr getId = - MethodInvocationExpr.builder() - .setExprReferenceExpr(responseVarExpr) - .setMethodName(getMethodFormat(operationResponse.nameFieldName())) - .build(); - Expr opNameObjectExpr = - NewObjectExpr.builder().setType(stringBuilderType).setArguments(getId).build(); - AssignmentExpr opNameAssignExpr = - AssignmentExpr.builder() - .setVariableExpr(opNameVarExpr.toBuilder().setIsDecl(true).build()) - .setValueExpr(opNameObjectExpr) - .build(); - createBody.add(ExprStatement.withExpr(opNameAssignExpr)); - - // Generate compound operation name - if (!protoMethod.isOperationPollingMethod()) { - // TODO: Change to ordered map - Map requestFields = inputOperationMessage.operationRequestFields(); - List fieldAnnotationNames = new ArrayList(requestFields.keySet()); - Collections.sort(fieldAnnotationNames); - for (String fieldName : fieldAnnotationNames) { - createBody.add(appendField(opNameVarExpr, requestVarExpr, requestFields.get(fieldName))); + TypeNode httpJsonOperationSnapshotType = + FIXED_REST_TYPESTORE.get(HttpJsonOperationSnapshot.class.getSimpleName()); + TypeNode operationSnapshotType = FIXED_TYPESTORE.get(OperationSnapshot.class.getSimpleName()); + + Message inputOperationMessage = + messageTypes.get(protoMethod.inputType().reference().fullName()); + Message outputOperationMessage = + messageTypes.get(protoMethod.outputType().reference().fullName()); + OperationResponse operationResponse = outputOperationMessage.operationResponse(); + + if (operationResponse == null) { + // AIP-151 LRO + // HttpJsonOperationSnapshot.create(response) + buildExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(httpJsonOperationSnapshotType) + .setMethodName("create") + .setArguments(responseVarExpr) + .setReturnType(operationSnapshotType) + .build(); + } else { + BiFunction, Function> + methodMaker = getMethodMaker(); + + // Generate opName + TypeNode stringBuilderType = + TypeNode.withReference(ConcreteReference.withClazz(StringBuilder.class)); + VariableExpr opNameVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(stringBuilderType).setName("opName").build()); + MethodInvocationExpr getId = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName(getMethodFormat(operationResponse.nameFieldName())) + .build(); + Expr opNameObjectExpr = + NewObjectExpr.builder().setType(stringBuilderType).setArguments(getId).build(); + AssignmentExpr opNameAssignExpr = + AssignmentExpr.builder() + .setVariableExpr(opNameVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr(opNameObjectExpr) + .build(); + createBody.add(ExprStatement.withExpr(opNameAssignExpr)); + + // Generate compound operation name + if (!protoMethod.isOperationPollingMethod()) { + // TODO: Change to ordered map + Map requestFields = inputOperationMessage.operationRequestFields(); + List fieldAnnotationNames = new ArrayList(requestFields.keySet()); + Collections.sort(fieldAnnotationNames); + for (String fieldName : fieldAnnotationNames) { + createBody.add(appendField(opNameVarExpr, requestVarExpr, requestFields.get(fieldName))); + } } - } - // Generate check for status == done - MethodInvocationExpr getStatusExpr = - MethodInvocationExpr.builder() - .setExprReferenceExpr(responseVarExpr) - .setMethodName(getMethodFormat(operationResponse.statusFieldName())) - .build(); + // Generate check for status == done + MethodInvocationExpr getStatusExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName(getMethodFormat(operationResponse.statusFieldName())) + .build(); - String statusTypeName = operationResponse.statusFieldTypeName(); - String statusClassName = statusTypeName.substring(statusTypeName.lastIndexOf('.') + 1); + String statusTypeName = operationResponse.statusFieldTypeName(); + String statusClassName = statusTypeName.substring(statusTypeName.lastIndexOf('.') + 1); - TypeNode opType = - protoMethod.hasLro() ? protoMethod.lro().responseType() : protoMethod.outputType(); + TypeNode opType = + protoMethod.hasLro() ? protoMethod.lro().responseType() : protoMethod.outputType(); - TypeNode statusType = - TypeNode.withReference( - VaporReference.builder() - .setName(statusClassName) - .setPakkage(opType.reference().fullName()) - .setIsStaticImport(false) - .build()); - VariableExpr statusDoneExpr = - VariableExpr.builder() - .setVariable(Variable.builder().setName("DONE").setType(TypeNode.INT).build()) - .setStaticReferenceType(statusType) - .build(); - MethodInvocationExpr statusEqualsExpr = - MethodInvocationExpr.builder() - .setExprReferenceExpr(statusDoneExpr) - .setMethodName("equals") - .setArguments(getStatusExpr) - .build(); + TypeNode statusType = + TypeNode.withReference( + VaporReference.builder() + .setName(statusClassName) + .setPakkage(opType.reference().fullName()) + .setIsStaticImport(false) + .build()); + VariableExpr statusDoneExpr = + VariableExpr.builder() + .setVariable(Variable.builder().setName("DONE").setType(TypeNode.INT).build()) + .setStaticReferenceType(statusType) + .build(); + MethodInvocationExpr statusEqualsExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(statusDoneExpr) + .setMethodName("equals") + .setArguments(getStatusExpr) + .build(); - // Generate return statement - TypeNode httpJsonOperationSnapshotType = - TypeNode.withReference(ConcreteReference.withClazz(HttpJsonOperationSnapshot.class)); + // Generate return statement - // Generate getter methods from annotations - MethodInvocationExpr opNameToStringExpr = - MethodInvocationExpr.builder() - .setExprReferenceExpr(opNameVarExpr) - .setMethodName("toString") - .build(); - MethodInvocationExpr getHttpErrorStatusCodeExpr = - MethodInvocationExpr.builder() - .setExprReferenceExpr(responseVarExpr) - .setMethodName(getMethodFormat(operationResponse.errorCodeFieldName())) - .build(); - MethodInvocationExpr getHttpErrorMessageExpr = - MethodInvocationExpr.builder() - .setExprReferenceExpr(responseVarExpr) - .setMethodName(getMethodFormat(operationResponse.errorMessageFieldName())) - .build(); - MethodInvocationExpr newBuilderExpr = - MethodInvocationExpr.builder() - .setStaticReferenceType(httpJsonOperationSnapshotType) - .setMethodName("newBuilder") - .build(); + // Generate getter methods from annotations + MethodInvocationExpr opNameToStringExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(opNameVarExpr) + .setMethodName("toString") + .build(); + MethodInvocationExpr getHttpErrorStatusCodeExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName(getMethodFormat(operationResponse.errorCodeFieldName())) + .build(); + MethodInvocationExpr getHttpErrorMessageExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(responseVarExpr) + .setMethodName(getMethodFormat(operationResponse.errorMessageFieldName())) + .build(); + MethodInvocationExpr newBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(httpJsonOperationSnapshotType) + .setMethodName("newBuilder") + .build(); - newBuilderExpr = - methodMaker - .apply("setName", Collections.singletonList(opNameToStringExpr)) - .apply(newBuilderExpr); - newBuilderExpr = - methodMaker - .apply("setMetadata", Collections.singletonList(responseVarExpr)) - .apply(newBuilderExpr); - newBuilderExpr = - methodMaker - .apply("setDone", Collections.singletonList(statusEqualsExpr)) - .apply(newBuilderExpr); - newBuilderExpr = - methodMaker - .apply("setResponse", Collections.singletonList(responseVarExpr)) - .apply(newBuilderExpr); - newBuilderExpr = - methodMaker - .apply("setError", Arrays.asList(getHttpErrorStatusCodeExpr, getHttpErrorMessageExpr)) - .apply(newBuilderExpr); - TypeNode operationSnapshotType = - TypeNode.withReference( - ConcreteReference.builder().setClazz(OperationSnapshot.class).build()); - MethodInvocationExpr buildExpr = - MethodInvocationExpr.builder() - .setExprReferenceExpr(newBuilderExpr) - .setMethodName("build") - .setReturnType(operationSnapshotType) - .build(); + newBuilderExpr = + methodMaker + .apply("setName", Collections.singletonList(opNameToStringExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setMetadata", Collections.singletonList(responseVarExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setDone", Collections.singletonList(statusEqualsExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setResponse", Collections.singletonList(responseVarExpr)) + .apply(newBuilderExpr); + newBuilderExpr = + methodMaker + .apply("setError", Arrays.asList(getHttpErrorStatusCodeExpr, getHttpErrorMessageExpr)) + .apply(newBuilderExpr); + buildExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(newBuilderExpr) + .setMethodName("build") + .setReturnType(operationSnapshotType) + .build(); + } // Generate lambda anonymous class return Collections.singletonList( LambdaExpr.builder() @@ -942,6 +978,36 @@ private List getHttpMethodTypeExpr(Method protoMethod) { return Collections.singletonList(expr); } + @Override + protected List createOperationsStubInitExpr( + Service service, + Expr thisExpr, + VariableExpr operationsStubClassVarExpr, + VariableExpr clientContextVarExpr, + VariableExpr callableFactoryVarExpr) { + TypeNode opeationsStubType = getTransportOperationsStubType(service); + String standardOpStub = HttpJsonOperationsStub.class.getName(); + + List arguments = + new ArrayList<>(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr)); + if (standardOpStub.equals(opeationsStubType.reference().fullName())) { + arguments.add(TYPE_REGISTRY_VAR_EXPR); + } + + return Collections.singletonList( + AssignmentExpr.builder() + .setVariableExpr( + operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) + .setValueExpr( + MethodInvocationExpr.builder() + .setStaticReferenceType(opeationsStubType) + .setMethodName("create") + .setArguments(arguments) + .setReturnType(operationsStubClassVarExpr.type()) + .build()) + .build()); + } + @Override protected List createLongRunningClient(Service service, TypeStore typeStore) { Method pollingMethod = service.operationPollingMethod(); @@ -1047,4 +1113,61 @@ protected Optional getCallableCreatorMethodName(TypeNode callableVarExpr } return Optional.of(String.format("create%sCallable", streamName)); } + + @Override + protected List createTypeRegistry(Service service) { + TypeNode typeRegistryType = FIXED_REST_TYPESTORE.get(TypeRegistry.class.getSimpleName()); + + VariableExpr typeRegistryVarExpr = + TYPE_REGISTRY_VAR_EXPR + .toBuilder() + .setIsDecl(true) + .setIsStatic(true) + .setScope(ScopeNode.PRIVATE) + .setIsFinal(true) + .build(); + + Map anyTypes = new HashMap<>(); + for (Method method : service.methods()) { + if (method.hasLro()) { + TypeNode anyType = method.lro().responseType(); + anyTypes.put(anyType.reference().fullName(), anyType); + anyType = method.lro().metadataType(); + anyTypes.put(anyType.reference().fullName(), anyType); + } + } + + Expr typeRegistryBuilderExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(typeRegistryType) + .setMethodName("newBuilder") + .build(); + + for (TypeNode anyType : anyTypes.values()) { + typeRegistryBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(typeRegistryBuilderExpr) + .setMethodName("add") + .setArguments( + MethodInvocationExpr.builder() + .setStaticReferenceType(anyType) + .setMethodName("getDescriptor") + .build()) + .build(); + } + + typeRegistryBuilderExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(typeRegistryBuilderExpr) + .setMethodName("build") + .setReturnType(typeRegistryType) + .build(); + + return Collections.singletonList( + ExprStatement.withExpr( + AssignmentExpr.builder() + .setVariableExpr(typeRegistryVarExpr) + .setValueExpr(typeRegistryBuilderExpr) + .build())); + } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java b/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java index eab59215bf..2502a9128e 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/RestContext.java @@ -14,7 +14,6 @@ package com.google.api.generator.gapic.composer.rest; -import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.httpjson.ApiMethodDescriptor; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; @@ -24,6 +23,7 @@ import com.google.api.gax.httpjson.ProtoOperationTransformers; import com.google.api.gax.httpjson.longrunning.OperationsClient; import com.google.api.gax.httpjson.longrunning.stub.HttpJsonOperationsStub; +import com.google.api.gax.httpjson.longrunning.stub.OperationsStub; import com.google.api.generator.gapic.composer.common.TransportContext; import com.google.api.generator.gapic.composer.utils.ClassNames; import com.google.api.generator.gapic.model.Transport; @@ -58,7 +58,7 @@ public abstract class RestContext extends TransportContext { .setTransportCallSettingsType(classToType(HttpJsonCallSettings.class)) .setTransportCallableFactoryType(classToType(HttpJsonCallableFactory.class)) // TODO: set to com.google.api.gax.httpjson.longrunning.stub.OperationsStub.class - .setOperationsStubTypes(ImmutableList.of(classToType(BackgroundResource.class))) + .setOperationsStubTypes(ImmutableList.of(classToType(OperationsStub.class))) .setTransportCallSettingsName("httpJsonCallSettings") // For RetrySettingsComposer .setOperationResponseTransformerType( diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden index ab84437e6e..6f5e7eab3b 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceCallableFactory.golden @@ -1,10 +1,11 @@ package com.google.showcase.v1beta1.stub; import com.google.api.core.BetaApi; -import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; +import com.google.api.gax.httpjson.longrunning.stub.OperationsStub; import com.google.api.gax.rpc.BatchingCallSettings; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.OperationCallSettings; @@ -12,6 +13,7 @@ import com.google.api.gax.rpc.OperationCallable; import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; +import com.google.longrunning.Operation; import javax.annotation.Generated; // AUTO-GENERATED DOCUMENTATION AND CLASS. @@ -23,7 +25,7 @@ import javax.annotation.Generated; @BetaApi @Generated("by gapic-generator-java") public class HttpJsonComplianceCallableFactory - implements HttpJsonStubCallableFactory { + implements HttpJsonStubCallableFactory { @Override public UnaryCallable createUnaryCallable( @@ -58,10 +60,18 @@ public class HttpJsonComplianceCallableFactory @Override public OperationCallable createOperationCallable( - HttpJsonCallSettings httpJsonCallSettings, + HttpJsonCallSettings httpJsonCallSettings, OperationCallSettings callSettings, ClientContext clientContext, - BackgroundResource operationsStub) { - return null; + OperationsStub operationsStub) { + UnaryCallable innerCallable = + HttpJsonCallableFactory.createBaseUnaryCallable( + httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); + HttpJsonOperationSnapshotCallable initialCallable = + new HttpJsonOperationSnapshotCallable( + innerCallable, + httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); + return HttpJsonCallableFactory.createOperationCallable( + callSettings, clientContext, operationsStub.longRunningClient(), initialCallable); } } diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden index 331e5bf961..6b6a701df9 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden @@ -13,6 +13,7 @@ import com.google.api.gax.httpjson.ProtoMessageResponseParser; import com.google.api.gax.httpjson.ProtoRestSerializer; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.UnaryCallable; +import com.google.protobuf.TypeRegistry; import com.google.showcase.v1beta1.RepeatRequest; import com.google.showcase.v1beta1.RepeatResponse; import java.io.IOException; @@ -33,6 +34,8 @@ import javax.annotation.Generated; @Generated("by gapic-generator-java") @BetaApi("A restructuring of stub classes is planned, so this may break in the future") public class HttpJsonComplianceStub extends ComplianceStub { + private static final TypeRegistry typeRegistry = TypeRegistry.newBuilder().build(); + private static final ApiMethodDescriptor repeatDataBodyMethodDescriptor = ApiMethodDescriptor.newBuilder() @@ -62,6 +65,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -96,6 +100,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -130,6 +135,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -176,6 +182,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -220,6 +227,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -261,6 +269,7 @@ public class HttpJsonComplianceStub extends ComplianceStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(RepeatResponse.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -315,27 +324,33 @@ public class HttpJsonComplianceStub extends ComplianceStub { HttpJsonCallSettings repeatDataBodyTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataBodyMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataBodyInfoTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataBodyInfoMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataQueryTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataQueryMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataSimplePathTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataSimplePathMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataPathResourceTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataPathResourceMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings repeatDataPathTrailingResourceTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(repeatDataPathTrailingResourceMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); this.repeatDataBodyCallable = diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java index 9e5e90fbe1..679bfc1ae2 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonAddressesStub.java @@ -43,6 +43,7 @@ import com.google.cloud.compute.v1.ListAddressesRequest; import com.google.cloud.compute.v1.Operation; import com.google.cloud.compute.v1.Operation.Status; +import com.google.protobuf.TypeRegistry; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -60,6 +61,9 @@ @Generated("by gapic-generator-java") @BetaApi("A restructuring of stub classes is planned, so this may break in the future") public class HttpJsonAddressesStub extends AddressesStub { + private static final TypeRegistry typeRegistry = + TypeRegistry.newBuilder().add(Operation.getDescriptor()).build(); + private static final ApiMethodDescriptor aggregatedListMethodDescriptor = ApiMethodDescriptor.newBuilder() @@ -105,6 +109,7 @@ public class HttpJsonAddressesStub extends AddressesStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(AddressAggregatedList.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -140,6 +145,7 @@ public class HttpJsonAddressesStub extends AddressesStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(Operation.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .setOperationSnapshotFactory( (DeleteAddressRequest request, Operation response) -> { @@ -190,6 +196,7 @@ public class HttpJsonAddressesStub extends AddressesStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(Operation.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .setOperationSnapshotFactory( (InsertAddressRequest request, Operation response) -> { @@ -244,6 +251,7 @@ public class HttpJsonAddressesStub extends AddressesStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(AddressList.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -307,18 +315,22 @@ protected HttpJsonAddressesStub( aggregatedListTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(aggregatedListMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings deleteTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(deleteMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings insertTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(insertMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings listTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(listMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); this.aggregatedListCallable = diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java index 24e9ad539a..16d93e6f94 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsCallableFactory.java @@ -17,10 +17,11 @@ package com.google.cloud.compute.v1.stub; import com.google.api.core.BetaApi; -import com.google.api.gax.core.BackgroundResource; import com.google.api.gax.httpjson.HttpJsonCallSettings; import com.google.api.gax.httpjson.HttpJsonCallableFactory; +import com.google.api.gax.httpjson.HttpJsonOperationSnapshotCallable; import com.google.api.gax.httpjson.HttpJsonStubCallableFactory; +import com.google.api.gax.httpjson.longrunning.stub.OperationsStub; import com.google.api.gax.rpc.BatchingCallSettings; import com.google.api.gax.rpc.ClientContext; import com.google.api.gax.rpc.OperationCallSettings; @@ -28,6 +29,7 @@ import com.google.api.gax.rpc.PagedCallSettings; import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.gax.rpc.UnaryCallable; +import com.google.longrunning.Operation; import javax.annotation.Generated; // AUTO-GENERATED DOCUMENTATION AND CLASS. @@ -39,7 +41,7 @@ @Generated("by gapic-generator-java") @BetaApi public class HttpJsonRegionOperationsCallableFactory - implements HttpJsonStubCallableFactory { + implements HttpJsonStubCallableFactory { @Override public UnaryCallable createUnaryCallable( @@ -74,10 +76,18 @@ public UnaryCallable createBatchingCa @Override public OperationCallable createOperationCallable( - HttpJsonCallSettings httpJsonCallSettings, + HttpJsonCallSettings httpJsonCallSettings, OperationCallSettings callSettings, ClientContext clientContext, - BackgroundResource operationsStub) { - return null; + OperationsStub operationsStub) { + UnaryCallable innerCallable = + HttpJsonCallableFactory.createBaseUnaryCallable( + httpJsonCallSettings, callSettings.getInitialCallSettings(), clientContext); + HttpJsonOperationSnapshotCallable initialCallable = + new HttpJsonOperationSnapshotCallable( + innerCallable, + httpJsonCallSettings.getMethodDescriptor().getOperationSnapshotFactory()); + return HttpJsonCallableFactory.createOperationCallable( + callSettings, clientContext, operationsStub.longRunningClient(), initialCallable); } } diff --git a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java index c167489173..0f081f8c40 100644 --- a/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java +++ b/test/integration/goldens/compute/com/google/cloud/compute/v1/stub/HttpJsonRegionOperationsStub.java @@ -37,6 +37,7 @@ import com.google.cloud.compute.v1.Operation; import com.google.cloud.compute.v1.Operation.Status; import com.google.cloud.compute.v1.WaitRegionOperationRequest; +import com.google.protobuf.TypeRegistry; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -55,6 +56,8 @@ @Generated("by gapic-generator-java") @BetaApi("A restructuring of stub classes is planned, so this may break in the future") public class HttpJsonRegionOperationsStub extends RegionOperationsStub { + private static final TypeRegistry typeRegistry = TypeRegistry.newBuilder().build(); + private static final ApiMethodDescriptor getMethodDescriptor = ApiMethodDescriptor.newBuilder() @@ -85,6 +88,7 @@ public class HttpJsonRegionOperationsStub extends RegionOperationsStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(Operation.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .setOperationSnapshotFactory( (GetRegionOperationRequest request, Operation response) -> { @@ -138,6 +142,7 @@ public class HttpJsonRegionOperationsStub extends RegionOperationsStub { .setResponseParser( ProtoMessageResponseParser.newBuilder() .setDefaultInstance(Operation.getDefaultInstance()) + .setDefaultTypeRegistry(typeRegistry) .build()) .build(); @@ -190,10 +195,12 @@ protected HttpJsonRegionOperationsStub( HttpJsonCallSettings getTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(getMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); HttpJsonCallSettings waitTransportSettings = HttpJsonCallSettings.newBuilder() .setMethodDescriptor(waitMethodDescriptor) + .setTypeRegistry(typeRegistry) .build(); this.getCallable = From d029941dc32e11391ffbab1cac4979350bea39d9 Mon Sep 17 00:00:00 2001 From: vam-google Date: Tue, 5 Oct 2021 19:06:24 -0700 Subject: [PATCH 8/9] chore: merge changes from master --- .../common/AbstractServiceClientTestClassComposer.java | 4 ++++ .../composer/common/AbstractServiceStubClassComposer.java | 2 +- .../composer/rest/HttpJsonServiceStubClassComposer.java | 5 ----- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java index 2ea1cfcd84..b38ca70edd 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientTestClassComposer.java @@ -20,8 +20,12 @@ import com.google.api.gax.rpc.BidiStreamingCallable; import com.google.api.gax.rpc.ClientStreamingCallable; import com.google.api.gax.rpc.InvalidArgumentException; +import com.google.api.gax.rpc.PagedCallSettings; +import com.google.api.gax.rpc.ServerStreamingCallSettings; import com.google.api.gax.rpc.ServerStreamingCallable; import com.google.api.gax.rpc.StatusCode; +import com.google.api.gax.rpc.StreamingCallSettings; +import com.google.api.gax.rpc.UnaryCallSettings; import com.google.api.generator.engine.ast.AnnotationNode; import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.ClassDefinition; diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java index c54ccbde39..b50f15ff38 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceStubClassComposer.java @@ -253,7 +253,7 @@ private static List createBackgroundResourceMethodOverrides() } private static TypeStore createTypes(Service service, Map messageTypes) { - List concreteClazzes = + List> concreteClazzes = Arrays.asList( BackgroundResource.class, BetaApi.class, diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java index 3710be16bf..172326176d 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java @@ -118,11 +118,6 @@ protected boolean generateOperationsStubLogic(Service service) { return service.hasLroMethods(); } - @Override - protected boolean generateOperationsStubLogic(Service service) { - return service.hasLroMethods(); - } - @Override protected Statement createMethodDescriptorVariableDecl( Service service, From 84c04c98867003aad6a6b2346ba024924130ce52 Mon Sep 17 00:00:00 2001 From: vam-google Date: Thu, 7 Oct 2021 15:58:42 -0700 Subject: [PATCH 9/9] chore: Address PR feedback --- repositories.bzl | 6 ++---- ...AbstractServiceCallableFactoryClassComposer.java | 12 ++++++------ .../common/AbstractServiceClientClassComposer.java | 2 +- .../AbstractTransportServiceStubClassComposer.java | 13 +++++-------- .../GrpcServiceCallableFactoryClassComposer.java | 2 +- ...HttpJsonServiceCallableFactoryClassComposer.java | 9 ++------- .../rest/HttpJsonServiceStubClassComposer.java | 6 +++--- .../google/api/generator/gapic/testdata/BUILD.bazel | 1 + .../api/generator/gapic/testdata/compliance.proto | 1 + 9 files changed, 22 insertions(+), 30 deletions(-) diff --git a/repositories.bzl b/repositories.bzl index 6091b21171..d9010f6151 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -65,14 +65,12 @@ def gapic_generator_java_repositories(): ], ) - # TODO: replace with upstream googleapis-discovery link once - # https://github.com/googleapis/googleapis-discovery/pull/59 is merged _maybe( http_archive, name = "com_google_googleapis_discovery", - strip_prefix = "googleapis-discovery-bb8a053b93ef8698297c41634aa9201f7e075277", + strip_prefix = "googleapis-discovery-34478e2969042ed837d33684360f1ee3be7d2f74", urls = [ - "https://github.com/vam-google/googleapis-discovery/archive/bb8a053b93ef8698297c41634aa9201f7e075277.zip", + "https://github.com/googleapis/googleapis-discovery/archive/34478e2969042ed837d33684360f1ee3be7d2f74.zip", ], ) diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java index 224bece718..0c2fc84036 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceCallableFactoryClassComposer.java @@ -78,7 +78,7 @@ public GapicClass generate(GapicContext context, Service service) { commentComposer.createTransportServiceCallableFactoryClassHeaderComments( service.name(), service.isDeprecated())) .setAnnotations(createClassAnnotations(service, typeStore)) - .setImplementsTypes(createClassImplements(typeStore, service)) + .setImplementsTypes(createClassImplements(service, typeStore)) .setName(className) .setMethods(createClassMethods(service, typeStore)) .setScope(ScopeNode.PUBLIC) @@ -111,7 +111,7 @@ protected List createClassAnnotations(Service service, TypeStore * @return {@code TypeNode} containing the interface to be implemented by the generated callable * factory class. */ - protected abstract List createClassImplements(TypeStore typeStore, Service service); + protected abstract List createClassImplements(Service service, TypeStore typeStore); protected List createClassMethods(Service service, TypeStore typeStore) { return Arrays.asList( @@ -297,11 +297,11 @@ protected MethodDefinition createGenericCallableMethod( } protected TypeNode getOperationsStubType(Service service) { - TypeNode opeationsStubType = service.operationServiceStubType(); - if (opeationsStubType == null) { - opeationsStubType = getTransportContext().operationsStubTypes().get(0); + TypeNode operationsStubType = service.operationServiceStubType(); + if (operationsStubType == null) { + operationsStubType = getTransportContext().operationsStubTypes().get(0); } - return opeationsStubType; + return operationsStubType; } diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java index 031f1cc2dd..beb777f543 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractServiceClientClassComposer.java @@ -752,7 +752,7 @@ private static MethodDefinition createMethodDefaultMethod( .copyAndSetGenerics( Arrays.asList( lro.responseType().reference(), lro.metadataType().reference()))); - if (method.hasLro() && method.lro().operationServiceStubType() != null) { + if (method.lro().operationServiceStubType() != null) { annotations.add( AnnotationNode.withTypeAndDescription( typeStore.get("BetaApi"), diff --git a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java index 3d3aafdaa9..0d190273a3 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java @@ -76,6 +76,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import javax.annotation.Generated; +import javax.annotation.Nullable; public abstract class AbstractTransportServiceStubClassComposer implements ClassComposer { private static final Statement EMPTY_LINE_STATEMENT = EmptyLineStatement.create(); @@ -152,13 +153,13 @@ public GapicClass generate(GapicContext context, Service service) { .build())); if (generateOperationsStubLogic(service)) { // Transport-specific service stub may have only one element of the following, thus get(0). - TypeNode opeationsStubType = getTransportOperationsStubType(service); + TypeNode operationsStubType = getTransportOperationsStubType(service); classMemberVarExprs.put( getTransportContext().transportOperationsStubNames().get(0), VariableExpr.withVariable( Variable.builder() .setName(getTransportContext().transportOperationsStubNames().get(0)) - .setType(opeationsStubType) + .setType(operationsStubType) .build())); } @@ -741,6 +742,7 @@ protected List createLongRunningClient(Service service, TypeStore typ return ImmutableList.of(); } + @Nullable protected VariableExpr declareLongRunningClient() { return null; } @@ -1001,12 +1003,7 @@ private List createStubOverrideMethods( } private boolean checkOperationPollingMethod(Service service) { - for (Method method : service.methods()) { - if (method.isOperationPollingMethod()) { - return true; - } - } - return false; + return service.methods().stream().anyMatch(Method::isOperationPollingMethod); } protected List createLongRunningClientGetters() { diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java index 38446187e8..581066f3e6 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceCallableFactoryClassComposer.java @@ -42,7 +42,7 @@ public static GrpcServiceCallableFactoryClassComposer instance() { } @Override - protected List createClassImplements(TypeStore typeStore, Service service) { + protected List createClassImplements(Service service, TypeStore typeStore) { return Arrays.asList(getTransportContext().stubCallableFactoryType()); } diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java index b295cb8f83..88ccc1e0c9 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceCallableFactoryClassComposer.java @@ -70,7 +70,7 @@ protected List createClassAnnotations(Service service, TypeStore } @Override - protected List createClassImplements(TypeStore typeStore, Service service) { + protected List createClassImplements(Service service, TypeStore typeStore) { TypeNode operationsStubType = getOperationsStubType(service); TypeNode operationType = service.operationType(); @@ -186,12 +186,7 @@ protected MethodDefinition createOperationCallableMethod(Service service, TypeSt VariableExpr initialCallableVarExpr = VariableExpr.builder() .setVariable( - Variable.builder() - .setName("initialCallable") - .setType( - initialCallableType) // TypeNode.withReference(ConcreteReference.withClazz(UnaryCallable.class))) - .build()) - // .setTemplateObjects(Arrays.asList(requestTemplateName, "OperationSnapshot")) + Variable.builder().setName("initialCallable").setType(initialCallableType).build()) .build(); MethodInvocationExpr getMethodDescriptorExpr = MethodInvocationExpr.builder() diff --git a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java index 172326176d..f3770e5ca9 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java @@ -985,12 +985,12 @@ protected List createOperationsStubInitExpr( VariableExpr operationsStubClassVarExpr, VariableExpr clientContextVarExpr, VariableExpr callableFactoryVarExpr) { - TypeNode opeationsStubType = getTransportOperationsStubType(service); + TypeNode operationsStubType = getTransportOperationsStubType(service); String standardOpStub = HttpJsonOperationsStub.class.getName(); List arguments = new ArrayList<>(Arrays.asList(clientContextVarExpr, callableFactoryVarExpr)); - if (standardOpStub.equals(opeationsStubType.reference().fullName())) { + if (standardOpStub.equals(operationsStubType.reference().fullName())) { arguments.add(TYPE_REGISTRY_VAR_EXPR); } @@ -1000,7 +1000,7 @@ protected List createOperationsStubInitExpr( operationsStubClassVarExpr.toBuilder().setExprReferenceExpr(thisExpr).build()) .setValueExpr( MethodInvocationExpr.builder() - .setStaticReferenceType(opeationsStubType) + .setStaticReferenceType(operationsStubType) .setMethodName("create") .setArguments(arguments) .setReturnType(operationsStubClassVarExpr.type()) diff --git a/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel index 1a5133b74c..ecbdd6a532 100644 --- a/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel +++ b/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel @@ -56,6 +56,7 @@ proto_library( "@com_google_googleapis//google/api:client_proto", "@com_google_googleapis//google/api:field_behavior_proto", "@com_google_googleapis//google/api:resource_proto", + "@com_google_googleapis//google/cloud:extended_operations_proto", "@com_google_googleapis//google/longrunning:operations_proto", "@com_google_googleapis//google/rpc:error_details_proto", "@com_google_googleapis//google/rpc:status_proto", diff --git a/src/test/java/com/google/api/generator/gapic/testdata/compliance.proto b/src/test/java/com/google/api/generator/gapic/testdata/compliance.proto index c602452b13..4467a387ab 100644 --- a/src/test/java/com/google/api/generator/gapic/testdata/compliance.proto +++ b/src/test/java/com/google/api/generator/gapic/testdata/compliance.proto @@ -16,6 +16,7 @@ syntax = "proto3"; import "google/api/annotations.proto"; import "google/api/client.proto"; +import "google/cloud/extended_operations.proto"; package google.showcase.v1beta1;