Skip to content

Commit 2a7064b

Browse files
authored
fix(mocks): Use java.lang.Object if there are protos named 'Object' [ggj] (#760)
* fix(mocks): Use java.lang.Object if there are protos named 'Object' * fix: add tests * Update MockServiceImplClassComposer.java * Update MockServiceImplClassComposer.java * Update MockServiceImplClassComposer.java * fix(resnames): Use anon resname classes when no non-only ds are present (#761)
1 parent 2091141 commit 2a7064b

16 files changed

Lines changed: 449 additions & 50 deletions

File tree

src/main/java/com/google/api/generator/engine/ast/AssignmentExpr.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ public AssignmentExpr build() {
6464
if (rhsType != TypeNode.NULL && !lhsType.isSupertypeOrEquals(rhsType)) {
6565
throw new TypeMismatchException(
6666
String.format(
67-
"LHS type %s must be a supertype of the RHS type %s",
68-
lhsType.reference().name(), rhsType.reference().name()));
67+
"LHS type %s of variable %s must be a supertype of the RHS type %s",
68+
lhsType.reference().name(),
69+
assignmentExpr.variableExpr().variable().identifier(),
70+
rhsType.reference().name()));
6971
}
7072
}
7173

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ java_library(
1717
"//src/main/java/com/google/api/generator/gapic/composer/resourcename",
1818
"//src/main/java/com/google/api/generator/gapic/model",
1919
"//src/main/java/com/google/api/generator/gapic/utils",
20+
"@com_google_api_api_common",
2021
"@com_google_googleapis//google/longrunning:longrunning_java_proto",
2122
"@com_google_guava_guava//jar",
2223
"@com_google_protobuf//java/core",

src/main/java/com/google/api/generator/gapic/composer/defaultvalue/DefaultValueComposer.java

Lines changed: 112 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,16 @@
1414

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

17+
import com.google.api.generator.engine.ast.AnonymousClassExpr;
18+
import com.google.api.generator.engine.ast.AssignmentExpr;
1719
import com.google.api.generator.engine.ast.ConcreteReference;
1820
import com.google.api.generator.engine.ast.Expr;
21+
import com.google.api.generator.engine.ast.ExprStatement;
22+
import com.google.api.generator.engine.ast.MethodDefinition;
1923
import com.google.api.generator.engine.ast.MethodInvocationExpr;
2024
import com.google.api.generator.engine.ast.NewObjectExpr;
2125
import com.google.api.generator.engine.ast.PrimitiveValue;
26+
import com.google.api.generator.engine.ast.ScopeNode;
2227
import com.google.api.generator.engine.ast.StringObjectValue;
2328
import com.google.api.generator.engine.ast.TypeNode;
2429
import com.google.api.generator.engine.ast.ValueExpr;
@@ -31,6 +36,7 @@
3136
import com.google.api.generator.gapic.model.ResourceName;
3237
import com.google.api.generator.gapic.utils.JavaStyle;
3338
import com.google.api.generator.gapic.utils.ResourceNameConstants;
39+
import com.google.common.annotations.VisibleForTesting;
3440
import com.google.common.base.Preconditions;
3541
import com.google.longrunning.Operation;
3642
import com.google.protobuf.Any;
@@ -157,6 +163,16 @@ static Expr createDefaultValue(Field f, boolean useExplicitInitTypeInGenerics) {
157163

158164
public static Expr createDefaultValue(
159165
ResourceName resourceName, List<ResourceName> resnames, String fieldOrMessageName) {
166+
return createDefaultValueResourceHelper(resourceName, resnames, fieldOrMessageName, true);
167+
}
168+
169+
@VisibleForTesting
170+
static Expr createDefaultValueResourceHelper(
171+
ResourceName resourceName,
172+
List<ResourceName> resnames,
173+
String fieldOrMessageName,
174+
boolean allowAnonResourceNameClass) {
175+
160176
boolean hasOnePattern = resourceName.patterns().size() == 1;
161177
if (resourceName.isOnlyWildcard()) {
162178
List<ResourceName> unexaminedResnames = new ArrayList<>(resnames);
@@ -170,9 +186,11 @@ public static Expr createDefaultValue(
170186
}
171187

172188
if (unexaminedResnames.isEmpty()) {
173-
return ValueExpr.withValue(
174-
StringObjectValue.withValue(
175-
String.format("%s%s", fieldOrMessageName, fieldOrMessageName.hashCode())));
189+
return allowAnonResourceNameClass
190+
? createAnonymousResourceNameClass(fieldOrMessageName)
191+
: ValueExpr.withValue(
192+
StringObjectValue.withValue(
193+
String.format("%s%s", fieldOrMessageName, fieldOrMessageName.hashCode())));
176194
}
177195
}
178196

@@ -247,10 +265,11 @@ public static Expr createSimpleMessageBuilderExpr(
247265
if (field.hasResourceReference()
248266
&& resourceNames.get(field.resourceReference().resourceTypeString()) != null) {
249267
defaultExpr =
250-
createDefaultValue(
268+
createDefaultValueResourceHelper(
251269
resourceNames.get(field.resourceReference().resourceTypeString()),
252270
resourceNames.values().stream().collect(Collectors.toList()),
253-
message.name());
271+
message.name(),
272+
/* allowAnonResourceNameClass = */ false);
254273
defaultExpr =
255274
MethodInvocationExpr.builder()
256275
.setExprReferenceExpr(defaultExpr)
@@ -345,4 +364,92 @@ public static Expr createSimplePagedResponse(
345364
.setReturnType(responseType)
346365
.build();
347366
}
367+
368+
@VisibleForTesting
369+
static AnonymousClassExpr createAnonymousResourceNameClass(String fieldOrMessageName) {
370+
TypeNode stringMapType =
371+
TypeNode.withReference(
372+
ConcreteReference.builder()
373+
.setClazz(Map.class)
374+
.setGenerics(
375+
Arrays.asList(
376+
ConcreteReference.withClazz(String.class),
377+
ConcreteReference.withClazz(String.class)))
378+
.build());
379+
380+
// Method code:
381+
// @Override
382+
// public Map<String, String> getFieldValuesMap() {
383+
// Map<String, String> fieldValuesMap = new HashMap<>();
384+
// fieldValuesMap.put("resource", "resource-12345");
385+
// return fieldValuesMap;
386+
// }
387+
VariableExpr fieldValuesMapVarExpr =
388+
VariableExpr.withVariable(
389+
Variable.builder().setType(stringMapType).setName("fieldValuesMap").build());
390+
StringObjectValue fieldOrMessageStringValue =
391+
StringObjectValue.withValue(
392+
String.format("%s%s", fieldOrMessageName, fieldOrMessageName.hashCode()));
393+
394+
List<Expr> bodyExprs =
395+
Arrays.asList(
396+
AssignmentExpr.builder()
397+
.setVariableExpr(fieldValuesMapVarExpr.toBuilder().setIsDecl(true).build())
398+
.setValueExpr(
399+
NewObjectExpr.builder()
400+
.setType(TypeNode.withReference(ConcreteReference.withClazz(HashMap.class)))
401+
.setIsGeneric(true)
402+
.build())
403+
.build(),
404+
MethodInvocationExpr.builder()
405+
.setExprReferenceExpr(fieldValuesMapVarExpr)
406+
.setMethodName("put")
407+
.setArguments(
408+
ValueExpr.withValue(StringObjectValue.withValue(fieldOrMessageName)),
409+
ValueExpr.withValue(fieldOrMessageStringValue))
410+
.build());
411+
412+
MethodDefinition getFieldValuesMapMethod =
413+
MethodDefinition.builder()
414+
.setIsOverride(true)
415+
.setScope(ScopeNode.PUBLIC)
416+
.setReturnType(stringMapType)
417+
.setName("getFieldValuesMap")
418+
.setBody(
419+
bodyExprs.stream().map(e -> ExprStatement.withExpr(e)).collect(Collectors.toList()))
420+
.setReturnExpr(fieldValuesMapVarExpr)
421+
.build();
422+
423+
// Method code:
424+
// @Override
425+
// public String getFieldValue(String fieldName) {
426+
// return getFieldValuesMap().get(fieldName);
427+
// }
428+
VariableExpr fieldNameVarExpr =
429+
VariableExpr.withVariable(
430+
Variable.builder().setType(TypeNode.STRING).setName("fieldName").build());
431+
MethodDefinition getFieldValueMethod =
432+
MethodDefinition.builder()
433+
.setIsOverride(true)
434+
.setScope(ScopeNode.PUBLIC)
435+
.setReturnType(TypeNode.STRING)
436+
.setName("getFieldValue")
437+
.setArguments(fieldNameVarExpr.toBuilder().setIsDecl(true).build())
438+
.setReturnExpr(
439+
MethodInvocationExpr.builder()
440+
.setExprReferenceExpr(
441+
MethodInvocationExpr.builder().setMethodName("getFieldValuesMap").build())
442+
.setMethodName("get")
443+
.setArguments(fieldNameVarExpr)
444+
.setReturnType(TypeNode.STRING)
445+
.build())
446+
.build();
447+
448+
return AnonymousClassExpr.builder()
449+
.setType(
450+
TypeNode.withReference(
451+
ConcreteReference.withClazz(com.google.api.resourcenames.ResourceName.class)))
452+
.setMethods(Arrays.asList(getFieldValuesMapMethod, getFieldValueMethod))
453+
.build();
454+
}
348455
}

src/main/java/com/google/api/generator/gapic/composer/grpc/MockServiceImplClassComposer.java

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.google.api.generator.engine.ast.MethodDefinition;
2929
import com.google.api.generator.engine.ast.MethodInvocationExpr;
3030
import com.google.api.generator.engine.ast.NewObjectExpr;
31+
import com.google.api.generator.engine.ast.Reference;
3132
import com.google.api.generator.engine.ast.RelationalOperationExpr;
3233
import com.google.api.generator.engine.ast.ScopeNode;
3334
import com.google.api.generator.engine.ast.Statement;
@@ -78,17 +79,9 @@ public class MockServiceImplClassComposer implements ClassComposer {
7879
Arrays.asList(FIXED_TYPESTORE.get("AbstractMessage").reference()))
7980
.build()))
8081
.build());
81-
private static final VariableExpr responsesVarExpr =
82-
VariableExpr.withVariable(
83-
Variable.builder()
84-
.setName("responses")
85-
.setType(
86-
TypeNode.withReference(
87-
ConcreteReference.builder()
88-
.setClazz(Queue.class)
89-
.setGenerics(Arrays.asList(ConcreteReference.withClazz(Object.class)))
90-
.build()))
91-
.build());
82+
83+
private static Reference javaObjectReference = ConcreteReference.withClazz(Object.class);
84+
private static VariableExpr responsesVarExpr;
9285

9386
private MockServiceImplClassComposer() {}
9487

@@ -97,12 +90,31 @@ public static MockServiceImplClassComposer instance() {
9790
}
9891

9992
@Override
100-
public GapicClass generate(GapicContext ignored, Service service) {
93+
public GapicClass generate(GapicContext context, Service service) {
10194
TypeStore typeStore = createDynamicTypes(service);
10295
String className = ClassNames.getMockServiceImplClassName(service);
10396
GapicClass.Kind kind = Kind.TEST;
10497
String pakkage = service.pakkage();
10598

99+
// Use the full name java.lang.Object if there is a proto message that is also named "Object".
100+
// Affects GCS.
101+
if (context.messages().keySet().stream().anyMatch(s -> s.equals("Object") || s.endsWith(".Object"))) {
102+
javaObjectReference =
103+
ConcreteReference.builder().setClazz(Object.class).setUseFullName(true).build();
104+
}
105+
106+
responsesVarExpr =
107+
VariableExpr.withVariable(
108+
Variable.builder()
109+
.setName("responses")
110+
.setType(
111+
TypeNode.withReference(
112+
ConcreteReference.builder()
113+
.setClazz(Queue.class)
114+
.setGenerics(Arrays.asList(javaObjectReference))
115+
.build()))
116+
.build());
117+
106118
ClassDefinition classDef =
107119
ClassDefinition.builder()
108120
.setPackageString(pakkage)
@@ -201,8 +213,7 @@ private static MethodDefinition createSetResponsesMethod(Service service) {
201213
Expr responseAssignExpr =
202214
AssignmentExpr.builder()
203215
.setVariableExpr(
204-
responsesVarExpr
205-
.toBuilder()
216+
responsesVarExpr.toBuilder()
206217
.setExprReferenceExpr(
207218
ValueExpr.withValue(ThisObjectValue.withType(getThisClassType(service))))
208219
.build())
@@ -212,8 +223,7 @@ private static MethodDefinition createSetResponsesMethod(Service service) {
212223
TypeNode.withReference(
213224
ConcreteReference.builder()
214225
.setClazz(LinkedList.class)
215-
.setGenerics(
216-
Arrays.asList(ConcreteReference.withClazz(Object.class)))
226+
.setGenerics(Arrays.asList(javaObjectReference))
217227
.build()))
218228
.setArguments(Arrays.asList(responsesArgVarExpr))
219229
.build())
@@ -267,7 +277,7 @@ private static List<MethodDefinition> createProtoMethodOverrides(Service service
267277

268278
private static MethodDefinition createGenericProtoMethodOverride(Method protoMethod) {
269279
ConcreteReference streamObserverRef = ConcreteReference.withClazz(StreamObserver.class);
270-
TypeNode objectType = TypeNode.withReference(ConcreteReference.withClazz(Object.class));
280+
TypeNode objectType = TypeNode.withReference(javaObjectReference);
271281
VariableExpr localResponseVarExpr =
272282
VariableExpr.withVariable(
273283
Variable.builder().setName("response").setType(objectType).build());
@@ -372,7 +382,7 @@ private static MethodDefinition createOnNextJavaMethod(
372382
VariableExpr valueVarExpr =
373383
VariableExpr.withVariable(
374384
Variable.builder().setName("value").setType(protoMethod.inputType()).build());
375-
TypeNode objectType = TypeNode.withReference(ConcreteReference.withClazz(Object.class));
385+
TypeNode objectType = TypeNode.withReference(javaObjectReference);
376386

377387
Statement addValueToRequestsStatement =
378388
ExprStatement.withExpr(

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

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,53 @@ public class EchoClient implements BackgroundResource {
769769
return stub.blockCallable();
770770
}
771771

772+
// AUTO-GENERATED DOCUMENTATION AND METHOD.
773+
/**
774+
* Sample code:
775+
*
776+
* <pre>{@code
777+
* try (EchoClient echoClient = EchoClient.create()) {
778+
* EchoRequest request =
779+
* EchoRequest.newBuilder()
780+
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
781+
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
782+
* .setSeverity(Severity.forNumber(0))
783+
* .setFoobar(Foobar.newBuilder().build())
784+
* .build();
785+
* Object response = echoClient.collideName(request);
786+
* }
787+
* }</pre>
788+
*
789+
* @param request The request object containing all of the parameters for the API call.
790+
* @throws com.google.api.gax.rpc.ApiException if the remote call fails
791+
*/
792+
public final Object collideName(EchoRequest request) {
793+
return collideNameCallable().call(request);
794+
}
795+
796+
// AUTO-GENERATED DOCUMENTATION AND METHOD.
797+
/**
798+
* Sample code:
799+
*
800+
* <pre>{@code
801+
* try (EchoClient echoClient = EchoClient.create()) {
802+
* EchoRequest request =
803+
* EchoRequest.newBuilder()
804+
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
805+
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
806+
* .setSeverity(Severity.forNumber(0))
807+
* .setFoobar(Foobar.newBuilder().build())
808+
* .build();
809+
* ApiFuture<Object> future = echoClient.collideNameCallable().futureCall(request);
810+
* // Do something.
811+
* Object response = future.get();
812+
* }
813+
* }</pre>
814+
*/
815+
public final UnaryCallable<EchoRequest, Object> collideNameCallable() {
816+
return stub.collideNameCallable();
817+
}
818+
772819
@Override
773820
public final void close() {
774821
stub.close();

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import com.google.showcase.v1beta1.BlockResponse;
1717
import com.google.showcase.v1beta1.EchoRequest;
1818
import com.google.showcase.v1beta1.EchoResponse;
1919
import com.google.showcase.v1beta1.ExpandRequest;
20+
import com.google.showcase.v1beta1.Object;
2021
import com.google.showcase.v1beta1.PagedExpandRequest;
2122
import com.google.showcase.v1beta1.PagedExpandResponse;
2223
import com.google.showcase.v1beta1.WaitMetadata;
@@ -87,6 +88,10 @@ public abstract class EchoStub implements BackgroundResource {
8788
throw new UnsupportedOperationException("Not implemented: blockCallable()");
8889
}
8990

91+
public UnaryCallable<EchoRequest, Object> collideNameCallable() {
92+
throw new UnsupportedOperationException("Not implemented: collideNameCallable()");
93+
}
94+
9095
@Override
9196
public abstract void close();
9297
}

0 commit comments

Comments
 (0)