Skip to content

Commit 3e1382f

Browse files
fix: enum value conflict in generated ProtoSchema descriptor. (#469)
* chore: regen readme (#464) autosynth cannot find the source of changes triggered by earlier changes in this repository, or by version upgrades to tools such as linters. * fix: Enum value confict in Proto conversion. Solution is to convert enum types always in enclosing struct type. Co-authored-by: Yoshi Automation Bot <yoshi-automation@google.com>
1 parent 5b6cadd commit 3e1382f

File tree

2 files changed

+41
-44
lines changed

2 files changed

+41
-44
lines changed

google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1alpha2/ProtoSchemaConverter.java

+27-33
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
// protobuf::DescriptorProto
3131
// that can be reconstructed by the backend.
3232
public class ProtoSchemaConverter {
33+
private static String getNameFromFullName(String fullName) {
34+
return fullName.replace('.', '_');
35+
}
36+
3337
private static ProtoSchema convertInternal(
3438
Descriptor input,
3539
Set<String> visitedTypes,
@@ -40,8 +44,8 @@ private static ProtoSchema convertInternal(
4044
if (rootProtoSchema == null) {
4145
rootProtoSchema = resultProto;
4246
}
43-
String protoName = input.getFullName();
44-
protoName = protoName.replace('.', '_');
47+
String protoFullName = input.getFullName();
48+
String protoName = getNameFromFullName(protoFullName);
4549
resultProto.setName(protoName);
4650
Set<String> localEnumTypes = new HashSet<String>();
4751
visitedTypes.add(input.getFullName());
@@ -51,9 +55,9 @@ private static ProtoSchema convertInternal(
5155
if (inputField.getType() == FieldDescriptor.Type.GROUP
5256
|| inputField.getType() == FieldDescriptor.Type.MESSAGE) {
5357
String msgFullName = inputField.getMessageType().getFullName();
54-
msgFullName = msgFullName.replace('.', '_');
58+
String msgName = getNameFromFullName(msgFullName);
5559
if (structTypes.contains(msgFullName)) {
56-
resultField.setTypeName(msgFullName);
60+
resultField.setTypeName(msgName);
5761
} else {
5862
if (visitedTypes.contains(msgFullName)) {
5963
throw new InvalidArgumentException(
@@ -76,42 +80,32 @@ private static ProtoSchema convertInternal(
7680
rootProtoSchema.getNestedType(rootProtoSchema.getNestedTypeCount() - 1).getName());
7781
}
7882
}
83+
7984
if (inputField.getType() == FieldDescriptor.Type.ENUM) {
85+
// For enums, in order to avoid value conflict, we will always define
86+
// a enclosing struct called enum_full_name_E that includes the actual
87+
// enum.
8088
String enumFullName = inputField.getEnumType().getFullName();
81-
// If the enum is defined within the current message, we don't want to
82-
// pull it out to the top since then the same enum values will not be
83-
// allowed if the value collides with other enums.
84-
if (enumFullName.startsWith(input.getFullName())) {
85-
String enumName = inputField.getEnumType().getName();
86-
if (localEnumTypes.contains(enumName)) {
87-
resultField.setTypeName(enumName);
88-
} else {
89-
resultProto.addEnumType(inputField.getEnumType().toProto());
90-
resultField.setTypeName(enumName);
91-
localEnumTypes.add(enumName);
92-
}
89+
String enclosingTypeName = getNameFromFullName(enumFullName) + "_E";
90+
String enumName = inputField.getEnumType().getName();
91+
String actualEnumFullName = enclosingTypeName + "." + enumName;
92+
if (enumTypes.contains(enumFullName)) {
93+
resultField.setTypeName(actualEnumFullName);
9394
} else {
94-
// If the enum is defined elsewhere, then redefine it at the top
95-
// message scope. There is a problem that different enum values might
96-
// be OK when living under its original scope, but when they all live
97-
// in top scope, their values cannot collide. Say if thers A.Color with
98-
// RED and B.Color with RED, if they are redefined here, the RED will
99-
// collide with each other and thus not allowed.
100-
enumFullName = enumFullName.replace('.', '_');
101-
if (enumTypes.contains(enumFullName)) {
102-
resultField.setTypeName(enumFullName);
103-
} else {
104-
EnumDescriptorProto enumType =
105-
inputField.getEnumType().toProto().toBuilder().setName(enumFullName).build();
106-
resultProto.addEnumType(enumType);
107-
resultField.setTypeName(enumFullName);
108-
enumTypes.add(enumFullName);
109-
}
95+
EnumDescriptorProto enumType = inputField.getEnumType().toProto();
96+
resultProto.addNestedType(
97+
DescriptorProto.newBuilder()
98+
.setName(enclosingTypeName)
99+
.addEnumType(enumType.toBuilder().setName(enumName))
100+
.build());
101+
resultField.setTypeName(actualEnumFullName);
102+
enumTypes.add(enumFullName);
110103
}
111104
}
112105
resultProto.addField(resultField);
113106
}
114-
structTypes.add(protoName);
107+
structTypes.add(protoFullName);
108+
115109
return ProtoSchema.newBuilder().setProtoDescriptor(resultProto.build()).build();
116110
}
117111

google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1alpha2/ProtoSchemaConverterTest.java

+14-11
Original file line numberDiff line numberDiff line change
@@ -76,23 +76,26 @@ public void convertSimple() {
7676
+ " number: 8\n"
7777
+ " label: LABEL_OPTIONAL\n"
7878
+ " type: TYPE_ENUM\n"
79-
+ " type_name: \"com_google_cloud_bigquery_storage_test_TestEnum\"\n"
79+
+ " type_name: \"com_google_cloud_bigquery_storage_test_TestEnum_E.TestEnum\"\n"
8080
+ "}\n"
8181
+ "field {\n"
8282
+ " name: \"string_value\"\n"
8383
+ " number: 9\n"
8484
+ " label: LABEL_REQUIRED\n"
8585
+ " type: TYPE_STRING\n"
8686
+ "}\n"
87-
+ "enum_type {\n"
88-
+ " name: \"com_google_cloud_bigquery_storage_test_TestEnum\"\n"
89-
+ " value {\n"
90-
+ " name: \"TestEnum0\"\n"
91-
+ " number: 0\n"
92-
+ " }\n"
93-
+ " value {\n"
94-
+ " name: \"TestEnum1\"\n"
95-
+ " number: 1\n"
87+
+ "nested_type {\n"
88+
+ " name: \"com_google_cloud_bigquery_storage_test_TestEnum_E\"\n"
89+
+ " enum_type {\n"
90+
+ " name: \"TestEnum\"\n"
91+
+ " value {\n"
92+
+ " name: \"TestEnum0\"\n"
93+
+ " number: 0\n"
94+
+ " }\n"
95+
+ " value {\n"
96+
+ " name: \"TestEnum1\"\n"
97+
+ " number: 1\n"
98+
+ " }\n"
9699
+ " }\n"
97100
+ "}\n",
98101
protoSchema.getProtoDescriptor().toString());
@@ -150,7 +153,7 @@ public void convertRecursive() {
150153
Assert.fail("No exception raised");
151154
} catch (InvalidArgumentException e) {
152155
Assert.assertEquals(
153-
"Recursive type is not supported:com.google.cloud.bigquery.storage.test.ContainsRecursive",
156+
"Recursive type is not supported:com.google.cloud.bigquery.storage.test.RecursiveType",
154157
e.getMessage());
155158
}
156159
}

0 commit comments

Comments
 (0)