Skip to content

Commit cfef132

Browse files
authored
Fix #4955: add removeIf, removeNulls for ArrayNode, ObjectNode (#4967)
1 parent 5bf3656 commit cfef132

File tree

6 files changed

+122
-17
lines changed

6 files changed

+122
-17
lines changed

release-notes/VERSION-2.x

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Project: jackson-databind
5050
(reported by Floris W)
5151
#4953: Allow clearing all caches to avoid classloader leaks
5252
(contributed by Joren I)
53+
#4955: Add more remove methods for `ArrayNode`, `ObjectNode` [STEP-3]
5354
#4959: Add explicit deserializer for `ThreadGroup`
5455
#4961: Serialization for `JsonFormat.Shape.ARRAY` does not work when
5556
there is `@JsonAnyGetter`

src/main/java/com/fasterxml/jackson/databind/node/ArrayNode.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.math.BigDecimal;
55
import java.math.BigInteger;
66
import java.util.*;
7+
import java.util.function.Predicate;
78
import java.util.stream.Stream;
89

910
import com.fasterxml.jackson.core.*;
@@ -533,6 +534,12 @@ public ArrayNode removeAll()
533534
return this;
534535
}
535536

537+
@Override
538+
public ArrayNode removeIf(Predicate<? super JsonNode> predicate) {
539+
_children.removeIf(predicate);
540+
return this;
541+
}
542+
536543
/*
537544
/**********************************************************
538545
/* Extended ObjectNode API, mutators, generic; addXxx()/insertXxx()/setXxx()

src/main/java/com/fasterxml/jackson/databind/node/ContainerNode.java

Lines changed: 29 additions & 0 deletions
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.function.Predicate;
56
import java.util.stream.Stream;
67

78
import com.fasterxml.jackson.core.*;
@@ -169,4 +170,32 @@ public final NumericNode numberNode(long v) {
169170
* @return Container node itself (to allow method call chaining)
170171
*/
171172
public abstract T removeAll();
173+
174+
/**
175+
* Method for removing matching those children (value) nodes container has that
176+
* match given predicate.
177+
*
178+
* @param predicate Predicate to use for matching: anything matching will be removed
179+
*
180+
* @return Container node itself (to allow method call chaining)
181+
*
182+
* @since 2.19
183+
*/
184+
public abstract T removeIf(Predicate<? super JsonNode> predicate);
185+
186+
/**
187+
* Method for removing {@code null} children (value) nodes container has (that is,
188+
* children for which {@code isNull()} returns true).
189+
* Short-cut for:
190+
*<pre>
191+
* removeIf(JsonNode::isNull);
192+
*<pre>
193+
*
194+
* @return Container node itself (to allow method call chaining)
195+
*
196+
* @since 2.19
197+
*/
198+
public T removeNulls() {
199+
return removeIf(JsonNode::isNull);
200+
}
172201
}

src/main/java/com/fasterxml/jackson/databind/node/ObjectNode.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.math.BigInteger;
66
import java.util.*;
77
import java.util.function.BiConsumer;
8+
import java.util.function.Predicate;
89
import java.util.stream.Stream;
910

1011
import com.fasterxml.jackson.core.*;
@@ -818,6 +819,12 @@ public ObjectNode removeAll()
818819
return this;
819820
}
820821

822+
@Override
823+
public ObjectNode removeIf(Predicate<? super JsonNode> predicate) {
824+
_children.values().removeIf(predicate);
825+
return this;
826+
}
827+
821828
/**
822829
* Method for adding given properties to this object node, overriding
823830
* any existing values for those properties.

src/test/java/com/fasterxml/jackson/databind/node/ArrayNodeTest.java

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
public class ArrayNodeTest
2323
extends DatabindTestUtil
2424
{
25+
private final ObjectMapper MAPPER = newJsonMapper();
26+
2527
@Test
2628
public void testDirectCreation() throws Exception
2729
{
@@ -110,7 +112,7 @@ public void testDirectCreation() throws Exception
110112
@Test
111113
public void testDirectCreation2() throws Exception
112114
{
113-
JsonNodeFactory f = objectMapper().getNodeFactory();
115+
JsonNodeFactory f = MAPPER.getNodeFactory();
114116
ArrayList<JsonNode> list = new ArrayList<>();
115117
list.add(f.booleanNode(true));
116118
list.add(f.textNode("foo"));
@@ -200,7 +202,7 @@ public void testArrayViaMapper() throws Exception
200202
{
201203
final String JSON = "[[[-0.027512,51.503221],[-0.008497,51.503221],[-0.008497,51.509744],[-0.027512,51.509744]]]";
202204

203-
JsonNode n = objectMapper().readTree(JSON);
205+
JsonNode n = MAPPER.readTree(JSON);
204206
assertNotNull(n);
205207
assertTrue(n.isArray());
206208
ArrayNode an = (ArrayNode) n;
@@ -239,7 +241,7 @@ public void testAdds()
239241
@Test
240242
public void testNullAdds()
241243
{
242-
JsonNodeFactory f = objectMapper().getNodeFactory();
244+
JsonNodeFactory f = MAPPER.getNodeFactory();
243245
ArrayNode array = f.arrayNode(14);
244246

245247
array.add((BigDecimal) null);
@@ -281,7 +283,7 @@ public void testAddAllWithNullInCollection()
281283
@Test
282284
public void testNullInserts()
283285
{
284-
JsonNodeFactory f = objectMapper().getNodeFactory();
286+
JsonNodeFactory f = MAPPER.getNodeFactory();
285287
ArrayNode array = f.arrayNode(3);
286288

287289
array.insert(0, (BigDecimal) null);
@@ -307,7 +309,7 @@ public void testNullInserts()
307309
@Test
308310
public void testNullSet()
309311
{
310-
JsonNodeFactory f = objectMapper().getNodeFactory();
312+
JsonNodeFactory f = MAPPER.getNodeFactory();
311313
ArrayNode array = f.arrayNode(3);
312314

313315
for (int i = 0; i < 14; i++) {
@@ -358,9 +360,8 @@ public void testNullChecking()
358360
@Test
359361
public void testNullChecking2()
360362
{
361-
ObjectMapper mapper = new ObjectMapper();
362-
ArrayNode src = mapper.createArrayNode();
363-
ArrayNode dest = mapper.createArrayNode();
363+
ArrayNode src = MAPPER.createArrayNode();
364+
ArrayNode dest = MAPPER.createArrayNode();
364365
src.add("element");
365366
dest.addAll(src);
366367
}
@@ -419,7 +420,7 @@ public void testArrayNodeEquality()
419420
@Test
420421
public void testSimpleArray() throws Exception
421422
{
422-
ArrayNode result = objectMapper().createArrayNode();
423+
ArrayNode result = MAPPER.createArrayNode();
423424

424425
assertTrue(result.isArray());
425426
assertType(result, ArrayNode.class);
@@ -455,7 +456,7 @@ public void testSimpleArray() throws Exception
455456
assertTrue(result.path(-100).isMissingNode());
456457

457458
// then construct and compare
458-
ArrayNode array2 = objectMapper().createArrayNode();
459+
ArrayNode array2 = MAPPER.createArrayNode();
459460
array2.addNull();
460461
array2.add(false);
461462
assertEquals(result, array2);
@@ -475,9 +476,8 @@ public void testSimpleArray() throws Exception
475476
@Test
476477
public void testSimpleMismatch() throws Exception
477478
{
478-
ObjectMapper mapper = objectMapper();
479479
try {
480-
mapper.readValue(" 123 ", ArrayNode.class);
480+
MAPPER.readValue(" 123 ", ArrayNode.class);
481481
fail("Should not pass");
482482
} catch (MismatchedInputException e) {
483483
verifyException(e, "from Integer value (token `JsonToken.VALUE_NUMBER_INT`)");
@@ -488,8 +488,7 @@ public void testSimpleMismatch() throws Exception
488488
@Test
489489
public void testStreamMethods()
490490
{
491-
ObjectMapper mapper = objectMapper();
492-
ArrayNode arr = mapper.createArrayNode();
491+
ArrayNode arr = MAPPER.createArrayNode();
493492
arr.add(1).add("foo");
494493
JsonNode n1 = arr.get(0);
495494
JsonNode n2 = arr.get(1);
@@ -507,4 +506,37 @@ public void testStreamMethods()
507506
// And then empty forEachEntry()
508507
arr.forEachEntry((k, v) -> { throw new UnsupportedOperationException(); });
509508
}
509+
510+
@Test
511+
public void testRemoveAll() throws Exception
512+
{
513+
assertEquals(_arrayNode("[]"),
514+
_arrayNode("['a', 2, null, true]").removeAll());
515+
}
516+
517+
// [databind#4955]: remove methods
518+
@Test
519+
public void testRemoveIf() throws Exception
520+
{
521+
assertEquals(_arrayNode("[3]"),
522+
_arrayNode("[2, 1, 3]")
523+
.removeIf(value -> value.asInt() <= 2));
524+
assertEquals(_arrayNode("[1]"),
525+
_arrayNode("[1, 2, 3]")
526+
.removeIf(value -> value.asInt() > 1));
527+
}
528+
529+
// [databind#4955]: remove methods
530+
@Test
531+
public void testRemoveNulls() throws Exception
532+
{
533+
assertEquals(_arrayNode("[2]"),
534+
_arrayNode("[null, null, 2, null]")
535+
.removeNulls());
536+
}
537+
538+
private ArrayNode _arrayNode(String json) throws Exception {
539+
return (ArrayNode) MAPPER.readTree(a2q(json));
540+
}
541+
510542
}

src/test/java/com/fasterxml/jackson/databind/node/ObjectNodeTest.java

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,6 @@ public void testNullChecking()
270270
assertEquals(4, o1.size());
271271
}
272272

273-
/**
274-
* Another test to verify [JACKSON-227]...
275-
*/
276273
@Test
277274
public void testNullChecking2()
278275
{
@@ -583,6 +580,38 @@ public void testStreamMethods()
583580
assertEquals(obj.properties(), map.entrySet());
584581
}
585582

583+
@Test
584+
public void testRemoveAll() throws Exception
585+
{
586+
assertEquals(_objNode("{}"),
587+
_objNode("{'a':1, 'b':2, 'c':3}").removeAll());
588+
}
589+
590+
// [databind#4955]: remove methods
591+
@Test
592+
public void testRemoveIf() throws Exception
593+
{
594+
assertEquals(_objNode("{'c':3}"),
595+
_objNode("{'a':1, 'b':2, 'c':3}")
596+
.removeIf(value -> value.asInt() <= 2));
597+
assertEquals(_objNode("{'a':1}"),
598+
_objNode("{'a':1, 'b':2, 'c':3}")
599+
.removeIf(value -> value.asInt() > 1));
600+
}
601+
602+
// [databind#4955]: remove methods
603+
@Test
604+
public void testRemoveNulls() throws Exception
605+
{
606+
assertEquals(_objNode("{'b':2}"),
607+
_objNode("{'a':null,'b':2,'c':null}")
608+
.removeNulls());
609+
}
610+
611+
private ObjectNode _objNode(String json) throws Exception {
612+
return (ObjectNode) MAPPER.readTree(a2q(json));
613+
}
614+
586615
private String _toString(JsonNode n) {
587616
return n.properties().stream()
588617
.map(e -> e.getKey() + "/" + e.getValue())

0 commit comments

Comments
 (0)