• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.node;
2 
3 import java.io.IOException;
4 import java.math.BigInteger;
5 import java.util.*;
6 
7 import static org.junit.Assert.*;
8 
9 import com.fasterxml.jackson.annotation.*;
10 
11 import com.fasterxml.jackson.core.*;
12 import com.fasterxml.jackson.core.JsonParser.NumberType;
13 import com.fasterxml.jackson.core.exc.InputCoercionException;
14 import com.fasterxml.jackson.databind.*;
15 import com.fasterxml.jackson.databind.exc.InvalidFormatException;
16 
17 public class TestTreeTraversingParser
18     extends BaseMapTest
19 {
20     static class Person {
21         public String name;
22         public int magicNumber;
23         public List<String> kids;
24     }
25 
26     @JsonIgnoreProperties(ignoreUnknown=true)
27     public static class Jackson370Bean {
28         public Inner inner;
29     }
30 
31     public static class Inner {
32         public String value;
33     }
34 
35     /*
36     /**********************************************************
37     /* Test methods
38     /**********************************************************
39      */
40 
41     private final ObjectMapper MAPPER = newJsonMapper();
42 
testSimple()43     public void testSimple() throws Exception
44     {
45         // For convenience, parse tree from JSON first
46         final String JSON =
47             "{ \"a\" : 123, \"list\" : [ 12.25, null, true, { }, [ ] ] }";
48         JsonNode tree = MAPPER.readTree(JSON);
49         JsonParser p = tree.traverse();
50 
51         assertNull(p.currentToken());
52         assertNull(p.currentName());
53 
54         assertToken(JsonToken.START_OBJECT, p.nextToken());
55         assertNull(p.currentName());
56         assertEquals("Expected START_OBJECT", JsonToken.START_OBJECT.asString(), p.getText());
57 
58         assertToken(JsonToken.FIELD_NAME, p.nextToken());
59         assertEquals("a", p.currentName());
60         assertEquals("a", p.getText());
61 
62         assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
63         assertEquals("a", p.currentName());
64         assertEquals(123, p.getIntValue());
65         assertEquals("123", p.getText());
66 
67         assertToken(JsonToken.FIELD_NAME, p.nextToken());
68         assertEquals("list", p.currentName());
69         assertEquals("list", p.getText());
70 
71         assertToken(JsonToken.START_ARRAY, p.nextToken());
72         assertEquals("list", p.currentName());
73         assertEquals(JsonToken.START_ARRAY.asString(), p.getText());
74 
75         assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
76         assertNull(p.currentName());
77         assertEquals(12.25, p.getDoubleValue(), 0);
78         assertEquals("12.25", p.getText());
79 
80         assertToken(JsonToken.VALUE_NULL, p.nextToken());
81         assertNull(p.currentName());
82         assertEquals(JsonToken.VALUE_NULL.asString(), p.getText());
83 
84         assertToken(JsonToken.VALUE_TRUE, p.nextToken());
85         assertNull(p.currentName());
86         assertTrue(p.getBooleanValue());
87         assertEquals(JsonToken.VALUE_TRUE.asString(), p.getText());
88 
89         assertToken(JsonToken.START_OBJECT, p.nextToken());
90         assertNull(p.currentName());
91         assertToken(JsonToken.END_OBJECT, p.nextToken());
92         assertNull(p.currentName());
93 
94         assertToken(JsonToken.START_ARRAY, p.nextToken());
95         assertNull(p.currentName());
96         assertToken(JsonToken.END_ARRAY, p.nextToken());
97         assertNull(p.currentName());
98 
99         assertToken(JsonToken.END_ARRAY, p.nextToken());
100 
101         assertToken(JsonToken.END_OBJECT, p.nextToken());
102         assertNull(p.currentName());
103 
104         assertNull(p.nextToken());
105 
106         p.close();
107         assertTrue(p.isClosed());
108     }
109 
testArray()110     public void testArray() throws Exception
111     {
112         // For convenience, parse tree from JSON first
113         JsonParser p = MAPPER.readTree("[]").traverse();
114         assertToken(JsonToken.START_ARRAY, p.nextToken());
115         assertToken(JsonToken.END_ARRAY, p.nextToken());
116         p.close();
117 
118         p = MAPPER.readTree("[[]]").traverse();
119         assertToken(JsonToken.START_ARRAY, p.nextToken());
120         assertToken(JsonToken.START_ARRAY, p.nextToken());
121         assertToken(JsonToken.END_ARRAY, p.nextToken());
122         assertToken(JsonToken.END_ARRAY, p.nextToken());
123         p.close();
124 
125         p = MAPPER.readTree("[[ 12.1 ]]").traverse();
126         assertToken(JsonToken.START_ARRAY, p.nextToken());
127         assertToken(JsonToken.START_ARRAY, p.nextToken());
128         assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
129         assertToken(JsonToken.END_ARRAY, p.nextToken());
130         assertToken(JsonToken.END_ARRAY, p.nextToken());
131         p.close();
132     }
133 
testNested()134     public void testNested() throws Exception
135     {
136         // For convenience, parse tree from JSON first
137         final String JSON =
138             "{\"coordinates\":[[[-3,\n1],[179.859681,51.175092]]]}"
139             ;
140         JsonNode tree = MAPPER.readTree(JSON);
141         JsonParser p = tree.traverse();
142         assertToken(JsonToken.START_OBJECT, p.nextToken());
143         assertToken(JsonToken.FIELD_NAME, p.nextToken());
144 
145         assertToken(JsonToken.START_ARRAY, p.nextToken());
146         assertToken(JsonToken.START_ARRAY, p.nextToken());
147 
148         assertToken(JsonToken.START_ARRAY, p.nextToken());
149         assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
150         assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
151         assertToken(JsonToken.END_ARRAY, p.nextToken());
152 
153         assertToken(JsonToken.START_ARRAY, p.nextToken());
154         assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
155         assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
156         assertToken(JsonToken.END_ARRAY, p.nextToken());
157 
158         assertToken(JsonToken.END_ARRAY, p.nextToken());
159         assertToken(JsonToken.END_ARRAY, p.nextToken());
160 
161         assertToken(JsonToken.END_OBJECT, p.nextToken());
162         p.close();
163     }
164 
165     /**
166      * Unit test that verifies that we can (re)parse sample document
167      * from JSON specification.
168      */
testSpecDoc()169     public void testSpecDoc() throws Exception
170     {
171         JsonNode tree = MAPPER.readTree(SAMPLE_DOC_JSON_SPEC);
172         JsonParser p = tree.traverse();
173         verifyJsonSpecSampleDoc(p, true);
174         p.close();
175     }
176 
testBinaryPojo()177     public void testBinaryPojo() throws Exception
178     {
179         byte[] inputBinary = new byte[] { 1, 2, 100 };
180         POJONode n = new POJONode(inputBinary);
181         JsonParser p = n.traverse();
182 
183         assertNull(p.currentToken());
184         assertToken(JsonToken.VALUE_EMBEDDED_OBJECT, p.nextToken());
185         byte[] data = p.getBinaryValue();
186         assertNotNull(data);
187         assertArrayEquals(inputBinary, data);
188         Object pojo = p.getEmbeddedObject();
189         assertSame(data, pojo);
190         p.close();
191     }
192 
testBinaryNode()193     public void testBinaryNode() throws Exception
194     {
195         byte[] inputBinary = new byte[] { 0, -5 };
196         BinaryNode n = new BinaryNode(inputBinary);
197         JsonParser p = n.traverse();
198 
199         assertNull(p.currentToken());
200         // exposed as POJO... not as VALUE_STRING
201         assertToken(JsonToken.VALUE_EMBEDDED_OBJECT, p.nextToken());
202         byte[] data = p.getBinaryValue();
203         assertNotNull(data);
204         assertArrayEquals(inputBinary, data);
205 
206         // but as importantly, can be viewed as base64 encoded thing:
207         assertEquals("APs=", p.getText());
208 
209         assertNull(p.nextToken());
210         p.close();
211     }
212 
testTextAsBinary()213     public void testTextAsBinary() throws Exception
214     {
215         TextNode n = new TextNode("   APs=\n");
216         JsonParser p = n.traverse();
217         assertNull(p.currentToken());
218         assertToken(JsonToken.VALUE_STRING, p.nextToken());
219         byte[] data = p.getBinaryValue();
220         assertNotNull(data);
221         assertArrayEquals(new byte[] { 0, -5 }, data);
222 
223         assertNull(p.nextToken());
224         p.close();
225         assertTrue(p.isClosed());
226 
227         // Also: let's verify we get an exception for garbage...
228         n = new TextNode("?!??");
229         p = n.traverse();
230         assertToken(JsonToken.VALUE_STRING, p.nextToken());
231         try {
232             p.getBinaryValue();
233         } catch (InvalidFormatException e) {
234             verifyException(e, "Illegal character");
235         }
236         p.close();
237     }
238 
239     /**
240      * Very simple test case to verify that tree-to-POJO
241      * conversion works ok
242      */
testDataBind()243     public void testDataBind() throws Exception
244     {
245         JsonNode tree = MAPPER.readTree
246             ("{ \"name\" : \"Tatu\", \n"
247              +"\"magicNumber\" : 42,"
248              +"\"kids\" : [ \"Leo\", \"Lila\", \"Leia\" ] \n"
249              +"}");
250         Person tatu = MAPPER.treeToValue(tree, Person.class);
251         assertNotNull(tatu);
252         assertEquals(42, tatu.magicNumber);
253         assertEquals("Tatu", tatu.name);
254         assertNotNull(tatu.kids);
255         assertEquals(3, tatu.kids.size());
256         assertEquals("Leo", tatu.kids.get(0));
257         assertEquals("Lila", tatu.kids.get(1));
258         assertEquals("Leia", tatu.kids.get(2));
259     }
260 
testSkipChildrenWrt370()261     public void testSkipChildrenWrt370() throws Exception
262     {
263         ObjectNode n = MAPPER.createObjectNode();
264         n.putObject("inner").put("value", "test");
265         n.putObject("unknown").putNull("inner");
266         Jackson370Bean obj = MAPPER.readValue(n.traverse(), Jackson370Bean.class);
267         assertNotNull(obj.inner);
268         assertEquals("test", obj.inner.value);
269     }
270 
271     // // // Numeric coercion checks, [databind#2189]
272 
testNumberOverflowInt()273     public void testNumberOverflowInt() throws IOException
274     {
275         final long tooBig = 1L + Integer.MAX_VALUE;
276         try (final JsonParser p = MAPPER.readTree("[ "+tooBig+" ]").traverse()) {
277             assertToken(JsonToken.START_ARRAY, p.nextToken());
278             assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
279             assertEquals(NumberType.LONG, p.getNumberType());
280             try {
281                 p.getIntValue();
282                 fail("Expected failure for `int` overflow");
283             } catch (InputCoercionException e) {
284                 verifyException(e, "Numeric value ("+tooBig+") out of range of int");
285             }
286         }
287         try (final JsonParser p = MAPPER.readTree("{ \"value\" : "+tooBig+" }").traverse()) {
288             assertToken(JsonToken.START_OBJECT, p.nextToken());
289             assertToken(JsonToken.FIELD_NAME, p.nextToken());
290             assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
291             assertEquals(NumberType.LONG, p.getNumberType());
292             try {
293                 p.getIntValue();
294                 fail("Expected failure for `int` overflow");
295             } catch (InputCoercionException e) {
296                 verifyException(e, "Numeric value ("+tooBig+") out of range of int");
297             }
298         }
299         // But also from floating-point
300         final String tooBig2 = "1.0e10";
301         try (final JsonParser p = MAPPER.readTree("[ "+tooBig2+" ]").traverse()) {
302             assertToken(JsonToken.START_ARRAY, p.nextToken());
303             assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
304             assertEquals(NumberType.DOUBLE, p.getNumberType());
305             try {
306                 p.getIntValue();
307                 fail("Expected failure for `int` overflow");
308             } catch (InputCoercionException e) {
309                 verifyException(e, "Numeric value ("+tooBig2+") out of range of int");
310             }
311         }
312     }
313 
testNumberOverflowLong()314     public void testNumberOverflowLong() throws IOException
315     {
316         final BigInteger tooBig = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
317         try (final JsonParser p = MAPPER.readTree("[ "+tooBig+" ]").traverse()) {
318             assertToken(JsonToken.START_ARRAY, p.nextToken());
319             assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
320             assertEquals(NumberType.BIG_INTEGER, p.getNumberType());
321             try {
322                 p.getLongValue();
323                 fail("Expected failure for `long` overflow");
324             } catch (InputCoercionException e) {
325                 verifyException(e, "Numeric value ("+tooBig+") out of range of long");
326             }
327         }
328         try (final JsonParser p = MAPPER.readTree("{ \"value\" : "+tooBig+" }").traverse()) {
329             assertToken(JsonToken.START_OBJECT, p.nextToken());
330             assertToken(JsonToken.FIELD_NAME, p.nextToken());
331             assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
332             assertEquals(NumberType.BIG_INTEGER, p.getNumberType());
333             try {
334                 p.getLongValue();
335                 fail("Expected failure for `long` overflow");
336             } catch (InputCoercionException e) {
337                 verifyException(e, "Numeric value ("+tooBig+") out of range of long");
338             }
339         }
340         // But also from floating-point
341         final String tooBig2 = "1.0e30";
342         try (final JsonParser p = MAPPER.readTree("[ "+tooBig2+" ]").traverse()) {
343             assertToken(JsonToken.START_ARRAY, p.nextToken());
344             assertToken(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
345             assertEquals(NumberType.DOUBLE, p.getNumberType());
346             try {
347                 p.getLongValue();
348                 fail("Expected failure for `long` overflow");
349             } catch (InputCoercionException e) {
350                 verifyException(e, "Numeric value ("+tooBig2+") out of range of long");
351             }
352         }
353 
354         // Plus, wrt [databind#2393], NON-failing cases
355         final long[] okValues = new long[] { 1L+Integer.MAX_VALUE, -1L + Integer.MIN_VALUE,
356                 Long.MAX_VALUE, Long.MIN_VALUE };
357         for (long okValue : okValues) {
358             try (final JsonParser p = MAPPER.readTree("{ \"value\" : "+okValue+" }").traverse()) {
359                 assertToken(JsonToken.START_OBJECT, p.nextToken());
360                 assertToken(JsonToken.FIELD_NAME, p.nextToken());
361                 assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken());
362                 assertEquals(NumberType.LONG, p.getNumberType());
363                 assertEquals(okValue, p.getLongValue());
364                 assertToken(JsonToken.END_OBJECT, p.nextToken());
365             }
366         }
367     }
368 }
369