Skip to content

Commit 30bb56d

Browse files
committed
Merge branch '2.19'
2 parents ce15ed6 + a7cf2f3 commit 30bb56d

File tree

13 files changed

+176
-10
lines changed

13 files changed

+176
-10
lines changed

release-notes/VERSION-2.x

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ Project: jackson-databind
3434
(requested by @nathanukey)
3535
#4849 Not able to deserialize Enum with default typing after upgrading 2.15.4 -> 2.17.1
3636
(reported by Kornel Zemla)
37+
#4863: Add basic Stream support in `JsonNode`: `valueStream()`, `entryStream()`,
38+
`forEachEntry()`
3739

3840
2.18.3 (not yet released)
3941

src/main/java/tools/jackson/databind/JsonNode.java

+40
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import java.math.BigDecimal;
44
import java.math.BigInteger;
55
import java.util.*;
6+
import java.util.function.BiConsumer;
7+
import java.util.stream.Stream;
68

79
import tools.jackson.core.*;
810
import tools.jackson.databind.exc.JsonNodeException;
@@ -1004,6 +1006,44 @@ public Set<Map.Entry<String, JsonNode>> properties() {
10041006
return Collections.emptySet();
10051007
}
10061008

1009+
/**
1010+
* Returns a stream of all value nodes of this Node, iff
1011+
* this node is an {@code ArrayNode} or {@code ObjectNode}.
1012+
* In case of {@code Object} node, property names (keys) are not included, only values.
1013+
* For other types of nodes, returns empty stream.
1014+
*
1015+
* @since 2.19
1016+
*/
1017+
public Stream<JsonNode> valueStream() {
1018+
return ClassUtil.emptyStream();
1019+
}
1020+
1021+
/**
1022+
* Returns a stream of all value nodes of this Node, iff
1023+
* this node is an an {@code ObjectNode}.
1024+
* For other types of nodes, returns empty stream.
1025+
*
1026+
* @since 2.19
1027+
*/
1028+
public Stream<Map.Entry<String, JsonNode>> entryStream() {
1029+
return ClassUtil.emptyStream();
1030+
}
1031+
1032+
/**
1033+
* If this node is an {@code ObjectNode}, erforms the given action for each entry
1034+
* until all entries have been processed or the action throws an exception.
1035+
* Exceptions thrown by the action are relayed to the caller.
1036+
* For other node types, no action is performed.
1037+
*<p>
1038+
* Actions are performed in the order of entries, same as order returned by
1039+
* method {@link #properties()}.
1040+
*
1041+
* @param action Action to perform for each entry
1042+
*/
1043+
public void forEachEntry(BiConsumer<? super String, ? super JsonNode> action) {
1044+
// No-op for all but ObjectNode
1045+
}
1046+
10071047
/*
10081048
/**********************************************************************
10091049
/* Public API, find methods

src/main/java/tools/jackson/databind/node/ArrayNode.java

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.math.BigDecimal;
44
import java.math.BigInteger;
55
import java.util.*;
6+
import java.util.stream.Stream;
67

78
import tools.jackson.core.*;
89
import tools.jackson.core.tree.ArrayTreeNode;
@@ -259,6 +260,11 @@ public JsonNode required(int index) {
259260
index, _children.size());
260261
}
261262

263+
@Override // @since 2.19
264+
public Stream<JsonNode> valueStream() {
265+
return _children.stream();
266+
}
267+
262268
@Override
263269
public boolean equals(Comparator<JsonNode> comparator, JsonNode o)
264270
{

src/main/java/tools/jackson/databind/node/ContainerNode.java

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.math.BigDecimal;
44
import java.math.BigInteger;
5+
import java.util.stream.Stream;
56

67
import tools.jackson.core.*;
78
import tools.jackson.databind.JsonNode;
@@ -54,6 +55,10 @@ protected ContainerNode(JsonNodeFactory nc) {
5455
@Override
5556
public abstract JsonNode get(String fieldName);
5657

58+
// Both ArrayNode and ObjectNode must re-implement
59+
@Override // @since 2.19
60+
public abstract Stream<JsonNode> valueStream();
61+
5762
@Override
5863
protected abstract ObjectNode _withObject(JsonPointer origPtr,
5964
JsonPointer currentPtr,

src/main/java/tools/jackson/databind/node/ObjectNode.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import java.math.BigDecimal;
44
import java.math.BigInteger;
55
import java.util.*;
6+
import java.util.function.BiConsumer;
7+
import java.util.stream.Stream;
68

79
import tools.jackson.core.*;
810
import tools.jackson.core.tree.ObjectTreeNode;
@@ -289,7 +291,22 @@ public Iterator<Map.Entry<String, JsonNode>> fields() {
289291
public Set<Map.Entry<String, JsonNode>> properties() {
290292
return _children.entrySet();
291293
}
292-
294+
295+
@Override // @since 2.19
296+
public Stream<JsonNode> valueStream() {
297+
return _children.values().stream();
298+
}
299+
300+
@Override // @since 2.19
301+
public Stream<Map.Entry<String, JsonNode>> entryStream() {
302+
return _children.entrySet().stream();
303+
}
304+
305+
@Override // @since 2.19
306+
public void forEachEntry(BiConsumer<? super String, ? super JsonNode> action) {
307+
_children.forEach(action);
308+
}
309+
293310
@Override
294311
public boolean equals(Comparator<JsonNode> comparator, JsonNode o)
295312
{

src/main/java/tools/jackson/databind/util/ClassUtil.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.lang.annotation.Annotation;
66
import java.lang.reflect.*;
77
import java.util.*;
8+
import java.util.stream.Stream;
89

910
import tools.jackson.core.JacksonException;
1011
import tools.jackson.core.JsonGenerator;
@@ -21,7 +22,7 @@ public final class ClassUtil
2122

2223
private final static Ctor[] NO_CTORS = new Ctor[0];
2324

24-
private final static Iterator<?> EMPTY_ITERATOR = Collections.emptyIterator();
25+
private final static Iterator<Object> EMPTY_ITERATOR = Collections.emptyIterator();
2526

2627
/*
2728
/**********************************************************************
@@ -34,6 +35,16 @@ public static <T> Iterator<T> emptyIterator() {
3435
return (Iterator<T>) EMPTY_ITERATOR;
3536
}
3637

38+
/**
39+
* @since 2.19
40+
*/
41+
public static <T> Stream<T> emptyStream() {
42+
// Looking at its implementation, seems there ought to be simpler/more
43+
// efficient way to create and return a shared singleton but... no luck
44+
// so far. So just use this for convenience for now:
45+
return Stream.empty();
46+
}
47+
3748
/*
3849
/**********************************************************************
3950
/* Methods that deal with inheritance

src/test/java/tools/jackson/databind/node/ArrayNodeTest.java

+30-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package tools.jackson.databind.node;
22

3-
import java.io.*;
43
import java.math.BigDecimal;
54
import java.math.BigInteger;
5+
import java.util.Arrays;
6+
import java.util.stream.Collectors;
67
import java.util.ArrayList;
78

89
import org.junit.jupiter.api.Test;
@@ -13,8 +14,6 @@
1314
import tools.jackson.databind.testutil.DatabindTestUtil;
1415
import tools.jackson.databind.util.RawValue;
1516

16-
import static java.util.Arrays.asList;
17-
1817
import static org.junit.jupiter.api.Assertions.*;
1918

2019
/**
@@ -24,7 +23,7 @@ public class ArrayNodeTest
2423
extends DatabindTestUtil
2524
{
2625
@Test
27-
public void testDirectCreation() throws IOException
26+
public void testDirectCreation() throws Exception
2827
{
2928
ArrayNode n = new ArrayNode(JsonNodeFactory.instance);
3029

@@ -108,7 +107,7 @@ public void testDirectCreation() throws IOException
108107
}
109108

110109
@Test
111-
public void testDirectCreation2() throws IOException
110+
public void testDirectCreation2() throws Exception
112111
{
113112
JsonNodeFactory f = objectMapper().getNodeFactory();
114113
ArrayList<JsonNode> list = new ArrayList<>();
@@ -139,7 +138,7 @@ public void testDirectCreation2() throws IOException
139138
}
140139

141140
@Test
142-
public void testArraySet() throws IOException {
141+
public void testArraySet() throws Exception {
143142
final ArrayNode array = JsonNodeFactory.instance.arrayNode();
144143
for (int i = 0; i < 20; i++) {
145144
array.add("Original Data");
@@ -267,7 +266,7 @@ public void testAddAllWithNullInCollection()
267266
final ArrayNode array = JsonNodeFactory.instance.arrayNode();
268267

269268
// test
270-
array.addAll(asList(null, JsonNodeFactory.instance.objectNode()));
269+
array.addAll(Arrays.asList(null, JsonNodeFactory.instance.objectNode()));
271270

272271
// assertions
273272
assertEquals(2, array.size());
@@ -478,4 +477,28 @@ public void testSimpleMismatch() throws Exception
478477
verifyException(e, "from Integer value (token `JsonToken.VALUE_NUMBER_INT`)");
479478
}
480479
}
480+
481+
// [databind#4863]: valueStream(), entryStream(), forEachEntry()
482+
@Test
483+
public void testStreamMethods()
484+
{
485+
ObjectMapper mapper = objectMapper();
486+
ArrayNode arr = mapper.createArrayNode();
487+
arr.add(1).add("foo");
488+
JsonNode n1 = arr.get(0);
489+
JsonNode n2 = arr.get(1);
490+
491+
// First, valueStream() testing
492+
assertEquals(2, arr.valueStream().count());
493+
assertEquals(Arrays.asList(n1, n2),
494+
arr.valueStream().collect(Collectors.toList()));
495+
496+
// And then entryStream() (empty)
497+
assertEquals(0, arr.entryStream().count());
498+
assertEquals(Arrays.asList(),
499+
arr.entryStream().collect(Collectors.toList()));
500+
501+
// And then empty forEachEntry()
502+
arr.forEachEntry((k, v) -> { throw new UnsupportedOperationException(); });
503+
}
481504
}

src/test/java/tools/jackson/databind/node/JsonNodeBasicTest.java

+6
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ public void testBoolean() throws Exception
6565
// also, equality should work ok
6666
assertEquals(result, BooleanNode.valueOf(true));
6767
assertEquals(result, BooleanNode.getTrue());
68+
69+
assertNonContainerStreamMethods(f);
6870
}
6971

7072
@Test
@@ -92,6 +94,8 @@ public void testBinary() throws Exception
9294

9395
assertEquals("AAMD", new BinaryNode(data).asText());
9496
assertNodeNumbersForNonNumeric(n);
97+
98+
assertNonContainerStreamMethods(n2);
9599
}
96100

97101
@Test
@@ -110,6 +114,8 @@ public void testPOJO()
110114
assertNodeNumbersForNonNumeric(n);
111115
// but if wrapping actual number, use it
112116
assertNodeNumbers(new POJONode(Integer.valueOf(123)), 123, 123.0);
117+
118+
assertNonContainerStreamMethods(n);
113119
}
114120

115121
// [databind#743]

src/test/java/tools/jackson/databind/node/NodeTestBase.java

+12
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,16 @@ protected void assertNodeNumbers(JsonNode n, int expInt, double expDouble)
3434

3535
assertTrue(n.isEmpty());
3636
}
37+
38+
// Testing for non-ContainerNode (ValueNode) stream method implementations
39+
//
40+
// @since 2.19
41+
protected void assertNonContainerStreamMethods(ValueNode n)
42+
{
43+
assertEquals(0, n.valueStream().count());
44+
assertEquals(0, n.entryStream().count());
45+
46+
// And then empty forEachEntry()
47+
n.forEachEntry((k, v) -> { throw new UnsupportedOperationException(); });
48+
}
3749
}

src/test/java/tools/jackson/databind/node/NullNodeTest.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ public void testBasicsWithNullNode() throws Exception
7070

7171
assertNodeNumbersForNonNumeric(n);
7272

73-
// 2.4
7473
assertEquals("null", n.asText());
74+
75+
assertNonContainerStreamMethods(n);
7576
}
7677

7778
@Test

src/test/java/tools/jackson/databind/node/NumberNodesTest.java

+13
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ public void testShort()
4545
assertTrue(ShortNode.valueOf((short) 0).canConvertToLong());
4646
assertTrue(ShortNode.valueOf(Short.MAX_VALUE).canConvertToLong());
4747
assertTrue(ShortNode.valueOf(Short.MIN_VALUE).canConvertToLong());
48+
49+
assertNonContainerStreamMethods(n);
4850
}
4951

5052
@Test
@@ -103,6 +105,7 @@ public void testInt()
103105
assertTrue(IntNode.valueOf(Integer.MAX_VALUE).canConvertToLong());
104106
assertTrue(IntNode.valueOf(Integer.MIN_VALUE).canConvertToLong());
105107

108+
assertNonContainerStreamMethods(n);
106109
}
107110

108111
@Test
@@ -132,6 +135,8 @@ public void testLong()
132135
assertTrue(LongNode.valueOf(0L).canConvertToLong());
133136
assertTrue(LongNode.valueOf(Long.MAX_VALUE).canConvertToLong());
134137
assertTrue(LongNode.valueOf(Long.MIN_VALUE).canConvertToLong());
138+
139+
assertNonContainerStreamMethods(n);
135140
}
136141

137142
@Test
@@ -195,6 +200,8 @@ public void testDouble() throws Exception
195200
n = (DoubleNode) num;
196201
assertEquals(-0.0, n.doubleValue());
197202
assertEquals("-0.0", String.valueOf(n.doubleValue()));
203+
204+
assertNonContainerStreamMethods(n);
198205
}
199206

200207
@Test
@@ -266,6 +273,8 @@ public void testFloat()
266273
assertTrue(FloatNode.valueOf(0L).canConvertToLong());
267274
assertTrue(FloatNode.valueOf(Integer.MAX_VALUE).canConvertToLong());
268275
assertTrue(FloatNode.valueOf(Integer.MIN_VALUE).canConvertToLong());
276+
277+
assertNonContainerStreamMethods(n);
269278
}
270279

271280
@Test
@@ -324,6 +333,8 @@ public void testDecimalNode() throws Exception
324333

325334
// also, equality should work ok
326335
assertEquals(result, DecimalNode.valueOf(value));
336+
337+
assertNonContainerStreamMethods(n);
327338
}
328339

329340
@Test
@@ -389,6 +400,8 @@ public void testBigIntegerNode() throws Exception
389400
assertTrue(BigIntegerNode.valueOf(BigInteger.ZERO).canConvertToLong());
390401
assertTrue(BigIntegerNode.valueOf(BigInteger.valueOf(Long.MAX_VALUE)).canConvertToLong());
391402
assertTrue(BigIntegerNode.valueOf(BigInteger.valueOf(Long.MIN_VALUE)).canConvertToLong());
403+
404+
assertNonContainerStreamMethods(n);
392405
}
393406

394407
@Test

0 commit comments

Comments
 (0)