Skip to content

Commit

Permalink
[ggj][codegen] fix: support singleton resnames' patterns in parsing a…
Browse files Browse the repository at this point in the history
…nd codegen (#574)

* fix: handle empty method_signature in parsing protos

* fix: add google/type:type_java_proto as default test dep

* fix: support singleton resource names in parsing and codegen
  • Loading branch information
miraleung authored Nov 26, 2020
1 parent 3b7bb40 commit d3fea22
Show file tree
Hide file tree
Showing 4 changed files with 287 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -187,17 +187,20 @@ static Optional<String> parseParentPattern(String pattern) {
return Optional.empty();
}

int lastTokenIndex = tokens.length - 2;
int minLengthWithParent = 4;
// Singleton patterns, e.g. projects/{project}/agent.
if (!lastToken.contains("{")) {
minLengthWithParent = 3;
lastTokenIndex = tokens.length - 1;
}

// No fully-formed parent. Expected: ancestors/{ancestor}/childNodes/{child_node}.
if (tokens.length < 4) {
if (tokens.length < minLengthWithParent) {
return Optional.empty();
}

Preconditions.checkState(
lastToken.contains("{"),
String.format(
"Pattern %s must end with a brace-encapsulated variable, e.g. {foobar}", pattern));

return Optional.of(String.join(SLASH, Arrays.asList(tokens).subList(0, tokens.length - 2)));
return Optional.of(String.join(SLASH, Arrays.asList(tokens).subList(0, lastTokenIndex)));
}

@VisibleForTesting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,26 @@ public void generateResourceNameClass_testingBlueprintPatternWithNonSlashSeparat
Path goldenFilePath = Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "TestName.golden");
Assert.assertCodeEquals(goldenFilePath, visitor.write());
}

@Test
public void generateResourceNameClass_childSingleton() {
ResourceName agentResname =
ResourceName.builder()
.setVariableName("agent")
.setPakkage("com.google.cloud.dialogflow.v2beta1")
.setResourceTypeString("dialogflow.googleapis.com/Agent")
.setPatterns(
Arrays.asList(
"projects/{project}/locations/{location}/agent", "projects/{project}/agent"))
.setParentMessageName("Agent")
.setDescription("This is a description")
.build();

GapicClass clazz = ResourceNameHelperClassComposer.instance().generate(agentResname);
JavaWriterVisitor visitor = new JavaWriterVisitor();
clazz.classDefinition().accept(visitor);
Utils.saveCodegenToFile(this.getClass(), "AgentName.golden", visitor.write());
Path goldenFilePath = Paths.get(ComposerConstants.GOLDENFILES_DIRECTORY, "AgentName.golden");
Assert.assertCodeEquals(goldenFilePath, visitor.write());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
package com.google.cloud.dialogflow.v2beta1;

import com.google.api.core.BetaApi;
import com.google.api.pathtemplate.PathTemplate;
import com.google.api.pathtemplate.ValidationException;
import com.google.api.resourcenames.ResourceName;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Generated;

// AUTO-GENERATED DOCUMENTATION AND CLASS.
@Generated("by gapic-generator-java")
public class AgentName implements ResourceName {
private static final PathTemplate PROJECT_LOCATION =
PathTemplate.createWithoutUrlEncoding("projects/{project}/locations/{location}/agent");
private static final PathTemplate PROJECT =
PathTemplate.createWithoutUrlEncoding("projects/{project}/agent");
private volatile Map<String, String> fieldValuesMap;
private PathTemplate pathTemplate;
private String fixedValue;
private final String project;
private final String location;

@Deprecated
protected AgentName() {
project = null;
location = null;
}

private AgentName(Builder builder) {
project = Preconditions.checkNotNull(builder.getProject());
location = Preconditions.checkNotNull(builder.getLocation());
pathTemplate = PROJECT_LOCATION;
}

private AgentName(ProjectBuilder builder) {
project = Preconditions.checkNotNull(builder.getProject());
location = null;
pathTemplate = PROJECT;
}

public String getProject() {
return project;
}

public String getLocation() {
return location;
}

public static Builder newBuilder() {
return new Builder();
}

@BetaApi("The per-pattern Builders are not stable yet and may be changed in the future.")
public static Builder newProjectLocationBuilder() {
return new Builder();
}

@BetaApi("The per-pattern Builders are not stable yet and may be changed in the future.")
public static ProjectBuilder newProjectBuilder() {
return new ProjectBuilder();
}

public Builder toBuilder() {
return new Builder(this);
}

public static AgentName of(String project, String location) {
return newBuilder().setProject(project).setLocation(location).build();
}

@BetaApi("The static create methods are not stable yet and may be changed in the future.")
public static AgentName ofProjectLocationName(String project, String location) {
return newBuilder().setProject(project).setLocation(location).build();
}

@BetaApi("The static create methods are not stable yet and may be changed in the future.")
public static AgentName ofProjectName(String project) {
return newProjectBuilder().setProject(project).build();
}

public static String format(String project, String location) {
return newBuilder().setProject(project).setLocation(location).build().toString();
}

@BetaApi("The static format methods are not stable yet and may be changed in the future.")
public static String formatProjectLocationName(String project, String location) {
return newBuilder().setProject(project).setLocation(location).build().toString();
}

@BetaApi("The static format methods are not stable yet and may be changed in the future.")
public static String formatProjectName(String project) {
return newProjectBuilder().setProject(project).build().toString();
}

public static AgentName parse(String formattedString) {
if (formattedString.isEmpty()) {
return null;
}
if (PROJECT_LOCATION.matches(formattedString)) {
Map<String, String> matchMap = PROJECT_LOCATION.match(formattedString);
return ofProjectLocationName(matchMap.get("project"), matchMap.get("location"));
} else if (PROJECT.matches(formattedString)) {
Map<String, String> matchMap = PROJECT.match(formattedString);
return ofProjectName(matchMap.get("project"));
}
throw new ValidationException("AgentName.parse: formattedString not in valid format");
}

public static List<AgentName> parseList(List<String> formattedStrings) {
List<AgentName> list = new ArrayList<>(formattedStrings.size());
for (String formattedString : formattedStrings) {
list.add(parse(formattedString));
}
return list;
}

public static List<String> toStringList(List<AgentName> values) {
List<String> list = new ArrayList<>(values.size());
for (AgentName value : values) {
if (Objects.isNull(value)) {
list.add("");
} else {
list.add(value.toString());
}
}
return list;
}

public static boolean isParsableFrom(String formattedString) {
return PROJECT_LOCATION.matches(formattedString) || PROJECT.matches(formattedString);
}

@Override
public Map<String, String> getFieldValuesMap() {
if (Objects.isNull(fieldValuesMap)) {
synchronized (this) {
if (Objects.isNull(fieldValuesMap)) {
ImmutableMap.Builder<String, String> fieldMapBuilder = ImmutableMap.builder();
if (!Objects.isNull(project)) {
fieldMapBuilder.put("project", project);
}
if (!Objects.isNull(location)) {
fieldMapBuilder.put("location", location);
}
fieldValuesMap = fieldMapBuilder.build();
}
}
}
return fieldValuesMap;
}

public String getFieldValue(String fieldName) {
return getFieldValuesMap().get(fieldName);
}

@Override
public String toString() {
return !Objects.isNull(fixedValue) ? fixedValue : pathTemplate.instantiate(getFieldValuesMap());
}

@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o != null || getClass() == o.getClass()) {
AgentName that = ((AgentName) o);
return Objects.equals(this.project, that.project)
&& Objects.equals(this.location, that.location);
}
return false;
}

@Override
public int hashCode() {
int h = 1;
h *= 1000003;
h ^= Objects.hashCode(fixedValue);
h *= 1000003;
h ^= Objects.hashCode(project);
h *= 1000003;
h ^= Objects.hashCode(location);
return h;
}

/** Builder for projects/{project}/locations/{location}/agent. */
public static class Builder {
private String project;
private String location;

protected Builder() {}

public String getProject() {
return project;
}

public String getLocation() {
return location;
}

public Builder setProject(String project) {
this.project = project;
return this;
}

public Builder setLocation(String location) {
this.location = location;
return this;
}

private Builder(AgentName agentName) {
Preconditions.checkArgument(
Objects.equals(agentName.pathTemplate, PROJECT_LOCATION),
"toBuilder is only supported when AgentName has the pattern of projects/{project}/locations/{location}/agent");
project = agentName.project;
location = agentName.location;
}

public AgentName build() {
return new AgentName(this);
}
}

/** Builder for projects/{project}/agent. */
@BetaApi("The per-pattern Builders are not stable yet and may be changed in the future.")
public static class ProjectBuilder {
private String project;

protected ProjectBuilder() {}

public String getProject() {
return project;
}

public ProjectBuilder setProject(String project) {
this.project = project;
return this;
}

public AgentName build() {
return new AgentName(this);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,12 @@ public void parseParentResourceName_badPattern() {
ResourceReferenceParser.parseParentResourceName(
"projects/{project}/billingAccounts",
MAIN_PACKAGE,
null,
MAIN_PACKAGE,
"com.google.cloud.billing.v1",
"cloudbilling.googleapis.com/Feature",
null,
new HashMap<String, ResourceName>());
assertFalse(parentResourceNameOpt.isPresent());
assertTrue(parentResourceNameOpt.isPresent());
assertEquals("projects/{project}", parentResourceNameOpt.get().patterns().get(0));
}

@Test
Expand Down Expand Up @@ -159,7 +160,8 @@ public void parseParentPattern_insufficientPathComponents() {
public void parseParentPattern_lastComponentIsNotAVariable() {
Optional<String> parentPatternOpt =
ResourceReferenceParser.parseParentPattern("projects/{project}/foobars");
assertFalse(parentPatternOpt.isPresent());
assertTrue(parentPatternOpt.isPresent());
assertEquals("projects/{project}", parentPatternOpt.get());
}

@Test
Expand Down

0 comments on commit d3fea22

Please sign in to comment.