@@ -14,35 +14,63 @@ public class TypeResolver
14
14
{
15
15
private final TypeResolver _parent ;
16
16
17
- private Map <String ,MessageElement > _nativeMessageTypes ;
17
+ /**
18
+ * For nested definitions we also need to know the name this context
19
+ * has (not used for root): this is unqualified name (that is, only
20
+ * name for context, not path)
21
+ */
22
+ private final String _contextName ;
23
+
24
+ /**
25
+ * Mapping from types declared within this scope (root types for
26
+ * root resolver; nested types for child resolvers)
27
+ */
28
+ private Map <String ,MessageElement > _declaredMessageTypes ;
18
29
19
30
private Map <String ,ProtobufEnum > _enumTypes ;
20
31
32
+ /**
33
+ * Mapping from names of types within this scope (with possible prefix as
34
+ * necessary) into resolve types.
35
+ */
21
36
private Map <String ,ProtobufMessage > _resolvedMessageTypes ;
22
-
23
- protected TypeResolver (TypeResolver p , Map <String ,MessageElement > nativeMsgs ,
37
+
38
+ protected TypeResolver (TypeResolver p , String name , Map <String ,MessageElement > declaredMsgs ,
24
39
Map <String ,ProtobufEnum > enums )
25
40
{
26
41
_parent = p ;
27
- if (enums == null ) {
28
- enums = Collections .emptyMap ();
29
- }
42
+ _contextName = name ;
30
43
_enumTypes = enums ;
31
- if (nativeMsgs == null ) {
32
- nativeMsgs = Collections .emptyMap ();
44
+ if (declaredMsgs == null ) {
45
+ declaredMsgs = Collections .emptyMap ();
33
46
}
34
- _nativeMessageTypes = nativeMsgs ;
47
+ _declaredMessageTypes = declaredMsgs ;
35
48
_resolvedMessageTypes = Collections .emptyMap ();
36
49
}
37
50
38
- public static TypeResolver construct (Collection <TypeElement > nativeTypes ) {
39
- return construct (null , nativeTypes );
51
+ /**
52
+ * Main entry method for public API, for resolving specific root-level type and other
53
+ * types it depends on.
54
+ */
55
+ public static ProtobufMessage resolve (Collection <TypeElement > nativeTypes , MessageElement rawType ) {
56
+ final TypeResolver rootR = construct (null , null , nativeTypes );
57
+ // Important: parent context for "root types", but child context for nested; further,
58
+ // resolution happens in "child" context to allow proper referencing
59
+ return TypeResolver .construct (rootR , rawType .name (), rawType .nestedElements ())
60
+ ._resolve (rawType );
40
61
}
41
-
42
- protected static TypeResolver construct (TypeResolver parent , Collection <TypeElement > nativeTypes )
62
+
63
+ protected ProtobufMessage resolve (TypeResolver parent , MessageElement rawType )
64
+ {
65
+ return TypeResolver .construct (this , rawType .name (), rawType .nestedElements ())
66
+ ._resolve (rawType );
67
+ }
68
+
69
+ protected static TypeResolver construct (TypeResolver parent , String localName ,
70
+ Collection <TypeElement > nativeTypes )
43
71
{
44
72
Map <String ,MessageElement > nativeMessages = null ;
45
- Map <String ,ProtobufEnum > enumTypes = null ;
73
+ Map <String ,ProtobufEnum > enumTypes = new LinkedHashMap <>() ;
46
74
47
75
for (TypeElement nt : nativeTypes ) {
48
76
if (nt instanceof MessageElement ) {
@@ -51,16 +79,25 @@ protected static TypeResolver construct(TypeResolver parent, Collection<TypeElem
51
79
}
52
80
nativeMessages .put (nt .name (), (MessageElement ) nt );
53
81
} else if (nt instanceof EnumElement ) {
54
- if (enumTypes == null ) {
55
- enumTypes = new LinkedHashMap <String ,ProtobufEnum >();
82
+ final ProtobufEnum enumType = constructEnum ((EnumElement ) nt );
83
+ enumTypes .put (nt .name (), enumType );
84
+ // ... and don't forget parent scopes!
85
+ if (parent != null ) {
86
+ parent .addEnumType (_scopedName (localName , nt .name ()), enumType );
56
87
}
57
- enumTypes .put (nt .name (), _constructEnum ((EnumElement ) nt ));
58
88
} // no other known types?
59
89
}
60
- return new TypeResolver (parent , nativeMessages , enumTypes );
90
+ return new TypeResolver (parent , localName , nativeMessages , enumTypes );
61
91
}
62
92
63
- protected static ProtobufEnum _constructEnum (EnumElement nativeEnum )
93
+ protected void addEnumType (String name , ProtobufEnum enumType ) {
94
+ _enumTypes .put (name , enumType );
95
+ if (_parent != null ) {
96
+ _parent .addEnumType (_scopedName (name ), enumType );
97
+ }
98
+ }
99
+
100
+ protected static ProtobufEnum constructEnum (EnumElement nativeEnum )
64
101
{
65
102
final Map <String ,Integer > valuesByName = new LinkedHashMap <String ,Integer >();
66
103
boolean standard = true ;
@@ -80,32 +117,15 @@ protected static ProtobufEnum _constructEnum(EnumElement nativeEnum)
80
117
return new ProtobufEnum (name , valuesByName , standard );
81
118
}
82
119
83
- public ProtobufMessage resolve (MessageElement rawType )
84
- {
85
- ProtobufMessage msg = _findResolvedMessage (rawType .name ());
86
- if (msg != null ) {
87
- return msg ;
88
- }
89
- /* Since MessageTypes can contain other type definitions, it is
90
- * important that we actually create a new context, that is,
91
- * new TypeResolver instance, and call resolution on that.
92
- */
93
- return TypeResolver .construct (this , rawType .nestedElements ())
94
- ._resolve (rawType );
95
- }
96
-
97
120
protected ProtobufMessage _resolve (MessageElement rawType )
98
121
{
99
122
List <FieldElement > rawFields = rawType .fields ();
100
123
ProtobufField [] resolvedFields = new ProtobufField [rawFields .size ()];
101
124
102
125
ProtobufMessage message = new ProtobufMessage (rawType .name (), resolvedFields );
103
- // Important: add type itself as (being) resolved, to allow for self-refs:
104
- if (_resolvedMessageTypes .isEmpty ()) {
105
- _resolvedMessageTypes = new HashMap <String ,ProtobufMessage >();
106
- }
107
- _resolvedMessageTypes .put (rawType .name (), message );
108
-
126
+ // Important: add type itself as (being) resolved, to allow for self- and cyclic refs
127
+ _parent .addResolvedMessageType (rawType .name (), message );
128
+
109
129
// and then resolve fields
110
130
int ix = 0 ;
111
131
for (FieldElement f : rawFields ) {
@@ -125,15 +145,14 @@ protected ProtobufMessage _resolve(MessageElement rawType)
125
145
pbf = resolvedF ;
126
146
} else {
127
147
// or, barring that local but as of yet unresolved message?
128
- MessageElement nativeMt = _nativeMessageTypes .get (typeStr );
148
+ MessageElement nativeMt = _declaredMessageTypes .get (typeStr );
129
149
if (nativeMt != null ) {
130
- pbf = new ProtobufField (f ,
131
- TypeResolver .construct (this , nativeMt .nestedElements ())._resolve (nativeMt ));
150
+ pbf = new ProtobufField (f , resolve (this , nativeMt ));
132
151
} else {
133
152
// If not, perhaps parent might have an answer?
134
- resolvedF = _parent ._findAnyResolved (f , typeStr );
153
+ resolvedF = ( _parent == null ) ? null : _parent ._findAnyResolved (f , typeStr );
135
154
if (resolvedF != null ) {
136
- pbf = resolvedF ;
155
+ pbf = resolvedF ;
137
156
} else {
138
157
// Ok, we are out of options here...
139
158
StringBuilder enumStr = _knownEnums (new StringBuilder ());
@@ -164,31 +183,42 @@ protected ProtobufMessage _resolve(MessageElement rawType)
164
183
return message ;
165
184
}
166
185
167
- private ProtobufMessage _findResolvedMessage (String typeStr )
168
- {
169
- ProtobufMessage msg = _resolvedMessageTypes .get (typeStr );
170
- if ((msg == null ) && (_parent !=null )) {
171
- return _parent ._findResolvedMessage (typeStr );
186
+ protected void addResolvedMessageType (String name , ProtobufMessage toResolve ) {
187
+ if (_resolvedMessageTypes .isEmpty ()) {
188
+ _resolvedMessageTypes = new HashMap <String ,ProtobufMessage >();
189
+ }
190
+ _resolvedMessageTypes .put (name , toResolve );
191
+ // But also: for parent scopes
192
+ if (_parent != null ) {
193
+ _parent .addResolvedMessageType (_scopedName (name ), toResolve );
172
194
}
173
- return msg ;
174
195
}
175
196
176
197
private ProtobufField _findAnyResolved (FieldElement nativeField , String typeStr )
177
198
{
178
- ProtobufField f = _findLocalResolved (nativeField , typeStr );
179
- if (f == null ) {
180
- MessageElement nativeMt = _nativeMessageTypes .get (typeStr );
181
- if (nativeMt != null ) {
182
- return new ProtobufField (nativeField ,
183
- TypeResolver .construct (this , nativeMt .nestedElements ())._resolve (nativeMt ));
199
+ for (TypeResolver r = this ; r != null ; r = r ._parent ) {
200
+ ProtobufField f = r ._findLocalResolved (nativeField , typeStr );
201
+ if (f != null ) {
202
+ return f ;
184
203
}
185
- if (_parent != null ) {
186
- return _parent ._findAnyResolved (nativeField , typeStr );
204
+ f = r ._findAndResolve (nativeField , typeStr );
205
+ if (f != null ) {
206
+ return f ;
187
207
}
188
208
}
189
- return f ;
209
+
210
+ return null ;
190
211
}
191
212
213
+ private ProtobufField _findAndResolve (FieldElement nativeField , String typeStr )
214
+ {
215
+ MessageElement nativeMt = _declaredMessageTypes .get (typeStr );
216
+ if (nativeMt != null ) {
217
+ return new ProtobufField (nativeField , resolve (this , nativeMt ));
218
+ }
219
+ return null ;
220
+ }
221
+
192
222
private StringBuilder _knownEnums (StringBuilder sb ) {
193
223
if (_parent != null ) {
194
224
sb = _parent ._knownEnums (sb );
@@ -206,7 +236,7 @@ private StringBuilder _knownMsgs(StringBuilder sb) {
206
236
if (_parent != null ) {
207
237
sb = _parent ._knownMsgs (sb );
208
238
}
209
- for (String name : _nativeMessageTypes .keySet ()) {
239
+ for (String name : _declaredMessageTypes .keySet ()) {
210
240
if (sb .length () > 0 ) {
211
241
sb .append (", " );
212
242
}
@@ -227,4 +257,12 @@ private ProtobufField _findLocalResolved(FieldElement nativeField, String typeSt
227
257
}
228
258
return null ;
229
259
}
260
+
261
+ private final String _scopedName (String localName ) {
262
+ return _scopedName (_contextName , localName );
263
+ }
264
+
265
+ private final static String _scopedName (String contextName , String localName ) {
266
+ return new StringBuilder (contextName ).append ('.' ).append (localName ).toString ();
267
+ }
230
268
}
0 commit comments