Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

Commit

Permalink
Generate method overloads when a resource field has multiple resource…
Browse files Browse the repository at this point in the history
… names configured (#3081)

- When a field has child_type reference and the referenced resource has multiple patterns, allow this field to be associated with multiple resources if all these resources combined have exactly all the parent patterns of the resource referenced by child_type.
- Generate method overloads if the field with multiple resource names are in a flattening config.
If there are multiple fields with multiple resource names, generate all possible combinations.
- Always generate an overload with all resource names treated as strings.
- In Java, repeated fields with resource name configs are always treated as List<String> to avoid multiple methods having the same signature after type erasure.
- The * annotation is not yet supported.

See changes to ArchiveBooks, LongRunningArchiveBooks and StreamingArchiveBooks for testing generating overloads for unary, longrunning and streaming methods.

See changes to MoveBooks for testing generating all the combinations.
  • Loading branch information
yihanzhen authored Jan 31, 2020
1 parent f7dd818 commit a57f59b
Show file tree
Hide file tree
Showing 42 changed files with 5,078 additions and 670 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import com.google.api.tools.framework.model.SimpleLocation;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
Expand Down Expand Up @@ -141,8 +142,8 @@ static DiscoGapicMethodConfig createDiscoGapicMethodConfig(
error = true;
}

ImmutableMap<String, String> fieldNamePatterns =
ImmutableMap.copyOf(methodConfigProto.getFieldNamePatterns());
ImmutableListMultimap<String, String> fieldNamePatterns =
ImmutableListMultimap.copyOf(methodConfigProto.getFieldNamePatterns().entrySet());

ResourceNameTreatment defaultResourceNameTreatment =
methodConfigProto.getResourceNameTreatment();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
import com.google.api.codegen.transformer.SurfaceNamer;
import com.google.api.codegen.viewmodel.CallingForm;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableMap;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/** The context for transforming a method to a view model object. */
@AutoValue
Expand Down Expand Up @@ -147,4 +150,14 @@ public List<CallingForm> getCallingForms() {
public MethodContext withCallingForms(List<CallingForm> callingForms) {
return this;
}

@Override
public ImmutableMap<String, String> getFieldResourceEntityMap() {
ImmutableMap.Builder<String, String> fieldResourceEntityMap = ImmutableMap.builder();
for (Map.Entry<String, Collection<String>> entry :
getMethodConfig().getFieldNamePatterns().asMap().entrySet()) {
fieldResourceEntityMap.put(entry.getKey(), ((List<String>) entry.getValue()).get(0));
}
return fieldResourceEntityMap.build();
}
}
109 changes: 70 additions & 39 deletions src/main/java/com/google/api/codegen/config/FieldConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,31 @@
import com.google.api.tools.framework.model.Field;
import com.google.api.tools.framework.model.SimpleLocation;
import com.google.auto.value.AutoValue;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;

/** FieldConfig represents a configuration for a Field, derived from the GAPIC config. */
/** FieldConfig represents a configuration for a Field. */
@AutoValue
public abstract class FieldConfig {
public abstract FieldModel getField();

@Nullable
public abstract ResourceNameTreatment getResourceNameTreatment();

/** The resource name config used to generate flattened API methods. */
@Nullable
public abstract ResourceNameConfig getResourceNameConfig();

/**
* The resource name config associated to a field in a proto message. Used to generate samples and
* tests for non-flattened methods, and iterator methods (e.g., iterateAllAsBookName) in page
* streaming responses.
*/
@Nullable
public abstract ResourceNameConfig getMessageResourceNameConfig();

Expand All @@ -48,7 +55,7 @@ public ResourceNameType getResourceNameType() {
return getResourceNameConfig().getResourceNameType();
}

private static FieldConfig createFieldConfig(
static FieldConfig createFieldConfig(
FieldModel field,
ResourceNameTreatment resourceNameTreatment,
ResourceNameConfig resourceNameConfig,
Expand All @@ -62,50 +69,24 @@ private static FieldConfig createFieldConfig(
throw new IllegalArgumentException(
"FieldConfig may not contain a ResourceNameConfig of type " + ResourceNameType.FIXED);
}
return new AutoValue_FieldConfig(
field, resourceNameTreatment, resourceNameConfig, messageResourceNameConfig);
}

/** Creates a FieldConfig for the given Field with ResourceNameTreatment set to None. */
public static FieldConfig createDefaultFieldConfig(FieldModel field) {
return FieldConfig.createFieldConfig(field, ResourceNameTreatment.NONE, null, null);
}

static FieldConfig createMessageFieldConfig(
ResourceNameMessageConfigs messageConfigs,
Map<String, ResourceNameConfig> resourceNameConfigs,
FieldModel field,
ResourceNameTreatment defaultResourceNameTreatment) {
return createFieldConfig(
null,
messageConfigs,
null,
resourceNameConfigs,
field,
ResourceNameTreatment.UNSET_TREATMENT,
defaultResourceNameTreatment);
return FieldConfig.newBuilder()
.setField(field)
.setResourceNameTreatment(resourceNameTreatment)
.setResourceNameConfig(resourceNameConfig)
.setMessageResourceNameConfig(messageResourceNameConfig)
.build();
}

/** Package-private since this is not used outside the config package. */
static FieldConfig createFieldConfig(
DiagCollector diagCollector,
@Nullable String messageFieldEntityName,
@Nullable String flattenedFieldEntityName,
ResourceNameMessageConfigs messageConfigs,
Map<String, String> fieldNamePatterns,
Map<String, ResourceNameConfig> resourceNameConfigs,
FieldModel field,
ResourceNameTreatment treatment,
ResourceNameTreatment defaultResourceNameTreatment) {
String messageFieldEntityName = null;
String flattenedFieldEntityName = null;
if (messageConfigs != null && messageConfigs.fieldHasResourceName(field)) {
messageFieldEntityName = messageConfigs.getFieldResourceName(field);
}
if (fieldNamePatterns != null) {
flattenedFieldEntityName = fieldNamePatterns.get(field.getNameAsParameter());
}
if (flattenedFieldEntityName == null) {
flattenedFieldEntityName = messageFieldEntityName;
}

if (treatment == ResourceNameTreatment.UNSET_TREATMENT) {
// No specific resource name treatment is specified, so we infer the correct treatment from
Expand Down Expand Up @@ -162,8 +143,14 @@ static FieldConfig createFieldConfig(

validate(messageConfigs, field, treatment, flattenedFieldResourceNameConfig);

return createFieldConfig(
field, treatment, flattenedFieldResourceNameConfig, messageFieldResourceNameConfig);
FieldConfig config =
newBuilder()
.setField(field)
.setResourceNameTreatment(treatment)
.setResourceNameConfig(flattenedFieldResourceNameConfig)
.setMessageResourceNameConfig(messageFieldResourceNameConfig)
.build();
return config;
}

private static ResourceNameConfig getResourceNameConfig(
Expand Down Expand Up @@ -213,7 +200,8 @@ public FieldConfig withResourceNameConfig(ResourceNameConfig resourceNameConfig)

public FieldConfig withResourceNameInSampleOnly() {
ResourceNameTreatment newTreatment = ResourceNameTreatment.NONE;
if (ResourceNameTreatment.STATIC_TYPES.equals(getResourceNameTreatment())) {
if (ResourceNameTreatment.STATIC_TYPES.equals(getResourceNameTreatment())
|| ResourceNameTreatment.SAMPLE_ONLY.equals(getResourceNameTreatment())) {
newTreatment = ResourceNameTreatment.SAMPLE_ONLY;
}
return FieldConfig.createFieldConfig(
Expand Down Expand Up @@ -241,6 +229,10 @@ public FieldConfig getMessageFieldConfig() {
getMessageResourceNameConfig());
}

public boolean isRepeatedResourceNameTypeField() {
return getField().isRepeated() && useResourceNameType();
}

/*
* Check that the provided resource name treatment and entityName are valid for the provided field.
*/
Expand Down Expand Up @@ -288,4 +280,43 @@ public static ImmutableMap<String, FieldConfig> toFieldConfigMap(
Iterable<FieldConfig> fieldConfigs) {
return Maps.uniqueIndex(fieldConfigs, f -> f.getField().getFullName());
}

@AutoValue.Builder
public abstract static class Builder {

public abstract Builder setField(FieldModel val);

public abstract Builder setResourceNameTreatment(ResourceNameTreatment val);

public abstract Builder setResourceNameConfig(ResourceNameConfig val);

public abstract Builder setMessageResourceNameConfig(ResourceNameConfig val);

public abstract FieldConfig build();
}

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

/**
* The string returned that the default toString() method generated by AutoValue is too verbose.
* Override it to provide just key information.
*/
@Override
public String toString() {
String resourceNameEntityId =
getResourceNameConfig() == null ? "null" : getResourceNameConfig().getEntityId();
String exampleResourceNameEntityId =
getMessageResourceNameConfig() == null
? "null"
: getMessageResourceNameConfig().getEntityId();

return MoreObjects.toStringHelper(this)
.add("fieldName", getField().getSimpleName())
.add("resourceNameEntityId", resourceNameEntityId)
.add("exampleResourceNameEntityId", exampleResourceNameEntityId)
.add("resourceTreatment", getResourceNameTreatment())
.toString();
}
}
Loading

0 comments on commit a57f59b

Please sign in to comment.