• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.node;
2 
3 import java.math.BigDecimal;
4 import java.math.BigInteger;
5 import java.util.*;
6 
7 import com.fasterxml.jackson.annotation.JsonCreator;
8 import com.fasterxml.jackson.annotation.JsonInclude;
9 import com.fasterxml.jackson.annotation.JsonValue;
10 import com.fasterxml.jackson.databind.*;
11 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
12 import com.fasterxml.jackson.databind.exc.MismatchedInputException;
13 
14 /**
15  * Additional tests for {@link ObjectNode} container class.
16  */
17 public class ObjectNodeTest
18     extends BaseMapTest
19 {
20     @JsonDeserialize(as = DataImpl.class)
21     public interface Data {
22     }
23 
24     public static class DataImpl implements Data
25     {
26         protected JsonNode root;
27 
28         @JsonCreator
DataImpl(JsonNode n)29         public DataImpl(JsonNode n) {
30             root = n;
31         }
32 
33         @JsonValue
value()34         public JsonNode value() { return root; }
35 
36         /*
37         public Wrapper(ObjectNode n) { root = n; }
38 
39         @JsonValue
40         public ObjectNode value() { return root; }
41         */
42     }
43 
44     static class ObNodeWrapper {
45         @JsonInclude(JsonInclude.Include.NON_EMPTY)
46         public ObjectNode node;
47 
ObNodeWrapper()48         protected ObNodeWrapper() { }
ObNodeWrapper(ObjectNode n)49         public ObNodeWrapper(ObjectNode n) {
50             node = n;
51         }
52     }
53 
54     // [databind#941]
55     static class MyValue
56     {
57         private final ObjectNode object;
58 
59         @JsonCreator
MyValue(ObjectNode object)60         public MyValue(ObjectNode object) { this.object = object; }
61 
62         @JsonValue
getObject()63         public ObjectNode getObject() { return object; }
64     }
65 
66     /*
67     /**********************************************************
68     /* Test methods
69     /**********************************************************
70      */
71 
72     private final ObjectMapper MAPPER = sharedMapper();
73 
testSimpleObject()74     public void testSimpleObject() throws Exception
75     {
76         String JSON = "{ \"key\" : 1, \"b\" : \"x\" }";
77         JsonNode root = MAPPER.readTree(JSON);
78 
79         // basic properties first:
80         assertFalse(root.isValueNode());
81         assertTrue(root.isContainerNode());
82         assertFalse(root.isArray());
83         assertTrue(root.isObject());
84         assertEquals(2, root.size());
85         assertFalse(root.isEmpty());
86 
87         Iterator<JsonNode> it = root.iterator();
88         assertNotNull(it);
89         assertTrue(it.hasNext());
90         JsonNode n = it.next();
91         assertNotNull(n);
92         assertEquals(IntNode.valueOf(1), n);
93 
94         assertTrue(it.hasNext());
95         n = it.next();
96         assertNotNull(n);
97         assertEquals(TextNode.valueOf("x"), n);
98 
99         assertFalse(it.hasNext());
100 
101         // Ok, then, let's traverse via extended interface
102         ObjectNode obNode = (ObjectNode) root;
103         Iterator<Map.Entry<String,JsonNode>> fit = obNode.fields();
104         // we also know that LinkedHashMap is used, i.e. order preserved
105         assertTrue(fit.hasNext());
106         Map.Entry<String,JsonNode> en = fit.next();
107         assertEquals("key", en.getKey());
108         assertEquals(IntNode.valueOf(1), en.getValue());
109 
110         assertTrue(fit.hasNext());
111         en = fit.next();
112         assertEquals("b", en.getKey());
113         assertEquals(TextNode.valueOf("x"), en.getValue());
114 
115         // Plus: we should be able to modify the node via iterator too:
116         fit.remove();
117         assertEquals(1, obNode.size());
118         assertEquals(IntNode.valueOf(1), root.get("key"));
119         assertNull(root.get("b"));
120     }
121     // for [databind#346]
testEmptyNodeAsValue()122     public void testEmptyNodeAsValue() throws Exception
123     {
124         Data w = MAPPER.readValue("{}", Data.class);
125         assertNotNull(w);
126     }
127 
testBasics()128     public void testBasics()
129     {
130         ObjectNode n = new ObjectNode(JsonNodeFactory.instance);
131         assertStandardEquals(n);
132         assertTrue(n.isEmpty());
133 
134         assertFalse(n.elements().hasNext());
135         assertFalse(n.fields().hasNext());
136         assertFalse(n.fieldNames().hasNext());
137         assertNull(n.get("a"));
138         assertTrue(n.path("a").isMissingNode());
139 
140         TextNode text = TextNode.valueOf("x");
141         assertSame(n, n.set("a", text));
142 
143         assertEquals(1, n.size());
144         assertTrue(n.elements().hasNext());
145         assertTrue(n.fields().hasNext());
146         assertTrue(n.fieldNames().hasNext());
147         assertSame(text, n.get("a"));
148         assertSame(text, n.path("a"));
149         assertNull(n.get("b"));
150         assertNull(n.get(0)); // not used with objects
151 
152         assertFalse(n.has(0));
153         assertFalse(n.hasNonNull(0));
154         assertTrue(n.has("a"));
155         assertTrue(n.hasNonNull("a"));
156         assertFalse(n.has("b"));
157         assertFalse(n.hasNonNull("b"));
158 
159         ObjectNode n2 = new ObjectNode(JsonNodeFactory.instance);
160         n2.put("b", 13);
161         assertFalse(n.equals(n2));
162         n.setAll(n2);
163 
164         assertEquals(2, n.size());
165         n.set("null", (JsonNode)null);
166         assertEquals(3, n.size());
167         // may be non-intuitive, but explicit nulls do exist in tree:
168         assertTrue(n.has("null"));
169         assertFalse(n.hasNonNull("null"));
170         // should replace, not add
171         n.put("null", "notReallNull");
172         assertEquals(3, n.size());
173         assertNotNull(n.remove("null"));
174         assertEquals(2, n.size());
175 
176         Map<String,JsonNode> nodes = new HashMap<String,JsonNode>();
177         nodes.put("d", text);
178         n.setAll(nodes);
179         assertEquals(3, n.size());
180 
181         n.removeAll();
182         assertEquals(0, n.size());
183     }
184 
testBigNumbers()185     public void testBigNumbers()
186     {
187         ObjectNode n = new ObjectNode(JsonNodeFactory.instance);
188         assertStandardEquals(n);
189         BigInteger I = BigInteger.valueOf(3);
190         BigDecimal DEC = new BigDecimal("0.1");
191 
192         n.put("a", DEC);
193         n.put("b", I);
194 
195         assertEquals(2, n.size());
196 
197         assertTrue(n.path("a").isBigDecimal());
198         assertEquals(DEC, n.get("a").decimalValue());
199         assertTrue(n.path("b").isBigInteger());
200         assertEquals(I, n.get("b").bigIntegerValue());
201     }
202 
203     /**
204      * Verify null handling
205      */
testNullChecking()206     public void testNullChecking()
207     {
208         ObjectNode o1 = JsonNodeFactory.instance.objectNode();
209         ObjectNode o2 = JsonNodeFactory.instance.objectNode();
210         // used to throw NPE before fix:
211         o1.setAll(o2);
212         assertEquals(0, o1.size());
213         assertEquals(0, o2.size());
214 
215         // also: nulls should be converted to NullNodes...
216         o1.set("x", null);
217         JsonNode n = o1.get("x");
218         assertNotNull(n);
219         assertSame(n, NullNode.instance);
220 
221         o1.put("str", (String) null);
222         n = o1.get("str");
223         assertNotNull(n);
224         assertSame(n, NullNode.instance);
225 
226         o1.put("d", (BigDecimal) null);
227         n = o1.get("d");
228         assertNotNull(n);
229         assertSame(n, NullNode.instance);
230 
231         o1.put("3", (BigInteger) null);
232         n = o1.get("3");
233         assertNotNull(3);
234         assertSame(n, NullNode.instance);
235 
236         assertEquals(4, o1.size());
237     }
238 
239     /**
240      * Another test to verify [JACKSON-227]...
241      */
testNullChecking2()242     public void testNullChecking2()
243     {
244         ObjectNode src = MAPPER.createObjectNode();
245         ObjectNode dest = MAPPER.createObjectNode();
246         src.put("a", "b");
247         dest.setAll(src);
248     }
249 
testRemove()250     public void testRemove()
251     {
252         ObjectNode ob = MAPPER.createObjectNode();
253         ob.put("a", "a");
254         ob.put("b", "b");
255         ob.put("c", "c");
256         assertEquals(3, ob.size());
257         assertSame(ob, ob.without(Arrays.asList("a", "c")));
258         assertEquals(1, ob.size());
259         assertEquals("b", ob.get("b").textValue());
260     }
261 
testRetain()262     public void testRetain()
263     {
264         ObjectNode ob = MAPPER.createObjectNode();
265         ob.put("a", "a");
266         ob.put("b", "b");
267         ob.put("c", "c");
268         assertEquals(3, ob.size());
269         assertSame(ob, ob.retain("a", "c"));
270         assertEquals(2, ob.size());
271         assertEquals("a", ob.get("a").textValue());
272         assertNull(ob.get("b"));
273         assertEquals("c", ob.get("c").textValue());
274     }
275 
testValidWith()276     public void testValidWith() throws Exception
277     {
278         ObjectNode root = MAPPER.createObjectNode();
279         assertEquals("{}", MAPPER.writeValueAsString(root));
280         JsonNode child = root.with("prop");
281         assertTrue(child instanceof ObjectNode);
282         assertEquals("{\"prop\":{}}", MAPPER.writeValueAsString(root));
283     }
284 
testValidWithArray()285     public void testValidWithArray() throws Exception
286     {
287         JsonNode root = MAPPER.createObjectNode();
288         assertEquals("{}", MAPPER.writeValueAsString(root));
289         ArrayNode child = root.withArray("arr");
290         assertTrue(child instanceof ArrayNode);
291         assertEquals("{\"arr\":[]}", MAPPER.writeValueAsString(root));
292     }
293 
testInvalidWith()294     public void testInvalidWith() throws Exception
295     {
296         JsonNode root = MAPPER.createArrayNode();
297         try { // should not work for non-ObjectNode nodes:
298             root.with("prop");
299             fail("Expected exception");
300         } catch (UnsupportedOperationException e) {
301             verifyException(e, "not of type ObjectNode");
302         }
303         // also: should fail of we already have non-object property
304         ObjectNode root2 = MAPPER.createObjectNode();
305         root2.put("prop", 13);
306         try { // should not work for non-ObjectNode nodes:
307             root2.with("prop");
308             fail("Expected exception");
309         } catch (UnsupportedOperationException e) {
310             verifyException(e, "has value that is not");
311         }
312     }
313 
testInvalidWithArray()314     public void testInvalidWithArray() throws Exception
315     {
316         JsonNode root = MAPPER.createArrayNode();
317         try { // should not work for non-ObjectNode nodes:
318             root.withArray("prop");
319             fail("Expected exception");
320         } catch (UnsupportedOperationException e) {
321             verifyException(e, "not of type ObjectNode");
322         }
323         // also: should fail of we already have non-Array property
324         ObjectNode root2 = MAPPER.createObjectNode();
325         root2.put("prop", 13);
326         try { // should not work for non-ObjectNode nodes:
327             root2.withArray("prop");
328             fail("Expected exception");
329         } catch (UnsupportedOperationException e) {
330             verifyException(e, "has value that is not");
331         }
332     }
333 
testSetAll()334     public void testSetAll() throws Exception
335     {
336         ObjectNode root = MAPPER.createObjectNode();
337         assertEquals(0, root.size());
338         HashMap<String,JsonNode> map = new HashMap<String,JsonNode>();
339         map.put("a", root.numberNode(1));
340         root.setAll(map);
341         assertEquals(1, root.size());
342         assertTrue(root.has("a"));
343         assertFalse(root.has("b"));
344 
345         map.put("b", root.numberNode(2));
346         root.setAll(map);
347         assertEquals(2, root.size());
348         assertTrue(root.has("a"));
349         assertTrue(root.has("b"));
350         assertEquals(2, root.path("b").intValue());
351 
352         // Then with ObjectNodes...
353         ObjectNode root2 = MAPPER.createObjectNode();
354         root2.setAll(root);
355         assertEquals(2, root.size());
356         assertEquals(2, root2.size());
357 
358         root2.setAll(root);
359         assertEquals(2, root.size());
360         assertEquals(2, root2.size());
361 
362         ObjectNode root3 = MAPPER.createObjectNode();
363         root3.put("a", 2);
364         root3.put("c", 3);
365         assertEquals(2, root3.path("a").intValue());
366         root3.setAll(root2);
367         assertEquals(3, root3.size());
368         assertEquals(1, root3.path("a").intValue());
369     }
370 
371     // [databind#237] (databind): support DeserializationFeature#FAIL_ON_READING_DUP_TREE_KEY
testFailOnDupKeys()372     public void testFailOnDupKeys() throws Exception
373     {
374         final String DUP_JSON = "{ \"a\":1, \"a\":2 }";
375 
376         // first: verify defaults:
377         assertFalse(MAPPER.isEnabled(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY));
378         ObjectNode root = (ObjectNode) MAPPER.readTree(DUP_JSON);
379         assertEquals(2, root.path("a").asInt());
380 
381         // and then enable checks:
382         try {
383             MAPPER.reader(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY).readTree(DUP_JSON);
384             fail("Should have thrown exception!");
385         } catch (JsonMappingException e) {
386             verifyException(e, "duplicate field 'a'");
387         }
388     }
389 
testFailOnDupNestedKeys()390     public void testFailOnDupNestedKeys() throws Exception
391     {
392         final String DOC = aposToQuotes(
393                 "{'node' : { 'data' : [ 1, 2, { 'a':3 }, { 'foo' : 1, 'bar' : 2, 'foo': 3}]}}"
394         );
395         try {
396             MAPPER.readerFor(ObNodeWrapper.class)
397                 .with(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY)
398                 .readValue(DOC);
399             fail("Should have thrown exception!");
400         } catch (JsonMappingException e) {
401             verifyException(e, "duplicate field 'foo'");
402         }
403     }
404 
testEqualityWrtOrder()405     public void testEqualityWrtOrder() throws Exception
406     {
407         ObjectNode ob1 = MAPPER.createObjectNode();
408         ObjectNode ob2 = MAPPER.createObjectNode();
409 
410         // same contents, different insertion order; should not matter
411 
412         ob1.put("a", 1);
413         ob1.put("b", 2);
414         ob1.put("c", 3);
415 
416         ob2.put("b", 2);
417         ob2.put("c", 3);
418         ob2.put("a", 1);
419 
420         assertTrue(ob1.equals(ob2));
421         assertTrue(ob2.equals(ob1));
422     }
423 
testSimplePath()424     public void testSimplePath() throws Exception
425     {
426         JsonNode root = MAPPER.readTree("{ \"results\" : { \"a\" : 3 } }");
427         assertTrue(root.isObject());
428         JsonNode rnode = root.path("results");
429         assertNotNull(rnode);
430         assertTrue(rnode.isObject());
431         assertEquals(3, rnode.path("a").intValue());
432     }
433 
testNonEmptySerialization()434     public void testNonEmptySerialization() throws Exception
435     {
436         ObNodeWrapper w = new ObNodeWrapper(MAPPER.createObjectNode()
437                 .put("a", 3));
438         assertEquals("{\"node\":{\"a\":3}}", MAPPER.writeValueAsString(w));
439         w = new ObNodeWrapper(MAPPER.createObjectNode());
440         assertEquals("{}", MAPPER.writeValueAsString(w));
441     }
442 
testIssue941()443     public void testIssue941() throws Exception
444     {
445         ObjectNode object = MAPPER.createObjectNode();
446 
447         String json = MAPPER.writeValueAsString(object);
448 //        System.out.println("json: "+json);
449 
450         ObjectNode de1 = MAPPER.readValue(json, ObjectNode.class);  // this works
451 //        System.out.println("Deserialized to ObjectNode: "+de1);
452         assertNotNull(de1);
453 
454         MyValue de2 = MAPPER.readValue(json, MyValue.class);  // but this throws exception
455 //        System.out.println("Deserialized to MyValue: "+de2);
456         assertNotNull(de2);
457     }
458 
testSimpleMismatch()459     public void testSimpleMismatch() throws Exception
460     {
461         ObjectMapper mapper = objectMapper();
462         try {
463             mapper.readValue("[ 1, 2, 3 ]", ObjectNode.class);
464             fail("Should not pass");
465         } catch (MismatchedInputException e) {
466             verifyException(e, "from Array value (token `JsonToken.START_ARRAY`)");
467         }
468     }
469 }
470