From bfb35cd31c05b5fbd2ea8073bcdcfdd3496bca12 Mon Sep 17 00:00:00 2001 From: Vadym Matsishevskyi <25311427+vam-google@users.noreply.github.com> Date: Fri, 21 Jan 2022 12:48:06 -0800 Subject: [PATCH] feat: make generated test values comply with url path template (#903) This includes nested messages creation when there are url paths with subfields mentioned (like `/v1/{field.name=projects/*/databases/*/collectionGroups/*/fields/*}`) This is needed for rest transports tests because, unlike grpc, request fields must match path templates for rest logic pass the tests. Main changes are in `DefaultValueComposer` and `HttpRuleParser` classes. The generated pattern-matching samples are in the following format: given the pattern pattern: `/v1/{field.name=projects/*/databases/*/collectionGroups/*/fields/*}` the value will be: `field.name=projects/project-1234/databases/database-1234/collectionGroups/collectionGroup-1234/fields/field-1234` --- ...bstractServiceClientTestClassComposer.java | 46 ++++-- .../composer/common/TransportContext.java | 4 + .../defaultvalue/DefaultValueComposer.java | 145 +++++++++++------ .../gapic/composer/grpc/GrpcContext.java | 1 + .../grpc/ServiceClientTestClassComposer.java | 16 +- .../composer/grpcrest/GrpcRestContext.java | 1 + .../HttpJsonServiceStubClassComposer.java | 2 +- .../gapic/composer/rest/RestContext.java | 1 + .../rest/ServiceClientTestClassComposer.java | 7 - .../ServiceClientSampleCodeComposer.java | 16 +- .../generator/gapic/model/HttpBindings.java | 23 ++- .../gapic/protoparser/HttpRuleParser.java | 42 ++++- .../protoparser/MethodSignatureParser.java | 1 + .../DefaultValueComposerTest.java | 44 ++--- .../rest/goldens/ComplianceClientTest.golden | 151 +++++++++++++++++- .../cloud/compute/v1/AddressesClientTest.java | 32 ++-- .../v1/RegionOperationsClientTest.java | 24 +-- 17 files changed, 403 insertions(+), 153 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 0784c38bb7..a02ac5cd1f 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 @@ -354,7 +354,7 @@ private MethodDefinition createRpcTestMethod( AssignmentExpr.builder() .setVariableExpr(responsesElementVarExpr.toBuilder().setIsDecl(true).build()) .setValueExpr( - DefaultValueComposer.createDefaultValue( + DefaultValueComposer.createValue( Field.builder() .setType(repeatedResponseType) .setName("responsesElement") @@ -377,7 +377,7 @@ private MethodDefinition createRpcTestMethod( method.name(), methodOutputMessage.name())); expectedResponseValExpr = - DefaultValueComposer.createSimplePagedResponse( + DefaultValueComposer.createSimplePagedResponseValue( method.outputType(), firstRepeatedField.name(), responsesElementVarExpr, @@ -385,7 +385,7 @@ private MethodDefinition createRpcTestMethod( } else { if (messageTypes.containsKey(methodOutputType.reference().fullName())) { expectedResponseValExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( + DefaultValueComposer.createSimpleMessageBuilderValue( messageTypes.get(methodOutputType.reference().fullName()), resourceNames, messageTypes); @@ -393,7 +393,7 @@ private MethodDefinition createRpcTestMethod( // Wrap this in a field so we don't have to split the helper into lots of different methods, // or duplicate it for VariableExpr. expectedResponseValExpr = - DefaultValueComposer.createDefaultValue( + DefaultValueComposer.createValue( Field.builder() .setType(methodOutputType) .setIsMessage(true) @@ -422,7 +422,7 @@ private MethodDefinition createRpcTestMethod( AssignmentExpr.builder() .setVariableExpr(resultOperationVarExpr.toBuilder().setIsDecl(true).build()) .setValueExpr( - DefaultValueComposer.createSimpleOperationBuilderExpr( + DefaultValueComposer.createSimpleOperationBuilderValue( String.format("%sTest", JavaStyle.toLowerCamelCase(method.name())), expectedResponseVarExpr)) .build()); @@ -457,22 +457,32 @@ private MethodDefinition createRpcTestMethod( argExprs.add(requestVarExpr); requestMessage = messageTypes.get(method.inputType().reference().fullName()); Preconditions.checkNotNull(requestMessage); + Map pathParamValuePatterns = Collections.emptyMap(); + if (getTransportContext().useValuePatterns() && method.hasHttpBindings()) { + pathParamValuePatterns = method.httpBindings().getPathParametersValuePatterns(); + } Expr valExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( - requestMessage, resourceNames, messageTypes); + DefaultValueComposer.createSimpleMessageBuilderValue( + requestMessage, resourceNames, messageTypes, pathParamValuePatterns); methodExprs.add( AssignmentExpr.builder() .setVariableExpr(requestVarExpr.toBuilder().setIsDecl(true).build()) .setValueExpr(valExpr) .build()); } else { + Map valuePatterns = Collections.emptyMap(); + if (getTransportContext().useValuePatterns() && method.hasHttpBindings()) { + valuePatterns = method.httpBindings().getPathParametersValuePatterns(); + } for (MethodArgument methodArg : methodSignature) { String methodArgName = JavaStyle.toLowerCamelCase(methodArg.name()); VariableExpr varExpr = VariableExpr.withVariable( Variable.builder().setType(methodArg.type()).setName(methodArgName).build()); argExprs.add(varExpr); - Expr valExpr = createDefaultValue(methodArg, resourceNames); + Expr valExpr = + DefaultValueComposer.createMethodArgValue( + methodArg, resourceNames, messageTypes, valuePatterns); methodExprs.add( AssignmentExpr.builder() .setVariableExpr(varExpr.toBuilder().setIsDecl(true).build()) @@ -737,9 +747,6 @@ protected abstract List createStreamingRpcExceptionTestStatements( Map resourceNames, Map messageTypes); - protected abstract Expr createDefaultValue( - MethodArgument methodArg, Map resourceNames); - protected List createRpcExceptionTestStatements( Method method, List methodSignature, @@ -748,6 +755,7 @@ protected List createRpcExceptionTestStatements( Map messageTypes) { List argVarExprs = new ArrayList<>(); List tryBodyExprs = new ArrayList<>(); + if (methodSignature.isEmpty()) { // Construct the actual request. VariableExpr varExpr = @@ -756,22 +764,32 @@ protected List createRpcExceptionTestStatements( argVarExprs.add(varExpr); Message requestMessage = messageTypes.get(method.inputType().reference().fullName()); Preconditions.checkNotNull(requestMessage); + Map valuePatterns = Collections.emptyMap(); + if (getTransportContext().useValuePatterns() && method.hasHttpBindings()) { + valuePatterns = method.httpBindings().getPathParametersValuePatterns(); + } Expr valExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( - requestMessage, resourceNames, messageTypes); + DefaultValueComposer.createSimpleMessageBuilderValue( + requestMessage, resourceNames, messageTypes, valuePatterns); tryBodyExprs.add( AssignmentExpr.builder() .setVariableExpr(varExpr.toBuilder().setIsDecl(true).build()) .setValueExpr(valExpr) .build()); } else { + Map valuePatterns = Collections.emptyMap(); + if (getTransportContext().useValuePatterns() && method.hasHttpBindings()) { + valuePatterns = method.httpBindings().getPathParametersValuePatterns(); + } for (MethodArgument methodArg : methodSignature) { String methodArgName = JavaStyle.toLowerCamelCase(methodArg.name()); VariableExpr varExpr = VariableExpr.withVariable( Variable.builder().setType(methodArg.type()).setName(methodArgName).build()); argVarExprs.add(varExpr); - Expr valExpr = createDefaultValue(methodArg, resourceNames); + Expr valExpr = + DefaultValueComposer.createMethodArgValue( + methodArg, resourceNames, messageTypes, valuePatterns); tryBodyExprs.add( AssignmentExpr.builder() .setVariableExpr(varExpr.toBuilder().setIsDecl(true).build()) 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 507ff662ca..5a171c19b5 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 @@ -81,6 +81,8 @@ public abstract class TransportContext { public abstract List operationsClientNames(); + public abstract boolean useValuePatterns(); + protected static TypeNode classToType(Class clazz) { return TypeNode.withReference(ConcreteReference.withClazz(clazz)); } @@ -140,6 +142,8 @@ public abstract Builder setTransportApiClientHeaderProviderBuilderNames( public abstract Builder setOperationsClientNames(List operationsClientNames); + public abstract Builder setUseValuePatterns(boolean useValuePatterns); + 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 957a5ca4d3..7a2d53fe44 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 @@ -50,19 +50,23 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.regex.Pattern; import java.util.stream.Collectors; public class DefaultValueComposer { - private static TypeNode OPERATION_TYPE = + private static final TypeNode OPERATION_TYPE = TypeNode.withReference(ConcreteReference.withClazz(Operation.class)); - private static TypeNode ANY_TYPE = TypeNode.withReference(ConcreteReference.withClazz(Any.class)); + private static final TypeNode ANY_TYPE = + TypeNode.withReference(ConcreteReference.withClazz(Any.class)); - public static Expr createDefaultValue( + private static final Pattern REPLACER_PATTERN = Pattern.compile("(\\w*)(\\w/|-\\d+/)\\*"); + + public static Expr createMethodArgValue( MethodArgument methodArg, Map resourceNames, - boolean forceResourceNameInitializer) { - if (methodArg.isResourceNameHelper() - || (forceResourceNameInitializer && methodArg.field().hasResourceReference())) { + Map messageTypes, + Map valuePatterns) { + if (methodArg.isResourceNameHelper()) { Preconditions.checkState( methodArg.field().hasResourceReference(), String.format( @@ -76,7 +80,7 @@ public static Expr createDefaultValue( "No resource name found for reference %s", methodArg.field().resourceReference().resourceTypeString())); Expr defValue = - createDefaultValue( + createResourceHelperValue( resourceName, methodArg.field().resourceReference().isChildType(), resourceNames.values().stream().collect(Collectors.toList()), @@ -94,26 +98,31 @@ public static Expr createDefaultValue( } if (methodArg.type().equals(methodArg.field().type())) { - return createDefaultValue(methodArg.field()); + return createValue(methodArg.field(), false, resourceNames, messageTypes, valuePatterns); } - return createDefaultValue( - Field.builder().setName(methodArg.name()).setType(methodArg.type()).build()); + return createValue(Field.builder().setName(methodArg.name()).setType(methodArg.type()).build()); } - public static Expr createDefaultValue(Field f) { - return createDefaultValue(f, false); + public static Expr createValue(Field field) { + return createValue( + field, false, Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap()); } - static Expr createDefaultValue(Field f, boolean useExplicitInitTypeInGenerics) { - if (f.isRepeated()) { + public static Expr createValue( + Field field, + boolean useExplicitInitTypeInGenerics, + Map resourceNames, + Map messageTypes, + Map valuePatterns) { + if (field.isRepeated()) { ConcreteReference.Builder refBuilder = - ConcreteReference.builder().setClazz(f.isMap() ? HashMap.class : ArrayList.class); + ConcreteReference.builder().setClazz(field.isMap() ? HashMap.class : ArrayList.class); if (useExplicitInitTypeInGenerics) { - if (f.isMap()) { - refBuilder = refBuilder.setGenerics(f.type().reference().generics().subList(0, 2)); + if (field.isMap()) { + refBuilder = refBuilder.setGenerics(field.type().reference().generics().subList(0, 2)); } else { - refBuilder = refBuilder.setGenerics(f.type().reference().generics().get(0)); + refBuilder = refBuilder.setGenerics(field.type().reference().generics().get(0)); } } @@ -121,51 +130,68 @@ static Expr createDefaultValue(Field f, boolean useExplicitInitTypeInGenerics) { return NewObjectExpr.builder().setType(newType).setIsGeneric(true).build(); } - if (f.isEnum()) { + if (field.isEnum()) { return MethodInvocationExpr.builder() - .setStaticReferenceType(f.type()) + .setStaticReferenceType(field.type()) .setMethodName("forNumber") .setArguments( ValueExpr.withValue( PrimitiveValue.builder().setType(TypeNode.INT).setValue("0").build())) - .setReturnType(f.type()) + .setReturnType(field.type()) .build(); } - if (f.isMessage()) { + if (field.isMessage()) { + String nestedFieldName = field.name(); + Map nestedValuePatterns = new HashMap<>(); + for (Map.Entry entry : valuePatterns.entrySet()) { + if (entry.getKey().startsWith(nestedFieldName + '.')) { + nestedValuePatterns.put( + entry.getKey().substring(nestedFieldName.length() + 1), entry.getValue()); + } + } + + if (!nestedValuePatterns.isEmpty()) { + Message nestedMessage = messageTypes.get(field.type().reference().fullName()); + if (nestedMessage != null) { + return createSimpleMessageBuilderValue( + nestedMessage, resourceNames, messageTypes, nestedValuePatterns); + } + } + MethodInvocationExpr newBuilderExpr = MethodInvocationExpr.builder() - .setStaticReferenceType(f.type()) + .setStaticReferenceType(field.type()) .setMethodName("newBuilder") .build(); return MethodInvocationExpr.builder() .setExprReferenceExpr(newBuilderExpr) .setMethodName("build") - .setReturnType(f.type()) + .setReturnType(field.type()) .build(); } - if (f.type().equals(TypeNode.STRING)) { - String javaFieldName = JavaStyle.toLowerCamelCase(f.name()); + if (field.type().equals(TypeNode.STRING)) { + String javaFieldName = JavaStyle.toLowerCamelCase(field.name()); return ValueExpr.withValue( StringObjectValue.withValue( - String.format("%s%s", javaFieldName, javaFieldName.hashCode()))); + constructValueMatchingPattern(javaFieldName, valuePatterns.get(javaFieldName)))); } - if (TypeNode.isNumericType(f.type())) { + if (TypeNode.isNumericType(field.type())) { return ValueExpr.withValue( PrimitiveValue.builder() - .setType(f.type()) - .setValue(String.format("%s", f.name().hashCode())) + .setType(field.type()) + .setValue(String.format("%s", field.name().hashCode())) .build()); } - if (f.type().equals(TypeNode.BOOLEAN)) { + if (field.type().equals(TypeNode.BOOLEAN)) { return ValueExpr.withValue( - PrimitiveValue.builder().setType(f.type()).setValue("true").build()); + PrimitiveValue.builder().setType(field.type()).setValue("true").build()); } - if (f.type().equals(TypeNode.BYTESTRING)) { + if (field.type().equals(TypeNode.BYTESTRING)) { return VariableExpr.builder() .setStaticReferenceType(TypeNode.BYTESTRING) .setVariable(Variable.builder().setName("EMPTY").setType(TypeNode.BYTESTRING).build()) @@ -174,16 +200,16 @@ static Expr createDefaultValue(Field f, boolean useExplicitInitTypeInGenerics) { throw new UnsupportedOperationException( String.format( - "Default value for field %s with type %s not implemented yet.", f.name(), f.type())); + "Default value for field %s with type %s not implemented yet.", + field.name(), field.type())); } - public static Expr createDefaultValue( + public static Expr createResourceHelperValue( ResourceName resourceName, boolean isChildType, List resnames, String fieldOrMessageName) { - return createDefaultValueResourceHelper( - resourceName, isChildType, resnames, fieldOrMessageName, true); + return createResourceHelperValue(resourceName, isChildType, resnames, fieldOrMessageName, true); } private static Optional findParentResource( @@ -207,7 +233,7 @@ private static Optional findParentResource( } @VisibleForTesting - static Expr createDefaultValueResourceHelper( + static Expr createResourceHelperValue( ResourceName resourceName, boolean isChildType, List resnames, @@ -223,12 +249,12 @@ static Expr createDefaultValueResourceHelper( for (ResourceName resname : resnames) { unexaminedResnames.remove(resname); if (!resname.isOnlyWildcard()) { - return createDefaultValue(resname, false, unexaminedResnames, fieldOrMessageName); + return createResourceHelperValue(resname, false, unexaminedResnames, fieldOrMessageName); } } return allowAnonResourceNameClass - ? createAnonymousResourceNameClass(fieldOrMessageName) + ? createAnonymousResourceNameClassValue(fieldOrMessageName) : ValueExpr.withValue( StringObjectValue.withValue( String.format("%s%s", fieldOrMessageName, fieldOrMessageName.hashCode()))); @@ -284,8 +310,17 @@ static Expr createDefaultValueResourceHelper( .build(); } - public static Expr createSimpleMessageBuilderExpr( + public static Expr createSimpleMessageBuilderValue( Message message, Map resourceNames, Map messageTypes) { + return createSimpleMessageBuilderValue( + message, resourceNames, messageTypes, Collections.emptyMap()); + } + + public static Expr createSimpleMessageBuilderValue( + Message message, + Map resourceNames, + Map messageTypes, + Map valuePatterns) { MethodInvocationExpr builderExpr = MethodInvocationExpr.builder() .setStaticReferenceType(message.type()) @@ -309,7 +344,7 @@ public static Expr createSimpleMessageBuilderExpr( if (field.hasResourceReference() && resourceNames.get(field.resourceReference().resourceTypeString()) != null) { defaultExpr = - createDefaultValueResourceHelper( + createResourceHelperValue( resourceNames.get(field.resourceReference().resourceTypeString()), field.resourceReference().isChildType(), resourceNames.values().stream().collect(Collectors.toList()), @@ -348,7 +383,7 @@ public static Expr createSimpleMessageBuilderExpr( } if (defaultExpr == null) { - defaultExpr = createDefaultValue(field, true); + defaultExpr = createValue(field, true, resourceNames, messageTypes, valuePatterns); } } builderExpr = @@ -367,7 +402,7 @@ public static Expr createSimpleMessageBuilderExpr( .build(); } - public static Expr createSimpleOperationBuilderExpr(String name, VariableExpr responseExpr) { + public static Expr createSimpleOperationBuilderValue(String name, VariableExpr responseExpr) { Expr operationExpr = MethodInvocationExpr.builder() .setStaticReferenceType(OPERATION_TYPE) @@ -405,7 +440,7 @@ public static Expr createSimpleOperationBuilderExpr(String name, VariableExpr re .build(); } - public static Expr createSimplePagedResponse( + public static Expr createSimplePagedResponseValue( TypeNode responseType, String repeatedFieldName, Expr responseElementVarExpr, boolean isMap) { // Code for paginated maps: // AggregatedMessageList.newBuilder() @@ -471,7 +506,7 @@ public static Expr createSimplePagedResponse( } @VisibleForTesting - static AnonymousClassExpr createAnonymousResourceNameClass(String fieldOrMessageName) { + static AnonymousClassExpr createAnonymousResourceNameClassValue(String fieldOrMessageName) { TypeNode stringMapType = TypeNode.withReference( ConcreteReference.builder() @@ -557,4 +592,22 @@ static AnonymousClassExpr createAnonymousResourceNameClass(String fieldOrMessage .setMethods(Arrays.asList(getFieldValuesMapMethod, getFieldValueMethod)) .build(); } + + private static String constructValueMatchingPattern(String fieldName, String pattern) { + if (pattern == null || pattern.isEmpty()) { + return fieldName + fieldName.hashCode(); + } + + final String suffix = "-" + (Math.abs((fieldName + pattern).hashCode()) % 10000); + + String value = pattern.replace("**", "*"); + + String prevTempl = null; + while (!value.equals(prevTempl)) { + prevTempl = value; + value = REPLACER_PATTERN.matcher(value).replaceFirst("$1$2$1" + suffix); + } + + return value.replace("*", fieldName + suffix); + } } 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 5f9b27963e..f8df523fa3 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 @@ -66,6 +66,7 @@ public abstract class GrpcContext extends TransportContext { // For ServiceClientClassComposer .setOperationsClientTypes(ImmutableList.of(classToType(OperationsClient.class))) .setOperationsClientNames(ImmutableList.of("operationsClient")) + .setUseValuePatterns(false) .build(); public static TransportContext 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 8cb761236a..f2e6f6ad2a 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 @@ -548,7 +548,7 @@ protected MethodDefinition createStreamingRpcTestMethod( Expr expectedResponseValExpr = null; if (messageTypes.containsKey(methodOutputType.reference().fullName())) { expectedResponseValExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( + DefaultValueComposer.createSimpleMessageBuilderValue( messageTypes.get(methodOutputType.reference().fullName()), resourceNames, messageTypes); @@ -556,7 +556,7 @@ protected MethodDefinition createStreamingRpcTestMethod( // Wrap this in a field so we don't have to split the helper into lots of different methods, // or duplicate it for VariableExpr. expectedResponseValExpr = - DefaultValueComposer.createDefaultValue( + DefaultValueComposer.createValue( Field.builder() .setType(methodOutputType) .setIsMessage(true) @@ -581,7 +581,7 @@ protected MethodDefinition createStreamingRpcTestMethod( AssignmentExpr.builder() .setVariableExpr(resultOperationVarExpr.toBuilder().setIsDecl(true).build()) .setValueExpr( - DefaultValueComposer.createSimpleOperationBuilderExpr( + DefaultValueComposer.createSimpleOperationBuilderValue( String.format("%sTest", JavaStyle.toLowerCamelCase(method.name())), expectedResponseVarExpr)) .build()); @@ -607,7 +607,7 @@ protected MethodDefinition createStreamingRpcTestMethod( Message requestMessage = messageTypes.get(method.inputType().reference().fullName()); Preconditions.checkNotNull(requestMessage); Expr valExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( + DefaultValueComposer.createSimpleMessageBuilderValue( requestMessage, resourceNames, messageTypes); methodExprs.add( AssignmentExpr.builder() @@ -880,7 +880,7 @@ protected List createStreamingRpcExceptionTestStatements( Message requestMessage = messageTypes.get(method.inputType().reference().fullName()); Preconditions.checkNotNull(requestMessage); Expr valExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( + DefaultValueComposer.createSimpleMessageBuilderValue( requestMessage, resourceNames, messageTypes); List statements = new ArrayList<>(); @@ -1053,12 +1053,6 @@ 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/grpcrest/GrpcRestContext.java b/src/main/java/com/google/api/generator/gapic/composer/grpcrest/GrpcRestContext.java index 59376001e2..2b52699f72 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 @@ -87,6 +87,7 @@ public abstract class GrpcRestContext extends TransportContext { classToType(com.google.api.gax.httpjson.longrunning.OperationsClient.class))) .setOperationsClientNames( ImmutableList.of("operationsClient", "httpJsonOperationsClient")) + .setUseValuePatterns(true) .build(); public static TransportContext instance() { 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 7643406830..7b9b05f160 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 @@ -335,7 +335,7 @@ private List getRequestFormatterExpr(Method protoMethod) { Arrays.asList( ValueExpr.withValue( StringObjectValue.withValue( - protoMethod.httpBindings().patternLowerCamel())), + protoMethod.httpBindings().lowerCamelPattern())), createFieldsExtractorClassInstance( protoMethod, extractorVarType, 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 2502a9128e..fd88157ee5 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 @@ -68,6 +68,7 @@ public abstract class RestContext extends TransportContext { // For ServiceClientClassComposer .setOperationsClientTypes(ImmutableList.of(classToType(OperationsClient.class))) .setOperationsClientNames(ImmutableList.of("httpJsonOperationsClient")) + .setUseValuePatterns(true) .build(); public static TransportContext 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 9df088bbd7..bfc69954de 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,7 +39,6 @@ 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; @@ -525,12 +524,6 @@ 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/samplecode/ServiceClientSampleCodeComposer.java b/src/main/java/com/google/api/generator/gapic/composer/samplecode/ServiceClientSampleCodeComposer.java index df5a6cc583..5ca7b573af 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 @@ -57,6 +57,7 @@ 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.function.Function; @@ -296,7 +297,7 @@ public static String composeRpcDefaultMethodHeaderSampleCode( String.format( "Could not find the message type %s.", method.inputType().reference().fullName())); Expr requestBuilderExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( + DefaultValueComposer.createSimpleMessageBuilderValue( requestMessage, resourceNames, messageTypes); AssignmentExpr requestAssignmentExpr = AssignmentExpr.builder() @@ -352,7 +353,7 @@ public static String composeLroCallableMethodHeaderSampleCode( String.format( "Could not find the message type %s.", method.inputType().reference().fullName())); Expr requestBuilderExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( + DefaultValueComposer.createSimpleMessageBuilderValue( requestMessage, resourceNames, messageTypes); AssignmentExpr requestAssignmentExpr = AssignmentExpr.builder() @@ -464,7 +465,7 @@ public static String composePagedCallableMethodHeaderSampleCode( String.format( "Could not find the message type %s.", method.inputType().reference().fullName())); Expr requestBuilderExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( + DefaultValueComposer.createSimpleMessageBuilderValue( requestMessage, resourceNames, messageTypes); AssignmentExpr requestAssignmentExpr = AssignmentExpr.builder() @@ -584,7 +585,7 @@ public static String composeRegularCallableMethodHeaderSampleCode( String.format( "Could not find the message type %s.", method.inputType().reference().fullName())); Expr requestBuilderExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( + DefaultValueComposer.createSimpleMessageBuilderValue( requestMessage, resourceNames, messageTypes); AssignmentExpr requestAssignmentExpr = AssignmentExpr.builder() @@ -632,7 +633,7 @@ public static String composeStreamCallableMethodHeaderSampleCode( String.format( "Could not find the message type %s.", method.inputType().reference().fullName())); Expr requestBuilderExpr = - DefaultValueComposer.createSimpleMessageBuilderExpr( + DefaultValueComposer.createSimpleMessageBuilderValue( requestMessage, resourceNames, messageTypes); AssignmentExpr requestAssignmentExpr = AssignmentExpr.builder() @@ -1291,7 +1292,7 @@ private static List createRpcMethodArgumentDefaultValueExprs( arg -> MethodInvocationExpr.builder() .setExprReferenceExpr( - DefaultValueComposer.createDefaultValue( + DefaultValueComposer.createResourceHelperValue( resourceNames.get(arg.field().resourceReference().resourceTypeString()), arg.field().resourceReference().isChildType(), resourceNameList, @@ -1303,7 +1304,8 @@ private static List createRpcMethodArgumentDefaultValueExprs( .map( arg -> !isStringTypedResourceName(arg, resourceNames) - ? DefaultValueComposer.createDefaultValue(arg, resourceNames, false) + ? DefaultValueComposer.createMethodArgValue( + arg, resourceNames, Collections.emptyMap(), Collections.emptyMap()) : stringResourceNameDefaultValueExpr.apply(arg)) .collect(Collectors.toList()); } 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 171f6b1bf7..32fa39c136 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 @@ -17,7 +17,10 @@ import com.google.api.generator.gapic.utils.JavaStyle; import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableSet; +import java.util.HashMap; +import java.util.Map; import java.util.Set; +import javax.annotation.Nullable; @AutoValue public abstract class HttpBindings { @@ -33,10 +36,16 @@ public enum HttpVerb { public abstract static class HttpBinding implements Comparable { public abstract String name(); + abstract String lowerCamelName(); + public abstract boolean isOptional(); - public static HttpBinding create(String name, boolean isOptional) { - return new AutoValue_HttpBindings_HttpBinding(name, isOptional); + @Nullable + public abstract String valuePattern(); + + public static HttpBinding create(String name, boolean isOptional, String valuePattern) { + return new AutoValue_HttpBindings_HttpBinding( + name, JavaStyle.toLowerCamelCase(name), isOptional, valuePattern); } // Do not forget to keep it in sync with equals() implementation. @@ -71,7 +80,7 @@ public static HttpBindings.Builder builder() { // For example: // in .proto file: "/global/instanceTemplates/{instance_template=*}" // in .java file: "/global/instanceTemplates/{instanceTemplate=*}" - public String patternLowerCamel() { + public String lowerCamelPattern() { String lowerCamelPattern = pattern(); for (HttpBinding pathParam : pathParameters()) { lowerCamelPattern = @@ -81,6 +90,14 @@ public String patternLowerCamel() { return lowerCamelPattern; } + public Map getPathParametersValuePatterns() { + Map valuePatterns = new HashMap<>(); + for (HttpBinding pathParameter : pathParameters()) { + valuePatterns.put(pathParameter.lowerCamelName(), pathParameter.valuePattern()); + } + return valuePatterns; + } + @AutoValue.Builder public abstract static class Builder { public abstract HttpBindings.Builder setHttpVerb(HttpVerb httpVerb); 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 36828206d3..5a37a38074 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 @@ -30,13 +30,18 @@ import com.google.protobuf.DescriptorProtos.MethodOptions; import com.google.protobuf.Descriptors.MethodDescriptor; import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; public class HttpRuleParser { private static final String ASTERISK = "*"; + private static final Pattern TEMPLATE_VALS_PATTERN = + Pattern.compile("\\{(?[\\w.]*)=(?