Skip to content

[ggj][codegen] fix: support singleton resnames' patterns in parsing and codegen #574

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

Merged
merged 4 commits into from
Nov 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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