30
30
// protobuf::DescriptorProto
31
31
// that can be reconstructed by the backend.
32
32
public class ProtoSchemaConverter {
33
+ private static String getNameFromFullName (String fullName ) {
34
+ return fullName .replace ('.' , '_' );
35
+ }
36
+
33
37
private static ProtoSchema convertInternal (
34
38
Descriptor input ,
35
39
Set <String > visitedTypes ,
@@ -40,8 +44,8 @@ private static ProtoSchema convertInternal(
40
44
if (rootProtoSchema == null ) {
41
45
rootProtoSchema = resultProto ;
42
46
}
43
- String protoName = input .getFullName ();
44
- protoName = protoName . replace ( '.' , '_' );
47
+ String protoFullName = input .getFullName ();
48
+ String protoName = getNameFromFullName ( protoFullName );
45
49
resultProto .setName (protoName );
46
50
Set <String > localEnumTypes = new HashSet <String >();
47
51
visitedTypes .add (input .getFullName ());
@@ -51,9 +55,9 @@ private static ProtoSchema convertInternal(
51
55
if (inputField .getType () == FieldDescriptor .Type .GROUP
52
56
|| inputField .getType () == FieldDescriptor .Type .MESSAGE ) {
53
57
String msgFullName = inputField .getMessageType ().getFullName ();
54
- msgFullName = msgFullName . replace ( '.' , '_' );
58
+ String msgName = getNameFromFullName ( msgFullName );
55
59
if (structTypes .contains (msgFullName )) {
56
- resultField .setTypeName (msgFullName );
60
+ resultField .setTypeName (msgName );
57
61
} else {
58
62
if (visitedTypes .contains (msgFullName )) {
59
63
throw new InvalidArgumentException (
@@ -76,42 +80,32 @@ private static ProtoSchema convertInternal(
76
80
rootProtoSchema .getNestedType (rootProtoSchema .getNestedTypeCount () - 1 ).getName ());
77
81
}
78
82
}
83
+
79
84
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.
80
88
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 );
93
94
} 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 );
110
103
}
111
104
}
112
105
resultProto .addField (resultField );
113
106
}
114
- structTypes .add (protoName );
107
+ structTypes .add (protoFullName );
108
+
115
109
return ProtoSchema .newBuilder ().setProtoDescriptor (resultProto .build ()).build ();
116
110
}
117
111
0 commit comments