Skip to content

Commit 003b993

Browse files
authored
feat: Dynamic Routing Headers for HttpJson (#1667)
* feat: Add RequestParamsExtractor to HttpJsonCallSettings * feat: Add RequestParamsCallable classes * feat: Update HttpJsonCallableFactory to use new RequestParamCallables * feat: Add RequestParam to CallOptions * feat: Add RequestParam header for HttpJson * feat: Add initial Dynamic Routing Header showcase test * feat: Ignore empty string for Request Param * feat: Regenerate test client code * feat: Do not generate HttpBinding logic for REST * feat: Add Dynamic Routing Header showcase test cases * feat: Move header key value to constant * feat: Add URLEncoding for header * feat: Update showcase interceptor name * feat: Generate HttpJson Dyanmic Routing Header Stub * feat: Fix Request Params Test * feat: Update variable names * feat: Add gRPC Dynamic Routing Header showcase test * feat: Clean up IT showcase test * chore: Add comments for RequestBuilderParams * feat: Generate test client code with Implict Routing Headers * feat: Regenerate test client code * fix: Generate httpjson golden test case * chore: Fix format issues * chore: Regenerate integration golden tests * chore: Add more tests for RequestParamsBuilder * chore: Update docs for showcase test * chore: Refactor TestClientInitializer to include interceptors * chore: Add null assertions for showcase test * chore: Remove String.valueOf check for routing params * chore: Remove String.valueOf check for routing params * chore: Regenerate the showcase clients * chore: Address pr comments * chore: Update Dynamic Routing Header test cases * chore: Use PercentEscaper for percent encoding * chore: Empty commit * chore: Migrate transport specific code to abstract class * chore: Address pr comments * chore: Address pr comments * chore: Use HttpJsonMetadata for headers * chore: Revert call options changes * chore: Set default request header map * chore: Move encoding logic to RequestUrlParamsEncoder * chore: Fix lint issues * chore: Add clirr ignore for RequestUrlParamsEncoder * chore: Address PR comments * chore: Address PR comments
1 parent e78b267 commit 003b993

File tree

64 files changed

+2704
-1136
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2704
-1136
lines changed

gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/common/AbstractTransportServiceStubClassComposer.java

+316-2
Large diffs are not rendered by default.

gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/grpc/GrpcServiceStubClassComposer.java

-294
Original file line numberDiff line numberDiff line change
@@ -16,40 +16,26 @@
1616

1717
import com.google.api.gax.grpc.GrpcCallSettings;
1818
import com.google.api.gax.grpc.GrpcStubCallableFactory;
19-
import com.google.api.gax.rpc.RequestParamsBuilder;
2019
import com.google.api.generator.engine.ast.AssignmentExpr;
2120
import com.google.api.generator.engine.ast.ConcreteReference;
2221
import com.google.api.generator.engine.ast.EnumRefExpr;
2322
import com.google.api.generator.engine.ast.Expr;
2423
import com.google.api.generator.engine.ast.ExprStatement;
25-
import com.google.api.generator.engine.ast.IfStatement;
26-
import com.google.api.generator.engine.ast.LambdaExpr;
27-
import com.google.api.generator.engine.ast.LogicalOperationExpr;
2824
import com.google.api.generator.engine.ast.MethodInvocationExpr;
29-
import com.google.api.generator.engine.ast.RelationalOperationExpr;
3025
import com.google.api.generator.engine.ast.ScopeNode;
3126
import com.google.api.generator.engine.ast.Statement;
3227
import com.google.api.generator.engine.ast.StringObjectValue;
3328
import com.google.api.generator.engine.ast.TypeNode;
3429
import com.google.api.generator.engine.ast.ValueExpr;
35-
import com.google.api.generator.engine.ast.Variable;
3630
import com.google.api.generator.engine.ast.VariableExpr;
3731
import com.google.api.generator.gapic.composer.common.AbstractTransportServiceStubClassComposer;
3832
import com.google.api.generator.gapic.composer.store.TypeStore;
39-
import com.google.api.generator.gapic.model.HttpBindings.HttpBinding;
4033
import com.google.api.generator.gapic.model.Message;
4134
import com.google.api.generator.gapic.model.Method;
42-
import com.google.api.generator.gapic.model.RoutingHeaderRule.RoutingHeaderParam;
4335
import com.google.api.generator.gapic.model.Service;
44-
import com.google.api.generator.gapic.utils.JavaStyle;
45-
import com.google.api.pathtemplate.PathTemplate;
46-
import com.google.common.base.Splitter;
47-
import com.google.common.collect.ImmutableList;
48-
import com.google.common.collect.ImmutableMap;
4936
import com.google.longrunning.stub.GrpcOperationsStub;
5037
import io.grpc.MethodDescriptor;
5138
import io.grpc.protobuf.ProtoUtils;
52-
import java.util.ArrayList;
5339
import java.util.Arrays;
5440
import java.util.HashSet;
5541
import java.util.List;
@@ -200,46 +186,6 @@ protected EnumRefExpr getMethodDescriptorMethodTypeExpr(Method protoMethod) {
200186
.build();
201187
}
202188

203-
@Override
204-
protected Expr createTransportSettingsInitExpr(
205-
Method method,
206-
VariableExpr transportSettingsVarExpr,
207-
VariableExpr methodDescriptorVarExpr,
208-
List<Statement> classStatements) {
209-
MethodInvocationExpr callSettingsBuilderExpr =
210-
MethodInvocationExpr.builder()
211-
.setStaticReferenceType(getTransportContext().transportCallSettingsType())
212-
.setGenerics(transportSettingsVarExpr.type().reference().generics())
213-
.setMethodName("newBuilder")
214-
.build();
215-
callSettingsBuilderExpr =
216-
MethodInvocationExpr.builder()
217-
.setExprReferenceExpr(callSettingsBuilderExpr)
218-
.setMethodName("setMethodDescriptor")
219-
.setArguments(Arrays.asList(methodDescriptorVarExpr))
220-
.build();
221-
222-
if (method.shouldSetParamsExtractor()) {
223-
callSettingsBuilderExpr =
224-
MethodInvocationExpr.builder()
225-
.setExprReferenceExpr(callSettingsBuilderExpr)
226-
.setMethodName("setParamsExtractor")
227-
.setArguments(createRequestParamsExtractorClassInstance(method, classStatements))
228-
.build();
229-
}
230-
231-
callSettingsBuilderExpr =
232-
MethodInvocationExpr.builder()
233-
.setExprReferenceExpr(callSettingsBuilderExpr)
234-
.setMethodName("build")
235-
.setReturnType(transportSettingsVarExpr.type())
236-
.build();
237-
return AssignmentExpr.builder()
238-
.setVariableExpr(transportSettingsVarExpr.toBuilder().setIsDecl(true).build())
239-
.setValueExpr(callSettingsBuilderExpr)
240-
.build();
241-
}
242-
243189
@Override
244190
protected String getProtoRpcFullMethodName(Service protoService, Method protoMethod) {
245191
if (protoMethod.isMixin()) {
@@ -255,244 +201,4 @@ protected String getProtoRpcFullMethodName(Service protoService, Method protoMet
255201
// long-term solution.
256202
return String.format("google.iam.v1.IAMPolicy/%s", protoMethod.name());
257203
}
258-
259-
private LambdaExpr createRequestParamsExtractorClassInstance(
260-
Method method, List<Statement> classStatements) {
261-
List<Statement> bodyStatements = new ArrayList<>();
262-
VariableExpr requestVarExpr =
263-
VariableExpr.withVariable(
264-
Variable.builder().setType(method.inputType()).setName("request").build());
265-
TypeNode returnType =
266-
TypeNode.withReference(
267-
ConcreteReference.builder()
268-
.setClazz(Map.class)
269-
.setGenerics(TypeNode.STRING.reference(), TypeNode.STRING.reference())
270-
.build());
271-
MethodInvocationExpr.Builder returnExpr =
272-
MethodInvocationExpr.builder().setReturnType(returnType);
273-
// If the google.api.routing annotation is present(even with empty routing parameters),
274-
// the implicit routing headers specified in the google.api.http annotation should not be sent
275-
if (method.routingHeaderRule() == null) {
276-
createRequestParamsExtractorBodyForHttpBindings(
277-
method, requestVarExpr, bodyStatements, returnExpr);
278-
} else {
279-
createRequestParamsExtractorBodyForRoutingHeaders(
280-
method, requestVarExpr, classStatements, bodyStatements, returnExpr);
281-
}
282-
283-
// Overrides extract().
284-
// https://github.com/googleapis/gax-java/blob/8d45d186e36ae97b789a6f89d80ae5213a773b65/gax/src/main/java/com/google/api/gax/rpc/RequestParamsExtractor.java#L55
285-
return LambdaExpr.builder()
286-
.setArguments(requestVarExpr.toBuilder().setIsDecl(true).build())
287-
.setBody(bodyStatements)
288-
.setReturnExpr(returnExpr.build())
289-
.build();
290-
}
291-
292-
private void createRequestParamsExtractorBodyForHttpBindings(
293-
Method method,
294-
VariableExpr requestVarExpr,
295-
List<Statement> bodyStatements,
296-
MethodInvocationExpr.Builder returnExprBuilder) {
297-
TypeNode paramsVarType =
298-
TypeNode.withReference(
299-
ConcreteReference.builder()
300-
.setClazz(ImmutableMap.Builder.class)
301-
.setGenerics(TypeNode.STRING.reference(), TypeNode.STRING.reference())
302-
.build());
303-
VariableExpr paramsVarExpr =
304-
VariableExpr.withVariable(
305-
Variable.builder().setName("params").setType(paramsVarType).build());
306-
307-
Expr paramsAssignExpr =
308-
AssignmentExpr.builder()
309-
.setVariableExpr(paramsVarExpr.toBuilder().setIsDecl(true).build())
310-
.setValueExpr(
311-
MethodInvocationExpr.builder()
312-
.setStaticReferenceType(FIXED_TYPESTORE.get("ImmutableMap"))
313-
.setMethodName("builder")
314-
.setReturnType(paramsVarType)
315-
.build())
316-
.build();
317-
bodyStatements.add(ExprStatement.withExpr(paramsAssignExpr));
318-
319-
for (HttpBinding httpBindingFieldBinding : method.httpBindings().pathParameters()) {
320-
MethodInvocationExpr requestBuilderExpr =
321-
createRequestFieldGetterExpr(requestVarExpr, httpBindingFieldBinding.name());
322-
Expr valueOfExpr =
323-
MethodInvocationExpr.builder()
324-
.setStaticReferenceType(TypeNode.STRING)
325-
.setMethodName("valueOf")
326-
.setArguments(requestBuilderExpr)
327-
.build();
328-
329-
Expr paramsPutExpr =
330-
MethodInvocationExpr.builder()
331-
.setExprReferenceExpr(paramsVarExpr)
332-
.setMethodName("put")
333-
.setArguments(
334-
ValueExpr.withValue(StringObjectValue.withValue(httpBindingFieldBinding.name())),
335-
valueOfExpr)
336-
.build();
337-
bodyStatements.add(ExprStatement.withExpr(paramsPutExpr));
338-
}
339-
340-
returnExprBuilder.setExprReferenceExpr(paramsVarExpr).setMethodName("build");
341-
}
342-
343-
private void createRequestParamsExtractorBodyForRoutingHeaders(
344-
Method method,
345-
VariableExpr requestVarExpr,
346-
List<Statement> classStatements,
347-
List<Statement> bodyStatements,
348-
MethodInvocationExpr.Builder returnExprBuilder) {
349-
TypeNode routingHeadersBuilderType =
350-
TypeNode.withReference(
351-
ConcreteReference.builder().setClazz(RequestParamsBuilder.class).build());
352-
VariableExpr routingHeadersBuilderVarExpr =
353-
VariableExpr.builder()
354-
.setVariable(
355-
Variable.builder().setName("builder").setType(routingHeadersBuilderType).build())
356-
.setIsDecl(true)
357-
.build();
358-
MethodInvocationExpr routingHeaderBuilderInvokeExpr =
359-
MethodInvocationExpr.builder()
360-
.setStaticReferenceType(routingHeadersBuilderType)
361-
.setMethodName("create")
362-
.setReturnType(routingHeadersBuilderType)
363-
.build();
364-
Expr routingHeadersBuilderInitExpr =
365-
AssignmentExpr.builder()
366-
.setVariableExpr(routingHeadersBuilderVarExpr)
367-
.setValueExpr(routingHeaderBuilderInvokeExpr)
368-
.build();
369-
bodyStatements.add(ExprStatement.withExpr(routingHeadersBuilderInitExpr));
370-
List<RoutingHeaderParam> routingHeaderParams = method.routingHeaderRule().routingHeaderParams();
371-
VariableExpr routingHeadersBuilderVarNonDeclExpr =
372-
VariableExpr.builder()
373-
.setVariable(
374-
Variable.builder().setName("builder").setType(routingHeadersBuilderType).build())
375-
.build();
376-
for (int i = 0; i < routingHeaderParams.size(); i++) {
377-
RoutingHeaderParam routingHeaderParam = routingHeaderParams.get(i);
378-
MethodInvocationExpr requestFieldGetterExpr =
379-
createRequestFieldGetterExpr(requestVarExpr, routingHeaderParam.fieldName());
380-
Expr routingHeaderKeyExpr =
381-
ValueExpr.withValue(StringObjectValue.withValue(routingHeaderParam.key()));
382-
String pathTemplateName =
383-
String.format("%s_%s_PATH_TEMPLATE", JavaStyle.toUpperSnakeCase(method.name()), i);
384-
TypeNode pathTemplateType =
385-
TypeNode.withReference(ConcreteReference.withClazz(PathTemplate.class));
386-
Variable pathTemplateVar =
387-
Variable.builder().setType(pathTemplateType).setName(pathTemplateName).build();
388-
Expr routingHeaderPatternExpr = VariableExpr.withVariable(pathTemplateVar);
389-
Statement pathTemplateClassVar =
390-
createPathTemplateClassStatement(routingHeaderParam, pathTemplateType, pathTemplateVar);
391-
classStatements.add(pathTemplateClassVar);
392-
MethodInvocationExpr addParamMethodExpr =
393-
MethodInvocationExpr.builder()
394-
.setExprReferenceExpr(routingHeadersBuilderVarNonDeclExpr)
395-
.setMethodName("add")
396-
.setArguments(requestFieldGetterExpr, routingHeaderKeyExpr, routingHeaderPatternExpr)
397-
.build();
398-
399-
ExprStatement addParamStatement = ExprStatement.withExpr(addParamMethodExpr);
400-
// No need to add null check if there is no nested fields
401-
if (routingHeaderParam.getDescendantFieldNames().size() == 1) {
402-
bodyStatements.add(addParamStatement);
403-
} else {
404-
IfStatement ifStatement =
405-
IfStatement.builder()
406-
.setConditionExpr(
407-
fieldValuesNotNullConditionExpr(
408-
requestVarExpr, routingHeaderParam.getDescendantFieldNames()))
409-
.setBody(ImmutableList.of(addParamStatement))
410-
.build();
411-
bodyStatements.add(ifStatement);
412-
}
413-
}
414-
returnExprBuilder
415-
.setExprReferenceExpr(routingHeadersBuilderVarNonDeclExpr)
416-
.setMethodName("build");
417-
}
418-
419-
private Statement createPathTemplateClassStatement(
420-
RoutingHeaderParam routingHeaderParam, TypeNode pathTemplateType, Variable pathTemplateVar) {
421-
VariableExpr pathTemplateVarExpr =
422-
VariableExpr.builder()
423-
.setVariable(pathTemplateVar)
424-
.setIsDecl(true)
425-
.setIsStatic(true)
426-
.setIsFinal(true)
427-
.setScope(ScopeNode.PRIVATE)
428-
.build();
429-
ValueExpr valueExpr =
430-
ValueExpr.withValue(StringObjectValue.withValue(routingHeaderParam.pattern()));
431-
Expr pathTemplateExpr =
432-
AssignmentExpr.builder()
433-
.setVariableExpr(pathTemplateVarExpr)
434-
.setValueExpr(
435-
MethodInvocationExpr.builder()
436-
.setStaticReferenceType(pathTemplateType)
437-
.setMethodName("create")
438-
.setArguments(valueExpr)
439-
.setReturnType(pathTemplateType)
440-
.build())
441-
.build();
442-
return ExprStatement.withExpr(pathTemplateExpr);
443-
}
444-
445-
private Expr fieldValuesNotNullConditionExpr(
446-
VariableExpr requestVarExpr, List<String> fieldNames) {
447-
MethodInvocationExpr.Builder requestFieldGetterExprBuilder =
448-
MethodInvocationExpr.builder().setExprReferenceExpr(requestVarExpr);
449-
Expr fieldValuesNotNullExpr = null;
450-
for (int i = 0; i < fieldNames.size() - 1; i++) {
451-
String currFieldName = fieldNames.get(i);
452-
String bindingFieldMethodName =
453-
String.format("get%s", JavaStyle.toUpperCamelCase(currFieldName));
454-
requestFieldGetterExprBuilder =
455-
requestFieldGetterExprBuilder.setMethodName(bindingFieldMethodName);
456-
// set return type of each method invocation to String just to pass the validation for
457-
// RelationalOperationExpr that both side of relational operation needs to be a valid equality
458-
// type
459-
MethodInvocationExpr requestGetterExpr =
460-
requestFieldGetterExprBuilder.setReturnType(TypeNode.STRING).build();
461-
Expr currentValueNotNullExpr =
462-
RelationalOperationExpr.notEqualToWithExprs(
463-
requestGetterExpr, ValueExpr.createNullExpr());
464-
if (fieldValuesNotNullExpr == null) {
465-
fieldValuesNotNullExpr = currentValueNotNullExpr;
466-
} else {
467-
fieldValuesNotNullExpr =
468-
LogicalOperationExpr.logicalAndWithExprs(
469-
fieldValuesNotNullExpr, currentValueNotNullExpr);
470-
}
471-
requestFieldGetterExprBuilder =
472-
MethodInvocationExpr.builder().setExprReferenceExpr(requestGetterExpr);
473-
}
474-
return fieldValuesNotNullExpr;
475-
}
476-
477-
private MethodInvocationExpr createRequestFieldGetterExpr(
478-
VariableExpr requestVarExpr, String fieldName) {
479-
MethodInvocationExpr.Builder requestFieldGetterExprBuilder =
480-
MethodInvocationExpr.builder().setExprReferenceExpr(requestVarExpr);
481-
List<String> descendantFields = Splitter.on(".").splitToList(fieldName);
482-
// Handle foo.bar cases by descending into the subfields.
483-
// e.g. foo.bar -> request.getFoo().getBar()
484-
for (int i = 0; i < descendantFields.size(); i++) {
485-
String currFieldName = descendantFields.get(i);
486-
String bindingFieldMethodName =
487-
String.format("get%s", JavaStyle.toUpperCamelCase(currFieldName));
488-
requestFieldGetterExprBuilder =
489-
requestFieldGetterExprBuilder.setMethodName(bindingFieldMethodName);
490-
if (i < descendantFields.size() - 1) {
491-
requestFieldGetterExprBuilder =
492-
MethodInvocationExpr.builder()
493-
.setExprReferenceExpr(requestFieldGetterExprBuilder.build());
494-
}
495-
}
496-
return requestFieldGetterExprBuilder.build();
497-
}
498204
}

gapic-generator-java/src/main/java/com/google/api/generator/gapic/composer/rest/HttpJsonServiceStubClassComposer.java

-39
Original file line numberDiff line numberDiff line change
@@ -210,45 +210,6 @@ protected List<MethodDefinition> createOperationsStubGetterMethod(
210210
return super.createOperationsStubGetterMethod(service, operationsStubVarExpr);
211211
}
212212

213-
@Override
214-
protected Expr createTransportSettingsInitExpr(
215-
Method method,
216-
VariableExpr transportSettingsVarExpr,
217-
VariableExpr methodDescriptorVarExpr,
218-
List<Statement> classStatements) {
219-
MethodInvocationExpr callSettingsBuilderExpr =
220-
MethodInvocationExpr.builder()
221-
.setStaticReferenceType(
222-
FIXED_REST_TYPESTORE.get(HttpJsonCallSettings.class.getSimpleName()))
223-
.setGenerics(transportSettingsVarExpr.type().reference().generics())
224-
.setMethodName("newBuilder")
225-
.build();
226-
callSettingsBuilderExpr =
227-
MethodInvocationExpr.builder()
228-
.setExprReferenceExpr(callSettingsBuilderExpr)
229-
.setMethodName("setMethodDescriptor")
230-
.setArguments(Arrays.asList(methodDescriptorVarExpr))
231-
.build();
232-
233-
callSettingsBuilderExpr =
234-
MethodInvocationExpr.builder()
235-
.setExprReferenceExpr(callSettingsBuilderExpr)
236-
.setMethodName("setTypeRegistry")
237-
.setArguments(Arrays.asList(TYPE_REGISTRY_VAR_EXPR))
238-
.build();
239-
240-
callSettingsBuilderExpr =
241-
MethodInvocationExpr.builder()
242-
.setExprReferenceExpr(callSettingsBuilderExpr)
243-
.setMethodName("build")
244-
.setReturnType(transportSettingsVarExpr.type())
245-
.build();
246-
return AssignmentExpr.builder()
247-
.setVariableExpr(transportSettingsVarExpr.toBuilder().setIsDecl(true).build())
248-
.setValueExpr(callSettingsBuilderExpr)
249-
.build();
250-
}
251-
252213
@Override
253214
protected List<AnnotationNode> createClassAnnotations(Service service) {
254215
List<AnnotationNode> annotations = super.createClassAnnotations(service);

0 commit comments

Comments
 (0)