Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.

Commit c5a32cc

Browse files
authored
[ggj][codegen] feat: Add alpha/beta API detection and fix per-class annotation (#633)
* fix: fix dep ordering in Bazel dedupe rules * feat: Add alpha/beta API detection and fix per-class annotations * fix: update integration tests
1 parent 2085654 commit c5a32cc

57 files changed

Lines changed: 404 additions & 265 deletions

File tree

Some content is hidden

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

src/main/java/com/google/api/generator/gapic/composer/GrpcServiceCallableFactoryClassComposer.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.google.api.generator.gapic.composer;
1616

17+
import com.google.api.core.BetaApi;
1718
import com.google.api.gax.grpc.GrpcCallSettings;
1819
import com.google.api.gax.grpc.GrpcCallableFactory;
1920
import com.google.api.gax.grpc.GrpcStubCallableFactory;
@@ -40,6 +41,7 @@
4041
import com.google.api.generator.gapic.composer.comment.StubCommentComposer;
4142
import com.google.api.generator.gapic.composer.store.TypeStore;
4243
import com.google.api.generator.gapic.composer.utils.ClassNames;
44+
import com.google.api.generator.gapic.composer.utils.PackageChecker;
4345
import com.google.api.generator.gapic.model.GapicClass;
4446
import com.google.api.generator.gapic.model.GapicClass.Kind;
4547
import com.google.api.generator.gapic.model.Message;
@@ -77,7 +79,7 @@ public GapicClass generate(Service service, Map<String, Message> ignore) {
7779
.setHeaderCommentStatements(
7880
StubCommentComposer.createGrpcServiceCallableFactoryClassHeaderComments(
7981
service.name()))
80-
.setAnnotations(createClassAnnotations(typeStore))
82+
.setAnnotations(createClassAnnotations(service.pakkage(), typeStore))
8183
.setImplementsTypes(createClassImplements(typeStore))
8284
.setName(className)
8385
.setMethods(createClassMethods(typeStore))
@@ -86,12 +88,17 @@ public GapicClass generate(Service service, Map<String, Message> ignore) {
8688
return GapicClass.create(kind, classDef);
8789
}
8890

89-
private static List<AnnotationNode> createClassAnnotations(TypeStore typeStore) {
90-
return Arrays.asList(
91+
private static List<AnnotationNode> createClassAnnotations(String pakkage, TypeStore typeStore) {
92+
List<AnnotationNode> annotations = new ArrayList<>();
93+
if (!PackageChecker.isGaApi(pakkage)) {
94+
annotations.add(AnnotationNode.withType(typeStore.get("BetaApi")));
95+
}
96+
annotations.add(
9197
AnnotationNode.builder()
9298
.setType(typeStore.get("Generated"))
93-
.setDescription("by gapic-generator")
99+
.setDescription("by gapic-generator-java")
94100
.build());
101+
return annotations;
95102
}
96103

97104
private static List<TypeNode> createClassImplements(TypeStore typeStore) {
@@ -343,6 +350,7 @@ private static TypeStore createTypes(Service service) {
343350
Arrays.asList(
344351
// Gax-java classes.
345352
BatchingCallSettings.class,
353+
BetaApi.class,
346354
BidiStreamingCallable.class,
347355
ClientContext.class,
348356
ClientStreamingCallable.class,

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.google.api.generator.gapic.composer;
1616

17+
import com.google.api.core.BetaApi;
1718
import com.google.api.gax.core.BackgroundResource;
1819
import com.google.api.gax.core.BackgroundResourceAggregation;
1920
import com.google.api.gax.grpc.GrpcCallSettings;
@@ -51,6 +52,7 @@
5152
import com.google.api.generator.gapic.composer.comment.StubCommentComposer;
5253
import com.google.api.generator.gapic.composer.store.TypeStore;
5354
import com.google.api.generator.gapic.composer.utils.ClassNames;
55+
import com.google.api.generator.gapic.composer.utils.PackageChecker;
5456
import com.google.api.generator.gapic.model.GapicClass;
5557
import com.google.api.generator.gapic.model.GapicClass.Kind;
5658
import com.google.api.generator.gapic.model.Message;
@@ -161,7 +163,7 @@ public GapicClass generate(Service service, Map<String, Message> ignore) {
161163
.setPackageString(pakkage)
162164
.setHeaderCommentStatements(
163165
StubCommentComposer.createGrpcServiceStubClassHeaderComments(service.name()))
164-
.setAnnotations(createClassAnnotations())
166+
.setAnnotations(createClassAnnotations(service.pakkage()))
165167
.setScope(ScopeNode.PUBLIC)
166168
.setName(className)
167169
.setExtendsType(typeStore.get(ClassNames.getServiceStubClassName(service)))
@@ -385,12 +387,17 @@ private static Map<String, VariableExpr> createCallableClassMembers(
385387
return callableClassMembers;
386388
}
387389

388-
private static List<AnnotationNode> createClassAnnotations() {
389-
return Arrays.asList(
390+
private static List<AnnotationNode> createClassAnnotations(String pakkage) {
391+
List<AnnotationNode> annotations = new ArrayList<>();
392+
if (!PackageChecker.isGaApi(pakkage)) {
393+
annotations.add(AnnotationNode.withType(FIXED_TYPESTORE.get("BetaApi")));
394+
}
395+
annotations.add(
390396
AnnotationNode.builder()
391397
.setType(FIXED_TYPESTORE.get("Generated"))
392398
.setDescription("by gapic-generator-java")
393399
.build());
400+
return annotations;
394401
}
395402

396403
private static List<MethodDefinition> createClassMethods(
@@ -1024,6 +1031,7 @@ private static TypeStore createStaticTypes() {
10241031
Arrays.asList(
10251032
BackgroundResource.class,
10261033
BackgroundResourceAggregation.class,
1034+
BetaApi.class,
10271035
BidiStreamingCallable.class,
10281036
ClientContext.class,
10291037
ClientStreamingCallable.class,

src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import com.google.api.generator.gapic.composer.samplecode.ServiceClientSampleCodeComposer;
5959
import com.google.api.generator.gapic.composer.store.TypeStore;
6060
import com.google.api.generator.gapic.composer.utils.ClassNames;
61+
import com.google.api.generator.gapic.composer.utils.PackageChecker;
6162
import com.google.api.generator.gapic.model.Field;
6263
import com.google.api.generator.gapic.model.GapicClass;
6364
import com.google.api.generator.gapic.model.GapicClass.Kind;
@@ -128,7 +129,7 @@ public GapicClass generate(Service service, Map<String, Message> messageTypes) {
128129
ClassDefinition.builder()
129130
.setHeaderCommentStatements(createClassHeaderComments(service, typeStore))
130131
.setPackageString(pakkage)
131-
.setAnnotations(createClassAnnotations(typeStore))
132+
.setAnnotations(createClassAnnotations(pakkage, typeStore))
132133
.setScope(ScopeNode.PUBLIC)
133134
.setName(className)
134135
.setImplementsTypes(createClassImplements(typeStore))
@@ -139,13 +140,17 @@ public GapicClass generate(Service service, Map<String, Message> messageTypes) {
139140
return GapicClass.create(kind, classDef);
140141
}
141142

142-
private static List<AnnotationNode> createClassAnnotations(TypeStore typeStore) {
143-
return Arrays.asList(
144-
AnnotationNode.withType(typeStore.get("BetaApi")),
143+
private static List<AnnotationNode> createClassAnnotations(String pakkage, TypeStore typeStore) {
144+
List<AnnotationNode> annotations = new ArrayList<>();
145+
if (!PackageChecker.isGaApi(pakkage)) {
146+
annotations.add(AnnotationNode.withType(typeStore.get("BetaApi")));
147+
}
148+
annotations.add(
145149
AnnotationNode.builder()
146150
.setType(typeStore.get("Generated"))
147-
.setDescription("by gapic-generator")
151+
.setDescription("by gapic-generator-java")
148152
.build());
153+
return annotations;
149154
}
150155

151156
private static List<TypeNode> createClassImplements(TypeStore typeStore) {

src/main/java/com/google/api/generator/gapic/composer/ServiceSettingsClassComposer.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import com.google.api.generator.gapic.composer.samplecode.SettingsSampleCodeComposer;
5555
import com.google.api.generator.gapic.composer.store.TypeStore;
5656
import com.google.api.generator.gapic.composer.utils.ClassNames;
57+
import com.google.api.generator.gapic.composer.utils.PackageChecker;
5758
import com.google.api.generator.gapic.model.GapicClass;
5859
import com.google.api.generator.gapic.model.GapicClass.Kind;
5960
import com.google.api.generator.gapic.model.Message;
@@ -104,7 +105,7 @@ public GapicClass generate(Service service, Map<String, Message> ignore) {
104105
.setPackageString(pakkage)
105106
.setHeaderCommentStatements(
106107
createClassHeaderComments(service, typeStore.get(className)))
107-
.setAnnotations(createClassAnnotations())
108+
.setAnnotations(createClassAnnotations(service.pakkage()))
108109
.setScope(ScopeNode.PUBLIC)
109110
.setName(className)
110111
.setExtendsType(
@@ -147,12 +148,17 @@ private static List<CommentStatement> createClassHeaderComments(
147148
classType);
148149
}
149150

150-
private static List<AnnotationNode> createClassAnnotations() {
151-
return Arrays.asList(
151+
private static List<AnnotationNode> createClassAnnotations(String pakkage) {
152+
List<AnnotationNode> annotations = new ArrayList<>();
153+
if (!PackageChecker.isGaApi(pakkage)) {
154+
annotations.add(AnnotationNode.withType(FIXED_TYPESTORE.get("BetaApi")));
155+
}
156+
annotations.add(
152157
AnnotationNode.builder()
153158
.setType(FIXED_TYPESTORE.get("Generated"))
154159
.setDescription("by gapic-generator-java")
155160
.build());
161+
return annotations;
156162
}
157163

158164
private static List<MethodDefinition> createClassMethods(Service service, TypeStore typeStore) {

src/main/java/com/google/api/generator/gapic/composer/ServiceStubClassComposer.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.google.api.generator.gapic.composer;
1616

17+
import com.google.api.core.BetaApi;
1718
import com.google.api.gax.core.BackgroundResource;
1819
import com.google.api.gax.rpc.BidiStreamingCallable;
1920
import com.google.api.gax.rpc.ClientStreamingCallable;
@@ -32,6 +33,7 @@
3233
import com.google.api.generator.gapic.composer.comment.StubCommentComposer;
3334
import com.google.api.generator.gapic.composer.store.TypeStore;
3435
import com.google.api.generator.gapic.composer.utils.ClassNames;
36+
import com.google.api.generator.gapic.composer.utils.PackageChecker;
3537
import com.google.api.generator.gapic.model.GapicClass;
3638
import com.google.api.generator.gapic.model.GapicClass.Kind;
3739
import com.google.api.generator.gapic.model.Message;
@@ -69,7 +71,7 @@ public GapicClass generate(Service service, Map<String, Message> messageTypes) {
6971
.setPackageString(pakkage)
7072
.setHeaderCommentStatements(
7173
StubCommentComposer.createServiceStubClassHeaderComments(service.name()))
72-
.setAnnotations(createClassAnnotations(typeStore))
74+
.setAnnotations(createClassAnnotations(service.pakkage(), typeStore))
7375
.setIsAbstract(true)
7476
.setImplementsTypes(createClassImplements(typeStore))
7577
.setName(className)
@@ -79,12 +81,17 @@ public GapicClass generate(Service service, Map<String, Message> messageTypes) {
7981
return GapicClass.create(kind, classDef);
8082
}
8183

82-
private static List<AnnotationNode> createClassAnnotations(TypeStore typeStore) {
83-
return Arrays.asList(
84+
private static List<AnnotationNode> createClassAnnotations(String pakkage, TypeStore typeStore) {
85+
List<AnnotationNode> annotations = new ArrayList<>();
86+
if (!PackageChecker.isGaApi(pakkage)) {
87+
annotations.add(AnnotationNode.withType(typeStore.get("BetaApi")));
88+
}
89+
annotations.add(
8490
AnnotationNode.builder()
8591
.setType(typeStore.get("Generated"))
86-
.setDescription("by gapic-generator")
92+
.setDescription("by gapic-generator-java")
8793
.build());
94+
return annotations;
8895
}
8996

9097
private static List<TypeNode> createClassImplements(TypeStore typeStore) {
@@ -215,6 +222,7 @@ private static TypeStore createTypes(Service service, Map<String, Message> messa
215222
List<Class> concreteClazzes =
216223
Arrays.asList(
217224
BackgroundResource.class,
225+
BetaApi.class,
218226
BidiStreamingCallable.class,
219227
ClientStreamingCallable.class,
220228
Generated.class,

src/main/java/com/google/api/generator/gapic/composer/ServiceStubSettingsClassComposer.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
import com.google.api.generator.gapic.composer.samplecode.SettingsSampleCodeComposer;
8686
import com.google.api.generator.gapic.composer.store.TypeStore;
8787
import com.google.api.generator.gapic.composer.utils.ClassNames;
88+
import com.google.api.generator.gapic.composer.utils.PackageChecker;
8889
import com.google.api.generator.gapic.model.Field;
8990
import com.google.api.generator.gapic.model.GapicBatchingSettings;
9091
import com.google.api.generator.gapic.model.GapicClass;
@@ -175,7 +176,7 @@ public GapicClass generate(
175176
.setPackageString(pakkage)
176177
.setHeaderCommentStatements(
177178
createClassHeaderComments(service, typeStore.get(className)))
178-
.setAnnotations(createClassAnnotations())
179+
.setAnnotations(createClassAnnotations(service.pakkage()))
179180
.setScope(ScopeNode.PUBLIC)
180181
.setName(className)
181182
.setExtendsType(createExtendsType(service, typeStore))
@@ -189,13 +190,17 @@ public GapicClass generate(
189190
return GapicClass.create(GapicClass.Kind.STUB, classDef);
190191
}
191192

192-
private static List<AnnotationNode> createClassAnnotations() {
193-
return Arrays.asList(
194-
AnnotationNode.withType(FIXED_TYPESTORE.get("BetaApi")),
193+
private static List<AnnotationNode> createClassAnnotations(String pakkage) {
194+
List<AnnotationNode> annotations = new ArrayList<>();
195+
if (!PackageChecker.isGaApi(pakkage)) {
196+
annotations.add(AnnotationNode.withType(FIXED_TYPESTORE.get("BetaApi")));
197+
}
198+
annotations.add(
195199
AnnotationNode.builder()
196200
.setType(FIXED_TYPESTORE.get("Generated"))
197201
.setDescription("by gapic-generator-java")
198202
.build());
203+
return annotations;
199204
}
200205

201206
private static List<CommentStatement> createClassHeaderComments(

src/main/java/com/google/api/generator/gapic/composer/utils/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ java_library(
1414
],
1515
deps = [
1616
"//src/main/java/com/google/api/generator/gapic/model",
17+
"@com_google_guava_guava//jar",
1718
],
1819
)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2021 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.api.generator.gapic.composer.utils;
16+
17+
import com.google.common.base.Preconditions;
18+
import com.google.common.base.Strings;
19+
import java.util.regex.Matcher;
20+
import java.util.regex.Pattern;
21+
22+
public class PackageChecker {
23+
private PackageChecker() {}
24+
25+
/**
26+
* Identifies whether a Java package is GA API. Assumes that the version appears in the last
27+
* component of the package, e.g. com.google.cloud.dataproc.v1beta1.
28+
*/
29+
public static boolean isGaApi(String pakkage) {
30+
String[] packageComponents = pakkage.split("\\.");
31+
Preconditions.checkState(
32+
packageComponents.length > 0, "No subcomponents found in Java package %s", pakkage);
33+
String versionComponent = packageComponents[packageComponents.length - 1];
34+
Matcher matcher = Pattern.compile("^v[0-9]+").matcher(versionComponent);
35+
Preconditions.checkState(
36+
matcher.find(),
37+
"No version component found in last subpackage %s of %s",
38+
versionComponent,
39+
pakkage);
40+
String versionSubstr = versionComponent.replace(matcher.group(), "");
41+
return Strings.isNullOrEmpty(versionSubstr)
42+
|| (!versionSubstr.contains("alpha") && !versionSubstr.contains("beta"));
43+
}
44+
}

src/test/java/com/google/api/generator/gapic/composer/constants/BUILD.bazel

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
load("@rules_java//java:defs.bzl", "java_library")
2-
31
package(default_visibility = ["//visibility:public"])
42

53
filegroup(

src/test/java/com/google/api/generator/gapic/composer/goldens/EchoClient.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ import javax.annotation.Generated;
8080
* <p>Please refer to the GitHub repository's samples for more quickstart code snippets.
8181
*/
8282
@BetaApi
83-
@Generated("by gapic-generator")
83+
@Generated("by gapic-generator-java")
8484
public class EchoClient implements BackgroundResource {
8585
private final EchoSettings settings;
8686
private final EchoStub stub;

0 commit comments

Comments
 (0)