Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Use parent type instead of child_type in method doc sample #862

Merged
merged 8 commits into from
Nov 3, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

public class DefaultValueComposer {
Expand Down Expand Up @@ -76,6 +77,7 @@ public static Expr createDefaultValue(
Expr defValue =
createDefaultValue(
resourceName,
methodArg.field().resourceReference().isChildType(),
resourceNames.values().stream().collect(Collectors.toList()),
methodArg.field().name());

Expand Down Expand Up @@ -175,17 +177,45 @@ static Expr createDefaultValue(Field f, boolean useExplicitInitTypeInGenerics) {
}

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

private static Optional<ResourceName> findParentResource(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this whole thing be included in ResourceReferenceParser class? This seems like a general resource names resolution logic, not necessarily specific to sample generation.

ResourceName childResource, List<ResourceName> resourceNames) {
for (ResourceName parent : resourceNames) {
for (String parentPattern : parent.patterns()) {
String[] parentPatternParts = parentPattern.split("/");
for (String childPattern : childResource.patterns()) {
String[] childPatternParts = childPattern.split("/");
if (parentPattern.length() < childPattern.length()
&& childPattern.startsWith(parentPattern)
&& childPatternParts.length - parentPatternParts.length == 2) {
return Optional.of(parent);
}
}
}
}

return Optional.empty();
}

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

if (isChildType) {
resourceName = findParentResource(resourceName, resnames).orElse(resourceName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the orElse part mean that if we did not manage to find a parent, the code will behave as before, basically meaning that the child is its own parent?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Do you think we should fail instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, just wanted to make sure I understood it right.

}

boolean hasOnePattern = resourceName.patterns().size() == 1;
if (resourceName.isOnlyWildcard()) {
List<ResourceName> unexaminedResnames = new ArrayList<>(resnames);
Expand All @@ -195,7 +225,7 @@ static Expr createDefaultValueResourceHelper(
continue;
}
unexaminedResnames.remove(resname);
return createDefaultValue(resname, unexaminedResnames, fieldOrMessageName);
return createDefaultValue(resname, false, unexaminedResnames, fieldOrMessageName);
}

if (unexaminedResnames.isEmpty()) {
Expand Down Expand Up @@ -283,6 +313,7 @@ public static Expr createSimpleMessageBuilderExpr(
defaultExpr =
createDefaultValueResourceHelper(
resourceNames.get(field.resourceReference().resourceTypeString()),
field.resourceReference().isChildType(),
resourceNames.values().stream().collect(Collectors.toList()),
message.name(),
/* allowAnonResourceNameClass = */ false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1301,6 +1301,7 @@ private static List<Expr> createRpcMethodArgumentDefaultValueExprs(
.setExprReferenceExpr(
DefaultValueComposer.createDefaultValue(
resourceNames.get(arg.field().resourceReference().resourceTypeString()),
arg.field().resourceReference().isChildType(),
resourceNameList,
arg.field().name()))
.setMethodName("toString")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -881,7 +881,11 @@ static String parsePageSizeFieldName(
// with monolith-gnerated libraries.
String pagedFieldName = null;

if (inputMessage.fieldMap().containsKey("page_token")
if (inputMessage != null
&& inputMessage.fieldMap() != null
Copy link
Contributor

@vam-google vam-google Nov 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this if statement get so much bigger? Specifically, looks like inputMessage.fieldMap() was guaranteed to not be null (as we would get NPE otherwise).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point on fieldMap() being non-nullible. However, inputMessage can be null as the new messaging test revealed.

&& inputMessage.fieldMap().containsKey("page_token")
&& outputMessage != null
&& outputMessage.fieldMap() != null
&& outputMessage.fieldMap().containsKey("next_page_token")) {
// List of potential field names representing page size.
// page_size gets priority over max_results if both are present
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.google.pubsub.v1.PubsubProto;
import com.google.showcase.v1beta1.EchoOuterClass;
import com.google.showcase.v1beta1.IdentityOuterClass;
import com.google.showcase.v1beta1.MessagingOuterClass;
import com.google.showcase.v1beta1.TestingOuterClass;
import com.google.testdata.v1.DeprecatedServiceOuterClass;
import google.cloud.CommonResources;
Expand All @@ -51,6 +52,7 @@
import java.util.Set;

public class TestProtoLoader {

private static final TestProtoLoader INSTANCE =
new TestProtoLoader(Transport.GRPC, "src/test/java/com/google/api/generator/gapic/testdata/");
private final String testFilesDirectory;
Expand Down Expand Up @@ -170,6 +172,35 @@ public GapicContext parseShowcaseIdentity() {
.build();
}

public GapicContext parseShowcaseMessaging() {
FileDescriptor fileDescriptor = MessagingOuterClass.getDescriptor();
ServiceDescriptor messagingService = fileDescriptor.getServices().get(0);
assertEquals(messagingService.getName(), "Messaging");

Map<String, Message> messageTypes = Parser.parseMessages(fileDescriptor);
Map<String, ResourceName> resourceNames = Parser.parseResourceNames(fileDescriptor);

FileDescriptor identityFileDescriptor = IdentityOuterClass.getDescriptor();
Map<String, ResourceName> identityResourceNames = Parser
.parseResourceNames(identityFileDescriptor);

resourceNames.put("showcase.googleapis.com/User",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? If there is stuff in the messaging.proto file, which just causes troubles but is not essential for the tests, please feel free to remove it. If there are missing imports please just add them on proot/bazel lavel.
Basically any API definition problems are expected to be solved on proto level, but not in the logic which loads/parse the protos.

identityResourceNames.get("showcase.googleapis.com/User"));

Set<ResourceName> outputResourceNames = new HashSet<>();
List<Service> services =
Parser.parseService(
fileDescriptor, messageTypes, resourceNames, Optional.empty(), outputResourceNames);

return GapicContext.builder()
.setMessages(messageTypes)
.setResourceNames(resourceNames)
.setServices(services)
.setHelperResourceNames(outputResourceNames)
.setTransport(transport)
.build();
}

public GapicContext parseShowcaseTesting() {
FileDescriptor testingFileDescriptor = TestingOuterClass.getDescriptor();
ServiceDescriptor testingService = testingFileDescriptor.getServices().get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ public void defaultValue_resourceNameWithOnePattern() {
Expr expr =
DefaultValueComposer.createDefaultValue(
resourceName,
false,
typeStringsToResourceNames.values().stream().collect(Collectors.toList()),
"ignored");
expr.accept(writerVisitor);
Expand All @@ -177,6 +178,7 @@ public void defaultValue_resourceNameWithMultiplePatterns() {
Expr expr =
DefaultValueComposer.createDefaultValue(
resourceName,
false,
typeStringsToResourceNames.values().stream().collect(Collectors.toList()),
"ignored");
expr.accept(writerVisitor);
Expand All @@ -194,6 +196,7 @@ public void defaultValue_resourceNameWithWildcardPattern() {
Expr expr =
DefaultValueComposer.createDefaultValue(
resourceName,
false,
typeStringsToResourceNames.values().stream().collect(Collectors.toList()),
"ignored");
expr.accept(writerVisitor);
Expand All @@ -216,6 +219,7 @@ public void defaultValue_wildcardResourceNameWithOnlyDeletedTopic() {
Expr expr =
DefaultValueComposer.createDefaultValue(
resourceName,
false,
typeStringsToResourceNames.values().stream().collect(Collectors.toList()),
"ignored");
expr.accept(writerVisitor);
Expand All @@ -236,6 +240,7 @@ public void defaultValue_resourceNameWithOnlyWildcards_valueOnly() {
Expr expr =
DefaultValueComposer.createDefaultValueResourceHelper(
resourceName,
false,
Collections.emptyList(),
fallbackField,
/* allowAnonResourceNameClass = */ false);
Expand All @@ -257,7 +262,7 @@ public void defaultValue_resourceNameWithOnlyWildcards_allowAnonResourceNameClas
String fallbackField = "foobar";
Expr expr =
DefaultValueComposer.createDefaultValue(
resourceName, Collections.emptyList(), fallbackField);
resourceName, false, Collections.emptyList(), fallbackField);
expr.accept(writerVisitor);
String expected =
LineFormatter.lines(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,17 @@ public void generateServiceClasses_bookshopNameConflicts() {
Path goldenFilePath = Paths.get(Utils.getGoldenDir(this.getClass()), "BookshopClient.golden");
assertCodeEquals(goldenFilePath, visitor.write());
}

@Test
public void generateServiceClasses_childTypeParentInJavadoc() {
GapicContext context = GrpcTestProtoLoader.instance().parseShowcaseMessaging();
Service protoService = context.services().get(0);
GapicClass clazz = ServiceClientClassComposer.instance().generate(context, protoService);

JavaWriterVisitor visitor = new JavaWriterVisitor();
clazz.classDefinition().accept(visitor);
Utils.saveCodegenToFile(this.getClass(), "MessagingClient.golden", visitor.write());
Path goldenFilePath = Paths.get(Utils.getGoldenDir(this.getClass()), "MessagingClient.golden");
assertCodeEquals(goldenFilePath, visitor.write());
}
}