diff --git a/src/main/java/com/google/api/generator/engine/ast/AssignmentExpr.java b/src/main/java/com/google/api/generator/engine/ast/AssignmentExpr.java index 9223e41783..1314505d1f 100644 --- a/src/main/java/com/google/api/generator/engine/ast/AssignmentExpr.java +++ b/src/main/java/com/google/api/generator/engine/ast/AssignmentExpr.java @@ -64,8 +64,10 @@ public AssignmentExpr build() { if (rhsType != TypeNode.NULL && !lhsType.isSupertypeOrEquals(rhsType)) { throw new TypeMismatchException( String.format( - "LHS type %s must be a supertype of the RHS type %s", - lhsType.reference().name(), rhsType.reference().name())); + "LHS type %s of variable %s must be a supertype of the RHS type %s", + lhsType.reference().name(), + assignmentExpr.variableExpr().variable().identifier(), + rhsType.reference().name())); } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/BUILD.bazel b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/BUILD.bazel index 178459f813..48171ec5d3 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/BUILD.bazel +++ b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/BUILD.bazel @@ -17,6 +17,7 @@ java_library( "//src/main/java/com/google/api/generator/gapic/composer/resourcename", "//src/main/java/com/google/api/generator/gapic/model", "//src/main/java/com/google/api/generator/gapic/utils", + "@com_google_api_api_common", "@com_google_googleapis//google/longrunning:longrunning_java_proto", "@com_google_guava_guava//jar", "@com_google_protobuf//java/core", diff --git a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java index fec4d3050f..707b46588e 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java @@ -14,11 +14,16 @@ package com.google.api.generator.gapic.composer.defaultvalue; +import com.google.api.generator.engine.ast.AnonymousClassExpr; +import com.google.api.generator.engine.ast.AssignmentExpr; import com.google.api.generator.engine.ast.ConcreteReference; import com.google.api.generator.engine.ast.Expr; +import com.google.api.generator.engine.ast.ExprStatement; +import com.google.api.generator.engine.ast.MethodDefinition; import com.google.api.generator.engine.ast.MethodInvocationExpr; import com.google.api.generator.engine.ast.NewObjectExpr; import com.google.api.generator.engine.ast.PrimitiveValue; +import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.StringObjectValue; import com.google.api.generator.engine.ast.TypeNode; import com.google.api.generator.engine.ast.ValueExpr; @@ -31,6 +36,7 @@ import com.google.api.generator.gapic.model.ResourceName; import com.google.api.generator.gapic.utils.JavaStyle; import com.google.api.generator.gapic.utils.ResourceNameConstants; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.longrunning.Operation; import com.google.protobuf.Any; @@ -157,6 +163,16 @@ static Expr createDefaultValue(Field f, boolean useExplicitInitTypeInGenerics) { public static Expr createDefaultValue( ResourceName resourceName, List resnames, String fieldOrMessageName) { + return createDefaultValueResourceHelper(resourceName, resnames, fieldOrMessageName, true); + } + + @VisibleForTesting + static Expr createDefaultValueResourceHelper( + ResourceName resourceName, + List resnames, + String fieldOrMessageName, + boolean allowAnonResourceNameClass) { + boolean hasOnePattern = resourceName.patterns().size() == 1; if (resourceName.isOnlyWildcard()) { List unexaminedResnames = new ArrayList<>(resnames); @@ -170,9 +186,11 @@ public static Expr createDefaultValue( } if (unexaminedResnames.isEmpty()) { - return ValueExpr.withValue( - StringObjectValue.withValue( - String.format("%s%s", fieldOrMessageName, fieldOrMessageName.hashCode()))); + return allowAnonResourceNameClass + ? createAnonymousResourceNameClass(fieldOrMessageName) + : ValueExpr.withValue( + StringObjectValue.withValue( + String.format("%s%s", fieldOrMessageName, fieldOrMessageName.hashCode()))); } } @@ -247,10 +265,11 @@ public static Expr createSimpleMessageBuilderExpr( if (field.hasResourceReference() && resourceNames.get(field.resourceReference().resourceTypeString()) != null) { defaultExpr = - createDefaultValue( + createDefaultValueResourceHelper( resourceNames.get(field.resourceReference().resourceTypeString()), resourceNames.values().stream().collect(Collectors.toList()), - message.name()); + message.name(), + /* allowAnonResourceNameClass = */ false); defaultExpr = MethodInvocationExpr.builder() .setExprReferenceExpr(defaultExpr) @@ -345,4 +364,92 @@ public static Expr createSimplePagedResponse( .setReturnType(responseType) .build(); } + + @VisibleForTesting + static AnonymousClassExpr createAnonymousResourceNameClass(String fieldOrMessageName) { + TypeNode stringMapType = + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(Map.class) + .setGenerics( + Arrays.asList( + ConcreteReference.withClazz(String.class), + ConcreteReference.withClazz(String.class))) + .build()); + + // Method code: + // @Override + // public Map getFieldValuesMap() { + // Map fieldValuesMap = new HashMap<>(); + // fieldValuesMap.put("resource", "resource-12345"); + // return fieldValuesMap; + // } + VariableExpr fieldValuesMapVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(stringMapType).setName("fieldValuesMap").build()); + StringObjectValue fieldOrMessageStringValue = + StringObjectValue.withValue( + String.format("%s%s", fieldOrMessageName, fieldOrMessageName.hashCode())); + + List bodyExprs = + Arrays.asList( + AssignmentExpr.builder() + .setVariableExpr(fieldValuesMapVarExpr.toBuilder().setIsDecl(true).build()) + .setValueExpr( + NewObjectExpr.builder() + .setType(TypeNode.withReference(ConcreteReference.withClazz(HashMap.class))) + .setIsGeneric(true) + .build()) + .build(), + MethodInvocationExpr.builder() + .setExprReferenceExpr(fieldValuesMapVarExpr) + .setMethodName("put") + .setArguments( + ValueExpr.withValue(StringObjectValue.withValue(fieldOrMessageName)), + ValueExpr.withValue(fieldOrMessageStringValue)) + .build()); + + MethodDefinition getFieldValuesMapMethod = + MethodDefinition.builder() + .setIsOverride(true) + .setScope(ScopeNode.PUBLIC) + .setReturnType(stringMapType) + .setName("getFieldValuesMap") + .setBody( + bodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList())) + .setReturnExpr(fieldValuesMapVarExpr) + .build(); + + // Method code: + // @Override + // public String getFieldValue(String fieldName) { + // return getFieldValuesMap().get(fieldName); + // } + VariableExpr fieldNameVarExpr = + VariableExpr.withVariable( + Variable.builder().setType(TypeNode.STRING).setName("fieldName").build()); + MethodDefinition getFieldValueMethod = + MethodDefinition.builder() + .setIsOverride(true) + .setScope(ScopeNode.PUBLIC) + .setReturnType(TypeNode.STRING) + .setName("getFieldValue") + .setArguments(fieldNameVarExpr.toBuilder().setIsDecl(true).build()) + .setReturnExpr( + MethodInvocationExpr.builder() + .setExprReferenceExpr( + MethodInvocationExpr.builder().setMethodName("getFieldValuesMap").build()) + .setMethodName("get") + .setArguments(fieldNameVarExpr) + .setReturnType(TypeNode.STRING) + .build()) + .build(); + + return AnonymousClassExpr.builder() + .setType( + TypeNode.withReference( + ConcreteReference.withClazz(com.google.api.resourcenames.ResourceName.class))) + .setMethods(Arrays.asList(getFieldValuesMapMethod, getFieldValueMethod)) + .build(); + } } diff --git a/src/main/java/com/google/api/generator/gapic/composer/grpc/MockServiceImplClassComposer.java b/src/main/java/com/google/api/generator/gapic/composer/grpc/MockServiceImplClassComposer.java index a58601197d..b561541e9b 100644 --- a/src/main/java/com/google/api/generator/gapic/composer/grpc/MockServiceImplClassComposer.java +++ b/src/main/java/com/google/api/generator/gapic/composer/grpc/MockServiceImplClassComposer.java @@ -28,6 +28,7 @@ import com.google.api.generator.engine.ast.MethodDefinition; import com.google.api.generator.engine.ast.MethodInvocationExpr; import com.google.api.generator.engine.ast.NewObjectExpr; +import com.google.api.generator.engine.ast.Reference; import com.google.api.generator.engine.ast.RelationalOperationExpr; import com.google.api.generator.engine.ast.ScopeNode; import com.google.api.generator.engine.ast.Statement; @@ -78,17 +79,9 @@ public class MockServiceImplClassComposer implements ClassComposer { Arrays.asList(FIXED_TYPESTORE.get("AbstractMessage").reference())) .build())) .build()); - private static final VariableExpr responsesVarExpr = - VariableExpr.withVariable( - Variable.builder() - .setName("responses") - .setType( - TypeNode.withReference( - ConcreteReference.builder() - .setClazz(Queue.class) - .setGenerics(Arrays.asList(ConcreteReference.withClazz(Object.class))) - .build())) - .build()); + + private static Reference javaObjectReference = ConcreteReference.withClazz(Object.class); + private static VariableExpr responsesVarExpr; private MockServiceImplClassComposer() {} @@ -97,12 +90,31 @@ public static MockServiceImplClassComposer instance() { } @Override - public GapicClass generate(GapicContext ignored, Service service) { + public GapicClass generate(GapicContext context, Service service) { TypeStore typeStore = createDynamicTypes(service); String className = ClassNames.getMockServiceImplClassName(service); GapicClass.Kind kind = Kind.TEST; String pakkage = service.pakkage(); + // Use the full name java.lang.Object if there is a proto message that is also named "Object". + // Affects GCS. + if (context.messages().keySet().stream().anyMatch(s -> s.equals("Object") || s.endsWith(".Object"))) { + javaObjectReference = + ConcreteReference.builder().setClazz(Object.class).setUseFullName(true).build(); + } + + responsesVarExpr = + VariableExpr.withVariable( + Variable.builder() + .setName("responses") + .setType( + TypeNode.withReference( + ConcreteReference.builder() + .setClazz(Queue.class) + .setGenerics(Arrays.asList(javaObjectReference)) + .build())) + .build()); + ClassDefinition classDef = ClassDefinition.builder() .setPackageString(pakkage) @@ -201,8 +213,7 @@ private static MethodDefinition createSetResponsesMethod(Service service) { Expr responseAssignExpr = AssignmentExpr.builder() .setVariableExpr( - responsesVarExpr - .toBuilder() + responsesVarExpr.toBuilder() .setExprReferenceExpr( ValueExpr.withValue(ThisObjectValue.withType(getThisClassType(service)))) .build()) @@ -212,8 +223,7 @@ private static MethodDefinition createSetResponsesMethod(Service service) { TypeNode.withReference( ConcreteReference.builder() .setClazz(LinkedList.class) - .setGenerics( - Arrays.asList(ConcreteReference.withClazz(Object.class))) + .setGenerics(Arrays.asList(javaObjectReference)) .build())) .setArguments(Arrays.asList(responsesArgVarExpr)) .build()) @@ -267,7 +277,7 @@ private static List createProtoMethodOverrides(Service service private static MethodDefinition createGenericProtoMethodOverride(Method protoMethod) { ConcreteReference streamObserverRef = ConcreteReference.withClazz(StreamObserver.class); - TypeNode objectType = TypeNode.withReference(ConcreteReference.withClazz(Object.class)); + TypeNode objectType = TypeNode.withReference(javaObjectReference); VariableExpr localResponseVarExpr = VariableExpr.withVariable( Variable.builder().setName("response").setType(objectType).build()); @@ -372,7 +382,7 @@ private static MethodDefinition createOnNextJavaMethod( VariableExpr valueVarExpr = VariableExpr.withVariable( Variable.builder().setName("value").setType(protoMethod.inputType()).build()); - TypeNode objectType = TypeNode.withReference(ConcreteReference.withClazz(Object.class)); + TypeNode objectType = TypeNode.withReference(javaObjectReference); Statement addValueToRequestsStatement = ExprStatement.withExpr( diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoClient.golden b/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoClient.golden index 5791d9086d..7759efb2f9 100644 --- a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoClient.golden +++ b/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoClient.golden @@ -769,6 +769,53 @@ public class EchoClient implements BackgroundResource { return stub.blockCallable(); } + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + *
{@code
+   * try (EchoClient echoClient = EchoClient.create()) {
+   *   EchoRequest request =
+   *       EchoRequest.newBuilder()
+   *           .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
+   *           .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
+   *           .setSeverity(Severity.forNumber(0))
+   *           .setFoobar(Foobar.newBuilder().build())
+   *           .build();
+   *   Object response = echoClient.collideName(request);
+   * }
+   * }
+ * + * @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 Object collideName(EchoRequest request) { + return collideNameCallable().call(request); + } + + // AUTO-GENERATED DOCUMENTATION AND METHOD. + /** + * Sample code: + * + *
{@code
+   * try (EchoClient echoClient = EchoClient.create()) {
+   *   EchoRequest request =
+   *       EchoRequest.newBuilder()
+   *           .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
+   *           .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
+   *           .setSeverity(Severity.forNumber(0))
+   *           .setFoobar(Foobar.newBuilder().build())
+   *           .build();
+   *   ApiFuture future = echoClient.collideNameCallable().futureCall(request);
+   *   // Do something.
+   *   Object response = future.get();
+   * }
+   * }
+   */
+  public final UnaryCallable collideNameCallable() {
+    return stub.collideNameCallable();
+  }
+
   @Override
   public final void close() {
     stub.close();
diff --git a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoStub.golden b/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoStub.golden
index 629e9939bb..9270f22851 100644
--- a/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoStub.golden
+++ b/src/test/java/com/google/api/generator/gapic/composer/common/goldens/EchoStub.golden
@@ -17,6 +17,7 @@ import com.google.showcase.v1beta1.BlockResponse;
 import com.google.showcase.v1beta1.EchoRequest;
 import com.google.showcase.v1beta1.EchoResponse;
 import com.google.showcase.v1beta1.ExpandRequest;
+import com.google.showcase.v1beta1.Object;
 import com.google.showcase.v1beta1.PagedExpandRequest;
 import com.google.showcase.v1beta1.PagedExpandResponse;
 import com.google.showcase.v1beta1.WaitMetadata;
@@ -87,6 +88,10 @@ public abstract class EchoStub implements BackgroundResource {
     throw new UnsupportedOperationException("Not implemented: blockCallable()");
   }
 
+  public UnaryCallable collideNameCallable() {
+    throw new UnsupportedOperationException("Not implemented: collideNameCallable()");
+  }
+
   @Override
   public abstract void close();
 }
diff --git a/src/test/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposerTest.java b/src/test/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposerTest.java
index 6a60b91e5d..f612b7112d 100644
--- a/src/test/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposerTest.java
+++ b/src/test/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposerTest.java
@@ -24,6 +24,7 @@
 import com.google.api.generator.gapic.model.Message;
 import com.google.api.generator.gapic.model.ResourceName;
 import com.google.api.generator.gapic.protoparser.Parser;
+import com.google.api.generator.testutils.LineFormatter;
 import com.google.protobuf.ByteString;
 import com.google.protobuf.Descriptors.FileDescriptor;
 import com.google.showcase.v1beta1.EchoOuterClass;
@@ -222,8 +223,8 @@ public void defaultValue_wildcardResourceNameWithOnlyDeletedTopic() {
   }
 
   @Test
-  public void defaultValue_resourceNameWithOnlyWildcards() {
-    // Edge case that should never happen in practice.
+  public void defaultValue_resourceNameWithOnlyWildcards_valueOnly() {
+    // Edge case that occurs in GCS.
     // Wildcard, but the resource names map has only other names that contain only the deleted-topic
     // constant.
     FileDescriptor lockerServiceFileDescriptor = LockerProto.getDescriptor();
@@ -233,13 +234,50 @@ public void defaultValue_resourceNameWithOnlyWildcards() {
         typeStringsToResourceNames.get("cloudresourcemanager.googleapis.com/Anything");
     String fallbackField = "foobar";
     Expr expr =
-        DefaultValueComposer.createDefaultValue(
-            resourceName, Collections.emptyList(), fallbackField);
+        DefaultValueComposer.createDefaultValueResourceHelper(
+            resourceName,
+            Collections.emptyList(),
+            fallbackField,
+            /* allowAnonResourceNameClass = */ false);
     expr.accept(writerVisitor);
     assertEquals(
         String.format("\"%s%s\"", fallbackField, fallbackField.hashCode()), writerVisitor.write());
   }
 
+  @Test
+  public void defaultValue_resourceNameWithOnlyWildcards_allowAnonResourceNameClass() {
+    // Edge case that occurs in GCS.
+    // Wildcard, but the resource names map has only other names that contain only the deleted-topic
+    // constant.
+    FileDescriptor lockerServiceFileDescriptor = LockerProto.getDescriptor();
+    Map typeStringsToResourceNames =
+        Parser.parseResourceNames(lockerServiceFileDescriptor);
+    ResourceName resourceName =
+        typeStringsToResourceNames.get("cloudresourcemanager.googleapis.com/Anything");
+    String fallbackField = "foobar";
+    Expr expr =
+        DefaultValueComposer.createDefaultValue(
+            resourceName, Collections.emptyList(), fallbackField);
+    expr.accept(writerVisitor);
+    String expected =
+        LineFormatter.lines(
+            "new ResourceName() {\n",
+            "@Override\n",
+            "public Map getFieldValuesMap() {\n",
+            "Map fieldValuesMap = new HashMap<>();\n",
+            "fieldValuesMap.put(\"foobar\", \"foobar-1268878963\");\n",
+            "return fieldValuesMap;\n",
+            "}\n",
+            "\n",
+            "@Override\n",
+            "public String getFieldValue(String fieldName) {\n",
+            "return getFieldValuesMap().get(fieldName);\n",
+            "}\n",
+            "\n",
+            "}");
+    assertEquals(expected, writerVisitor.write());
+  }
+
   @Test
   public void createSimpleMessage_basicPrimitivesOnly() {
     FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor();
@@ -307,4 +345,28 @@ public void createSimpleMessage_onlyOneofs() {
     expr.accept(writerVisitor);
     assertEquals("WaitRequest.newBuilder().build()", writerVisitor.write());
   }
+
+  @Test
+  public void createAnonymousResourceNameClass() {
+    Expr expr = DefaultValueComposer.createAnonymousResourceNameClass("resource");
+    expr.accept(writerVisitor);
+    String expected =
+        LineFormatter.lines(
+            "new ResourceName() {\n",
+            "@Override\n",
+            "public Map getFieldValuesMap() {\n",
+            "Map fieldValuesMap = new HashMap<>();\n",
+            "fieldValuesMap.put(\"resource\", \"resource-341064690\");\n",
+            "return fieldValuesMap;\n",
+            "}\n",
+            "\n",
+            "@Override\n",
+            "public String getFieldValue(String fieldName) {\n",
+            "return getFieldValuesMap().get(fieldName);\n",
+            "}\n",
+            "\n",
+            "}");
+
+    assertEquals(expected, writerVisitor.write());
+  }
 }
diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoClientTest.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoClientTest.golden
index 85e397b89b..1372cdd94e 100644
--- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoClientTest.golden
+++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoClientTest.golden
@@ -838,4 +838,56 @@ public class EchoClientTest {
       // Expected exception.
     }
   }
+
+  @Test
+  public void collideNameTest() throws Exception {
+    Object expectedResponse = Object.newBuilder().setContent("content951530617").build();
+    mockEcho.addResponse(expectedResponse);
+
+    EchoRequest request =
+        EchoRequest.newBuilder()
+            .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
+            .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
+            .setSeverity(Severity.forNumber(0))
+            .setFoobar(Foobar.newBuilder().build())
+            .build();
+
+    Object actualResponse = client.collideName(request);
+    Assert.assertEquals(expectedResponse, actualResponse);
+
+    List actualRequests = mockEcho.getRequests();
+    Assert.assertEquals(1, actualRequests.size());
+    EchoRequest actualRequest = ((EchoRequest) actualRequests.get(0));
+
+    Assert.assertEquals(request.getName(), actualRequest.getName());
+    Assert.assertEquals(request.getParent(), actualRequest.getParent());
+    Assert.assertEquals(request.getContent(), actualRequest.getContent());
+    Assert.assertEquals(request.getError(), actualRequest.getError());
+    Assert.assertEquals(request.getSeverity(), actualRequest.getSeverity());
+    Assert.assertEquals(request.getFoobar(), actualRequest.getFoobar());
+    Assert.assertTrue(
+        channelProvider.isHeaderSent(
+            ApiClientHeaderProvider.getDefaultApiClientHeaderKey(),
+            GaxGrpcProperties.getDefaultApiClientHeaderPattern()));
+  }
+
+  @Test
+  public void collideNameExceptionTest() throws Exception {
+    StatusRuntimeException exception = new StatusRuntimeException(io.grpc.Status.INVALID_ARGUMENT);
+    mockEcho.addException(exception);
+
+    try {
+      EchoRequest request =
+          EchoRequest.newBuilder()
+              .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
+              .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
+              .setSeverity(Severity.forNumber(0))
+              .setFoobar(Foobar.newBuilder().build())
+              .build();
+      client.collideName(request);
+      Assert.fail("No exception raised");
+    } catch (InvalidArgumentException e) {
+      // Expected exception.
+    }
+  }
 }
diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoSettings.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoSettings.golden
index d94e7838ef..f0f05bcb52 100644
--- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoSettings.golden
+++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoSettings.golden
@@ -111,6 +111,11 @@ public class EchoSettings extends ClientSettings {
     return ((EchoStubSettings) getStubSettings()).blockSettings();
   }
 
+  /** Returns the object with the settings used for calls to collideName. */
+  public UnaryCallSettings collideNameSettings() {
+    return ((EchoStubSettings) getStubSettings()).collideNameSettings();
+  }
+
   public static final EchoSettings create(EchoStubSettings stub) throws IOException {
     return new EchoSettings.Builder(stub.toBuilder()).build();
   }
@@ -263,6 +268,11 @@ public class EchoSettings extends ClientSettings {
       return getStubSettingsBuilder().blockSettings();
     }
 
+    /** Returns the builder for the settings used for calls to collideName. */
+    public UnaryCallSettings.Builder collideNameSettings() {
+      return getStubSettingsBuilder().collideNameSettings();
+    }
+
     @Override
     public EchoSettings build() throws IOException {
       return new EchoSettings(this);
diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoStubSettings.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoStubSettings.golden
index 97586b0d03..62b7684ad1 100644
--- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoStubSettings.golden
+++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/EchoStubSettings.golden
@@ -41,6 +41,7 @@ import com.google.showcase.v1beta1.BlockResponse;
 import com.google.showcase.v1beta1.EchoRequest;
 import com.google.showcase.v1beta1.EchoResponse;
 import com.google.showcase.v1beta1.ExpandRequest;
+import com.google.showcase.v1beta1.Object;
 import com.google.showcase.v1beta1.PagedExpandRequest;
 import com.google.showcase.v1beta1.PagedExpandResponse;
 import com.google.showcase.v1beta1.WaitMetadata;
@@ -103,6 +104,7 @@ public class EchoStubSettings extends StubSettings {
   private final OperationCallSettings
       waitOperationSettings;
   private final UnaryCallSettings blockSettings;
+  private final UnaryCallSettings collideNameSettings;
 
   private static final PagedListDescriptor
       PAGED_EXPAND_PAGE_STR_DESC =
@@ -262,6 +264,11 @@ public class EchoStubSettings extends StubSettings {
     return blockSettings;
   }
 
+  /** Returns the object with the settings used for calls to collideName. */
+  public UnaryCallSettings collideNameSettings() {
+    return collideNameSettings;
+  }
+
   @BetaApi("A restructuring of stub classes is planned, so this may break in the future")
   public EchoStub createStub() throws IOException {
     if (getTransportChannelProvider()
@@ -345,6 +352,7 @@ public class EchoStubSettings extends StubSettings {
     waitSettings = settingsBuilder.waitSettings().build();
     waitOperationSettings = settingsBuilder.waitOperationSettings().build();
     blockSettings = settingsBuilder.blockSettings().build();
+    collideNameSettings = settingsBuilder.collideNameSettings().build();
   }
 
   /** Builder for EchoStubSettings. */
@@ -365,6 +373,7 @@ public class EchoStubSettings extends StubSettings {
     private final OperationCallSettings.Builder
         waitOperationSettings;
     private final UnaryCallSettings.Builder blockSettings;
+    private final UnaryCallSettings.Builder collideNameSettings;
     private static final ImmutableMap>
         RETRYABLE_CODE_DEFINITIONS;
 
@@ -425,6 +434,7 @@ public class EchoStubSettings extends StubSettings {
       waitSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
       waitOperationSettings = OperationCallSettings.newBuilder();
       blockSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
+      collideNameSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
 
       unaryMethodSettingsBuilders =
           ImmutableList.>of(
@@ -432,7 +442,8 @@ public class EchoStubSettings extends StubSettings {
               pagedExpandSettings,
               simplePagedExpandSettings,
               waitSettings,
-              blockSettings);
+              blockSettings,
+              collideNameSettings);
       initDefaults(this);
     }
 
@@ -449,6 +460,7 @@ public class EchoStubSettings extends StubSettings {
       waitSettings = settings.waitSettings.toBuilder();
       waitOperationSettings = settings.waitOperationSettings.toBuilder();
       blockSettings = settings.blockSettings.toBuilder();
+      collideNameSettings = settings.collideNameSettings.toBuilder();
 
       unaryMethodSettingsBuilders =
           ImmutableList.>of(
@@ -456,7 +468,8 @@ public class EchoStubSettings extends StubSettings {
               pagedExpandSettings,
               simplePagedExpandSettings,
               waitSettings,
-              blockSettings);
+              blockSettings,
+              collideNameSettings);
     }
 
     private static Builder createDefault() {
@@ -503,6 +516,11 @@ public class EchoStubSettings extends StubSettings {
           .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes"))
           .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params"));
 
+      builder
+          .collideNameSettings()
+          .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes"))
+          .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params"));
+
       builder
           .waitOperationSettings()
           .setInitialCallSettings(
@@ -602,6 +620,11 @@ public class EchoStubSettings extends StubSettings {
       return blockSettings;
     }
 
+    /** Returns the builder for the settings used for calls to collideName. */
+    public UnaryCallSettings.Builder collideNameSettings() {
+      return collideNameSettings;
+    }
+
     @Override
     public EchoStubSettings build() throws IOException {
       return new EchoStubSettings(this);
diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcEchoStub.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcEchoStub.golden
index 194849ba09..d1a4a303bd 100644
--- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcEchoStub.golden
+++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/GrpcEchoStub.golden
@@ -21,6 +21,7 @@ import com.google.showcase.v1beta1.BlockResponse;
 import com.google.showcase.v1beta1.EchoRequest;
 import com.google.showcase.v1beta1.EchoResponse;
 import com.google.showcase.v1beta1.ExpandRequest;
+import com.google.showcase.v1beta1.Object;
 import com.google.showcase.v1beta1.PagedExpandRequest;
 import com.google.showcase.v1beta1.PagedExpandResponse;
 import com.google.showcase.v1beta1.WaitMetadata;
@@ -117,6 +118,14 @@ public class GrpcEchoStub extends EchoStub {
           .setResponseMarshaller(ProtoUtils.marshaller(BlockResponse.getDefaultInstance()))
           .build();
 
+  private static final MethodDescriptor collideNameMethodDescriptor =
+      MethodDescriptor.newBuilder()
+          .setType(MethodDescriptor.MethodType.UNARY)
+          .setFullMethodName("google.showcase.v1beta1.Echo/CollideName")
+          .setRequestMarshaller(ProtoUtils.marshaller(EchoRequest.getDefaultInstance()))
+          .setResponseMarshaller(ProtoUtils.marshaller(Object.getDefaultInstance()))
+          .build();
+
   private final UnaryCallable echoCallable;
   private final ServerStreamingCallable expandCallable;
   private final ClientStreamingCallable collectCallable;
@@ -131,6 +140,7 @@ public class GrpcEchoStub extends EchoStub {
   private final UnaryCallable waitCallable;
   private final OperationCallable waitOperationCallable;
   private final UnaryCallable blockCallable;
+  private final UnaryCallable collideNameCallable;
 
   private final BackgroundResource backgroundResources;
   private final GrpcOperationsStub operationsStub;
@@ -206,6 +216,10 @@ public class GrpcEchoStub extends EchoStub {
         GrpcCallSettings.newBuilder()
             .setMethodDescriptor(blockMethodDescriptor)
             .build();
+    GrpcCallSettings collideNameTransportSettings =
+        GrpcCallSettings.newBuilder()
+            .setMethodDescriptor(collideNameMethodDescriptor)
+            .build();
 
     this.echoCallable =
         callableFactory.createUnaryCallable(
@@ -247,6 +261,9 @@ public class GrpcEchoStub extends EchoStub {
     this.blockCallable =
         callableFactory.createUnaryCallable(
             blockTransportSettings, settings.blockSettings(), clientContext);
+    this.collideNameCallable =
+        callableFactory.createUnaryCallable(
+            collideNameTransportSettings, settings.collideNameSettings(), clientContext);
 
     this.backgroundResources =
         new BackgroundResourceAggregation(clientContext.getBackgroundResources());
@@ -317,6 +334,11 @@ public class GrpcEchoStub extends EchoStub {
     return blockCallable;
   }
 
+  @Override
+  public UnaryCallable collideNameCallable() {
+    return collideNameCallable;
+  }
+
   @Override
   public final void close() {
     shutdown();
diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/MockDeprecatedServiceImpl.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/MockDeprecatedServiceImpl.golden
index f400f9aa20..7092d93a9e 100644
--- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/MockDeprecatedServiceImpl.golden
+++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/MockDeprecatedServiceImpl.golden
@@ -15,7 +15,7 @@ import javax.annotation.Generated;
 @Generated("by gapic-generator-java")
 public class MockDeprecatedServiceImpl extends DeprecatedServiceImplBase {
   private List requests;
-  private Queue responses;
+  private Queue responses;
 
   public MockDeprecatedServiceImpl() {
     requests = new ArrayList<>();
@@ -31,7 +31,7 @@ public class MockDeprecatedServiceImpl extends DeprecatedServiceImplBase {
   }
 
   public void setResponses(List responses) {
-    this.responses = new LinkedList(responses);
+    this.responses = new LinkedList(responses);
   }
 
   public void addException(Exception exception) {
@@ -45,7 +45,7 @@ public class MockDeprecatedServiceImpl extends DeprecatedServiceImplBase {
 
   @Override
   public void fastFibonacci(FibonacciRequest request, StreamObserver responseObserver) {
-    Object response = responses.poll();
+    java.lang.Object response = responses.poll();
     if (response instanceof Empty) {
       requests.add(request);
       responseObserver.onNext(((Empty) response));
@@ -65,7 +65,7 @@ public class MockDeprecatedServiceImpl extends DeprecatedServiceImplBase {
 
   @Override
   public void slowFibonacci(FibonacciRequest request, StreamObserver responseObserver) {
-    Object response = responses.poll();
+    java.lang.Object response = responses.poll();
     if (response instanceof Empty) {
       requests.add(request);
       responseObserver.onNext(((Empty) response));
diff --git a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/MockEchoImpl.golden b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/MockEchoImpl.golden
index 50da1d568c..ae3ff13888 100644
--- a/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/MockEchoImpl.golden
+++ b/src/test/java/com/google/api/generator/gapic/composer/grpc/goldens/MockEchoImpl.golden
@@ -15,7 +15,7 @@ import javax.annotation.Generated;
 @Generated("by gapic-generator-java")
 public class MockEchoImpl extends EchoImplBase {
   private List requests;
-  private Queue responses;
+  private Queue responses;
 
   public MockEchoImpl() {
     requests = new ArrayList<>();
@@ -31,7 +31,7 @@ public class MockEchoImpl extends EchoImplBase {
   }
 
   public void setResponses(List responses) {
-    this.responses = new LinkedList(responses);
+    this.responses = new LinkedList(responses);
   }
 
   public void addException(Exception exception) {
@@ -45,7 +45,7 @@ public class MockEchoImpl extends EchoImplBase {
 
   @Override
   public void echo(EchoRequest request, StreamObserver responseObserver) {
-    Object response = responses.poll();
+    java.lang.Object response = responses.poll();
     if (response instanceof EchoResponse) {
       requests.add(request);
       responseObserver.onNext(((EchoResponse) response));
@@ -65,7 +65,7 @@ public class MockEchoImpl extends EchoImplBase {
 
   @Override
   public void expand(ExpandRequest request, StreamObserver responseObserver) {
-    Object response = responses.poll();
+    java.lang.Object response = responses.poll();
     if (response instanceof EchoResponse) {
       requests.add(request);
       responseObserver.onNext(((EchoResponse) response));
@@ -90,7 +90,7 @@ public class MockEchoImpl extends EchoImplBase {
           @Override
           public void onNext(EchoRequest value) {
             requests.add(value);
-            final Object response = responses.remove();
+            final java.lang.Object response = responses.remove();
             if (response instanceof EchoResponse) {
               responseObserver.onNext(((EchoResponse) response));
             } else if (response instanceof Exception) {
@@ -126,7 +126,7 @@ public class MockEchoImpl extends EchoImplBase {
           @Override
           public void onNext(EchoRequest value) {
             requests.add(value);
-            final Object response = responses.remove();
+            final java.lang.Object response = responses.remove();
             if (response instanceof EchoResponse) {
               responseObserver.onNext(((EchoResponse) response));
             } else if (response instanceof Exception) {
@@ -163,7 +163,7 @@ public class MockEchoImpl extends EchoImplBase {
           @Override
           public void onNext(EchoRequest value) {
             requests.add(value);
-            final Object response = responses.remove();
+            final java.lang.Object response = responses.remove();
             if (response instanceof EchoResponse) {
               responseObserver.onNext(((EchoResponse) response));
             } else if (response instanceof Exception) {
@@ -195,7 +195,7 @@ public class MockEchoImpl extends EchoImplBase {
   @Override
   public void pagedExpand(
       PagedExpandRequest request, StreamObserver responseObserver) {
-    Object response = responses.poll();
+    java.lang.Object response = responses.poll();
     if (response instanceof PagedExpandResponse) {
       requests.add(request);
       responseObserver.onNext(((PagedExpandResponse) response));
@@ -216,7 +216,7 @@ public class MockEchoImpl extends EchoImplBase {
   @Override
   public void simplePagedExpand(
       PagedExpandRequest request, StreamObserver responseObserver) {
-    Object response = responses.poll();
+    java.lang.Object response = responses.poll();
     if (response instanceof PagedExpandResponse) {
       requests.add(request);
       responseObserver.onNext(((PagedExpandResponse) response));
@@ -236,7 +236,7 @@ public class MockEchoImpl extends EchoImplBase {
 
   @Override
   public void wait(WaitRequest request, StreamObserver responseObserver) {
-    Object response = responses.poll();
+    java.lang.Object response = responses.poll();
     if (response instanceof Operation) {
       requests.add(request);
       responseObserver.onNext(((Operation) response));
@@ -256,7 +256,7 @@ public class MockEchoImpl extends EchoImplBase {
 
   @Override
   public void block(BlockRequest request, StreamObserver responseObserver) {
-    Object response = responses.poll();
+    java.lang.Object response = responses.poll();
     if (response instanceof BlockResponse) {
       requests.add(request);
       responseObserver.onNext(((BlockResponse) response));
@@ -273,4 +273,24 @@ public class MockEchoImpl extends EchoImplBase {
                   Exception.class.getName())));
     }
   }
+
+  @Override
+  public void collideName(EchoRequest request, StreamObserver responseObserver) {
+    java.lang.Object response = responses.poll();
+    if (response instanceof Object) {
+      requests.add(request);
+      responseObserver.onNext(((Object) response));
+      responseObserver.onCompleted();
+    } else if (response instanceof Exception) {
+      responseObserver.onError(((Exception) response));
+    } else {
+      responseObserver.onError(
+          new IllegalArgumentException(
+              String.format(
+                  "Unrecognized response type %s for method CollideName, expected %s or %s",
+                  response == null ? "null" : response.getClass().getName(),
+                  Object.class.getName(),
+                  Exception.class.getName())));
+    }
+  }
 }
diff --git a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/ComplianceStubSettings.golden b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/ComplianceStubSettings.golden
index 7715034885..b5123e9c71 100644
--- a/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/ComplianceStubSettings.golden
+++ b/src/test/java/com/google/api/generator/gapic/composer/rest/goldens/ComplianceStubSettings.golden
@@ -41,6 +41,7 @@ import com.google.showcase.v1beta1.BlockResponse;
 import com.google.showcase.v1beta1.EchoRequest;
 import com.google.showcase.v1beta1.EchoResponse;
 import com.google.showcase.v1beta1.ExpandRequest;
+import com.google.showcase.v1beta1.Object;
 import com.google.showcase.v1beta1.PagedExpandRequest;
 import com.google.showcase.v1beta1.PagedExpandResponse;
 import com.google.showcase.v1beta1.WaitMetadata;
@@ -103,6 +104,7 @@ public class EchoStubSettings extends StubSettings {
   private final OperationCallSettings
       waitOperationSettings;
   private final UnaryCallSettings blockSettings;
+  private final UnaryCallSettings collideNameSettings;
 
   private static final PagedListDescriptor
       PAGED_EXPAND_PAGE_STR_DESC =
@@ -262,6 +264,11 @@ public class EchoStubSettings extends StubSettings {
     return blockSettings;
   }
 
+  /** Returns the object with the settings used for calls to collideName. */
+  public UnaryCallSettings collideNameSettings() {
+    return collideNameSettings;
+  }
+
   @BetaApi("A restructuring of stub classes is planned, so this may break in the future")
   public EchoStub createStub() throws IOException {
     if (getTransportChannelProvider()
@@ -346,6 +353,7 @@ public class EchoStubSettings extends StubSettings {
     waitSettings = settingsBuilder.waitSettings().build();
     waitOperationSettings = settingsBuilder.waitOperationSettings().build();
     blockSettings = settingsBuilder.blockSettings().build();
+    collideNameSettings = settingsBuilder.collideNameSettings().build();
   }
 
   /** Builder for EchoStubSettings. */
@@ -366,6 +374,7 @@ public class EchoStubSettings extends StubSettings {
     private final OperationCallSettings.Builder
         waitOperationSettings;
     private final UnaryCallSettings.Builder blockSettings;
+    private final UnaryCallSettings.Builder collideNameSettings;
     private static final ImmutableMap>
         RETRYABLE_CODE_DEFINITIONS;
 
@@ -426,6 +435,7 @@ public class EchoStubSettings extends StubSettings {
       waitSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
       waitOperationSettings = OperationCallSettings.newBuilder();
       blockSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
+      collideNameSettings = UnaryCallSettings.newUnaryCallSettingsBuilder();
 
       unaryMethodSettingsBuilders =
           ImmutableList.>of(
@@ -433,7 +443,8 @@ public class EchoStubSettings extends StubSettings {
               pagedExpandSettings,
               simplePagedExpandSettings,
               waitSettings,
-              blockSettings);
+              blockSettings,
+              collideNameSettings);
       initDefaults(this);
     }
 
@@ -450,6 +461,7 @@ public class EchoStubSettings extends StubSettings {
       waitSettings = settings.waitSettings.toBuilder();
       waitOperationSettings = settings.waitOperationSettings.toBuilder();
       blockSettings = settings.blockSettings.toBuilder();
+      collideNameSettings = settings.collideNameSettings.toBuilder();
 
       unaryMethodSettingsBuilders =
           ImmutableList.>of(
@@ -457,7 +469,8 @@ public class EchoStubSettings extends StubSettings {
               pagedExpandSettings,
               simplePagedExpandSettings,
               waitSettings,
-              blockSettings);
+              blockSettings,
+              collideNameSettings);
     }
 
     private static Builder createDefault() {
@@ -504,6 +517,11 @@ public class EchoStubSettings extends StubSettings {
           .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes"))
           .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params"));
 
+      builder
+          .collideNameSettings()
+          .setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes"))
+          .setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params"));
+
       builder
           .waitOperationSettings()
           .setInitialCallSettings(
@@ -603,6 +621,11 @@ public class EchoStubSettings extends StubSettings {
       return blockSettings;
     }
 
+    /** Returns the builder for the settings used for calls to collideName. */
+    public UnaryCallSettings.Builder collideNameSettings() {
+      return collideNameSettings;
+    }
+
     @Override
     public EchoStubSettings build() throws IOException {
       return new EchoStubSettings(this);
diff --git a/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java b/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java
index b19aa30b92..da661e5d42 100644
--- a/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java
+++ b/src/test/java/com/google/api/generator/gapic/protoparser/ParserTest.java
@@ -110,7 +110,7 @@ public void parseMethods_basic() {
             Optional.empty(),
             outputResourceNames);
 
-    assertEquals(9, methods.size());
+    assertEquals(10, methods.size());
 
     // Methods should appear in the same order as in the protobuf file.
     Method echoMethod = methods.get(0);
@@ -167,7 +167,7 @@ public void parseMethods_basicLro() {
             Optional.empty(),
             outputResourceNames);
 
-    assertEquals(9, methods.size());
+    assertEquals(10, methods.size());
 
     // Methods should appear in the same order as in the protobuf file.
     Method waitMethod = methods.get(7);
diff --git a/src/test/java/com/google/api/generator/gapic/testdata/echo.proto b/src/test/java/com/google/api/generator/gapic/testdata/echo.proto
index 136ee598f8..ea262faf32 100644
--- a/src/test/java/com/google/api/generator/gapic/testdata/echo.proto
+++ b/src/test/java/com/google/api/generator/gapic/testdata/echo.proto
@@ -130,6 +130,15 @@ service Echo {
       body: "*"
     };
   };
+
+  // This method primarily tests Java name collisions by using the Object
+  // message.
+  rpc CollideName(EchoRequest) returns (Object) {
+    option (google.api.http) = {
+      post: "/v1beta1/echo:foo"
+      body: "*"
+    };
+  }
 }
 
 // A severity enum used to test enum capabilities in GAPIC surfaces
@@ -193,6 +202,12 @@ message EchoResponse {
   Severity severity = 2;
 }
 
+// Tests name collisions with java.lang.Object.
+message Object {
+  // The content specified in the request.
+  string content = 1;
+}
+
 // The request message for the Expand method.
 message ExpandRequest {
   // The content that will be split into words and returned on the stream.