Skip to content

Commit

Permalink
fix(mocks): Use java.lang.Object if there are protos named 'Object' […
Browse files Browse the repository at this point in the history
…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)
  • Loading branch information
miraleung committed Jun 10, 2021
1 parent 2091141 commit 2a7064b
Show file tree
Hide file tree
Showing 16 changed files with 449 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -157,6 +163,16 @@ static Expr createDefaultValue(Field f, boolean useExplicitInitTypeInGenerics) {

public static Expr createDefaultValue(
ResourceName resourceName, List<ResourceName> resnames, String fieldOrMessageName) {
return createDefaultValueResourceHelper(resourceName, resnames, fieldOrMessageName, true);
}

@VisibleForTesting
static Expr createDefaultValueResourceHelper(
ResourceName resourceName,
List<ResourceName> resnames,
String fieldOrMessageName,
boolean allowAnonResourceNameClass) {

boolean hasOnePattern = resourceName.patterns().size() == 1;
if (resourceName.isOnlyWildcard()) {
List<ResourceName> unexaminedResnames = new ArrayList<>(resnames);
Expand All @@ -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())));
}
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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<String, String> getFieldValuesMap() {
// Map<String, String> 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<Expr> 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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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() {}

Expand All @@ -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)
Expand Down Expand Up @@ -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())
Expand All @@ -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())
Expand Down Expand Up @@ -267,7 +277,7 @@ private static List<MethodDefinition> 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());
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,53 @@ public class EchoClient implements BackgroundResource {
return stub.blockCallable();
}

// AUTO-GENERATED DOCUMENTATION AND METHOD.
/**
* Sample code:
*
* <pre>{@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);
* }
* }</pre>
*
* @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:
*
* <pre>{@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<Object> future = echoClient.collideNameCallable().futureCall(request);
* // Do something.
* Object response = future.get();
* }
* }</pre>
*/
public final UnaryCallable<EchoRequest, Object> collideNameCallable() {
return stub.collideNameCallable();
}

@Override
public final void close() {
stub.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -87,6 +88,10 @@ public abstract class EchoStub implements BackgroundResource {
throw new UnsupportedOperationException("Not implemented: blockCallable()");
}

public UnaryCallable<EchoRequest, Object> collideNameCallable() {
throw new UnsupportedOperationException("Not implemented: collideNameCallable()");
}

@Override
public abstract void close();
}
Loading

0 comments on commit 2a7064b

Please sign in to comment.