Skip to content

Commit 4d043de

Browse files
authored
feat: Numeric enums in routing headers (#2328)
* chore: Numeric enums in routing headers
1 parent 762c125 commit 4d043de

File tree

10 files changed

+255
-7
lines changed

10 files changed

+255
-7
lines changed

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

+20-3
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,10 @@ private void createRequestParamsExtractorBodyForHttpBindings(
13001300
for (HttpBindings.HttpBinding httpBindingFieldBinding :
13011301
method.httpBindings().pathParameters()) {
13021302
MethodInvocationExpr requestBuilderExpr =
1303-
createRequestFieldGetterExpr(requestVarExpr, httpBindingFieldBinding.name());
1303+
createRequestFieldGetterExpr(
1304+
requestVarExpr,
1305+
httpBindingFieldBinding.name(),
1306+
httpBindingFieldBinding.field() != null && httpBindingFieldBinding.field().isEnum());
13041307
Expr valueOfExpr =
13051308
MethodInvocationExpr.builder()
13061309
.setStaticReferenceType(TypeNode.STRING)
@@ -1360,8 +1363,10 @@ private void createRequestParamsExtractorBodyForRoutingHeaders(
13601363
.build();
13611364
for (int i = 0; i < routingHeaderParams.size(); i++) {
13621365
RoutingHeaderRule.RoutingHeaderParam routingHeaderParam = routingHeaderParams.get(i);
1366+
// Explicit routing headers are implemented as strings currently, hence sending "false"
1367+
// in isFieldEnum() for it.
13631368
MethodInvocationExpr requestFieldGetterExpr =
1364-
createRequestFieldGetterExpr(requestVarExpr, routingHeaderParam.fieldName());
1369+
createRequestFieldGetterExpr(requestVarExpr, routingHeaderParam.fieldName(), false);
13651370
Expr routingHeaderKeyExpr =
13661371
ValueExpr.withValue(StringObjectValue.withValue(routingHeaderParam.key()));
13671372
String pathTemplateName =
@@ -1462,7 +1467,7 @@ private Expr fieldValuesNotNullConditionExpr(
14621467
}
14631468

14641469
private MethodInvocationExpr createRequestFieldGetterExpr(
1465-
VariableExpr requestVarExpr, String fieldName) {
1470+
VariableExpr requestVarExpr, String fieldName, boolean isFieldEnum) {
14661471
MethodInvocationExpr.Builder requestFieldGetterExprBuilder =
14671472
MethodInvocationExpr.builder().setExprReferenceExpr(requestVarExpr);
14681473
List<String> descendantFields = Splitter.on(".").splitToList(fieldName);
@@ -1472,6 +1477,18 @@ private MethodInvocationExpr createRequestFieldGetterExpr(
14721477
String currFieldName = descendantFields.get(i);
14731478
String bindingFieldMethodName =
14741479
String.format("get%s", JavaStyle.toUpperCamelCase(currFieldName));
1480+
1481+
// Only at the last descendant field, if enum, we want to extract the value.
1482+
// For example, consider the chain request.getFoo().getBar().
1483+
// If you added "Value" to both fields (getFooValue().getBarValue()),
1484+
// it would not work correctly, as getFooValue() may return an int or some other type,
1485+
// and calling getBarValue() on it wouldn't make sense
1486+
// By adding "Value" only at the last descendant field,
1487+
// you ensure that the modification aligns with the expected method
1488+
// chaining behavior and correctly retrieves the underlying value of the enum field."
1489+
if (i == descendantFields.size() - 1 && isFieldEnum) {
1490+
bindingFieldMethodName = bindingFieldMethodName + "Value";
1491+
}
14751492
requestFieldGetterExprBuilder =
14761493
requestFieldGetterExprBuilder.setMethodName(bindingFieldMethodName);
14771494
if (i < descendantFields.size() - 1) {

gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcRoutingHeadersStub.golden

+34
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import com.google.api.gax.rpc.ClientContext;
88
import com.google.api.gax.rpc.RequestParamsBuilder;
99
import com.google.api.gax.rpc.UnaryCallable;
1010
import com.google.api.pathtemplate.PathTemplate;
11+
import com.google.explicit.dynamic.routing.header.EnumRequest;
12+
import com.google.explicit.dynamic.routing.header.EnumResponse;
1113
import com.google.explicit.dynamic.routing.header.Request;
1214
import com.google.explicit.dynamic.routing.header.RequestWithNestedField;
1315
import com.google.longrunning.stub.GrpcOperationsStub;
@@ -156,6 +158,16 @@ public class GrpcExplicitDynamicRoutingHeaderTestingStub
156158
.setResponseMarshaller(ProtoUtils.marshaller(Empty.getDefaultInstance()))
157159
.build();
158160

161+
private static final MethodDescriptor<EnumRequest, EnumResponse>
162+
implicitRoutingHeaderWithEnumTestMethodDescriptor =
163+
MethodDescriptor.<EnumRequest, EnumResponse>newBuilder()
164+
.setType(MethodDescriptor.MethodType.UNARY)
165+
.setFullMethodName(
166+
"google.explicit.dynamic.routing.header.ExplicitDynamicRoutingHeaderTesting/ImplicitRoutingHeaderWithEnumTest")
167+
.setRequestMarshaller(ProtoUtils.marshaller(EnumRequest.getDefaultInstance()))
168+
.setResponseMarshaller(ProtoUtils.marshaller(EnumResponse.getDefaultInstance()))
169+
.build();
170+
159171
private final UnaryCallable<Request, Empty> example1TestCallable;
160172
private final UnaryCallable<Request, Empty> example2TestCallable;
161173
private final UnaryCallable<Request, Empty> example3TestCallable;
@@ -170,6 +182,7 @@ public class GrpcExplicitDynamicRoutingHeaderTestingStub
170182
private final UnaryCallable<Request, Empty> backwardsCompatible2TestCallable;
171183
private final UnaryCallable<Request, Empty> backwardsCompatible3TestCallable;
172184
private final UnaryCallable<RequestWithNestedField, Empty> nestedFieldTestCallable;
185+
private final UnaryCallable<EnumRequest, EnumResponse> implicitRoutingHeaderWithEnumTestCallable;
173186

174187
private final BackgroundResource backgroundResources;
175188
private final GrpcOperationsStub operationsStub;
@@ -427,6 +440,17 @@ public class GrpcExplicitDynamicRoutingHeaderTestingStub
427440
return builder.build();
428441
})
429442
.build();
443+
GrpcCallSettings<EnumRequest, EnumResponse> implicitRoutingHeaderWithEnumTestTransportSettings =
444+
GrpcCallSettings.<EnumRequest, EnumResponse>newBuilder()
445+
.setMethodDescriptor(implicitRoutingHeaderWithEnumTestMethodDescriptor)
446+
.setParamsExtractor(
447+
request -> {
448+
RequestParamsBuilder builder = RequestParamsBuilder.create();
449+
builder.add(
450+
"info.enum_test", String.valueOf(request.getInfo().getEnumTestValue()));
451+
return builder.build();
452+
})
453+
.build();
430454

431455
this.example1TestCallable =
432456
callableFactory.createUnaryCallable(
@@ -476,6 +500,11 @@ public class GrpcExplicitDynamicRoutingHeaderTestingStub
476500
this.nestedFieldTestCallable =
477501
callableFactory.createUnaryCallable(
478502
nestedFieldTestTransportSettings, settings.nestedFieldTestSettings(), clientContext);
503+
this.implicitRoutingHeaderWithEnumTestCallable =
504+
callableFactory.createUnaryCallable(
505+
implicitRoutingHeaderWithEnumTestTransportSettings,
506+
settings.implicitRoutingHeaderWithEnumTestSettings(),
507+
clientContext);
479508

480509
this.backgroundResources =
481510
new BackgroundResourceAggregation(clientContext.getBackgroundResources());
@@ -555,6 +584,11 @@ public class GrpcExplicitDynamicRoutingHeaderTestingStub
555584
return nestedFieldTestCallable;
556585
}
557586

587+
@Override
588+
public UnaryCallable<EnumRequest, EnumResponse> implicitRoutingHeaderWithEnumTestCallable() {
589+
return implicitRoutingHeaderWithEnumTestCallable;
590+
}
591+
558592
@Override
559593
public final void close() {
560594
try {

gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcTestingStub.golden

+1-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ public class GrpcTestingStub extends TestingStub {
266266
builder.add("name", String.valueOf(request.getName()));
267267
builder.add(
268268
"test_to_verify.name", String.valueOf(request.getTestToVerify().getName()));
269-
builder.add("type", String.valueOf(request.getType()));
269+
builder.add("type", String.valueOf(request.getTypeValue()));
270270
return builder.build();
271271
})
272272
.build();

gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonComplianceStub.golden

+2-1
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,8 @@ public class HttpJsonComplianceStub extends ComplianceStub {
426426
builder.add("info.f_bool", String.valueOf(request.getInfo().getFBool()));
427427
builder.add("info.f_double", String.valueOf(request.getInfo().getFDouble()));
428428
builder.add("info.f_int32", String.valueOf(request.getInfo().getFInt32()));
429-
builder.add("info.f_kingdom", String.valueOf(request.getInfo().getFKingdom()));
429+
builder.add(
430+
"info.f_kingdom", String.valueOf(request.getInfo().getFKingdomValue()));
430431
builder.add("info.f_string", String.valueOf(request.getInfo().getFString()));
431432
return builder.build();
432433
})

gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/HttpJsonRoutingHeadersStub.golden

+65
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import com.google.api.gax.rpc.ClientContext;
1414
import com.google.api.gax.rpc.RequestParamsBuilder;
1515
import com.google.api.gax.rpc.UnaryCallable;
1616
import com.google.api.pathtemplate.PathTemplate;
17+
import com.google.explicit.dynamic.routing.header.EnumRequest;
18+
import com.google.explicit.dynamic.routing.header.EnumResponse;
1719
import com.google.explicit.dynamic.routing.header.Request;
1820
import com.google.explicit.dynamic.routing.header.RequestWithNestedField;
1921
import com.google.protobuf.Empty;
@@ -140,9 +142,48 @@ public class HttpJsonExplicitDynamicRoutingHeaderTestingStub
140142
.build())
141143
.build();
142144

145+
private static final ApiMethodDescriptor<EnumRequest, EnumResponse>
146+
implicitRoutingHeaderWithEnumTestMethodDescriptor =
147+
ApiMethodDescriptor.<EnumRequest, EnumResponse>newBuilder()
148+
.setFullMethodName(
149+
"google.explicit.dynamic.routing.header.ExplicitDynamicRoutingHeaderTesting/ImplicitRoutingHeaderWithEnumTest")
150+
.setHttpMethod("POST")
151+
.setType(ApiMethodDescriptor.MethodType.UNARY)
152+
.setRequestFormatter(
153+
ProtoMessageRequestFormatter.<EnumRequest>newBuilder()
154+
.setPath(
155+
"/v1beta1/{info.enumTest}",
156+
request -> {
157+
Map<String, String> fields = new HashMap<>();
158+
ProtoRestSerializer<EnumRequest> serializer =
159+
ProtoRestSerializer.create();
160+
serializer.putPathParam(
161+
fields, "info.enumTest", request.getInfo().getEnumTestValue());
162+
return fields;
163+
})
164+
.setQueryParamsExtractor(
165+
request -> {
166+
Map<String, List<String>> fields = new HashMap<>();
167+
ProtoRestSerializer<EnumRequest> serializer =
168+
ProtoRestSerializer.create();
169+
return fields;
170+
})
171+
.setRequestBodyExtractor(
172+
request ->
173+
ProtoRestSerializer.create()
174+
.toBody("*", request.toBuilder().build(), false))
175+
.build())
176+
.setResponseParser(
177+
ProtoMessageResponseParser.<EnumResponse>newBuilder()
178+
.setDefaultInstance(EnumResponse.getDefaultInstance())
179+
.setDefaultTypeRegistry(typeRegistry)
180+
.build())
181+
.build();
182+
143183
private final UnaryCallable<Request, Empty> backwardsCompatible1TestCallable;
144184
private final UnaryCallable<Request, Empty> backwardsCompatible2TestCallable;
145185
private final UnaryCallable<Request, Empty> backwardsCompatible3TestCallable;
186+
private final UnaryCallable<EnumRequest, EnumResponse> implicitRoutingHeaderWithEnumTestCallable;
146187

147188
private final BackgroundResource backgroundResources;
148189
private final HttpJsonStubCallableFactory callableFactory;
@@ -223,6 +264,19 @@ public class HttpJsonExplicitDynamicRoutingHeaderTestingStub
223264
return builder.build();
224265
})
225266
.build();
267+
HttpJsonCallSettings<EnumRequest, EnumResponse>
268+
implicitRoutingHeaderWithEnumTestTransportSettings =
269+
HttpJsonCallSettings.<EnumRequest, EnumResponse>newBuilder()
270+
.setMethodDescriptor(implicitRoutingHeaderWithEnumTestMethodDescriptor)
271+
.setTypeRegistry(typeRegistry)
272+
.setParamsExtractor(
273+
request -> {
274+
RequestParamsBuilder builder = RequestParamsBuilder.create();
275+
builder.add(
276+
"info.enum_test", String.valueOf(request.getInfo().getEnumTestValue()));
277+
return builder.build();
278+
})
279+
.build();
226280

227281
this.backwardsCompatible1TestCallable =
228282
callableFactory.createUnaryCallable(
@@ -239,6 +293,11 @@ public class HttpJsonExplicitDynamicRoutingHeaderTestingStub
239293
backwardsCompatible3TestTransportSettings,
240294
settings.backwardsCompatible3TestSettings(),
241295
clientContext);
296+
this.implicitRoutingHeaderWithEnumTestCallable =
297+
callableFactory.createUnaryCallable(
298+
implicitRoutingHeaderWithEnumTestTransportSettings,
299+
settings.implicitRoutingHeaderWithEnumTestSettings(),
300+
clientContext);
242301

243302
this.backgroundResources =
244303
new BackgroundResourceAggregation(clientContext.getBackgroundResources());
@@ -250,6 +309,7 @@ public class HttpJsonExplicitDynamicRoutingHeaderTestingStub
250309
methodDescriptors.add(backwardsCompatible1TestMethodDescriptor);
251310
methodDescriptors.add(backwardsCompatible2TestMethodDescriptor);
252311
methodDescriptors.add(backwardsCompatible3TestMethodDescriptor);
312+
methodDescriptors.add(implicitRoutingHeaderWithEnumTestMethodDescriptor);
253313
return methodDescriptors;
254314
}
255315

@@ -268,6 +328,11 @@ public class HttpJsonExplicitDynamicRoutingHeaderTestingStub
268328
return backwardsCompatible3TestCallable;
269329
}
270330

331+
@Override
332+
public UnaryCallable<EnumRequest, EnumResponse> implicitRoutingHeaderWithEnumTestCallable() {
333+
return implicitRoutingHeaderWithEnumTestCallable;
334+
}
335+
271336
@Override
272337
public UnaryCallable<Request, Empty> example1TestCallable() {
273338
throw new UnsupportedOperationException(

gapic-generator-java/src/test/proto/explicit_dynamic_routing_header_testing.proto

+28
Original file line numberDiff line numberDiff line change
@@ -265,9 +265,37 @@ service ExplicitDynamicRoutingHeaderTesting {
265265
}
266266
};
267267
}
268+
269+
// This method echoes the request. This method exercises
270+
// including a non-proto3-optional enum field in the URL path while sending the
271+
// entire request object in the REST body.
272+
rpc ImplicitRoutingHeaderWithEnumTest(EnumRequest) returns (EnumResponse) {
273+
option (google.api.http) = {
274+
post: "/v1beta1/{info.enum_test}"
275+
body: "*"
276+
};
277+
}
278+
}
279+
280+
message EnumRequest {
281+
string name = 1;
282+
EnumMessage info = 2;
268283
}
269284

285+
message EnumResponse {
286+
EnumRequest request = 1;
287+
}
270288

289+
message EnumMessage {
290+
enum EnumValues {
291+
ENUM_VALUE_1 = 0;
292+
ENUM_VALUE_2 = 1;
293+
ENUM_VALUE_3 = 2;
294+
ENUM_VALUE_4 = 3;
295+
}
296+
// scalar types
297+
EnumValues enum_test = 22;
298+
}
271299

272300
// Example message:
273301
//

showcase/gapic-showcase/src/main/java/com/google/showcase/v1beta1/stub/GrpcComplianceStub.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,8 @@ protected GrpcComplianceStub(
273273
builder.add("info.f_bool", String.valueOf(request.getInfo().getFBool()));
274274
builder.add("info.f_double", String.valueOf(request.getInfo().getFDouble()));
275275
builder.add("info.f_int32", String.valueOf(request.getInfo().getFInt32()));
276-
builder.add("info.f_kingdom", String.valueOf(request.getInfo().getFKingdom()));
276+
builder.add(
277+
"info.f_kingdom", String.valueOf(request.getInfo().getFKingdomValue()));
277278
builder.add("info.f_string", String.valueOf(request.getInfo().getFString()));
278279
return builder.build();
279280
})

showcase/gapic-showcase/src/main/java/com/google/showcase/v1beta1/stub/HttpJsonComplianceStub.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,8 @@ protected HttpJsonComplianceStub(
787787
builder.add("info.f_bool", String.valueOf(request.getInfo().getFBool()));
788788
builder.add("info.f_double", String.valueOf(request.getInfo().getFDouble()));
789789
builder.add("info.f_int32", String.valueOf(request.getInfo().getFInt32()));
790-
builder.add("info.f_kingdom", String.valueOf(request.getInfo().getFKingdom()));
790+
builder.add(
791+
"info.f_kingdom", String.valueOf(request.getInfo().getFKingdomValue()));
791792
builder.add("info.f_string", String.valueOf(request.getInfo().getFString()));
792793
return builder.build();
793794
})

0 commit comments

Comments
 (0)