diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 879cf86d0a..42dad748c5 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -1829,3 +1829,8 @@ Eduard Gomoliako (Gems@github) Mathijs Vogelzang (mathijs81@github) * Reported #4678: Java records don't serialize with `MapperFeature.REQUIRE_SETTERS_FOR_GETTERS` (2.18.0) + +Rikkarth (rikkarth@github) + * Contributed #4709: Add `JacksonCollectors` with `toArrayNode()` implementation + (2.18.0) + diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index fece6f0582..c581a2268f 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -79,6 +79,8 @@ Project: jackson-databind (reported by @lnthai2002) #4699: Add extra `writeNumber()` method in `TokenBuffer` (contributed by @pjfanning) +#4709: Add `JacksonCollectors` with `toArrayNode()` implementation + (contributed by @rikkarth) 2.17.2 (05-Jul-2024) diff --git a/src/main/java/com/fasterxml/jackson/databind/util/JacksonCollectors.java b/src/main/java/com/fasterxml/jackson/databind/util/JacksonCollectors.java new file mode 100644 index 0000000000..c6b47fc4e4 --- /dev/null +++ b/src/main/java/com/fasterxml/jackson/databind/util/JacksonCollectors.java @@ -0,0 +1,53 @@ +package com.fasterxml.jackson.databind.util; + +import java.util.stream.Collector; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.JsonNodeCreator; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; + +/** + * Utility class that provides custom {@link Collector} implementations to support Stream operations. + *

+ * This class is not meant to be instantiated and serves only as a utility class. + *

+ * + * @since 2.18 + */ +public abstract class JacksonCollectors { + /** + * Creates a {@link Collector} that collects {@link JsonNode} elements into an {@link ArrayNode}. + *

+ * This method uses a {@link JsonNodeFactory} to create an empty {@link ArrayNode} and then adds each + * {@link JsonNode} to it. + *

+ *

+ * Short-cut to + *{@code toArrayNode(JsonNodeFactory.instance}} + * + * @return a {@link Collector} that collects {@link JsonNode} elements into an {@link ArrayNode} + */ + public static Collector toArrayNode() { + return toArrayNode(JsonNodeFactory.instance); + } + + /** + * Creates a {@link Collector} that collects {@link JsonNode} elements into an {@link ArrayNode}. + *

+ * This method uses a {@link JsonNodeFactory} to create an empty {@link ArrayNode} and then adds each + * {@link JsonNode} to it. + *

+ * + * @param nodeCreator Factory for constructing {@link ArrayNode} to contain nodes in + * + * @return a {@link Collector} that collects {@link JsonNode} elements into an {@link ArrayNode} + */ + public static Collector toArrayNode(JsonNodeCreator nodeCreator) { + return Collector.of( + nodeCreator::arrayNode, // supplier + ArrayNode::add, // accumulator + ArrayNode::addAll // combiner + ); + } +} diff --git a/src/test/java/com/fasterxml/jackson/databind/util/JacksonCollectorsTest.java b/src/test/java/com/fasterxml/jackson/databind/util/JacksonCollectorsTest.java new file mode 100644 index 0000000000..e589d045b1 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/util/JacksonCollectorsTest.java @@ -0,0 +1,33 @@ +package com.fasterxml.jackson.databind.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.util.stream.IntStream; +import org.junit.jupiter.api.Test; + +public class JacksonCollectorsTest { + + @Test + public void testToArrayNode() + { + final ObjectMapper objectMapper = new ObjectMapper(); + + final JsonNode jsonNodeResult = IntStream.range(0, 10) + .mapToObj(i -> { + ObjectNode objectNode = objectMapper.createObjectNode(); + objectNode.put("testString", "example"); + objectNode.put("testNumber", i); + objectNode.put("testBoolean", true); + + return objectNode; + }) + .collect(JacksonCollectors.toArrayNode()); + + assertEquals(10, jsonNodeResult.size()); + jsonNodeResult.forEach(jsonNode -> assertFalse(jsonNode.isEmpty())); + } +}