package com.fasterxml.jackson.databind.node; import java.io.*; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.TextNode; import com.fasterxml.jackson.databind.node.TreeTraversingParser; /** * Additional tests for {@link ArrayNode} container class. */ public class ArrayNodeTest extends BaseMapTest { public void testDirectCreation() throws IOException { ArrayNode n = new ArrayNode(JsonNodeFactory.instance); assertStandardEquals(n); assertFalse(n.elements().hasNext()); assertFalse(n.fieldNames().hasNext()); TextNode text = TextNode.valueOf("x"); n.add(text); assertEquals(1, n.size()); 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()); 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, 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()); // Try serializing it for fun, too... JsonGenerator g = objectMapper().getFactory().createGenerator(new StringWriter()); n.serialize(g, null); g.close(); n.removeAll(); assertEquals(0, n.size()); } public void testDirectCreation2() throws IOException { JsonNodeFactory f = objectMapper().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()); } 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 = objectMapper().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()); } 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()); 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()); } public void testNullAdds() { JsonNodeFactory f = objectMapper().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()); } } public void testNullInserts() { JsonNodeFactory f = objectMapper().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()); } } 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()); } public void testNullChecking2() { ObjectMapper mapper = new ObjectMapper(); ArrayNode src = mapper.createArrayNode(); ArrayNode dest = mapper.createArrayNode(); src.add("element"); dest.addAll(src); } 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()); assertNotNull(p.getTokenLocation()); assertNotNull(p.getCurrentLocation()); assertNull(p.getEmbeddedObject()); assertNull(p.currentNode()); //assertNull(p.getNumberType()); assertToken(JsonToken.START_ARRAY, p.nextToken()); p.skipChildren(); assertToken(JsonToken.END_ARRAY, p.getCurrentToken()); p.close(); p = new TreeTraversingParser(n, null); p.nextToken(); assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken()); assertEquals(JsonParser.NumberType.INT, p.getNumberType()); p.close(); } 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)); } public void testSimpleArray() throws Exception { ArrayNode result = objectMapper().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(BooleanNode.FALSE, result.path(1)); assertEquals(BooleanNode.FALSE, result.get(1)); assertEquals(2, result.size()); assertNull(result.get(-1)); assertNull(result.get(2)); JsonNode missing = result.path(2); assertTrue(missing.isMissingNode()); assertTrue(result.path(-100).isMissingNode()); // then construct and compare ArrayNode array2 = objectMapper().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()); } public void testSimpleMismatch() throws Exception { ObjectMapper mapper = objectMapper(); try { mapper.readValue(" 123 ", ArrayNode.class); fail("Should not pass"); } catch (MismatchedInputException e) { verifyException(e, "out of VALUE_NUMBER_INT token"); } } }