Skip to content

Commit

Permalink
Merge branch '2.19'
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Dec 23, 2024
2 parents ce15ed6 + a7cf2f3 commit 30bb56d
Show file tree
Hide file tree
Showing 13 changed files with 176 additions and 10 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Project: jackson-databind
(requested by @nathanukey)
#4849 Not able to deserialize Enum with default typing after upgrading 2.15.4 -> 2.17.1
(reported by Kornel Zemla)
#4863: Add basic Stream support in `JsonNode`: `valueStream()`, `entryStream()`,
`forEachEntry()`

2.18.3 (not yet released)

Expand Down
40 changes: 40 additions & 0 deletions src/main/java/tools/jackson/databind/JsonNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.stream.Stream;

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

/**
* Returns a stream of all value nodes of this Node, iff
* this node is an {@code ArrayNode} or {@code ObjectNode}.
* In case of {@code Object} node, property names (keys) are not included, only values.
* For other types of nodes, returns empty stream.
*
* @since 2.19
*/
public Stream<JsonNode> valueStream() {
return ClassUtil.emptyStream();
}

/**
* Returns a stream of all value nodes of this Node, iff
* this node is an an {@code ObjectNode}.
* For other types of nodes, returns empty stream.
*
* @since 2.19
*/
public Stream<Map.Entry<String, JsonNode>> entryStream() {
return ClassUtil.emptyStream();
}

/**
* If this node is an {@code ObjectNode}, erforms the given action for each entry
* until all entries have been processed or the action throws an exception.
* Exceptions thrown by the action are relayed to the caller.
* For other node types, no action is performed.
*<p>
* Actions are performed in the order of entries, same as order returned by
* method {@link #properties()}.
*
* @param action Action to perform for each entry
*/
public void forEachEntry(BiConsumer<? super String, ? super JsonNode> action) {
// No-op for all but ObjectNode
}

/*
/**********************************************************************
/* Public API, find methods
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/tools/jackson/databind/node/ArrayNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Stream;

import tools.jackson.core.*;
import tools.jackson.core.tree.ArrayTreeNode;
Expand Down Expand Up @@ -259,6 +260,11 @@ public JsonNode required(int index) {
index, _children.size());
}

@Override // @since 2.19
public Stream<JsonNode> valueStream() {
return _children.stream();
}

@Override
public boolean equals(Comparator<JsonNode> comparator, JsonNode o)
{
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/tools/jackson/databind/node/ContainerNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.stream.Stream;

import tools.jackson.core.*;
import tools.jackson.databind.JsonNode;
Expand Down Expand Up @@ -54,6 +55,10 @@ protected ContainerNode(JsonNodeFactory nc) {
@Override
public abstract JsonNode get(String fieldName);

// Both ArrayNode and ObjectNode must re-implement
@Override // @since 2.19
public abstract Stream<JsonNode> valueStream();

@Override
protected abstract ObjectNode _withObject(JsonPointer origPtr,
JsonPointer currentPtr,
Expand Down
19 changes: 18 additions & 1 deletion src/main/java/tools/jackson/databind/node/ObjectNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.stream.Stream;

import tools.jackson.core.*;
import tools.jackson.core.tree.ObjectTreeNode;
Expand Down Expand Up @@ -289,7 +291,22 @@ public Iterator<Map.Entry<String, JsonNode>> fields() {
public Set<Map.Entry<String, JsonNode>> properties() {
return _children.entrySet();
}


@Override // @since 2.19
public Stream<JsonNode> valueStream() {
return _children.values().stream();
}

@Override // @since 2.19
public Stream<Map.Entry<String, JsonNode>> entryStream() {
return _children.entrySet().stream();
}

@Override // @since 2.19
public void forEachEntry(BiConsumer<? super String, ? super JsonNode> action) {
_children.forEach(action);
}

@Override
public boolean equals(Comparator<JsonNode> comparator, JsonNode o)
{
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/tools/jackson/databind/util/ClassUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Stream;

import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
Expand All @@ -21,7 +22,7 @@ public final class ClassUtil

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

private final static Iterator<?> EMPTY_ITERATOR = Collections.emptyIterator();
private final static Iterator<Object> EMPTY_ITERATOR = Collections.emptyIterator();

/*
/**********************************************************************
Expand All @@ -34,6 +35,16 @@ public static <T> Iterator<T> emptyIterator() {
return (Iterator<T>) EMPTY_ITERATOR;
}

/**
* @since 2.19
*/
public static <T> Stream<T> emptyStream() {
// Looking at its implementation, seems there ought to be simpler/more
// efficient way to create and return a shared singleton but... no luck
// so far. So just use this for convenience for now:
return Stream.empty();
}

/*
/**********************************************************************
/* Methods that deal with inheritance
Expand Down
37 changes: 30 additions & 7 deletions src/test/java/tools/jackson/databind/node/ArrayNodeTest.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package tools.jackson.databind.node;

import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.ArrayList;

import org.junit.jupiter.api.Test;
Expand All @@ -13,8 +14,6 @@
import tools.jackson.databind.testutil.DatabindTestUtil;
import tools.jackson.databind.util.RawValue;

import static java.util.Arrays.asList;

import static org.junit.jupiter.api.Assertions.*;

/**
Expand All @@ -24,7 +23,7 @@ public class ArrayNodeTest
extends DatabindTestUtil
{
@Test
public void testDirectCreation() throws IOException
public void testDirectCreation() throws Exception
{
ArrayNode n = new ArrayNode(JsonNodeFactory.instance);

Expand Down Expand Up @@ -108,7 +107,7 @@ public void testDirectCreation() throws IOException
}

@Test
public void testDirectCreation2() throws IOException
public void testDirectCreation2() throws Exception
{
JsonNodeFactory f = objectMapper().getNodeFactory();
ArrayList<JsonNode> list = new ArrayList<>();
Expand Down Expand Up @@ -139,7 +138,7 @@ public void testDirectCreation2() throws IOException
}

@Test
public void testArraySet() throws IOException {
public void testArraySet() throws Exception {
final ArrayNode array = JsonNodeFactory.instance.arrayNode();
for (int i = 0; i < 20; i++) {
array.add("Original Data");
Expand Down Expand Up @@ -267,7 +266,7 @@ public void testAddAllWithNullInCollection()
final ArrayNode array = JsonNodeFactory.instance.arrayNode();

// test
array.addAll(asList(null, JsonNodeFactory.instance.objectNode()));
array.addAll(Arrays.asList(null, JsonNodeFactory.instance.objectNode()));

// assertions
assertEquals(2, array.size());
Expand Down Expand Up @@ -478,4 +477,28 @@ public void testSimpleMismatch() throws Exception
verifyException(e, "from Integer value (token `JsonToken.VALUE_NUMBER_INT`)");
}
}

// [databind#4863]: valueStream(), entryStream(), forEachEntry()
@Test
public void testStreamMethods()
{
ObjectMapper mapper = objectMapper();
ArrayNode arr = mapper.createArrayNode();
arr.add(1).add("foo");
JsonNode n1 = arr.get(0);
JsonNode n2 = arr.get(1);

// First, valueStream() testing
assertEquals(2, arr.valueStream().count());
assertEquals(Arrays.asList(n1, n2),
arr.valueStream().collect(Collectors.toList()));

// And then entryStream() (empty)
assertEquals(0, arr.entryStream().count());
assertEquals(Arrays.asList(),
arr.entryStream().collect(Collectors.toList()));

// And then empty forEachEntry()
arr.forEachEntry((k, v) -> { throw new UnsupportedOperationException(); });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public void testBoolean() throws Exception
// also, equality should work ok
assertEquals(result, BooleanNode.valueOf(true));
assertEquals(result, BooleanNode.getTrue());

assertNonContainerStreamMethods(f);
}

@Test
Expand Down Expand Up @@ -92,6 +94,8 @@ public void testBinary() throws Exception

assertEquals("AAMD", new BinaryNode(data).asText());
assertNodeNumbersForNonNumeric(n);

assertNonContainerStreamMethods(n2);
}

@Test
Expand All @@ -110,6 +114,8 @@ public void testPOJO()
assertNodeNumbersForNonNumeric(n);
// but if wrapping actual number, use it
assertNodeNumbers(new POJONode(Integer.valueOf(123)), 123, 123.0);

assertNonContainerStreamMethods(n);
}

// [databind#743]
Expand Down
12 changes: 12 additions & 0 deletions src/test/java/tools/jackson/databind/node/NodeTestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,16 @@ protected void assertNodeNumbers(JsonNode n, int expInt, double expDouble)

assertTrue(n.isEmpty());
}

// Testing for non-ContainerNode (ValueNode) stream method implementations
//
// @since 2.19
protected void assertNonContainerStreamMethods(ValueNode n)
{
assertEquals(0, n.valueStream().count());
assertEquals(0, n.entryStream().count());

// And then empty forEachEntry()
n.forEachEntry((k, v) -> { throw new UnsupportedOperationException(); });
}
}
3 changes: 2 additions & 1 deletion src/test/java/tools/jackson/databind/node/NullNodeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ public void testBasicsWithNullNode() throws Exception

assertNodeNumbersForNonNumeric(n);

// 2.4
assertEquals("null", n.asText());

assertNonContainerStreamMethods(n);
}

@Test
Expand Down
13 changes: 13 additions & 0 deletions src/test/java/tools/jackson/databind/node/NumberNodesTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public void testShort()
assertTrue(ShortNode.valueOf((short) 0).canConvertToLong());
assertTrue(ShortNode.valueOf(Short.MAX_VALUE).canConvertToLong());
assertTrue(ShortNode.valueOf(Short.MIN_VALUE).canConvertToLong());

assertNonContainerStreamMethods(n);
}

@Test
Expand Down Expand Up @@ -103,6 +105,7 @@ public void testInt()
assertTrue(IntNode.valueOf(Integer.MAX_VALUE).canConvertToLong());
assertTrue(IntNode.valueOf(Integer.MIN_VALUE).canConvertToLong());

assertNonContainerStreamMethods(n);
}

@Test
Expand Down Expand Up @@ -132,6 +135,8 @@ public void testLong()
assertTrue(LongNode.valueOf(0L).canConvertToLong());
assertTrue(LongNode.valueOf(Long.MAX_VALUE).canConvertToLong());
assertTrue(LongNode.valueOf(Long.MIN_VALUE).canConvertToLong());

assertNonContainerStreamMethods(n);
}

@Test
Expand Down Expand Up @@ -195,6 +200,8 @@ public void testDouble() throws Exception
n = (DoubleNode) num;
assertEquals(-0.0, n.doubleValue());
assertEquals("-0.0", String.valueOf(n.doubleValue()));

assertNonContainerStreamMethods(n);
}

@Test
Expand Down Expand Up @@ -266,6 +273,8 @@ public void testFloat()
assertTrue(FloatNode.valueOf(0L).canConvertToLong());
assertTrue(FloatNode.valueOf(Integer.MAX_VALUE).canConvertToLong());
assertTrue(FloatNode.valueOf(Integer.MIN_VALUE).canConvertToLong());

assertNonContainerStreamMethods(n);
}

@Test
Expand Down Expand Up @@ -324,6 +333,8 @@ public void testDecimalNode() throws Exception

// also, equality should work ok
assertEquals(result, DecimalNode.valueOf(value));

assertNonContainerStreamMethods(n);
}

@Test
Expand Down Expand Up @@ -389,6 +400,8 @@ public void testBigIntegerNode() throws Exception
assertTrue(BigIntegerNode.valueOf(BigInteger.ZERO).canConvertToLong());
assertTrue(BigIntegerNode.valueOf(BigInteger.valueOf(Long.MAX_VALUE)).canConvertToLong());
assertTrue(BigIntegerNode.valueOf(BigInteger.valueOf(Long.MIN_VALUE)).canConvertToLong());

assertNonContainerStreamMethods(n);
}

@Test
Expand Down
Loading

0 comments on commit 30bb56d

Please sign in to comment.