Skip to content

Commit c6f00f8

Browse files
committed
JsonParser - resolving [] after close array ] is processed. Working toward eliminating 2nd pass through graph.
1 parent db3c717 commit c6f00f8

File tree

8 files changed

+49
-27
lines changed

8 files changed

+49
-27
lines changed

src/main/java/com/cedarsoftware/io/JsonIo.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ public static <T> T toObjects(InputStream in, ReadOptions readOptions, Class<T>
192192
throw new JsonIoException(e);
193193
}
194194
finally {
195-
if (readOptions.isCloseStream()) {
196-
if (jr != null) {
195+
if (jr != null) {
196+
if (readOptions.isCloseStream()) {
197197
jr.close();
198198
}
199199
}

src/main/java/com/cedarsoftware/io/JsonParser.java

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import java.io.IOException;
44
import java.io.Reader;
5-
import java.lang.reflect.Array;
65
import java.math.BigDecimal;
76
import java.math.BigInteger;
87
import java.util.ArrayList;
@@ -77,6 +76,7 @@ protected boolean removeEldestEntry(Map.Entry eldest) {
7776
private int curParseDepth = 0;
7877
private final boolean allowNanAndInfinity;
7978
private final int maxParseDepth;
79+
private final Resolver resolver;
8080
private final ReadOptions readOptions;
8181
private final ReferenceTracker references;
8282

@@ -140,6 +140,7 @@ protected boolean removeEldestEntry(Map.Entry eldest) {
140140

141141
JsonParser(FastReader reader, Resolver resolver) {
142142
input = reader;
143+
this.resolver = resolver;
143144
readOptions = resolver.getReadOptions();
144145
references = resolver.getReferences();
145146
maxParseDepth = readOptions.getMaxDepth();
@@ -298,21 +299,7 @@ private Object readArray(Class<?> suggestedType) throws IOException {
298299
}
299300

300301
--curParseDepth;
301-
302-
// JsonObject jsonArray = new JsonObject();
303-
// jsonArray.setJsonArray(list.toArray());
304-
// jsonArray.setTarget(Array.newInstance(suggestedType == null ? Object.class : suggestedType, list.size()));
305-
// return jsonArray;
306-
if (suggestedType == null || suggestedType == Object.class) {
307-
// No suggested type, so use Object[]
308-
return list.toArray();
309-
} else {
310-
// suggested type is the component type of the array, for example "Person.class" for Person[], "Location.class" for Location[], etc.
311-
JsonObject jsonArray = new JsonObject();
312-
jsonArray.setJsonArray(list.toArray());
313-
jsonArray.setTarget(Array.newInstance(suggestedType, list.size()));
314-
return jsonArray;
315-
}
302+
return resolver.resolveArray(suggestedType, list);
316303
}
317304

318305
/**

src/main/java/com/cedarsoftware/io/JsonReader.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ public JsonReader(ReadOptions readOptions) {
207207
public <T> T readObject(Class<T> rootType) {
208208
T returnValue;
209209
try {
210+
// if (readOptions.isReturningJsonObjects()) {
211+
// rootType = null;
212+
// }
210213
returnValue = (T) parser.readValue(rootType);
211214
if (returnValue == null) {
212215
return null; // easy, done.

src/main/java/com/cedarsoftware/io/ObjectResolver.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public void traverseFields(final JsonObject jsonObj)
9797
handleMissingField(jsonObj, rhs, key);
9898
} //else no handler so ignore.
9999
}
100+
jsonObj.setFinished();
100101
}
101102

102103
/**
@@ -294,7 +295,10 @@ protected void traverseCollection(final JsonObject jsonObj)
294295
col.add(null);
295296
} else if ((special = readWithFactoryIfExists(element, null)) != null) {
296297
col.add(special);
297-
} else if (element instanceof String || element instanceof Boolean || element instanceof Double || element instanceof Long) { // Allow Strings, Booleans, Longs, and Doubles to be "inline" without Java object decoration (@id, @type, etc.)
298+
} else if (element instanceof String || element instanceof Boolean || element instanceof Double || element instanceof Long) {
299+
// TODO: (String) element, shouldn't that cause a ClassCastException when Boolean, Doouble, or Long. Does
300+
// the readWithFactoryIfExists pick up these types? If so, does this line ever get hit?
301+
// Allow Strings, Booleans, Longs, and Doubles to be "inline" without Java object decoration (@id, @type, etc.)
298302
col.add(mayEnumClass == null ? element : Enum.valueOf(mayEnumClass, (String) element));
299303
} else if (element.getClass().isArray()) {
300304
final JsonObject jObj = new JsonObject();
@@ -425,6 +429,7 @@ protected void traverseArray(final JsonObject jsonObj)
425429
}
426430
}
427431
}
432+
jsonObj.setFinished();
428433
jsonObj.clear();
429434
}
430435

src/main/java/com/cedarsoftware/io/Resolver.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ public <T> T traverseJsonObject(JsonObject root) {
242242
}
243243
visited.put(jsonObj, null);
244244
traverseSpecificType(jsonObj);
245+
// jsonObj.setFinished();
245246
}
246247
return (T) root.getTarget();
247248
}
@@ -453,11 +454,11 @@ private Object createInstanceUsingType(JsonObject jsonObj) {
453454

454455
/**
455456
* If a ClassFactory is associated to the passed in Class (clazz), then use the ClassFactory
456-
* to create an instance. If a ClassFactory create the instance, it may optionall load
457+
* to create an instance. If a ClassFactory creates the instance, it may optionally load
457458
* the values into the instance, using the values from the passed in JsonObject. If the
458459
* ClassFactory instance creates AND loads the object, it is indicated on the ClassFactory
459460
* by the isObjectFinal() method returning true. Therefore, the JsonObject instance that is
460-
* loaded, is marked with 'isFinished=true' so that no more process is needed for this instance.
461+
* loaded, is marked with 'isFinished=true' so that no more processing is needed for this instance.
461462
*/
462463
Object createInstanceUsingClassFactory(Class c, JsonObject jsonObj) {
463464
// If a ClassFactory exists for a class, use it to instantiate the class. The ClassFactory
@@ -689,4 +690,20 @@ Object createJavaFromJson(Object root) {
689690
return root;
690691
}
691692
}
693+
694+
Object resolveArray(Class<?> suggestedType, List<Object> list)
695+
{
696+
if (suggestedType == null || suggestedType == Object.class) {
697+
// No suggested type, so use Object[]
698+
return list.toArray();
699+
}
700+
701+
JsonObject jsonArray = new JsonObject();
702+
jsonArray.setTarget(Array.newInstance(suggestedType, list.size()));
703+
jsonArray.setJsonArray(list.toArray());
704+
traverseJsonObject(jsonArray);
705+
jsonArray.setFinished();
706+
// return jsonArray.getTarget();
707+
return jsonArray;
708+
}
692709
}

src/test/java/com/cedarsoftware/io/NoTypeTest.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ void personsTestWithPersonArrayRootAsNativeJsonObjects()
9999
String json = MetaUtils.loadResourceAsString("noTypes/persons.json");
100100

101101
try {
102-
TestUtil.toObjects(json, new ReadOptionsBuilder().returnAsNativeJsonObjects().build(), Person[].class);
102+
Object o = TestUtil.toObjects(json, new ReadOptionsBuilder().returnAsNativeJsonObjects().build(), Person[].class);
103+
System.out.println("o = " + o);
103104
fail();
104105
} catch (JsonIoException e) {
105106
assert e.getMessage().contains("Either use null for root, or set");
@@ -206,10 +207,18 @@ void testStringArrayHeteroItems() {
206207

207208
@Test
208209
void testStringArrayHeteroItemsNoChance() {
209-
String json = "[\"foo\", [null]]";
210+
// String[] does not allow an array as an element
211+
assertThrows(JsonIoException.class, () -> {String[] strings = TestUtil.toObjects("[\"foo\", [null]]", String[].class); });
210212

211-
// String[]
212-
assertThrows(JsonIoException.class, () -> {String[] strings = TestUtil.toObjects(json, String[].class); });
213+
String json = "[\"foo\", null]";
214+
215+
// Explicit String[]
216+
String[] strings = TestUtil.toObjects(json, String[].class);
217+
assert strings.length == 2;
218+
assert strings[0].equals("foo");
219+
assert strings[1] == null;
220+
221+
json = "[\"foo\", [null]]";
213222

214223
// Implied Object[]
215224
Object[] array = TestUtil.toObjects(json, null);

src/test/resources/noTypes/persons.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"age": 50,
55
"salary": 225000.0
66
},
7-
{"name": "Jane",
7+
{
8+
"name": "Jane",
89
"age": 40,
910
"salary": 314000.0
1011
}

user-guide-readOptions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ vectors.
8989
Set the maximum number of `Class` to `Field` mappings and `Class` to filter mappings. This will allow infrequently used `Class's`
9090
to drop from the cache - they will be dynamically added back if not in the cache. Reduces operational memory foot print.
9191
> #### `int` lruSize()
92-
>- [ ] Return the LRU size
92+
>- [ ] Return the LRU size. Default is 1000.
9393
9494
> #### `ReadOptionsBuilder` lruSize(`int size`)
9595
>- [ ] Set the max LRU cache size

0 commit comments

Comments
 (0)