Skip to content

Commit e63d1b4

Browse files
authored
feat: Update Gapic generator and Gax to emit api-versioning via header (#2671)
This is part 2, following changes in #2630 Changes in this pr: - ApiClientHeaderProvider: add key and token setter for api version. - AbstractServiceStubSettingsClassComposer: add logic to set this header when api-version is present (not null or empty) - Unit and golden tests to reflect above changes. (This includeds a few new golden files created for tests based on the dedicated proto created in #2630) This pr does not include gapic-showcased testing for now. --- manual tested with [gapic-showcase](https://github.com/googleapis/gapic-showcase) v0.33.0 steps: - Use gapic-showcase v0.33.0 (which includes update in 1484) - use `gapic-showcase run -v` which prints the request header - From showcase folder, run `mvn verify -P enable-integration-tests -Dit.test=ITAutoPopulatedFields.java -pl=gapic-showcase` Printed header in manual testing Grpc ``` 2024/04/16 10:26:41 Received Unary Request for Method: /google.showcase.v1beta1.Echo/Echo 2024/04/16 10:26:41 Request headers: 2024/04/16 10:26:41 grpc-accept-encoding: gzip 2024/04/16 10:26:41 content-type: application/grpc 2024/04/16 10:26:41 x-goog-api-version: v1_20240408 2024/04/16 10:26:41 :authority: localhost:7469 2024/04/16 10:26:41 user-agent: grpc-java-netty/1.62.2 2024/04/16 10:26:41 x-goog-api-client: gl-java/17.0.7__Eclipse-Adoptium__Temurin-17.0.7-7 gapic/0.0.1-SNAPSHOT gax/2.46.2-SNAPSHOT grpc/1.62.2 2024/04/16 10:26:41 Request: error:{code:2} request_id:"1e26ee16-ed07-4eeb-be0e-49b769678779" other_request_id:"40883e5d-3b20-4add-854c-9808bd009260" 2024/04/16 10:26:41 Returning Error: rpc error: code = Unknown desc = ``` Httpjson ``` 2024/04/16 10:26:41 Received POST request matching '/v1beta1/echo:echo': "/v1beta1/echo:echo" 2024/04/16 10:26:41 urlPathParams (expect 0, have 0): map[] 2024/04/16 10:26:41 urlRequestHeaders: User-Agent: "Google-HTTP-Java-Client/1.44.1 (gzip)" Content-Type: "application/json; charset=utf-8" Connection: "keep-alive" Accept-Encoding: "gzip" X-Goog-Api-Client: "gl-java/17.0.7__Eclipse-Adoptium__Temurin-17.0.7-7 gapic/0.0.1-SNAPSHOT gax/2.46.2-SNAPSHOT rest/" X-Goog-Api-Version: "v1_20240408" Accept: "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" Content-Length: "129" 2024/04/16 10:26:41 request: { "error": { "code": 500, "message": "", "details": [] }, "severity": "UNNECESSARY", "header": "", "otherHeader": "", "requestId": "e690a84b-176d-421e-9e5d-ba752f68fec8", "otherRequestId": "47e0fbde-056a-43ae-bba6-8b6770d861f7" } ```
1 parent 849bb50 commit e63d1b4

File tree

17 files changed

+1358
-38
lines changed

17 files changed

+1358
-38
lines changed

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,16 @@ protected MethodDefinition createApiClientHeaderProviderBuilderMethod(
370370
.setReturnType(returnType)
371371
.build();
372372

373+
if (service.hasApiVersion()) {
374+
375+
returnExpr =
376+
MethodInvocationExpr.builder()
377+
.setExprReferenceExpr(returnExpr)
378+
.setMethodName("setApiVersionToken")
379+
.setArguments(ValueExpr.withValue(StringObjectValue.withValue(service.apiVersion())))
380+
.setReturnType(returnType)
381+
.build();
382+
}
373383
return MethodDefinition.builder()
374384
.setScope(ScopeNode.PUBLIC)
375385
.setIsStatic(true)

gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpc/ServiceStubSettingsClassComposerTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ public static Collection<Object[]> data() {
5454
GrpcTestProtoLoader.instance().parseDeprecatedService(),
5555
"localhost:7469",
5656
"v1"
57+
},
58+
{
59+
"ApiVersionTestingStubSettings",
60+
GrpcTestProtoLoader.instance().parseApiVersionTesting(),
61+
"localhost:7469",
62+
"v1"
5763
}
5864
});
5965
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
package com.google.api.version.test.stub;
2+
3+
import com.google.api.core.ApiFunction;
4+
import com.google.api.gax.core.GaxProperties;
5+
import com.google.api.gax.core.GoogleCredentialsProvider;
6+
import com.google.api.gax.core.InstantiatingExecutorProvider;
7+
import com.google.api.gax.grpc.GaxGrpcProperties;
8+
import com.google.api.gax.grpc.GrpcTransportChannel;
9+
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
10+
import com.google.api.gax.retrying.RetrySettings;
11+
import com.google.api.gax.rpc.ApiClientHeaderProvider;
12+
import com.google.api.gax.rpc.ClientContext;
13+
import com.google.api.gax.rpc.StatusCode;
14+
import com.google.api.gax.rpc.StubSettings;
15+
import com.google.api.gax.rpc.TransportChannelProvider;
16+
import com.google.api.gax.rpc.UnaryCallSettings;
17+
import com.google.api.version.test.EchoRequest;
18+
import com.google.api.version.test.EchoResponse;
19+
import com.google.common.collect.ImmutableList;
20+
import com.google.common.collect.ImmutableMap;
21+
import com.google.common.collect.ImmutableSet;
22+
import com.google.common.collect.Lists;
23+
import java.io.IOException;
24+
import java.util.List;
25+
import javax.annotation.Generated;
26+
27+
// AUTO-GENERATED DOCUMENTATION AND CLASS.
28+
/**
29+
* Settings class to configure an instance of {@link EchoWithVersionStub}.
30+
*
31+
* <p>The default instance has everything set to sensible defaults:
32+
*
33+
* <ul>
34+
* <li>The default service address (localhost) and default port (7469) are used.
35+
* <li>Credentials are acquired automatically through Application Default Credentials.
36+
* <li>Retries are configured for idempotent methods but not for non-idempotent methods.
37+
* </ul>
38+
*
39+
* <p>The builder of this class is recursive, so contained classes are themselves builders. When
40+
* build() is called, the tree of builders is called to create the complete settings object.
41+
*
42+
* <p>For example, to set the total timeout of echoWithVersionMethod to 30 seconds:
43+
*
44+
* <pre>{@code
45+
* // This snippet has been automatically generated and should be regarded as a code template only.
46+
* // It will require modifications to work:
47+
* // - It may require correct/in-range values for request initialization.
48+
* // - It may require specifying regional endpoints when creating the service client as shown in
49+
* // https://cloud.google.com/java/docs/setup#configure_endpoints_for_the_client_library
50+
* EchoWithVersionStubSettings.Builder echoWithVersionSettingsBuilder =
51+
* EchoWithVersionStubSettings.newBuilder();
52+
* echoWithVersionSettingsBuilder
53+
* .echoWithVersionMethodSettings()
54+
* .setRetrySettings(
55+
* echoWithVersionSettingsBuilder
56+
* .echoWithVersionMethodSettings()
57+
* .getRetrySettings()
58+
* .toBuilder()
59+
* .setTotalTimeout(Duration.ofSeconds(30))
60+
* .build());
61+
* EchoWithVersionStubSettings echoWithVersionSettings = echoWithVersionSettingsBuilder.build();
62+
* }</pre>
63+
*/
64+
@Generated("by gapic-generator-java")
65+
public class EchoWithVersionStubSettings extends StubSettings<EchoWithVersionStubSettings> {
66+
/** The default scopes of the service. */
67+
private static final ImmutableList<String> DEFAULT_SERVICE_SCOPES =
68+
ImmutableList.<String>builder().add("https://www.googleapis.com/auth/cloud-platform").build();
69+
70+
private final UnaryCallSettings<EchoRequest, EchoResponse> echoWithVersionMethodSettings;
71+
72+
/** Returns the object with the settings used for calls to echoWithVersionMethod. */
73+
public UnaryCallSettings<EchoRequest, EchoResponse> echoWithVersionMethodSettings() {
74+
return echoWithVersionMethodSettings;
75+
}
76+
77+
public EchoWithVersionStub createStub() throws IOException {
78+
if (getTransportChannelProvider()
79+
.getTransportName()
80+
.equals(GrpcTransportChannel.getGrpcTransportName())) {
81+
return GrpcEchoWithVersionStub.create(this);
82+
}
83+
throw new UnsupportedOperationException(
84+
String.format(
85+
"Transport not supported: %s", getTransportChannelProvider().getTransportName()));
86+
}
87+
88+
/** Returns a builder for the default ExecutorProvider for this service. */
89+
public static InstantiatingExecutorProvider.Builder defaultExecutorProviderBuilder() {
90+
return InstantiatingExecutorProvider.newBuilder();
91+
}
92+
93+
/** Returns the default service endpoint. */
94+
public static String getDefaultEndpoint() {
95+
return "localhost:7469";
96+
}
97+
98+
/** Returns the default mTLS service endpoint. */
99+
public static String getDefaultMtlsEndpoint() {
100+
return "localhost:7469";
101+
}
102+
103+
/** Returns the default service scopes. */
104+
public static List<String> getDefaultServiceScopes() {
105+
return DEFAULT_SERVICE_SCOPES;
106+
}
107+
108+
/** Returns a builder for the default credentials for this service. */
109+
public static GoogleCredentialsProvider.Builder defaultCredentialsProviderBuilder() {
110+
return GoogleCredentialsProvider.newBuilder()
111+
.setScopesToApply(DEFAULT_SERVICE_SCOPES)
112+
.setUseJwtAccessWithScope(true);
113+
}
114+
115+
/** Returns a builder for the default ChannelProvider for this service. */
116+
public static InstantiatingGrpcChannelProvider.Builder defaultGrpcTransportProviderBuilder() {
117+
return InstantiatingGrpcChannelProvider.newBuilder()
118+
.setMaxInboundMessageSize(Integer.MAX_VALUE);
119+
}
120+
121+
public static TransportChannelProvider defaultTransportChannelProvider() {
122+
return defaultGrpcTransportProviderBuilder().build();
123+
}
124+
125+
public static ApiClientHeaderProvider.Builder defaultApiClientHeaderProviderBuilder() {
126+
return ApiClientHeaderProvider.newBuilder()
127+
.setGeneratedLibToken(
128+
"gapic", GaxProperties.getLibraryVersion(EchoWithVersionStubSettings.class))
129+
.setTransportToken(GaxGrpcProperties.getGrpcTokenName(), GaxGrpcProperties.getGrpcVersion())
130+
.setApiVersionToken("fake_version");
131+
}
132+
133+
/** Returns a new builder for this class. */
134+
public static Builder newBuilder() {
135+
return Builder.createDefault();
136+
}
137+
138+
/** Returns a new builder for this class. */
139+
public static Builder newBuilder(ClientContext clientContext) {
140+
return new Builder(clientContext);
141+
}
142+
143+
/** Returns a builder containing all the values of this settings class. */
144+
public Builder toBuilder() {
145+
return new Builder(this);
146+
}
147+
148+
protected EchoWithVersionStubSettings(Builder settingsBuilder) throws IOException {
149+
super(settingsBuilder);
150+
151+
echoWithVersionMethodSettings = settingsBuilder.echoWithVersionMethodSettings().build();
152+
}
153+
154+
/** Builder for EchoWithVersionStubSettings. */
155+
public static class Builder extends StubSettings.Builder<EchoWithVersionStubSettings, Builder> {
156+
private final ImmutableList<UnaryCallSettings.Builder<?, ?>> unaryMethodSettingsBuilders;
157+
private final UnaryCallSettings.Builder<EchoRequest, EchoResponse>
158+
echoWithVersionMethodSettings;
159+
private static final ImmutableMap<String, ImmutableSet<StatusCode.Code>>
160+
RETRYABLE_CODE_DEFINITIONS;
161+
162+
static {
163+
ImmutableMap.Builder<String, ImmutableSet<StatusCode.Code>> definitions =
164+
ImmutableMap.builder();
165+
definitions.put("no_retry_codes", ImmutableSet.copyOf(Lists.<StatusCode.Code>newArrayList()));
166+
RETRYABLE_CODE_DEFINITIONS = definitions.build();
167+
}
168+
169+
private static final ImmutableMap<String, RetrySettings> RETRY_PARAM_DEFINITIONS;
170+
171+
static {
172+
ImmutableMap.Builder<String, RetrySettings> definitions = ImmutableMap.builder();
173+
RetrySettings settings = null;
174+
settings = RetrySettings.newBuilder().setRpcTimeoutMultiplier(1.0).build();
175+
definitions.put("no_retry_params", settings);
176+
RETRY_PARAM_DEFINITIONS = definitions.build();
177+
}
178+
179+
protected Builder() {
180+
this(((ClientContext) null));
181+
}
182+
183+
protected Builder(ClientContext clientContext) {
184+
super(clientContext);
185+
186+
echoWithVersionMethodSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
187+
188+
unaryMethodSettingsBuilders =
189+
ImmutableList.<UnaryCallSettings.Builder<?, ?>>of(echoWithVersionMethodSettings);
190+
initDefaults(this);
191+
}
192+
193+
protected Builder(EchoWithVersionStubSettings settings) {
194+
super(settings);
195+
196+
echoWithVersionMethodSettings = settings.echoWithVersionMethodSettings.toBuilder();
197+
198+
unaryMethodSettingsBuilders =
199+
ImmutableList.<UnaryCallSettings.Builder<?, ?>>of(echoWithVersionMethodSettings);
200+
}
201+
202+
private static Builder createDefault() {
203+
Builder builder = new Builder(((ClientContext) null));
204+
205+
builder.setTransportChannelProvider(defaultTransportChannelProvider());
206+
builder.setCredentialsProvider(defaultCredentialsProviderBuilder().build());
207+
builder.setInternalHeaderProvider(defaultApiClientHeaderProviderBuilder().build());
208+
builder.setMtlsEndpoint(getDefaultMtlsEndpoint());
209+
builder.setSwitchToMtlsEndpointAllowed(true);
210+
211+
return initDefaults(builder);
212+
}
213+
214+
private static Builder initDefaults(Builder builder) {
215+
builder
216+
.echoWithVersionMethodSettings()
217+
.setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_codes"))
218+
.setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_params"));
219+
220+
return builder;
221+
}
222+
223+
/**
224+
* Applies the given settings updater function to all of the unary API methods in this service.
225+
*
226+
* <p>Note: This method does not support applying settings to streaming methods.
227+
*/
228+
public Builder applyToAllUnaryMethods(
229+
ApiFunction<UnaryCallSettings.Builder<?, ?>, Void> settingsUpdater) {
230+
super.applyToAllUnaryMethods(unaryMethodSettingsBuilders, settingsUpdater);
231+
return this;
232+
}
233+
234+
public ImmutableList<UnaryCallSettings.Builder<?, ?>> unaryMethodSettingsBuilders() {
235+
return unaryMethodSettingsBuilders;
236+
}
237+
238+
/** Returns the builder for the settings used for calls to echoWithVersionMethod. */
239+
public UnaryCallSettings.Builder<EchoRequest, EchoResponse> echoWithVersionMethodSettings() {
240+
return echoWithVersionMethodSettings;
241+
}
242+
243+
@Override
244+
public EchoWithVersionStubSettings build() throws IOException {
245+
return new EchoWithVersionStubSettings(this);
246+
}
247+
}
248+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.api.version.test.stub.samples;
18+
19+
// [START goldensample_generated_EchoWithVersionStubSettings_EchoWithVersionMethod_sync]
20+
import com.google.api.version.test.stub.EchoWithVersionStubSettings;
21+
import java.time.Duration;
22+
23+
public class SyncEchoWithVersionMethod {
24+
25+
public static void main(String[] args) throws Exception {
26+
syncEchoWithVersionMethod();
27+
}
28+
29+
public static void syncEchoWithVersionMethod() throws Exception {
30+
// This snippet has been automatically generated and should be regarded as a code template only.
31+
// It will require modifications to work:
32+
// - It may require correct/in-range values for request initialization.
33+
// - It may require specifying regional endpoints when creating the service client as shown in
34+
// https://cloud.google.com/java/docs/setup#configure_endpoints_for_the_client_library
35+
EchoWithVersionStubSettings.Builder echoWithVersionSettingsBuilder =
36+
EchoWithVersionStubSettings.newBuilder();
37+
echoWithVersionSettingsBuilder
38+
.echoWithVersionMethodSettings()
39+
.setRetrySettings(
40+
echoWithVersionSettingsBuilder
41+
.echoWithVersionMethodSettings()
42+
.getRetrySettings()
43+
.toBuilder()
44+
.setTotalTimeout(Duration.ofSeconds(30))
45+
.build());
46+
EchoWithVersionStubSettings echoWithVersionSettings = echoWithVersionSettingsBuilder.build();
47+
}
48+
}
49+
// [END goldensample_generated_EchoWithVersionStubSettings_EchoWithVersionMethod_sync]

gapic-generator-java/src/test/java/com/google/api/generator/gapic/composer/grpcrest/ServiceStubSettingsClassComposerTest.java

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,37 +23,38 @@
2323
import com.google.api.generator.test.protoloader.GrpcRestTestProtoLoader;
2424
import java.nio.file.Path;
2525
import java.nio.file.Paths;
26+
import java.util.Arrays;
27+
import java.util.Collection;
2628
import org.junit.Test;
29+
import org.junit.runner.RunWith;
30+
import org.junit.runners.Parameterized;
2731

32+
@RunWith(Parameterized.class)
2833
public class ServiceStubSettingsClassComposerTest {
34+
@Parameterized.Parameters
35+
public static Collection<Object[]> data() {
36+
return Arrays.asList(
37+
new Object[][] {
38+
{"EchoStubSettings.golden", GrpcRestTestProtoLoader.instance().parseShowcaseEcho()},
39+
{"WickedStubSettings.golden", GrpcRestTestProtoLoader.instance().parseShowcaseWicked()}
40+
});
41+
}
42+
43+
@Parameterized.Parameter public String goldenFileName;
44+
45+
@Parameterized.Parameter(1)
46+
public GapicContext context;
47+
2948
@Test
3049
public void generateServiceClasses() {
31-
GapicContext context = GrpcRestTestProtoLoader.instance().parseShowcaseEcho();
3250
Service echoProtoService = context.services().get(0);
3351
GapicClass clazz =
3452
ServiceStubSettingsClassComposer.instance().generate(context, echoProtoService);
3553

3654
JavaWriterVisitor visitor = new JavaWriterVisitor();
3755
clazz.classDefinition().accept(visitor);
38-
GoldenFileWriter.saveCodegenToFile(this.getClass(), "EchoStubSettings.golden", visitor.write());
39-
Path goldenFilePath =
40-
Paths.get(GoldenFileWriter.getGoldenDir(this.getClass()), "EchoStubSettings.golden");
41-
Assert.assertCodeEquals(goldenFilePath, visitor.write());
42-
}
43-
44-
@Test
45-
public void generateServiceClassesWicked() {
46-
GapicContext context = GrpcRestTestProtoLoader.instance().parseShowcaseWicked();
47-
Service wickedProtoService = context.services().get(0);
48-
GapicClass clazz =
49-
ServiceStubSettingsClassComposer.instance().generate(context, wickedProtoService);
50-
51-
JavaWriterVisitor visitor = new JavaWriterVisitor();
52-
clazz.classDefinition().accept(visitor);
53-
GoldenFileWriter.saveCodegenToFile(
54-
this.getClass(), "WickedStubSettings.golden", visitor.write());
55-
Path goldenFilePath =
56-
Paths.get(GoldenFileWriter.getGoldenDir(this.getClass()), "WickedStubSettings.golden");
56+
GoldenFileWriter.saveCodegenToFile(this.getClass(), goldenFileName, visitor.write());
57+
Path goldenFilePath = Paths.get(GoldenFileWriter.getGoldenDir(this.getClass()), goldenFileName);
5758
Assert.assertCodeEquals(goldenFilePath, visitor.write());
5859
}
5960
}

0 commit comments

Comments
 (0)