Repository navigation
Conversation
johnjaylward
left a comment
There was a problem hiding this comment.
Overall this looks like a good start, However I'd personally like to see a few more test cases around getting data out and null handling in both the JSONObject and JSONArray streams.
Looking at #673 and #674, I think we should look towards always returning valid JSON value types from the streams. It is something we missed out on with the iterators and prevents people from having a consistent interface.
We should also be sure that the streams themselves (specifically the ones provided as part of the API, not the follow-on calls as part of the tests) do not throw exceptions by using opt operations wherever possible.
| * @return Stream of array elements | ||
| */ | ||
| public Stream<Object> stream() { | ||
| return IntStream.range(0, length()).mapToObj(this::get); |
There was a problem hiding this comment.
I think this should not be this::get and instead should be this::opt. Stream should not throw exceptions, which get will do if a value is null.
We should also be sure to include at least one test case that has null in the array.
There was a problem hiding this comment.
I think this should not be
this::getand instead should bethis::opt. Stream should not throw exceptions, whichgetwill do if a value isnull.We should also be sure to include at least one test case that has
nullin the array.
Seems to be working as is, but not sure why. Test cases are updated, let me know if this code or the tests should still be changed.
There was a problem hiding this comment.
I stepped through the code and that Parser is converting null to JSONObject.NULL, which is expected.
Let's add these 2 additional tests, which are very similar, but add different ways of composing the data instead of just using the parser. This second test shows the issue I was worried about:
@Test
public void testStream_ComposeFromArray() {
@SuppressWarnings("boxing")
Object[] expectedList = new Object[] { 1, 2, 3, true, false, null, "abc", "def", new JSONObject("{ \"a\": \"b\" }"), new JSONArray()};
JSONArray jsonArray = new JSONArray(expectedList);
List<Object> actualList = jsonArray.stream()
.collect(Collectors.toList());
System.out.println(actualList);
assertEquals(actualList.size(), expectedList.length);
for (int i = 0; i < actualList.size(); ++i) {
Object actual = actualList.get(i);
Object expected = expectedList[i];
if (actual instanceof JSONObject) {
assertTrue("Json Object test",((JSONObject) actual).similar(expected));
} else if (actual instanceof JSONArray) {
assertTrue("Json Array test", ((JSONArray) actual).similar(expected));
} else if (JSONObject.NULL.equals(expected)) {
assertTrue("Null test", JSONObject.NULL.equals(actual));
} else {
assertEquals("value test: "+expected, expected, actual);
}
}
} @Test
public void testStream_ComposeFromCode() {
JSONArray jsonArray = new JSONArray();
jsonArray.put(1).put(2).put(3)
.put(true).put(false)
.put((Object)null)
.put("abc").put("def")
.put(new JSONObject("{ \"a\": \"b\" }"))
.put(new JSONArray())
;
@SuppressWarnings("boxing")
Object[] expectedList = new Object[] { 1, 2, 3, true, false, null, "abc", "def", new JSONObject("{ \"a\": \"b\" }"), new JSONArray()};
List<Object> actualList = jsonArray.stream()
.collect(Collectors.toList());
System.out.println(actualList);
assertEquals(actualList.size(), expectedList.length);
for (int i = 0; i < actualList.size(); ++i) {
Object actual = actualList.get(i);
Object expected = expectedList[i];
if (actual instanceof JSONObject) {
assertTrue("Json Object test",((JSONObject) actual).similar(expected));
} else if (actual instanceof JSONArray) {
assertTrue("Json Array test", ((JSONArray) actual).similar(expected));
} else if (JSONObject.NULL.equals(expected)) {
assertTrue("Null test", JSONObject.NULL.equals(actual));
} else {
assertEquals("value test: "+expected, expected, actual);
}
}
}There was a problem hiding this comment.
Added tests.
Replaced this::get with this::opt
| * @version 2016-08-15 | ||
| */ | ||
| public class JSONObject { | ||
| public class JSONObject implements Iterable<String> { |
There was a problem hiding this comment.
I'm not sure this is the best Iterable<> that could have been chosen.
Would it make more sense to implement this closer to the Map<>.entrySet()? Something like: public class JSONObject implements Iterable<Map.Entry<String, Object>>?
Or maybe even better would be to keep it very similar to Map<> and not have it directly implement Iterable<> at all. Instead offer similar functions that the Map interface does:
keySetentrySetvalues
Each of those methods would return proper Iterable implementations.
There was a problem hiding this comment.
Implementation now streams entrySet() without Iterable<>.
| JSONArray jsonArray = new JSONArray(data); | ||
|
|
||
| // Get employees from the engineering dept | ||
| List<String> actualList = StreamSupport.stream(jsonArray.spliterator(), false) |
There was a problem hiding this comment.
This test doesn't seem to be testing the new Stream method. It appears to only be testing Iteratable<>.spliterator() method.
This is a valid test, but I don't think this is doing the coverage that you wanted for the new method.
There was a problem hiding this comment.
Replaced with new tests
| public void testStream_1_3_2() { | ||
| JSONArray jsonArray = null; | ||
|
|
||
| assertThrows(NullPointerException.class, () -> { |
There was a problem hiding this comment.
I don't think this test is adding anything here. It seems obvious that an NPE would be thrown in this case.
| public void test_2_3_2() { | ||
| JSONObject jsonObject = null; | ||
|
|
||
| assertThrows(NullPointerException.class, () -> { |
There was a problem hiding this comment.
I don't think this test is adding anything here. It seems obvious that an NPE would be thrown in this case.
| * @return Stream of array elements | ||
| */ | ||
| public Stream<Object> stream() { | ||
| return IntStream.range(0, length()).mapToObj(this::get); |
There was a problem hiding this comment.
I stepped through the code and that Parser is converting null to JSONObject.NULL, which is expected.
Let's add these 2 additional tests, which are very similar, but add different ways of composing the data instead of just using the parser. This second test shows the issue I was worried about:
@Test
public void testStream_ComposeFromArray() {
@SuppressWarnings("boxing")
Object[] expectedList = new Object[] { 1, 2, 3, true, false, null, "abc", "def", new JSONObject("{ \"a\": \"b\" }"), new JSONArray()};
JSONArray jsonArray = new JSONArray(expectedList);
List<Object> actualList = jsonArray.stream()
.collect(Collectors.toList());
System.out.println(actualList);
assertEquals(actualList.size(), expectedList.length);
for (int i = 0; i < actualList.size(); ++i) {
Object actual = actualList.get(i);
Object expected = expectedList[i];
if (actual instanceof JSONObject) {
assertTrue("Json Object test",((JSONObject) actual).similar(expected));
} else if (actual instanceof JSONArray) {
assertTrue("Json Array test", ((JSONArray) actual).similar(expected));
} else if (JSONObject.NULL.equals(expected)) {
assertTrue("Null test", JSONObject.NULL.equals(actual));
} else {
assertEquals("value test: "+expected, expected, actual);
}
}
} @Test
public void testStream_ComposeFromCode() {
JSONArray jsonArray = new JSONArray();
jsonArray.put(1).put(2).put(3)
.put(true).put(false)
.put((Object)null)
.put("abc").put("def")
.put(new JSONObject("{ \"a\": \"b\" }"))
.put(new JSONArray())
;
@SuppressWarnings("boxing")
Object[] expectedList = new Object[] { 1, 2, 3, true, false, null, "abc", "def", new JSONObject("{ \"a\": \"b\" }"), new JSONArray()};
List<Object> actualList = jsonArray.stream()
.collect(Collectors.toList());
System.out.println(actualList);
assertEquals(actualList.size(), expectedList.length);
for (int i = 0; i < actualList.size(); ++i) {
Object actual = actualList.get(i);
Object expected = expectedList[i];
if (actual instanceof JSONObject) {
assertTrue("Json Object test",((JSONObject) actual).similar(expected));
} else if (actual instanceof JSONArray) {
assertTrue("Json Array test", ((JSONArray) actual).similar(expected));
} else if (JSONObject.NULL.equals(expected)) {
assertTrue("Null test", JSONObject.NULL.equals(actual));
} else {
assertEquals("value test: "+expected, expected, actual);
}
}
}|
Added the new unit tests |
|
Closing due to lack of activity. |
What problem does this code solve?
JSONObject and JSONArray should support streams for functional programming.
There are multiple ways this could be added. If you know of a better way, please post your comments to this PR.
This change requires Java 8. Going forward, Java 6 and Java 7 library builds are no longer supported. The last release for Java 6/7 is 20230618. Users who still need Java 6/7 support should open an issue in this repo.
Risks
Low
Changes to the API?
New API methods were added
Will this require a new release?
Yes
Should the documentation be updated?
No
Does it break the unit tests?
No. New unit tests were added
Was any code refactored in this commit?
Review status
code review action items pending