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

0 comments on commit 2a7064b

Please sign in to comment.