From c2a7c0729296bf670fc286bfe9ba2b31d552ffc7 Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 9 Jun 2021 13:09:06 -0700 Subject: [PATCH 1/6] fix(mocks): Use java.lang.Object if there are protos named 'Object' --- .../grpc/MockServiceImplClassComposer.java | 49 ++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) 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..5f27542b16 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,34 @@ 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() + .map(s -> s.substring(Math.max(0, s.lastIndexOf(".") + 1), s.length())) + .collect(Collectors.toSet()) + .contains("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 +216,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 +226,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 +280,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 +385,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( From fc2eb98264f47eaf7c8c600f9533da2ad061c2c7 Mon Sep 17 00:00:00 2001 From: Mira Leung Date: Wed, 9 Jun 2021 13:37:07 -0700 Subject: [PATCH 2/6] fix: add tests --- .../composer/common/goldens/EchoClient.golden | 47 +++++++++++++++++ .../composer/common/goldens/EchoStub.golden | 5 ++ .../grpc/goldens/EchoClientTest.golden | 52 +++++++++++++++++++ .../composer/grpc/goldens/EchoSettings.golden | 10 ++++ .../grpc/goldens/EchoStubSettings.golden | 27 +++++++++- .../composer/grpc/goldens/GrpcEchoStub.golden | 22 ++++++++ .../goldens/MockDeprecatedServiceImpl.golden | 8 +-- .../composer/grpc/goldens/MockEchoImpl.golden | 42 +++++++++++---- .../goldens/ComplianceStubSettings.golden | 27 +++++++++- .../gapic/protoparser/ParserTest.java | 4 +- .../api/generator/gapic/testdata/echo.proto | 15 ++++++ 11 files changed, 238 insertions(+), 21 deletions(-) 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/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.

From e54bdba2a372649806922e9aaef45d49fd694fce Mon Sep 17 00:00:00 2001
From: Mira Leung 
Date: Wed, 9 Jun 2021 14:19:45 -0700
Subject: [PATCH 3/6] Update MockServiceImplClassComposer.java

---
 .../gapic/composer/grpc/MockServiceImplClassComposer.java       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 5f27542b16..b68f884cc9 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
@@ -99,7 +99,7 @@ public GapicClass generate(GapicContext context, Service service) {
     // 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()
-        .map(s -> s.substring(Math.max(0, s.lastIndexOf(".") + 1), s.length()))
+        .map(s -> s.substring(s.lastIndexOf('.') + 1, s.length()))
         .collect(Collectors.toSet())
         .contains("Object")) {
       javaObjectReference =

From 63429c811d51eb98d8cd827e96ef2a0551cb7071 Mon Sep 17 00:00:00 2001
From: Mira Leung 
Date: Wed, 9 Jun 2021 14:21:28 -0700
Subject: [PATCH 4/6] Update MockServiceImplClassComposer.java

---
 .../gapic/composer/grpc/MockServiceImplClassComposer.java    | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

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 b68f884cc9..4a168d8d67 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
@@ -98,10 +98,7 @@ public GapicClass generate(GapicContext context, Service service) {
 
     // 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()
-        .map(s -> s.substring(s.lastIndexOf('.') + 1, s.length()))
-        .collect(Collectors.toSet())
-        .contains("Object")) {
+    if (context.messages().keySet().stream().anyMatch(s -> s.equals("Object") || s.endsWith(".Object")) {
       javaObjectReference =
           ConcreteReference.builder().setClazz(Object.class).setUseFullName(true).build();
     }

From 08b62e3b5fd2b1ef09ddba0224e9d16b7a24c67e Mon Sep 17 00:00:00 2001
From: Mira Leung 
Date: Wed, 9 Jun 2021 15:15:34 -0700
Subject: [PATCH 5/6] Update MockServiceImplClassComposer.java

---
 .../gapic/composer/grpc/MockServiceImplClassComposer.java       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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 4a168d8d67..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
@@ -98,7 +98,7 @@ public GapicClass generate(GapicContext context, Service service) {
 
     // 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")) {
+    if (context.messages().keySet().stream().anyMatch(s -> s.equals("Object") || s.endsWith(".Object"))) {
       javaObjectReference =
           ConcreteReference.builder().setClazz(Object.class).setUseFullName(true).build();
     }

From 2403572e9433e79f5134e5683a2c6b10d8aa8e8f Mon Sep 17 00:00:00 2001
From: Mira Leung 
Date: Wed, 9 Jun 2021 17:01:53 -0700
Subject: [PATCH 6/6] fix(resnames): Use anon resname classes when no non-only
 ds are present

---
 .../generator/engine/ast/AssignmentExpr.java  |   6 +-
 .../gapic/composer/defaultvalue/BUILD.bazel   |   1 +
 .../defaultvalue/DefaultValueComposer.java    | 117 +++++++++++++++++-
 .../DefaultValueComposerTest.java             |  70 ++++++++++-
 4 files changed, 183 insertions(+), 11 deletions(-)

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/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());
+  }
 }