ArrayNodeTest.java
package com.fasterxml.jackson.databind.node;
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;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import com.fasterxml.jackson.databind.util.RawValue;
import static org.junit.jupiter.api.Assertions.*;
/**
* Additional tests for {@link ArrayNode} container class.
*/
public class ArrayNodeTest
extends DatabindTestUtil
{
private final ObjectMapper MAPPER = newJsonMapper();
@Test
public void testDirectCreation() throws Exception
{
ArrayNode n = new ArrayNode(JsonNodeFactory.instance);
assertFalse(n.isBoolean());
assertFalse(n.isTextual());
assertFalse(n.isNumber());
assertFalse(n.canConvertToInt());
assertFalse(n.canConvertToLong());
assertFalse(n.canConvertToExactIntegral());
assertStandardEquals(n);
assertFalse(n.elements().hasNext());
assertFalse(n.fieldNames().hasNext());
assertTrue(n.isEmpty());
TextNode text = TextNode.valueOf("x");
n.add(text);
assertEquals(1, n.size());
assertFalse(n.isEmpty());
assertFalse(0 == n.hashCode());
assertTrue(n.elements().hasNext());
// no field names for arrays
assertFalse(n.fieldNames().hasNext());
assertNull(n.get("x")); // not used with arrays
assertTrue(n.path("x").isMissingNode());
assertFalse(n.optional("x").isPresent());
assertSame(text, n.get(0));
// single element, so:
assertFalse(n.has("field"));
assertFalse(n.hasNonNull("field"));
assertTrue(n.has(0));
assertTrue(n.hasNonNull(0));
assertFalse(n.has(1));
assertFalse(n.hasNonNull(1));
// add null node too
n.add((JsonNode) null);
assertEquals(2, n.size());
assertTrue(n.get(1).isNull());
assertTrue(n.has(1));
assertFalse(n.hasNonNull(1));
// change to text
n.set(1, text);
assertSame(text, n.get(1));
n.set(0, (JsonNode) null);
assertTrue(n.get(0).isNull());
// and finally, clear it all
ArrayNode n2 = new ArrayNode(JsonNodeFactory.instance);
n2.add("foobar");
assertFalse(n.equals(n2));
n.addAll(n2);
assertEquals(3, n.size());
assertFalse(n.get(0).isTextual());
assertNotNull(n.remove(0));
assertEquals(2, n.size());
assertTrue(n.get(0).isTextual());
assertNull(n.remove(-1));
assertNull(n.remove(100));
assertEquals(2, n.size());
ArrayList<JsonNode> nodes = new ArrayList<JsonNode>();
nodes.add(text);
n.addAll(nodes);
assertEquals(3, n.size());
assertNull(n.get(10000));
assertNull(n.remove(-4));
TextNode text2 = TextNode.valueOf("b");
n.insert(0, text2);
assertEquals(4, n.size());
assertSame(text2, n.get(0));
assertNotNull(n.addArray());
assertEquals(5, n.size());
n.addPOJO("foo");
assertEquals(6, n.size());
n.removeAll();
assertEquals(0, n.size());
}
@Test
public void testDirectCreation2() throws Exception
{
JsonNodeFactory f = MAPPER.getNodeFactory();
ArrayList<JsonNode> list = new ArrayList<>();
list.add(f.booleanNode(true));
list.add(f.textNode("foo"));
ArrayNode n = new ArrayNode(f, list);
assertEquals(2, n.size());
assertTrue(n.get(0).isBoolean());
assertTrue(n.get(1).isTextual());
// also, should fail with invalid set attempt
try {
n.set(2, f.nullNode());
fail("Should not pass");
} catch (IndexOutOfBoundsException e) {
verifyException(e, "illegal index");
}
n.insert(1, (String) null);
assertEquals(3, n.size());
assertTrue(n.get(0).isBoolean());
assertTrue(n.get(1).isNull());
assertTrue(n.get(2).isTextual());
n.removeAll();
n.insert(0, (JsonNode) null);
assertEquals(1, n.size());
assertTrue(n.get(0).isNull());
}
@Test
public void testArraySet() throws Exception {
final ArrayNode array = JsonNodeFactory.instance.arrayNode();
for (int i = 0; i < 20; i++) {
array.add("Original Data");
}
array.setPOJO(0, "MyPojo");
array.setRawValue(1, new RawValue("MyRawValue"));
array.setNull(2);
array.set(3, (short) 155);
array.set(4, Short.valueOf((short) 130));
array.set(5, 132);
array.set(6, Integer.valueOf(452));
array.set(7, 4342L);
array.set(8, Long.valueOf(154242L));
array.set(9, 1.25f);
array.set(10, Float.valueOf(242.25f));
array.set(11, 132.25D);
array.set(12, Double.valueOf(231.5D));
array.set(13, BigDecimal.TEN);
array.set(14, BigInteger.ONE);
array.set(15, "Modified Data");
array.set(16, true);
array.set(17, Boolean.FALSE);
array.set(18, new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
assertEquals("MyPojo", ((POJONode) array.get(0)).getPojo());
assertEquals(new RawValue("MyRawValue"), ((POJONode) array.get(1)).getPojo());
assertEquals(NullNode.instance, array.get(2));
assertEquals((short) 155, array.get(3).shortValue());
assertEquals((short) 130, array.get(4).shortValue());
assertEquals(132, array.get(5).intValue());
assertEquals(452, array.get(6).intValue());
assertEquals(4342L, array.get(7).longValue());
assertEquals(154242L, array.get(8).longValue());
assertEquals(1.25f, array.get(9).floatValue(), 0.00001f);
assertEquals(242.25f, array.get(10).floatValue(), 0.00001f);
assertEquals(132.25D, array.get(11).doubleValue(), 0.000000001d);
assertEquals(231.5D, array.get(12).doubleValue(), 0.000000001d);
assertEquals(0, BigDecimal.TEN.compareTo(array.get(13).decimalValue()));
assertEquals(BigInteger.ONE, array.get(14).bigIntegerValue());
assertEquals("Modified Data", array.get(15).textValue());
assertTrue(array.get(16).booleanValue());
assertFalse(array.get(17).booleanValue());
assertArrayEquals(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, array.get(18).binaryValue());
assertEquals(20, array.size());
for (int i = 0; i < 20; i++) {
if (i <= 18) {
assertNotEquals("Original Data", array.get(i).textValue());
} else {
assertEquals("Original Data", array.get(i).textValue());
}
}
}
@Test
public void testArrayViaMapper() throws Exception
{
final String JSON = "[[[-0.027512,51.503221],[-0.008497,51.503221],[-0.008497,51.509744],[-0.027512,51.509744]]]";
JsonNode n = MAPPER.readTree(JSON);
assertNotNull(n);
assertTrue(n.isArray());
ArrayNode an = (ArrayNode) n;
assertEquals(1, an.size());
ArrayNode an2 = (ArrayNode) n.get(0);
assertTrue(an2.isArray());
assertEquals(4, an2.size());
}
@Test
public void testAdds()
{
ArrayNode n = new ArrayNode(JsonNodeFactory.instance);
assertNotNull(n.addArray());
assertNotNull(n.addObject());
n.addPOJO("foobar");
n.add(1);
n.add(1L);
n.add(0.5);
n.add(0.5f);
n.add(new BigDecimal("0.2"));
n.add(BigInteger.TEN);
assertEquals(9, n.size());
assertFalse(n.isEmpty());
assertNotNull(n.insertArray(0));
assertNotNull(n.insertObject(0));
n.insertPOJO(2, "xxx");
assertEquals(12, n.size());
n.insert(0, BigInteger.ONE);
n.insert(0, new BigDecimal("0.1"));
assertEquals(14, n.size());
}
@Test
public void testNullAdds()
{
JsonNodeFactory f = MAPPER.getNodeFactory();
ArrayNode array = f.arrayNode(14);
array.add((BigDecimal) null);
array.add((BigInteger) null);
array.add((Boolean) null);
array.add((byte[]) null);
array.add((Double) null);
array.add((Float) null);
array.add((Integer) null);
array.add((JsonNode) null);
array.add((Long) null);
array.add((String) null);
assertEquals(10, array.size());
for (JsonNode node : array) {
assertTrue(node.isNull());
}
}
@Test
public void testAddAllWithNullInCollection()
{
// preparation
final ArrayNode array = JsonNodeFactory.instance.arrayNode();
// test
array.addAll(Arrays.asList(null, JsonNodeFactory.instance.objectNode()));
// assertions
assertEquals(2, array.size());
for (JsonNode node : array) {
assertNotNull(node);
}
assertEquals(NullNode.getInstance(), array.get(0));
}
@Test
public void testNullInserts()
{
JsonNodeFactory f = MAPPER.getNodeFactory();
ArrayNode array = f.arrayNode(3);
array.insert(0, (BigDecimal) null);
array.insert(0, (BigInteger) null);
array.insert(0, (Boolean) null);
// Offsets out of the range are fine; negative become 0;
// super big just add at the end
array.insert(-56, (byte[]) null);
array.insert(0, (Double) null);
array.insert(200, (Float) null);
array.insert(0, (Integer) null);
array.insert(1, (JsonNode) null);
array.insert(array.size(), (Long) null);
array.insert(1, (String) null);
assertEquals(10, array.size());
for (JsonNode node : array) {
assertTrue(node.isNull());
}
}
@Test
public void testNullSet()
{
JsonNodeFactory f = MAPPER.getNodeFactory();
ArrayNode array = f.arrayNode(3);
for (int i = 0; i < 14; i++) {
array.add("Not Null");
}
for (JsonNode node : array) {
assertFalse(node.isNull());
}
array.set(0, (BigDecimal) null);
array.set(1, (BigInteger) null);
array.set(2, (Boolean) null);
array.set(3, (byte[]) null);
array.set(4, (Double) null);
array.set(5, (Float) null);
array.set(6, (Integer) null);
array.set(7, (Short) null);
array.set(8, (JsonNode) null);
array.set(9, (Long) null);
array.set(10, (String) null);
array.setNull(11);
array.setRawValue(12, null);
array.setPOJO(13, null);
assertEquals(14, array.size());
for (JsonNode node : array) {
assertTrue(node.isNull());
}
}
@Test
public void testNullChecking()
{
ArrayNode a1 = JsonNodeFactory.instance.arrayNode();
ArrayNode a2 = JsonNodeFactory.instance.arrayNode();
// used to throw NPE before fix:
a1.addAll(a2);
assertEquals(0, a1.size());
assertEquals(0, a2.size());
a2.addAll(a1);
assertEquals(0, a1.size());
assertEquals(0, a2.size());
}
@Test
public void testNullChecking2()
{
ArrayNode src = MAPPER.createArrayNode();
ArrayNode dest = MAPPER.createArrayNode();
src.add("element");
dest.addAll(src);
}
@Test
public void testParser() throws Exception
{
ArrayNode n = new ArrayNode(JsonNodeFactory.instance);
n.add(123);
TreeTraversingParser p = new TreeTraversingParser(n, null);
p.setCodec(null);
assertNull(p.getCodec());
assertNotNull(p.getParsingContext());
assertTrue(p.getParsingContext().inRoot());
assertNotNull(p.currentTokenLocation());
assertNotNull(p.currentLocation());
assertNull(p.getEmbeddedObject());
assertNull(p.currentNode());
//assertNull(p.getNumberType());
assertToken(JsonToken.START_ARRAY, p.nextToken());
assertNotNull(p.getParsingContext());
assertTrue(p.getParsingContext().inArray());
p.skipChildren();
assertToken(JsonToken.END_ARRAY, p.currentToken());
p.close();
p = new TreeTraversingParser(n, null);
p.nextToken();
assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
assertEquals(JsonParser.NumberType.INT, p.getNumberType());
p.close();
}
@Test
public void testArrayNodeEquality()
{
ArrayNode n1 = new ArrayNode(null);
ArrayNode n2 = new ArrayNode(null);
assertTrue(n1.equals(n2));
assertTrue(n2.equals(n1));
n1.add(TextNode.valueOf("Test"));
assertFalse(n1.equals(n2));
assertFalse(n2.equals(n1));
n2.add(TextNode.valueOf("Test"));
assertTrue(n1.equals(n2));
assertTrue(n2.equals(n1));
}
@Test
public void testSimpleArray() throws Exception
{
ArrayNode result = MAPPER.createArrayNode();
assertTrue(result.isArray());
assertType(result, ArrayNode.class);
assertFalse(result.isObject());
assertFalse(result.isNumber());
assertFalse(result.isNull());
assertFalse(result.isTextual());
// and let's add stuff...
result.add(false);
result.insertNull(0);
// should be equal to itself no matter what
assertEquals(result, result);
assertFalse(result.equals(null)); // but not to null
// plus see that we can access stuff
assertEquals(NullNode.instance, result.path(0));
assertEquals(NullNode.instance, result.get(0));
assertEquals(NullNode.instance, result.optional(0).get());
assertEquals(BooleanNode.FALSE, result.path(1));
assertEquals(BooleanNode.FALSE, result.get(1));
assertEquals(BooleanNode.FALSE, result.optional(1).get());
assertEquals(2, result.size());
assertNull(result.get(-1));
assertNull(result.get(2));
assertFalse(result.optional(-1).isPresent());
assertFalse(result.optional(2).isPresent());
JsonNode missing = result.path(2);
assertTrue(missing.isMissingNode());
assertTrue(result.path(-100).isMissingNode());
// then construct and compare
ArrayNode array2 = MAPPER.createArrayNode();
array2.addNull();
array2.add(false);
assertEquals(result, array2);
// plus remove entries
JsonNode rm1 = array2.remove(0);
assertEquals(NullNode.instance, rm1);
assertEquals(1, array2.size());
assertEquals(BooleanNode.FALSE, array2.get(0));
assertFalse(result.equals(array2));
JsonNode rm2 = array2.remove(0);
assertEquals(BooleanNode.FALSE, rm2);
assertEquals(0, array2.size());
}
@Test
public void testSimpleMismatch() throws Exception
{
try {
MAPPER.readValue(" 123 ", ArrayNode.class);
fail("Should not pass");
} catch (MismatchedInputException e) {
verifyException(e, "from Integer value (token `JsonToken.VALUE_NUMBER_INT`)");
}
}
// [databind#4863]: valueStream(), entryStream(), forEachEntry()
@Test
public void testStreamMethods()
{
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.propertyStream().count());
assertEquals(Arrays.asList(),
arr.propertyStream().collect(Collectors.toList()));
// And then empty forEachEntry()
arr.forEachEntry((k, v) -> { throw new UnsupportedOperationException(); });
}
@Test
public void testRemoveAll() throws Exception
{
assertEquals(_arrayNode("[]"),
_arrayNode("['a', 2, null, true]").removeAll());
}
// [databind#4955]: remove methods
@Test
public void testRemoveIf() throws Exception
{
assertEquals(_arrayNode("[3]"),
_arrayNode("[2, 1, 3]")
.removeIf(value -> value.asInt() <= 2));
assertEquals(_arrayNode("[1]"),
_arrayNode("[1, 2, 3]")
.removeIf(value -> value.asInt() > 1));
}
// [databind#4955]: remove methods
@Test
public void testRemoveNulls() throws Exception
{
assertEquals(_arrayNode("[2]"),
_arrayNode("[null, null, 2, null]")
.removeNulls());
}
private ArrayNode _arrayNode(String json) throws Exception {
return (ArrayNode) MAPPER.readTree(a2q(json));
}
}