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

feat: add parsing of autopopulated fields from serviceyaml #2312

Merged
merged 15 commits into from Dec 28, 2023
Expand Up @@ -14,6 +14,7 @@

package com.google.api.generator.gapic.model;

import com.google.api.FieldInfo.Format;
import com.google.api.generator.engine.ast.TypeNode;
import com.google.auto.value.AutoValue;
import java.util.Objects;
Expand All @@ -32,6 +33,12 @@ public abstract class Field {

public abstract TypeNode type();

// If the field is annotated with google.api.field_behavior = REQUIRED, then this is true.
alicejli marked this conversation as resolved.
Show resolved Hide resolved
public abstract boolean isRequired();

@Nullable
public abstract Format fieldInfoFormat();

public abstract boolean isMessage();

public abstract boolean isEnum();
Expand Down Expand Up @@ -72,6 +79,8 @@ public boolean equals(Object o) {
return name().equals(other.name())
&& originalName().equals(other.originalName())
&& type().equals(other.type())
&& isRequired() == other.isRequired()
&& fieldInfoFormat() == other.fieldInfoFormat()
alicejli marked this conversation as resolved.
Show resolved Hide resolved
&& isMessage() == other.isMessage()
&& isEnum() == other.isEnum()
&& isRepeated() == other.isRepeated()
Expand Down Expand Up @@ -101,6 +110,7 @@ public int hashCode() {

public static Builder builder() {
return new AutoValue_Field.Builder()
.setIsRequired(false)
.setIsMessage(false)
.setIsEnum(false)
.setIsRepeated(false)
Expand All @@ -117,6 +127,10 @@ public abstract static class Builder {

public abstract Builder setType(TypeNode type);

public abstract Builder setIsRequired(boolean isRequired);

public abstract Builder setFieldInfoFormat(Format fieldInfoFormat);

public abstract Builder setIsMessage(boolean isMessage);

public abstract Builder setIsEnum(boolean isEnum);
Expand Down
Expand Up @@ -17,6 +17,7 @@
import com.google.api.generator.engine.ast.TypeNode;
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;

Expand Down Expand Up @@ -69,6 +70,16 @@ public boolean isPaged() {
// [["content", "error"], ["content", "error", "info"]].
public abstract ImmutableList<List<MethodArgument>> methodSignatures();

public abstract List<String> autoPopulatedFields();
alicejli marked this conversation as resolved.
Show resolved Hide resolved

/**
* If a service's service_config.yaml file contains method_settings.auto_populated_fields for this
* method, and the method is a Unary-type, then this is true
*/
public boolean hasAutoPopulatedFields() {
alicejli marked this conversation as resolved.
Show resolved Hide resolved
return autoPopulatedFields().size() > 0 && stream() == Stream.NONE;
alicejli marked this conversation as resolved.
Show resolved Hide resolved
}

public abstract boolean operationPollingMethod();

public boolean hasLro() {
Expand Down Expand Up @@ -123,6 +134,7 @@ public boolean isSupportedByTransport(Transport transport) {
public static Builder builder() {
return new AutoValue_Method.Builder()
.setStream(Stream.NONE)
.setAutoPopulatedFields(new ArrayList<>())
.setMethodSignatures(ImmutableList.of())
.setIsBatching(false)
.setIsDeprecated(false)
Expand Down Expand Up @@ -170,6 +182,8 @@ public abstract static class Builder {

public abstract Builder setOperationPollingMethod(boolean operationPollingMethod);

public abstract Builder setAutoPopulatedFields(List<String> autoPopulatedFields);

public abstract Builder setRoutingHeaderRule(RoutingHeaderRule routingHeaderRule);

public abstract Method build();
Expand Down
Expand Up @@ -16,7 +16,12 @@

import com.google.api.ClientProto;
import com.google.api.DocumentationRule;
import com.google.api.FieldBehavior;
import com.google.api.FieldBehaviorProto;
import com.google.api.FieldInfo.Format;
import com.google.api.FieldInfoProto;
import com.google.api.HttpRule;
import com.google.api.MethodSettings;
import com.google.api.ResourceDescriptor;
import com.google.api.ResourceProto;
import com.google.api.generator.engine.ast.TypeNode;
Expand Down Expand Up @@ -47,6 +52,7 @@
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.longrunning.OperationInfo;
Expand Down Expand Up @@ -493,6 +499,7 @@ public static List<Service> parseService(
messageTypes,
resourceNames,
serviceConfigOpt,
serviceYamlProtoOpt,
outputArgResourceNames,
transport))
.build();
Expand Down Expand Up @@ -683,9 +690,15 @@ static List<Method> parseMethods(
Map<String, Message> messageTypes,
Map<String, ResourceName> resourceNames,
Optional<GapicServiceConfig> serviceConfigOpt,
Optional<com.google.api.Service> serviceYamlProtoOpt,
Set<ResourceName> outputArgResourceNames,
Transport transport) {
List<Method> methods = new ArrayList<>();

// Parse the serviceYaml for autopopulated methods and fields once and put into a map
ImmutableMap<String, List<String>> autoPopulatedMethodsWithFields =
parseAutoPopulatedMethodsAndFields(serviceYamlProtoOpt);

for (MethodDescriptor protoMethod : serviceDescriptor.getMethods()) {
// Parse the method.
TypeNode inputType = TypeParser.parseType(protoMethod.getInputType());
Expand All @@ -699,6 +712,12 @@ static List<Method> parseMethods(
}
}

// Associate the autopopulated fields with the correct method
List<String> autoPopulatedFields = new ArrayList<>();
if (autoPopulatedMethodsWithFields.containsKey(protoMethod.getFullName())) {
autoPopulatedFields = autoPopulatedMethodsWithFields.get(protoMethod.getFullName());
}

boolean isDeprecated = false;
if (protoMethod.getOptions().hasDeprecated()) {
isDeprecated = protoMethod.getOptions().getDeprecated();
Expand Down Expand Up @@ -743,6 +762,7 @@ static List<Method> parseMethods(
resourceNames,
outputArgResourceNames))
.setHttpBindings(httpBindings)
.setAutoPopulatedFields(autoPopulatedFields)
.setRoutingHeaderRule(routingHeaderRule)
.setIsBatching(isBatching)
.setPageSizeFieldName(parsePageSizeFieldName(protoMethod, messageTypes, transport))
Expand Down Expand Up @@ -970,6 +990,8 @@ private static Field parseField(
FieldOptions fieldOptions = fieldDescriptor.getOptions();
MessageOptions messageOptions = messageDescriptor.getOptions();
ResourceReference resourceReference = null;
boolean isRequired = false;
Format fieldInfoFormat = null;
if (fieldOptions.hasExtension(ResourceProto.resourceReference)) {
com.google.api.ResourceReference protoResourceReference =
fieldOptions.getExtension(ResourceProto.resourceReference);
Expand Down Expand Up @@ -1000,6 +1022,16 @@ private static Field parseField(
}
}

if (fieldOptions.hasExtension(FieldInfoProto.fieldInfo)) {
fieldInfoFormat = fieldOptions.getExtension(FieldInfoProto.fieldInfo).getFormat();
}
if (fieldOptions.getExtensionCount(FieldBehaviorProto.fieldBehavior) > 0) {
blakeli0 marked this conversation as resolved.
Show resolved Hide resolved
if (fieldOptions
.getExtension(FieldBehaviorProto.fieldBehavior)
.contains(FieldBehavior.REQUIRED)) ;
isRequired = true;
}

Field.Builder fieldBuilder = Field.builder();
if (fieldDescriptor.getFile().toProto().hasSourceCodeInfo()) {
SourceCodeInfoLocation protoFieldLocation =
Expand Down Expand Up @@ -1030,6 +1062,8 @@ private static Field parseField(
fieldDescriptor.getContainingOneof() != null
&& fieldDescriptor.getContainingOneof().isSynthetic())
.setIsRepeated(fieldDescriptor.isRepeated())
.setIsRequired(isRequired)
.setFieldInfoFormat(fieldInfoFormat)
.setIsMap(fieldDescriptor.isMapField())
.setResourceReference(resourceReference)
.build();
Expand Down Expand Up @@ -1124,4 +1158,27 @@ static String parseNestedProtoTypeName(String fullyQualifiedName) {
.collect(Collectors.toList());
return String.join(".", nestedTypeComponents);
}

/**
* Converts a serviceYaml file to a map of methods and autopopulated fields TODO: Confirm whether
* or not wildcards need to be supported. If so, update this logic.
*/
@VisibleForTesting
static ImmutableMap<String, List<String>> parseAutoPopulatedMethodsAndFields(
Optional<com.google.api.Service> serviceYamlProtoOpt) {
ImmutableMap.Builder<String, List<String>> autoPopulatedMethodsWithFieldsBuilder =
ImmutableMap.builder();
if (serviceYamlProtoOpt.isPresent()
&& serviceYamlProtoOpt.get().hasPublishing()
&& serviceYamlProtoOpt.get().getPublishing().getMethodSettingsList().size() > 0) {
for (MethodSettings methodSettings :
serviceYamlProtoOpt.get().getPublishing().getMethodSettingsList()) {
if (methodSettings.getAutoPopulatedFieldsCount() > 0) {
autoPopulatedMethodsWithFieldsBuilder.put(
methodSettings.getSelector(), methodSettings.getAutoPopulatedFieldsList());
}
}
}
return autoPopulatedMethodsWithFieldsBuilder.build();
}
}
Expand Up @@ -568,6 +568,7 @@ public void createSimpleMessage_containsMessagesEnumsAndResourceName() {
"EchoRequest.newBuilder().setName("
+ "FoobarName.ofProjectFoobarName(\"[PROJECT]\", \"[FOOBAR]\").toString())"
+ ".setParent(FoobarName.ofProjectFoobarName(\"[PROJECT]\", \"[FOOBAR]\").toString())"
+ ".setRequestId(\"requestId693933066\")"
+ ".setSeverity(Severity.forNumber(0))"
+ ".setFoobar(Foobar.newBuilder().build()).build()",
writerVisitor.write());
Expand Down
Expand Up @@ -516,6 +516,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setRequestId("requestId693933066")
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
Expand Down Expand Up @@ -545,6 +546,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setRequestId("requestId693933066")
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
Expand All @@ -570,7 +572,11 @@ public class EchoClient implements BackgroundResource {
* // https://cloud.google.com/java/docs/setup#configure_endpoints_for_the_client_library
* try (EchoClient echoClient = EchoClient.create()) {
* ExpandRequest request =
* ExpandRequest.newBuilder().setContent("content951530617").setInfo("info3237038").build();
* ExpandRequest.newBuilder()
* .setContent("content951530617")
* .setInfo("info3237038")
* .setRequestId("requestId693933066")
* .build();
* ServerStream<EchoResponse> stream = echoClient.expandCallable().call(request);
* for (EchoResponse response : stream) {
* // Do something when a response is received.
Expand Down Expand Up @@ -616,6 +622,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setRequestId("requestId693933066")
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
Expand Down Expand Up @@ -643,6 +650,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setRequestId("requestId693933066")
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
Expand Down Expand Up @@ -673,6 +681,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setRequestId("requestId693933066")
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
Expand Down Expand Up @@ -1081,6 +1090,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setRequestId("requestId693933066")
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
Expand Down Expand Up @@ -1110,6 +1120,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setRequestId("requestId693933066")
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
Expand Down