From cb1b534701b95781e5195e57eacf6d0abff252bf Mon Sep 17 00:00:00 2001 From: vam-google Date: Tue, 21 Sep 2021 03:31:40 -0700 Subject: [PATCH] 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 =