From 99236807a36b65a90197040e230ec5eb8fcd6407 Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Sat, 24 Oct 2020 19:02:33 -0700 Subject: [PATCH] [ggj][codegen] feat: add package-info.java codegen (#414) * fix: refactor requestBuilder into separate method in ServiceClientClassComposer * feat: add varargs to AnonClass and ref setter methods * feat: add HTTP annotation parsing/validation * feat: Generate RequestParamsExtractor in GrpcServiceStub * feat: add GrpcPublisherStub test to exercise HTTP subfields * fix: add ByteString to DefaultValueComposer * fix: Use repeated field name for paged RPC unit tests * fix: refactor exception field, use paged repeated field name, add pubsub client test * fix: ensure all testgen methods throw Exceptions * fix: Fix resname helper method names for of* and format* * fix: use only generated resnames in codegen * fix: propagate of*Name changes to resname codegen * fix: fix method arg resname mappings, add logging test * fix: ensure paged tests use the right repeated resp. type * feat: add PackageInfoDefinition AST node * feat: add package-info.java codegen --- .../engine/ast/PackageInfoDefinition.java | 2 + .../google/api/generator/gapic/Generator.java | 4 +- .../ClientLibraryPackageInfoComposer.java | 43 +++++++++++++++++++ .../generator/gapic/composer/Composer.java | 14 ++++++ .../gapic/model/GapicPackageInfo.java | 39 +++++++++++++++++ .../generator/gapic/protowriter/Writer.java | 20 ++++++++- 6 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposer.java create mode 100644 src/main/java/com/google/api/generator/gapic/model/GapicPackageInfo.java diff --git a/src/main/java/com/google/api/generator/engine/ast/PackageInfoDefinition.java b/src/main/java/com/google/api/generator/engine/ast/PackageInfoDefinition.java index f20495dd11..4930701318 100644 --- a/src/main/java/com/google/api/generator/engine/ast/PackageInfoDefinition.java +++ b/src/main/java/com/google/api/generator/engine/ast/PackageInfoDefinition.java @@ -30,6 +30,8 @@ public abstract class PackageInfoDefinition implements AstNode { public abstract ImmutableList annotations(); + public abstract Builder toBuilder(); + @Override public void accept(AstNodeVisitor visitor) { visitor.visit(this); diff --git a/src/main/java/com/google/api/generator/gapic/Generator.java b/src/main/java/com/google/api/generator/gapic/Generator.java index 80b3e93636..0b7268010f 100644 --- a/src/main/java/com/google/api/generator/gapic/Generator.java +++ b/src/main/java/com/google/api/generator/gapic/Generator.java @@ -17,6 +17,7 @@ import com.google.api.generator.gapic.composer.Composer; import com.google.api.generator.gapic.model.GapicClass; import com.google.api.generator.gapic.model.GapicContext; +import com.google.api.generator.gapic.model.GapicPackageInfo; import com.google.api.generator.gapic.protoparser.Parser; import com.google.api.generator.gapic.protowriter.Writer; import com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest; @@ -27,8 +28,9 @@ public class Generator { public static CodeGeneratorResponse generateGapic(CodeGeneratorRequest request) { GapicContext context = Parser.parse(request); List clazzes = Composer.composeServiceClasses(context); + GapicPackageInfo packageInfo = Composer.composePackageInfo(context); String outputFilename = "temp-codegen.srcjar"; - CodeGeneratorResponse response = Writer.writeCode(clazzes, outputFilename); + CodeGeneratorResponse response = Writer.writeCode(clazzes, packageInfo, outputFilename); return response; } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposer.java b/src/main/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposer.java new file mode 100644 index 0000000000..7bbafa7f2e --- /dev/null +++ b/src/main/java/com/google/api/generator/gapic/composer/ClientLibraryPackageInfoComposer.java @@ -0,0 +1,43 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.gapic.composer; + +import com.google.api.generator.engine.ast.AnnotationNode; +import com.google.api.generator.engine.ast.ConcreteReference; +import com.google.api.generator.engine.ast.PackageInfoDefinition; +import com.google.api.generator.engine.ast.TypeNode; +import com.google.api.generator.gapic.model.GapicContext; +import com.google.api.generator.gapic.model.GapicPackageInfo; +import com.google.common.base.Preconditions; +import javax.annotation.Generated; + +public class ClientLibraryPackageInfoComposer { + public static GapicPackageInfo generatePackageInfo(GapicContext context) { + Preconditions.checkState(!context.services().isEmpty(), "No services found to generate"); + // Pick some service's package, as we assume they are all the same. + String libraryPakkage = context.services().get(0).pakkage(); + + PackageInfoDefinition packageInfo = + PackageInfoDefinition.builder() + .setPakkage(libraryPakkage) + .setAnnotations( + AnnotationNode.builder() + .setType(TypeNode.withReference(ConcreteReference.withClazz(Generated.class))) + .setDescription("by gapic-generator-java") + .build()) + .build(); + return GapicPackageInfo.with(packageInfo); + } +} diff --git a/src/main/java/com/google/api/generator/gapic/composer/Composer.java b/src/main/java/com/google/api/generator/gapic/composer/Composer.java index e2c2775bed..02e1dc9bcc 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/Composer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/Composer.java @@ -19,6 +19,7 @@ import com.google.api.generator.gapic.model.GapicClass; import com.google.api.generator.gapic.model.GapicClass.Kind; import com.google.api.generator.gapic.model.GapicContext; +import com.google.api.generator.gapic.model.GapicPackageInfo; import com.google.api.generator.gapic.model.GapicServiceConfig; import com.google.api.generator.gapic.model.Message; import com.google.api.generator.gapic.model.ResourceName; @@ -49,6 +50,10 @@ public static List composeServiceClasses(GapicContext context) { return addApacheLicense(clazzes); } + public static GapicPackageInfo composePackageInfo(GapicContext context) { + return addApacheLicense(ClientLibraryPackageInfoComposer.generatePackageInfo(context)); + } + public static List generateServiceClasses( @Nonnull Service service, @Nullable GapicServiceConfig serviceConfig, @@ -131,4 +136,13 @@ protected static List addApacheLicense(List gapicClassLi }) .collect(Collectors.toList()); } + + private static GapicPackageInfo addApacheLicense(GapicPackageInfo gapicPackageInfo) { + return GapicPackageInfo.with( + gapicPackageInfo + .packageInfo() + .toBuilder() + .setFileHeader(CommentComposer.APACHE_LICENSE_COMMENT) + .build()); + } } diff --git a/src/main/java/com/google/api/generator/gapic/model/GapicPackageInfo.java b/src/main/java/com/google/api/generator/gapic/model/GapicPackageInfo.java new file mode 100644 index 0000000000..5c6ac6c3a7 --- /dev/null +++ b/src/main/java/com/google/api/generator/gapic/model/GapicPackageInfo.java @@ -0,0 +1,39 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.api.generator.gapic.model; + +import com.google.api.generator.engine.ast.PackageInfoDefinition; +import com.google.auto.value.AutoValue; + +/** A thin wrapper around PackageInfoDefinition to maintain a clean separation of concerns. */ +@AutoValue +public abstract class GapicPackageInfo { + public abstract PackageInfoDefinition packageInfo(); + + public static GapicPackageInfo with(PackageInfoDefinition packageInfo) { + return builder().setPackageInfo(packageInfo).build(); + } + + static Builder builder() { + return new AutoValue_GapicPackageInfo.Builder(); + } + + @AutoValue.Builder + abstract static class Builder { + abstract Builder setPackageInfo(PackageInfoDefinition packageInfo); + + abstract GapicPackageInfo build(); + } +} diff --git a/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java b/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java index 55c61c9e07..fdbcbe2ba7 100644 --- a/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java +++ b/src/main/java/com/google/api/generator/gapic/protowriter/Writer.java @@ -15,8 +15,10 @@ package com.google.api.generator.gapic.protowriter; import com.google.api.generator.engine.ast.ClassDefinition; +import com.google.api.generator.engine.ast.PackageInfoDefinition; import com.google.api.generator.engine.writer.JavaWriterVisitor; import com.google.api.generator.gapic.model.GapicClass; +import com.google.api.generator.gapic.model.GapicPackageInfo; import com.google.protobuf.ByteString; import com.google.protobuf.compiler.PluginProtos.CodeGeneratorResponse; import java.io.IOException; @@ -31,7 +33,8 @@ public GapicWriterException(String errorMessage) { } } - public static CodeGeneratorResponse writeCode(List clazzes, String outputFilePath) { + public static CodeGeneratorResponse writeCode( + List clazzes, GapicPackageInfo gapicPackageInfo, String outputFilePath) { ByteString.Output output = ByteString.newOutput(); JavaWriterVisitor codeWriter = new JavaWriterVisitor(); JarOutputStream jos = null; @@ -62,6 +65,21 @@ public static CodeGeneratorResponse writeCode(List clazzes, String o } } + // Write the package info. + PackageInfoDefinition packageInfo = gapicPackageInfo.packageInfo(); + packageInfo.accept(codeWriter); + String code = codeWriter.write(); + codeWriter.clear(); + + String path = "src/main/java/" + packageInfo.pakkage().replaceAll("\\.", "/"); + JarEntry jarEntry = new JarEntry(String.format("%s/package-info.java", path)); + try { + jos.putNextEntry(jarEntry); + jos.write(code.getBytes()); + } catch (IOException e) { + throw new GapicWriterException("Could not write code for package-info.java"); + } + try { jos.finish(); jos.flush();