From ceaaddbd08651df694e7b11834ae71556aa366aa Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 7 Oct 2020 16:18:54 -0700 Subject: [PATCH 1/2] fix: refactor requestBuilder into separate method in ServiceClientClassComposer --- .../composer/ServiceClientClassComposer.java | 138 +++--- .../api/generator/gapic/composer/BUILD.bazel | 4 +- .../ServiceClientClassComposerTest.java | 39 +- .../composer/goldens/IdentityClient.golden | 407 ++++++++++++++++++ .../api/generator/gapic/testdata/BUILD.bazel | 1 + .../generator/gapic/testdata/identity.proto | 192 +++++++++ 6 files changed, 705 insertions(+), 76 deletions(-) create mode 100644 src/test/java/com/google/api/generator/gapic/composer/goldens/IdentityClient.golden create mode 100644 src/test/java/com/google/api/generator/gapic/testdata/identity.proto diff --git a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java index 177fffb162..eb9d4abc99 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/ServiceClientClassComposer.java @@ -64,6 +64,7 @@ import com.google.api.generator.gapic.model.MethodArgument; import com.google.api.generator.gapic.model.Service; import com.google.api.generator.gapic.utils.JavaStyle; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.util.concurrent.MoreExecutors; @@ -90,6 +91,9 @@ public class ServiceClientClassComposer implements ClassComposer { private static final String PAGED_CALLABLE_NAME_PATTERN = "%sPagedCallable"; private static final String OPERATION_CALLABLE_NAME_PATTERN = "%sOperationCallable"; + private static final Reference LIST_REFERENCE = ConcreteReference.withClazz(List.class); + private static final Reference MAP_REFERENCE = ConcreteReference.withClazz(Map.class); + private enum CallableMethodKind { REGULAR, LRO, @@ -499,8 +503,6 @@ private static List createMethodVariants( } String methodInputTypeName = methodInputType.reference().name(); - Reference listRef = ConcreteReference.withClazz(List.class); - Reference mapRef = ConcreteReference.withClazz(Map.class); // Make the method signature order deterministic, which helps with unit testing and per-version // diffs. @@ -544,71 +546,12 @@ private static List createMethodVariants( .setIsDecl(true) .build(); - MethodInvocationExpr newBuilderExpr = - MethodInvocationExpr.builder() - .setMethodName("newBuilder") - .setStaticReferenceType(methodInputType) - .build(); - // TODO(miraleung): Handle nested arguments and descending setters here. - for (MethodArgument argument : signature) { - String argumentName = JavaStyle.toLowerCamelCase(argument.name()); - TypeNode argumentType = argument.type(); - String setterMethodVariantPattern = "set%s"; - if (TypeNode.isReferenceType(argumentType)) { - if (listRef.isSupertypeOrEquals(argumentType.reference())) { - setterMethodVariantPattern = "addAll%s"; - } else if (mapRef.isSupertypeOrEquals(argumentType.reference())) { - setterMethodVariantPattern = "putAll%s"; - } - } - String setterMethodName = - String.format(setterMethodVariantPattern, JavaStyle.toUpperCamelCase(argumentName)); - - Expr argVarExpr = - VariableExpr.withVariable( - Variable.builder().setName(argumentName).setType(argumentType).build()); - - if (argument.isResourceNameHelper()) { - MethodInvocationExpr isNullCheckExpr = - MethodInvocationExpr.builder() - .setStaticReferenceType(types.get("Objects")) - .setMethodName("isNull") - .setArguments(Arrays.asList(argVarExpr)) - .setReturnType(TypeNode.BOOLEAN) - .build(); - Expr nullExpr = ValueExpr.withValue(NullObjectValue.create()); - MethodInvocationExpr toStringExpr = - MethodInvocationExpr.builder() - .setExprReferenceExpr(argVarExpr) - .setMethodName("toString") - .setReturnType(TypeNode.STRING) - .build(); - argVarExpr = - TernaryExpr.builder() - .setConditionExpr(isNullCheckExpr) - .setThenExpr(nullExpr) - .setElseExpr(toStringExpr) - .build(); - } + Expr requestBuilderExpr = createRequestBuilderExpr(method, signature, types); - newBuilderExpr = - MethodInvocationExpr.builder() - .setMethodName(setterMethodName) - .setArguments(Arrays.asList(argVarExpr)) - .setExprReferenceExpr(newBuilderExpr) - .build(); - } - - MethodInvocationExpr builderExpr = - MethodInvocationExpr.builder() - .setMethodName("build") - .setExprReferenceExpr(newBuilderExpr) - .setReturnType(methodInputType) - .build(); AssignmentExpr requestAssignmentExpr = AssignmentExpr.builder() .setVariableExpr(requestVarExpr) - .setValueExpr(builderExpr) + .setValueExpr(requestBuilderExpr) .build(); List statements = Arrays.asList(ExprStatement.withExpr(requestAssignmentExpr)); @@ -1373,6 +1316,75 @@ private static ClassDefinition createNestedRpcFixedSizeCollectionClass( .build(); } + @VisibleForTesting + static Expr createRequestBuilderExpr( + Method method, List signature, Map types) { + TypeNode methodInputType = method.inputType(); + MethodInvocationExpr newBuilderExpr = + MethodInvocationExpr.builder() + .setMethodName("newBuilder") + .setStaticReferenceType(methodInputType) + .build(); + // TODO(miraleung): Handle nested arguments and descending setters here. + for (MethodArgument argument : signature) { + String argumentName = JavaStyle.toLowerCamelCase(argument.name()); + TypeNode argumentType = argument.type(); + String setterMethodVariantPattern = "set%s"; + if (TypeNode.isReferenceType(argumentType)) { + if (LIST_REFERENCE.isSupertypeOrEquals(argumentType.reference())) { + setterMethodVariantPattern = "addAll%s"; + } else if (MAP_REFERENCE.isSupertypeOrEquals(argumentType.reference())) { + setterMethodVariantPattern = "putAll%s"; + } + } + String setterMethodName = + String.format(setterMethodVariantPattern, JavaStyle.toUpperCamelCase(argumentName)); + + Expr argVarExpr = + VariableExpr.withVariable( + Variable.builder().setName(argumentName).setType(argumentType).build()); + + if (argument.isResourceNameHelper()) { + MethodInvocationExpr isNullCheckExpr = + MethodInvocationExpr.builder() + .setStaticReferenceType(types.get("Objects")) + .setMethodName("isNull") + .setArguments(Arrays.asList(argVarExpr)) + .setReturnType(TypeNode.BOOLEAN) + .build(); + Expr nullExpr = ValueExpr.withValue(NullObjectValue.create()); + MethodInvocationExpr toStringExpr = + MethodInvocationExpr.builder() + .setExprReferenceExpr(argVarExpr) + .setMethodName("toString") + .setReturnType(TypeNode.STRING) + .build(); + argVarExpr = + TernaryExpr.builder() + .setConditionExpr(isNullCheckExpr) + .setThenExpr(nullExpr) + .setElseExpr(toStringExpr) + .build(); + } + + newBuilderExpr = + MethodInvocationExpr.builder() + .setMethodName(setterMethodName) + .setArguments(Arrays.asList(argVarExpr)) + .setExprReferenceExpr(newBuilderExpr) + .build(); + } + + MethodInvocationExpr builderExpr = + MethodInvocationExpr.builder() + .setMethodName("build") + .setExprReferenceExpr(newBuilderExpr) + .setReturnType(methodInputType) + .build(); + + return builderExpr; + } + private static Map createTypes( Service service, Map messageTypes) { Map types = new HashMap<>(); diff --git a/src/test/java/com/google/api/generator/gapic/composer/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/composer/BUILD.bazel index d04f29e1c9..3a689014d3 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/BUILD.bazel +++ b/src/test/java/com/google/api/generator/gapic/composer/BUILD.bazel @@ -11,6 +11,8 @@ UPDATE_GOLDENS_TESTS = [ "MockServiceClassComposerTest", "MockServiceImplClassComposerTest", "ResourceNameHelperClassComposerTest", + "ServiceClientClassComposerTest", + "ServiceClientTestClassComposerTest", "ServiceSettingsClassComposerTest", "ServiceStubSettingsClassComposerTest", "ServiceStubClassComposerTest", @@ -20,8 +22,6 @@ TESTS = UPDATE_GOLDENS_TESTS + [ "DefaultValueComposerTest", "ResourceNameTokenizerTest", "RetrySettingsComposerTest", - "ServiceClientClassComposerTest", - "ServiceClientTestClassComposerTest", ] TEST_DEPS = [ diff --git a/src/test/java/com/google/api/generator/gapic/composer/ServiceClientClassComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/ServiceClientClassComposerTest.java index f0c0d70102..7e2f8d24d0 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/ServiceClientClassComposerTest.java +++ b/src/test/java/com/google/api/generator/gapic/composer/ServiceClientClassComposerTest.java @@ -27,28 +27,22 @@ import com.google.protobuf.Descriptors.FileDescriptor; import com.google.protobuf.Descriptors.ServiceDescriptor; import com.google.showcase.v1beta1.EchoOuterClass; +import com.google.showcase.v1beta1.IdentityOuterClass; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import org.junit.Before; import org.junit.Test; public class ServiceClientClassComposerTest { - private ServiceDescriptor echoService; - private FileDescriptor echoFileDescriptor; - - @Before - public void setUp() { - echoFileDescriptor = EchoOuterClass.getDescriptor(); - echoService = echoFileDescriptor.getServices().get(0); - assertEquals(echoService.getName(), "Echo"); - } - @Test public void generateServiceClasses() { + FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor(); + ServiceDescriptor echoService = echoFileDescriptor.getServices().get(0); + assertEquals(echoService.getName(), "Echo"); + Map messageTypes = Parser.parseMessages(echoFileDescriptor); Map resourceNames = Parser.parseResourceNames(echoFileDescriptor); Set outputResourceNames = new HashSet<>(); @@ -65,4 +59,27 @@ public void generateServiceClasses() { Path goldenFilePath = Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "EchoClient.golden"); assertCodeEquals(goldenFilePath, visitor.write()); } + + @Test + public void generateServiceClasses_methodSignatureHasNestedFields() { + FileDescriptor fileDescriptor = IdentityOuterClass.getDescriptor(); + ServiceDescriptor identityService = fileDescriptor.getServices().get(0); + assertEquals(identityService.getName(), "Identity"); + + Map messageTypes = Parser.parseMessages(fileDescriptor); + Map resourceNames = Parser.parseResourceNames(fileDescriptor); + Set outputResourceNames = new HashSet<>(); + List services = + Parser.parseService(fileDescriptor, messageTypes, resourceNames, outputResourceNames); + + Service protoService = services.get(0); + GapicClass clazz = ServiceClientClassComposer.instance().generate(protoService, messageTypes); + + JavaWriterVisitor visitor = new JavaWriterVisitor(); + clazz.classDefinition().accept(visitor); + Utils.saveCodegenToFile(this.getClass(), "IdentityClient.golden", visitor.write()); + Path goldenFilePath = + Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "IdentityClient.golden"); + assertCodeEquals(goldenFilePath, visitor.write()); + } } diff --git a/src/test/java/com/google/api/generator/gapic/composer/goldens/IdentityClient.golden b/src/test/java/com/google/api/generator/gapic/composer/goldens/IdentityClient.golden new file mode 100644 index 0000000000..0f6f1a418d --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/composer/goldens/IdentityClient.golden @@ -0,0 +1,407 @@ +package com.google.showcase.v1beta1; + +import com.google.api.core.ApiFunction; +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.core.BetaApi; +import com.google.api.gax.core.BackgroundResource; +import com.google.api.gax.paging.AbstractFixedSizeCollection; +import com.google.api.gax.paging.AbstractPage; +import com.google.api.gax.paging.AbstractPagedListResponse; +import com.google.api.gax.rpc.PageContext; +import com.google.api.gax.rpc.UnaryCallable; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.protobuf.Empty; +import com.google.showcase.v1beta1.stub.IdentityStub; +import com.google.showcase.v1beta1.stub.IdentityStubSettings; +import java.io.IOException; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import javax.annotation.Generated; + +// AUTO-GENERATED DOCUMENTATION AND CLASS. +/** + * This class provides the ability to make remote calls to the backing service through method calls + * that map to API methods. Sample code to get started: + * + *

Note: close() needs to be called on the echoClient object to clean up resources such as + * threads. In the example above, try-with-resources is used, which automatically calls close(). + * + *

The surface of this class includes several types of Java methods for each of the API's + * methods: + * + *

    + *
  1. A "flattened" method. With this type of method, the fields of the request type have been + * converted into function parameters. It may be the case that not all fields are available as + * parameters, and not every API method will have a flattened method entry point. + *
  2. A "request object" method. This type of method only takes one parameter, a request object, + * which must be constructed before the call. Not every API method will have a request object + * method. + *
  3. A "callable" method. This type of method takes no parameters and returns an immutable API + * callable object, which can be used to initiate calls to the service. + *
+ * + *

See the individual methods for example code. + * + *

Many parameters require resource names to be formatted in a particular way. To assist with + * these names, this class includes a format method for each type of name, and additionally a parse + * method to extract the individual identifiers contained within names that are returned. + * + *

This class can be customized by passing in a custom instance of IdentitySettings to create(). + * For example: + * + *

To customize credentials: + * + *

To customize the endpoint: + */ +@BetaApi +@Generated("by gapic-generator") +public class IdentityClient implements BackgroundResource { + private final IdentitySettings settings; + private final IdentityStub stub; + + /** Constructs an instance of EchoClient with default settings. */ + public static final IdentityClient create() throws IOException { + return create(IdentitySettings.newBuilder().build()); + } + + /** + * Constructs an instance of EchoClient, using the given settings. The channels are created based + * on the settings passed in, or defaults for any settings that are not set. + */ + public static final IdentityClient create(IdentitySettings settings) throws IOException { + return new IdentityClient(settings); + } + + /** + * Constructs an instance of EchoClient, using the given stub for making calls. This is for + * advanced usage - prefer using create(IdentitySettings). + */ + @BetaApi("A restructuring of stub classes is planned, so this may break in the future") + public static final IdentityClient create(IdentityStub stub) { + return new IdentityClient(stub); + } + + /** + * Constructs an instance of EchoClient, using the given settings. This is protected so that it is + * easy to make a subclass, but otherwise, the static factory methods should be preferred. + */ + protected IdentityClient(IdentitySettings settings) throws IOException { + this.settings = settings; + this.stub = ((IdentityStubSettings) settings.getStubSettings()).createStub(); + } + + @BetaApi("A restructuring of stub classes is planned, so this may break in the future") + protected IdentityClient(IdentityStub stub) { + this.settings = null; + this.stub = stub; + } + + public final IdentitySettings getSettings() { + return settings; + } + + @BetaApi("A restructuring of stub classes is planned, so this may break in the future") + public IdentityStub getStub() { + return stub; + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param parent + * @param display_name + * @param email + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User createUser(String parent, String displayName, String email) { + CreateUserRequest request = + CreateUserRequest.newBuilder() + .setParent(parent) + .setDisplayName(displayName) + .setEmail(email) + .build(); + return createUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param parent + * @param display_name + * @param email + * @param age + * @param nickname + * @param enable_notifications + * @param height_feet + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User createUser( + String parent, + String displayName, + String email, + int age, + String nickname, + boolean enableNotifications, + double heightFeet) { + CreateUserRequest request = + CreateUserRequest.newBuilder() + .setParent(parent) + .setDisplayName(displayName) + .setEmail(email) + .setAge(age) + .setNickname(nickname) + .setEnableNotifications(enableNotifications) + .setHeightFeet(heightFeet) + .build(); + return createUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User createUser(CreateUserRequest request) { + return createUserCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable createUserCallable() { + return stub.createUserCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param name + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User getUser(UserName name) { + GetUserRequest request = + GetUserRequest.newBuilder().setName(Objects.isNull(name) ? null : name.toString()).build(); + return getUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param name + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User getUser(String name) { + GetUserRequest request = GetUserRequest.newBuilder().setName(name).build(); + return getUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User getUser(GetUserRequest request) { + return getUserCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable getUserCallable() { + return stub.getUserCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final User updateUser(UpdateUserRequest request) { + return updateUserCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable updateUserCallable() { + return stub.updateUserCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param name + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Empty deleteUser(UserName name) { + DeleteUserRequest request = + DeleteUserRequest.newBuilder() + .setName(Objects.isNull(name) ? null : name.toString()) + .build(); + return deleteUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param name + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Empty deleteUser(String name) { + DeleteUserRequest request = DeleteUserRequest.newBuilder().setName(name).build(); + return deleteUser(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final Empty deleteUser(DeleteUserRequest request) { + return deleteUserCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable deleteUserCallable() { + return stub.deleteUserCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + * @param request The request object containing all of the parameters for the API call. + * @throws com.google.api.gax.rpc.ApiException if the remote call fails + */ + public final ListUsersPagedResponse listUsers(ListUsersRequest request) { + return listUsersPagedCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable listUsersPagedCallable() { + return stub.listUsersPagedCallable(); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** Sample code: */ + public final UnaryCallable listUsersCallable() { + return stub.listUsersCallable(); + } + + @Override + public final void close() { + stub.close(); + } + + @Override + public void shutdown() { + stub.shutdown(); + } + + @Override + public boolean isShutdown() { + return stub.isShutdown(); + } + + @Override + public boolean isTerminated() { + return stub.isTerminated(); + } + + @Override + public void shutdownNow() { + stub.shutdownNow(); + } + + @Override + public boolean awaitTermination(long duration, TimeUnit unit) throws InterruptedException { + return stub.awaitTermination(duration, unit); + } + + public static class ListUsersPagedResponse + extends AbstractPagedListResponse< + ListUsersRequest, ListUsersResponse, User, ListUsersPage, ListUsersFixedSizeCollection> { + + public static ApiFuture createAsync( + PageContext context, + ApiFuture futureResponse) { + ApiFuture futurePage = + ListUsersPage.createEmptyPage().createPageAsync(context, futureResponse); + return ApiFutures.transform( + futurePage, + new ApiFunction() { + @Override + public ListUsersPagedResponse apply(ListUsersPage input) { + return new ListUsersPagedResponse(input); + } + }, + MoreExecutors.directExecutor()); + } + + private ListUsersPagedResponse(ListUsersPage page) { + super(page, ListUsersFixedSizeCollection.createEmptyCollection()); + } + } + + public static class ListUsersPage + extends AbstractPage { + + private ListUsersPage( + PageContext context, + ListUsersResponse response) { + super(context, response); + } + + private static ListUsersPage createEmptyPage() { + return new ListUsersPage(null, null); + } + + @Override + protected ListUsersPage createPage( + PageContext context, + ListUsersResponse response) { + return new ListUsersPage(context, response); + } + + @Override + public ApiFuture createPageAsync( + PageContext context, + ApiFuture futureResponse) { + return super.createPageAsync(context, futureResponse); + } + } + + public static class ListUsersFixedSizeCollection + extends AbstractFixedSizeCollection< + ListUsersRequest, ListUsersResponse, User, ListUsersPage, ListUsersFixedSizeCollection> { + + private ListUsersFixedSizeCollection(List pages, int collectionSize) { + super(pages, collectionSize); + } + + private static ListUsersFixedSizeCollection createEmptyCollection() { + return new ListUsersFixedSizeCollection(null, 0); + } + + @Override + protected ListUsersFixedSizeCollection createCollection( + List pages, int collectionSize) { + return new ListUsersFixedSizeCollection(pages, collectionSize); + } + } +} diff --git a/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel b/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel index a846eaf638..9682b5c414 100644 --- a/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel +++ b/src/test/java/com/google/api/generator/gapic/testdata/BUILD.bazel @@ -32,6 +32,7 @@ proto_library( name = "showcase_proto", srcs = [ "echo.proto", + "identity.proto", "testing.proto", ], deps = [ diff --git a/src/test/java/com/google/api/generator/gapic/testdata/identity.proto b/src/test/java/com/google/api/generator/gapic/testdata/identity.proto new file mode 100644 index 0000000000..5ed47e8c59 --- /dev/null +++ b/src/test/java/com/google/api/generator/gapic/testdata/identity.proto @@ -0,0 +1,192 @@ +// Copyright 2018 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 +// +// https://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. + +syntax = "proto3"; + +import "google/api/annotations.proto"; +import "google/api/client.proto"; +import "google/api/field_behavior.proto"; +import "google/api/resource.proto"; +import "google/protobuf/empty.proto"; +import "google/protobuf/field_mask.proto"; +import "google/protobuf/timestamp.proto"; + +package google.showcase.v1beta1; + +option go_package = "github.com/googleapis/gapic-showcase/server/genproto"; +option java_package = "com.google.showcase.v1beta1"; +option java_multiple_files = true; + +// A simple identity service. +service Identity { + // This service is meant to only run locally on the port 7469 (keypad digits + // for "show"). + option (google.api.default_host) = "localhost:7469"; + option (google.api.oauth_scopes) = + "https://www.googleapis.com/auth/cloud-platform"; + + // Creates a user. + rpc CreateUser(CreateUserRequest) returns (User) { + option (google.api.http) = { + post: "/v1beta1/{parent=users}" + body: "*" + }; + option (google.api.method_signature) = + "parent,user.display_name,user.email"; + option (google.api.method_signature) = + "parent,user.display_name,user.email,user.age,user.nickname,user.enable_notifications,user.height_feet"; + } + + // Retrieves the User with the given uri. + rpc GetUser(GetUserRequest) returns (User) { + option (google.api.http) = { + get: "/v1beta1/{name=users/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Updates a user. + rpc UpdateUser(UpdateUserRequest) returns (User) { + option (google.api.http) = { + patch: "/v1beta1/{user.name=users/*}" + body: "*" + }; + } + + // Deletes a user, their profile, and all of their authored messages. + rpc DeleteUser(DeleteUserRequest) returns (google.protobuf.Empty) { + option (google.api.http) = { + delete: "/v1beta1/{name=users/*}" + }; + option (google.api.method_signature) = "name"; + } + + // Lists all users. + rpc ListUsers(ListUsersRequest) returns (ListUsersResponse) { + option (google.api.http) = { + get: "/v1beta1/users" + }; + } +} + +// A user. +message User { + option (google.api.resource) = { + type: "showcase.googleapis.com/User" + pattern: "users/{user}" + }; + + // The resource name of the user. + string name = 1; + + // The display_name of the user. + string display_name = 2 [(google.api.field_behavior) = REQUIRED]; + + // The email address of the user. + string email = 3 [(google.api.field_behavior) = REQUIRED]; + + // The timestamp at which the user was created. + google.protobuf.Timestamp create_time = 4 + [(google.api.field_behavior) = OUTPUT_ONLY]; + + // The latest timestamp at which the user was updated. + google.protobuf.Timestamp update_time = 5 + [(google.api.field_behavior) = OUTPUT_ONLY]; + + // The age of the use in years. + optional int32 age = 6; + + // The height of the user in feet. + optional double height_feet = 7; + + // The nickname of the user. + // + // (-- aip.dev/not-precedent: An empty string is a valid nickname. + // Ordinarily, proto3_optional should not be used on a `string` field. --) + optional string nickname = 8; + + // Enables the receiving of notifications. The default is true if unset. + // + // (-- aip.dev/not-precedent: The default for the feature is true. + // Ordinarily, the default for a `bool` field should be false. --) + optional bool enable_notifications = 9; +} + +// The request message for the google.showcase.v1beta1.Identity\CreateUser +// method. +message CreateUserRequest { + string parent = 1 [ + (google.api.resource_reference).child_type = "showcase.googleapis.com/User", + (google.api.field_behavior) = REQUIRED + ]; + // The user to create. + User user = 2 [(google.api.field_behavior) = REQUIRED]; +} + +// The request message for the google.showcase.v1beta1.Identity\GetUser +// method. +message GetUserRequest { + // The resource name of the requested user. + string name = 1 [ + (google.api.resource_reference).type = "showcase.googleapis.com/User", + (google.api.field_behavior) = REQUIRED + ]; +} + +// The request message for the google.showcase.v1beta1.Identity\UpdateUser +// method. +message UpdateUserRequest { + // The user to update. + User user = 1; + + // The field mask to determine wich fields are to be updated. If empty, the + // server will assume all fields are to be updated. + google.protobuf.FieldMask update_mask = 2; +} + +// The request message for the google.showcase.v1beta1.Identity\DeleteUser +// method. +message DeleteUserRequest { + // The resource name of the user to delete. + string name = 1 [ + (google.api.resource_reference).type = "showcase.googleapis.com/User", + (google.api.field_behavior) = REQUIRED + ]; +} + +// The request message for the google.showcase.v1beta1.Identity\ListUsers +// method. +message ListUsersRequest { + // The maximum number of users to return. Server may return fewer users + // than requested. If unspecified, server will pick an appropriate default. + int32 page_size = 1; + + // The value of google.showcase.v1beta1.ListUsersResponse.next_page_token + // returned from the previous call to + // `google.showcase.v1beta1.Identity\ListUsers` method. + string page_token = 2; +} + +// The response message for the google.showcase.v1beta1.Identity\ListUsers +// method. +message ListUsersResponse { + // The list of users. + repeated User users = 1; + + // A token to retrieve next page of results. + // Pass this value in ListUsersRequest.page_token field in the subsequent + // call to `google.showcase.v1beta1.Message\ListUsers` method to retrieve the + // next page of results. + string next_page_token = 2; +} From bdcb62ecd23604ae07d47501503866e8c77e0d0c Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 21 Oct 2020 13:19:44 -0700 Subject: [PATCH 2/2] feat: add varargs to AnonClass and ref setter methods --- .../api/generator/engine/ast/AnonymousClassExpr.java | 5 +++++ .../google/api/generator/engine/ast/ConcreteReference.java | 7 ++++++- .../google/api/generator/engine/ast/VaporReference.java | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/google/api/generator/engine/ast/AnonymousClassExpr.java b/src/main/java/com/google/api/generator/engine/ast/AnonymousClassExpr.java index 7cbce07ff0..e4ddc7e11d 100644 --- a/src/main/java/com/google/api/generator/engine/ast/AnonymousClassExpr.java +++ b/src/main/java/com/google/api/generator/engine/ast/AnonymousClassExpr.java @@ -17,6 +17,7 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -45,6 +46,10 @@ public static Builder builder() { public abstract static class Builder { public abstract Builder setType(TypeNode type); + public Builder setMethods(MethodDefinition... methods) { + return setMethods(Arrays.asList(methods)); + } + public abstract Builder setMethods(List methods); public abstract Builder setStatements(List statements); diff --git a/src/main/java/com/google/api/generator/engine/ast/ConcreteReference.java b/src/main/java/com/google/api/generator/engine/ast/ConcreteReference.java index 7d37a02417..58494fe7a5 100644 --- a/src/main/java/com/google/api/generator/engine/ast/ConcreteReference.java +++ b/src/main/java/com/google/api/generator/engine/ast/ConcreteReference.java @@ -16,6 +16,7 @@ import com.google.auto.value.AutoValue; import com.google.common.collect.ImmutableList; +import java.util.Arrays; import java.util.List; import java.util.Objects; import javax.annotation.Nullable; @@ -210,7 +211,11 @@ public abstract static class Builder { public abstract Builder setWildcardUpperBound(Reference reference); - public abstract Builder setGenerics(List clazzes); + public Builder setGenerics(Reference... references) { + return setGenerics(Arrays.asList(references)); + } + + public abstract Builder setGenerics(List references); public abstract Builder setIsStaticImport(boolean isStaticImport); diff --git a/src/main/java/com/google/api/generator/engine/ast/VaporReference.java b/src/main/java/com/google/api/generator/engine/ast/VaporReference.java index c3b237bdf3..cd9361ebe3 100644 --- a/src/main/java/com/google/api/generator/engine/ast/VaporReference.java +++ b/src/main/java/com/google/api/generator/engine/ast/VaporReference.java @@ -17,6 +17,7 @@ import com.google.auto.value.AutoValue; import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; +import java.util.Arrays; import java.util.List; import java.util.Objects; import javax.annotation.Nullable; @@ -146,6 +147,10 @@ public abstract static class Builder { public abstract Builder setUseFullName(boolean useFullName); + public Builder setGenerics(Reference... references) { + return setGenerics(Arrays.asList(references)); + } + public abstract Builder setGenerics(List clazzes); public abstract Builder setEnclosingClassName(String enclosingClassName);