Skip to content

Commit 5a8f1c2

Browse files
committed
Merge branch '2.9' into 2.10
2 parents c4b9d90 + 48794b4 commit 5a8f1c2

File tree

6 files changed

+141
-143
lines changed

6 files changed

+141
-143
lines changed

protobuf/src/main/java/com/fasterxml/jackson/dataformat/protobuf/schema/NativeProtobufSchema.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public ProtobufSchema forType(String messageTypeName)
6464
+"') has no message type with name '"+messageTypeName+"': known types: "
6565
+getMessageNames());
6666
}
67-
return new ProtobufSchema(this, TypeResolver.construct(_nativeTypes).resolve(msg));
67+
return new ProtobufSchema(this, TypeResolver.resolve(_nativeTypes, msg));
6868
}
6969

7070
/**
@@ -78,7 +78,7 @@ public ProtobufSchema forFirstType()
7878
throw new IllegalArgumentException("Protobuf schema definition (name '"+_name
7979
+"') contains no message type definitions");
8080
}
81-
return new ProtobufSchema(this, TypeResolver.construct(_nativeTypes).resolve(msg));
81+
return new ProtobufSchema(this, TypeResolver.resolve(_nativeTypes, msg));
8282
}
8383

8484
public List<String> getMessageNames() {

protobuf/src/main/java/com/fasterxml/jackson/dataformat/protobuf/schema/TypeResolver.java

Lines changed: 98 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,63 @@ public class TypeResolver
1414
{
1515
private final TypeResolver _parent;
1616

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;
1829

1930
private Map<String,ProtobufEnum> _enumTypes;
2031

32+
/**
33+
* Mapping from names of types within this scope (with possible prefix as
34+
* necessary) into resolve types.
35+
*/
2136
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,
2439
Map<String,ProtobufEnum> enums)
2540
{
2641
_parent = p;
27-
if (enums == null) {
28-
enums = Collections.emptyMap();
29-
}
42+
_contextName = name;
3043
_enumTypes = enums;
31-
if (nativeMsgs == null) {
32-
nativeMsgs = Collections.emptyMap();
44+
if (declaredMsgs == null) {
45+
declaredMsgs = Collections.emptyMap();
3346
}
34-
_nativeMessageTypes = nativeMsgs;
47+
_declaredMessageTypes = declaredMsgs;
3548
_resolvedMessageTypes = Collections.emptyMap();
3649
}
3750

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);
4061
}
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)
4371
{
4472
Map<String,MessageElement> nativeMessages = null;
45-
Map<String,ProtobufEnum> enumTypes = null;
73+
Map<String,ProtobufEnum> enumTypes = new LinkedHashMap<>();
4674

4775
for (TypeElement nt : nativeTypes) {
4876
if (nt instanceof MessageElement) {
@@ -51,16 +79,25 @@ protected static TypeResolver construct(TypeResolver parent, Collection<TypeElem
5179
}
5280
nativeMessages.put(nt.name(), (MessageElement) nt);
5381
} 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);
5687
}
57-
enumTypes.put(nt.name(), _constructEnum((EnumElement) nt));
5888
} // no other known types?
5989
}
60-
return new TypeResolver(parent, nativeMessages, enumTypes);
90+
return new TypeResolver(parent, localName, nativeMessages, enumTypes);
6191
}
6292

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)
64101
{
65102
final Map<String,Integer> valuesByName = new LinkedHashMap<String,Integer>();
66103
boolean standard = true;
@@ -80,32 +117,15 @@ protected static ProtobufEnum _constructEnum(EnumElement nativeEnum)
80117
return new ProtobufEnum(name, valuesByName, standard);
81118
}
82119

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-
97120
protected ProtobufMessage _resolve(MessageElement rawType)
98121
{
99122
List<FieldElement> rawFields = rawType.fields();
100123
ProtobufField[] resolvedFields = new ProtobufField[rawFields.size()];
101124

102125
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+
109129
// and then resolve fields
110130
int ix = 0;
111131
for (FieldElement f : rawFields) {
@@ -125,15 +145,14 @@ protected ProtobufMessage _resolve(MessageElement rawType)
125145
pbf = resolvedF;
126146
} else {
127147
// or, barring that local but as of yet unresolved message?
128-
MessageElement nativeMt = _nativeMessageTypes.get(typeStr);
148+
MessageElement nativeMt = _declaredMessageTypes.get(typeStr);
129149
if (nativeMt != null) {
130-
pbf = new ProtobufField(f,
131-
TypeResolver.construct(this, nativeMt.nestedElements())._resolve(nativeMt));
150+
pbf = new ProtobufField(f, resolve(this, nativeMt));
132151
} else {
133152
// If not, perhaps parent might have an answer?
134-
resolvedF = _parent._findAnyResolved(f, typeStr);
153+
resolvedF = (_parent == null) ? null : _parent._findAnyResolved(f, typeStr);
135154
if (resolvedF != null) {
136-
pbf = resolvedF;
155+
pbf = resolvedF;
137156
} else {
138157
// Ok, we are out of options here...
139158
StringBuilder enumStr = _knownEnums(new StringBuilder());
@@ -164,31 +183,42 @@ protected ProtobufMessage _resolve(MessageElement rawType)
164183
return message;
165184
}
166185

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);
172194
}
173-
return msg;
174195
}
175196

176197
private ProtobufField _findAnyResolved(FieldElement nativeField, String typeStr)
177198
{
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;
184203
}
185-
if (_parent != null) {
186-
return _parent._findAnyResolved(nativeField, typeStr);
204+
f = r._findAndResolve(nativeField, typeStr);
205+
if (f != null) {
206+
return f;
187207
}
188208
}
189-
return f;
209+
210+
return null;
190211
}
191212

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+
192222
private StringBuilder _knownEnums(StringBuilder sb) {
193223
if (_parent != null) {
194224
sb = _parent._knownEnums(sb);
@@ -206,7 +236,7 @@ private StringBuilder _knownMsgs(StringBuilder sb) {
206236
if (_parent != null) {
207237
sb = _parent._knownMsgs(sb);
208238
}
209-
for (String name : _nativeMessageTypes.keySet()) {
239+
for (String name : _declaredMessageTypes.keySet()) {
210240
if (sb.length() > 0) {
211241
sb.append(", ");
212242
}
@@ -227,4 +257,12 @@ private ProtobufField _findLocalResolved(FieldElement nativeField, String typeSt
227257
}
228258
return null;
229259
}
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+
}
230268
}

protobuf/src/test/java/com/fasterxml/jackson/dataformat/protobuf/failing/SchemGenForSelfRef140Test.java

Lines changed: 0 additions & 76 deletions
This file was deleted.
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.fasterxml.jackson.dataformat.protobuf.failing;
1+
package com.fasterxml.jackson.dataformat.protobuf.schema;
22

33
import java.util.List;
44

@@ -10,12 +10,12 @@ public class ReadCyclicSchema140Test extends ProtobufTestBase
1010
final protected static String PROTOC_CYCLIC =
1111
"message Front {\n"
1212
+" optional string id = 1;\n"
13-
+" optional Back id = 2;\n"
13+
+" optional Back next = 2;\n"
1414
+"}\n"
1515
+"message Back {\n"
1616
+" optional string id = 1;\n"
1717
+" optional string extra = 2;\n"
18-
+" optional Front id = 3;\n"
18+
+" optional Front next = 3;\n"
1919
+"}\n"
2020
;
2121

@@ -26,9 +26,10 @@ public void testCyclicDefinition() throws Exception
2626
List<String> all = schema.getMessageTypes();
2727
assertEquals(2, all.size());
2828
assertEquals("Front", all.get(0));
29-
assertEquals("Back", all.get(0));
29+
assertEquals("Back", all.get(1));
3030
ProtobufMessage msg = schema.getRootType();
31-
assertEquals(3, msg.getFieldCount());
31+
assertEquals("Front", msg.getName());
32+
assertEquals(2, msg.getFieldCount());
3233
ProtobufField f = msg.field("id");
3334
assertNotNull(f);
3435
assertEquals("id", f.name);

0 commit comments

Comments
 (0)