Skip to content
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
39 changes: 36 additions & 3 deletions src/main/java/com/google/api/generator/gapic/model/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.annotation.Nullable;

@AutoValue
Expand All @@ -33,6 +34,12 @@ public abstract class Message {
// a specific field.
public abstract ImmutableList<Field> fields();

// String :: number value map for enums.
// TODO(unsupported): Consider making enums a separate POJO. However, that would require
// passing in a map of Message and another map of Enum types, which is not needed for
// 99.99% of protobuf generation.
public abstract ImmutableMap<String, Integer> enumValues();

public abstract TypeNode type();

public abstract ImmutableMap<String, Field> fieldMap();
Expand All @@ -49,6 +56,10 @@ public abstract class Message {

public abstract Builder toBuilder();

public boolean isEnum() {
return !enumValues().isEmpty();
}

public boolean hasResource() {
return resource() != null;
}
Expand All @@ -66,7 +77,11 @@ public Field findAndUnwrapFirstRepeatedField() {
}

public static Builder builder() {
return new AutoValue_Message.Builder().setOuterNestedTypes(Collections.emptyList());
return new AutoValue_Message.Builder()
.setOuterNestedTypes(Collections.emptyList())
.setFields(Collections.emptyList())
.setFieldMap(Collections.emptyMap())
.setEnumValues(Collections.emptyMap());
}

@AutoValue.Builder
Expand All @@ -75,6 +90,15 @@ public abstract static class Builder {

public abstract Builder setFields(List<Field> fields);

public Builder setEnumValues(List<String> names, List<Integer> numbers) {
return setEnumValues(
IntStream.range(0, names.size())
.boxed()
.collect(Collectors.toMap(i -> names.get(i), i -> numbers.get(i))));
}

public abstract Builder setEnumValues(Map<String, Integer> enumValues);

public abstract Builder setType(TypeNode type);

public abstract Builder setResource(ResourceName resource);
Expand All @@ -85,11 +109,20 @@ public abstract static class Builder {

abstract ImmutableList<Field> fields();

abstract ImmutableMap<String, Integer> enumValues();

abstract Message autoBuild();

public Message build() {
setFieldMap(fields().stream().collect(Collectors.toMap(f -> f.name(), f -> f)));
return autoBuild();
Message message = autoBuild();
if (!message.fields().isEmpty()) {
message =
message
.toBuilder()
.setFieldMap(fields().stream().collect(Collectors.toMap(f -> f.name(), f -> f)))
.autoBuild();
}
return message;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
import com.google.protobuf.DescriptorProtos.ServiceOptions;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.DescriptorValidationException;
import com.google.protobuf.Descriptors.EnumDescriptor;
import com.google.protobuf.Descriptors.EnumValueDescriptor;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.MethodDescriptor;
Expand Down Expand Up @@ -121,6 +123,7 @@ public static GapicContext parse(CodeGeneratorRequest request) {
// While this takes an extra pass through the protobufs, the extra time is relatively trivial
// and is worth the larger reduced maintenance cost.
Map<String, Message> messages = parseMessages(request, outputResourceReferencesSeen);

Map<String, ResourceName> resourceNames = parseResourceNames(request);
messages = updateResourceNamesInMessages(messages, resourceNames.values());

Expand Down Expand Up @@ -343,6 +346,20 @@ public static Map<String, Message> parseMessages(
for (Descriptor messageDescriptor : fileDescriptor.getMessageTypes()) {
messages.putAll(parseMessages(messageDescriptor, outputResourceReferencesSeen));
}
// We treat enums as messages since we primarily care only about the type representation.
for (EnumDescriptor enumDescriptor : fileDescriptor.getEnumTypes()) {
String name = enumDescriptor.getName();
List<EnumValueDescriptor> valueDescriptors = enumDescriptor.getValues();
messages.put(
name,
Message.builder()
.setType(TypeParser.parseType(enumDescriptor))
.setName(name)
.setEnumValues(
valueDescriptors.stream().map(v -> v.getName()).collect(Collectors.toList()),
valueDescriptors.stream().map(v -> v.getNumber()).collect(Collectors.toList()))
.build());
}
return messages;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ public static TypeNode parseType(@Nonnull Descriptor messageDescriptor) {
return TypeNode.withReference(parseMessageReference(messageDescriptor));
}

public static TypeNode parseType(@Nonnull EnumDescriptor enumDescriptor) {
return TypeNode.withReference(parseEnumReference(enumDescriptor));
}

public static String getPackage(FileDescriptor fileDescriptor) {
String pakkage = fileDescriptor.getOptions().getJavaPackage();
if (Strings.isNullOrEmpty(pakkage)) {
Expand Down Expand Up @@ -177,8 +181,29 @@ static Reference parseMessageReference(@Nonnull Descriptor messageDescriptor) {
static Reference parseEnumReference(@Nonnull EnumDescriptor enumDescriptor) {
// This is similar to parseMessageReference, but we make it a separate method because
// EnumDescriptor and Descriptor are sibling types.
FileOptions fileOptions = enumDescriptor.getFile().getOptions();
String javaOuterClassname =
fileOptions.hasJavaOuterClassname() ? fileOptions.getJavaOuterClassname() : null;

// Some older protos don't have java_multiple_files option set, and don't have the outer
// classname option set either.
if (!fileOptions.getJavaMultipleFiles() && !fileOptions.hasJavaOuterClassname()) {
String fullFilePath = JavaStyle.toUpperCamelCase(enumDescriptor.getFile().getName());
javaOuterClassname =
JavaStyle.toUpperCamelCase(
fullFilePath.substring(
fullFilePath.lastIndexOf("/") + 1, fullFilePath.lastIndexOf(".")));
}

boolean hasJavaOuterClass =
!Strings.isNullOrEmpty(javaOuterClassname) && !fileOptions.getJavaMultipleFiles();
List<String> outerNestedTypeNames = new ArrayList<>();
if (hasJavaOuterClass) {
outerNestedTypeNames.add(javaOuterClassname);
}

Descriptor containingType = enumDescriptor.getContainingType();

// Handles nesting.
while (containingType != null) {
// Outermost type in the nested type hierarchy lies at index 0.
Expand All @@ -194,11 +219,18 @@ static Reference parseEnumReference(@Nonnull EnumDescriptor enumDescriptor) {
.setEnclosingClassNames(outerNestedTypeNames)
.build();
String protoPackage = enumDescriptor.getFile().getPackage();
String enumFullName = enumDescriptor.getFullName();
if (hasJavaOuterClass) {
enumFullName =
String.format(
"%s.%s.%s",
enumFullName.substring(0, enumFullName.lastIndexOf(DOT)),
javaOuterClassname,
enumFullName.substring(enumFullName.lastIndexOf(DOT) + 1));
}

Preconditions.checkState(
enumReference
.fullName()
.replace(pakkage, protoPackage)
.equals(enumDescriptor.getFullName()),
enumReference.fullName().replace(pakkage, protoPackage).equals(enumFullName),
String.format(
"Parsed enum name %s does not match actual name %s",
enumReference.fullName().replace(pakkage, ""),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import com.google.api.generator.engine.ast.Expr;
import com.google.api.generator.engine.ast.TypeNode;
import com.google.api.generator.engine.writer.JavaWriterVisitor;
import com.google.api.generator.gapic.composer.defaultvalue.DefaultValueComposer;
import com.google.api.generator.gapic.model.Field;
import com.google.api.generator.gapic.model.Message;
import com.google.api.generator.gapic.model.ResourceName;
Expand Down Expand Up @@ -273,6 +272,7 @@ public void createSimpleMessage_containsMessagesEnumsAndResourceName() {
"EchoRequest.newBuilder().setName("
+ "FoobarName.ofProjectFoobarName(\"[PROJECT]\", \"[FOOBAR]\").toString())"
+ ".setParent(FoobarName.ofProjectFoobarName(\"[PROJECT]\", \"[FOOBAR]\").toString())"
+ ".setSeverity(Severity.forNumber(0))"
+ ".setFoobar(Foobar.newBuilder().build()).build()",
writerVisitor.write());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
* EchoResponse response = echoClient.echo(request);
Expand All @@ -337,6 +338,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
* ApiFuture<EchoResponse> future = echoClient.echoCallable().futureCall(request);
Expand Down Expand Up @@ -397,6 +399,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
* requestObserver.onNext(request);
Expand All @@ -418,6 +421,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
* bidiStream.send(request);
Expand All @@ -442,6 +446,7 @@ public class EchoClient implements BackgroundResource {
* EchoRequest.newBuilder()
* .setName(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setParent(FoobarName.ofProjectFoobarName("[PROJECT]", "[FOOBAR]").toString())
* .setSeverity(Severity.forNumber(0))
* .setFoobar(Foobar.newBuilder().build())
* .build();
* bidiStream.send(request);
Expand Down
Loading