1 package com.fasterxml.jackson.databind.node;
2
3 import com.fasterxml.jackson.core.*;
4 import com.fasterxml.jackson.core.type.WritableTypeId;
5 import com.fasterxml.jackson.databind.JsonNode;
6 import com.fasterxml.jackson.databind.SerializerProvider;
7 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
8 import com.fasterxml.jackson.databind.util.RawValue;
9
10 import java.io.IOException;
11 import java.math.BigDecimal;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Comparator;
16 import java.util.Iterator;
17 import java.util.List;
18
19 /**
20 * Node class that represents Arrays mapped from JSON content.
21 *<p>
22 * Note: class was <code>final</code> temporarily for Jackson 2.2.
23 */
24 public class ArrayNode
25 extends ContainerNode<ArrayNode>
26 implements java.io.Serializable // since 2.10
27 {
28 private static final long serialVersionUID = 1L;
29
30 private final List<JsonNode> _children;
31
32 public ArrayNode(JsonNodeFactory nf) {
33 super(nf);
34 _children = new ArrayList<JsonNode>();
35 }
36
37 /**
38 * @since 2.8
39 */
40 public ArrayNode(JsonNodeFactory nf, int capacity) {
41 super(nf);
42 _children = new ArrayList<JsonNode>(capacity);
43 }
44
45 /**
46 * @since 2.7
47 */
48 public ArrayNode(JsonNodeFactory nf, List<JsonNode> children) {
49 super(nf);
50 _children = children;
51 }
52
53 @Override
54 protected JsonNode _at(JsonPointer ptr) {
55 return get(ptr.getMatchingIndex());
56 }
57
58 // note: co-variant to allow caller-side type safety
59 @SuppressWarnings("unchecked")
60 @Override
61 public ArrayNode deepCopy()
62 {
63 ArrayNode ret = new ArrayNode(_nodeFactory);
64
65 for (JsonNode element: _children)
66 ret._children.add(element.deepCopy());
67
68 return ret;
69 }
70
71 /*
72 /**********************************************************
73 /* Overrides for JsonSerializable.Base
74 /**********************************************************
75 */
76
77 @Override
78 public boolean isEmpty(SerializerProvider serializers) {
79 return _children.isEmpty();
80 }
81
82 /*
83 /**********************************************************
84 /* Implementation of core JsonNode API
85 /**********************************************************
86 */
87
88 @Override
89 public JsonNodeType getNodeType() {
90 return JsonNodeType.ARRAY;
91 }
92
93 @Override
94 public boolean isArray() {
95 return true;
96 }
97
98 @Override public JsonToken asToken() { return JsonToken.START_ARRAY; }
99
100 @Override
101 public int size() {
102 return _children.size();
103 }
104
105 @Override // since 2.10
106 public boolean isEmpty() { return _children.isEmpty(); }
107
108 @Override
109 public Iterator<JsonNode> elements() {
110 return _children.iterator();
111 }
112
113 @Override
114 public JsonNode get(int index) {
115 if ((index >= 0) && (index < _children.size())) {
116 return _children.get(index);
117 }
118 return null;
119 }
120
121 @Override
122 public JsonNode get(String fieldName) { return null; }
123
124 @Override
125 public JsonNode path(String fieldName) { return MissingNode.getInstance(); }
126
127 @Override
128 public JsonNode path(int index) {
129 if (index >= 0 && index < _children.size()) {
130 return _children.get(index);
131 }
132 return MissingNode.getInstance();
133 }
134
135 @Override
136 public JsonNode required(int index) {
137 if ((index >= 0) && (index < _children.size())) {
138 return _children.get(index);
139 }
140 return _reportRequiredViolation("No value at index #%d [0, %d) of `ArrayNode`",
141 index, _children.size());
142 }
143
144 @Override
145 public boolean equals(Comparator<JsonNode> comparator, JsonNode o)
146 {
147 if (!(o instanceof ArrayNode)) {
148 return false;
149 }
150 ArrayNode other = (ArrayNode) o;
151 final int len = _children.size();
152 if (other.size() != len) {
153 return false;
154 }
155 List<JsonNode> l1 = _children;
156 List<JsonNode> l2 = other._children;
157 for (int i = 0; i < len; ++i) {
158 if (!l1.get(i).equals(comparator, l2.get(i))) {
159 return false;
160 }
161 }
162 return true;
163 }
164
165 /*
166 /**********************************************************
167 /* Public API, serialization
168 /**********************************************************
169 */
170
171 @Override
172 public void serialize(JsonGenerator f, SerializerProvider provider) throws IOException
173 {
174 final List<JsonNode> c = _children;
175 final int size = c.size();
176 f.writeStartArray(this, size);
177 for (int i = 0; i < size; ++i) { // we'll typically have array list
178 // For now, assuming it's either BaseJsonNode, JsonSerializable
179 JsonNode n = c.get(i);
180 ((BaseJsonNode) n).serialize(f, provider);
181 }
182 f.writeEndArray();
183 }
184
185 @Override
186 public void serializeWithType(JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer)
187 throws IOException
188 {
189 WritableTypeId typeIdDef = typeSer.writeTypePrefix(g,
190 typeSer.typeId(this, JsonToken.START_ARRAY));
191 for (JsonNode n : _children) {
192 ((BaseJsonNode)n).serialize(g, provider);
193 }
194 typeSer.writeTypeSuffix(g, typeIdDef);
195 }
196
197 /*
198 /**********************************************************
199 /* Public API, finding value nodes
200 /**********************************************************
201 */
202
203 @Override
204 public JsonNode findValue(String fieldName)
205 {
206 for (JsonNode node : _children) {
207 JsonNode value = node.findValue(fieldName);
208 if (value != null) {
209 return value;
210 }
211 }
212 return null;
213 }
214
215 @Override
216 public List<JsonNode> findValues(String fieldName, List<JsonNode> foundSoFar)
217 {
218 for (JsonNode node : _children) {
219 foundSoFar = node.findValues(fieldName, foundSoFar);
220 }
221 return foundSoFar;
222 }
223
224 @Override
225 public List<String> findValuesAsText(String fieldName, List<String> foundSoFar)
226 {
227 for (JsonNode node : _children) {
228 foundSoFar = node.findValuesAsText(fieldName, foundSoFar);
229 }
230 return foundSoFar;
231 }
232
233 @Override
234 public ObjectNode findParent(String fieldName)
235 {
236 for (JsonNode node : _children) {
237 JsonNode parent = node.findParent(fieldName);
238 if (parent != null) {
239 return (ObjectNode) parent;
240 }
241 }
242 return null;
243 }
244
245 @Override
246 public List<JsonNode> findParents(String fieldName, List<JsonNode> foundSoFar)
247 {
248 for (JsonNode node : _children) {
249 foundSoFar = node.findParents(fieldName, foundSoFar);
250 }
251 return foundSoFar;
252 }
253
254 /*
255 /**********************************************************
256 /* Extended ObjectNode API, accessors
257 /**********************************************************
258 */
259
260 /**
261 * Method that will set specified field, replacing old value,
262 * if any.
263 *
264 * @param value to set field to; if null, will be converted
265 * to a {@link NullNode} first (to remove field entry, call
266 * {@link #remove} instead)
267 *
268 * @return Old value of the field, if any; null if there was no
269 * old value.
270 */
271 public JsonNode set(int index, JsonNode value)
272 {
273 if (value == null) { // let's not store 'raw' nulls but nodes
274 value = nullNode();
275 }
276 if (index < 0 || index >= _children.size()) {
277 throw new IndexOutOfBoundsException("Illegal index "+ index +", array size "+size());
278 }
279 return _children.set(index, value);
280 }
281
282 /**
283 * Method for adding specified node at the end of this array.
284 *
285 * @return This node, to allow chaining
286 */
287 public ArrayNode add(JsonNode value)
288 {
289 if (value == null) { // let's not store 'raw' nulls but nodes
290 value = nullNode();
291 }
292 _add(value);
293 return this;
294 }
295
296 /**
297 * Method for adding all child nodes of given Array, appending to
298 * child nodes this array contains
299 *
300 * @param other Array to add contents from
301 *
302 * @return This node (to allow chaining)
303 */
304 public ArrayNode addAll(ArrayNode other)
305 {
306 _children.addAll(other._children);
307 return this;
308 }
309
310 /**
311 * Method for adding given nodes as child nodes of this array node.
312 *
313 * @param nodes Nodes to add
314 *
315 * @return This node (to allow chaining)
316 */
317 public ArrayNode addAll(Collection<? extends JsonNode> nodes)
318 {
319 for (JsonNode node : nodes) {
320 add(node);
321 }
322 return this;
323 }
324
325 /**
326 * Method for inserting specified child node as an element
327 * of this Array. If index is 0 or less, it will be inserted as
328 * the first element; if {@code >= size()}, appended at the end, and otherwise
329 * inserted before existing element in specified index.
330 * No exceptions are thrown for any index.
331 *
332 * @return This node (to allow chaining)
333 */
334 public ArrayNode insert(int index, JsonNode value)
335 {
336 if (value == null) {
337 value = nullNode();
338 }
339 _insert(index, value);
340 return this;
341 }
342
343 /**
344 * Method for removing an entry from this ArrayNode.
345 * Will return value of the entry at specified index, if entry existed;
346 * null if not.
347 *
348 * @return Node removed, if any; null if none
349 */
350 public JsonNode remove(int index)
351 {
352 if (index >= 0 && index < _children.size()) {
353 return _children.remove(index);
354 }
355 return null;
356 }
357
358 /**
359 * Method for removing all elements of this array, leaving the
360 * array empty.
361 *
362 * @return This node (to allow chaining)
363 */
364 @Override
365 public ArrayNode removeAll()
366 {
367 _children.clear();
368 return this;
369 }
370
371 /*
372 /**********************************************************
373 /* Extended ObjectNode API, mutators, generic; addXxx()/insertXxx()
374 /**********************************************************
375 */
376
377 /**
378 * Method that will construct an ArrayNode and add it at the end
379 * of this array node.
380 *
381 * @return Newly constructed ArrayNode
382 */
383 public ArrayNode addArray()
384 {
385 ArrayNode n = arrayNode();
386 _add(n);
387 return n;
388 }
389
390 /**
391 * Method that will construct an ObjectNode and add it at the end
392 * of this array node.
393 *
394 * @return Newly constructed ObjectNode
395 */
396 public ObjectNode addObject()
397 {
398 ObjectNode n = objectNode();
399 _add(n);
400 return n;
401 }
402
403 /**
404 * Method that will construct a POJONode and add it at the end
405 * of this array node.
406 *
407 * @return This array node, to allow chaining
408 */
409 public ArrayNode addPOJO(Object value)
410 {
411 if (value == null) {
412 addNull();
413 } else {
414 _add(pojoNode(value));
415 }
416 return this;
417 }
418
419 /**
420 * @return This array node, to allow chaining
421 *
422 * @since 2.6
423 */
424 public ArrayNode addRawValue(RawValue raw) {
425 if (raw == null) {
426 addNull();
427 } else {
428 _add(rawValueNode(raw));
429 }
430 return this;
431 }
432
433 /**
434 * Method that will add a null value at the end of this array node.
435 *
436 * @return This array node, to allow chaining
437 */
438 public ArrayNode addNull()
439 {
440 _add(nullNode());
441 return this;
442 }
443
444 /**
445 * Method for adding specified number at the end of this array.
446 *
447 * @return This array node, to allow chaining
448 */
449 public ArrayNode add(int v) {
450 _add(numberNode(v));
451 return this;
452 }
453
454 /**
455 * Alternative method that we need to avoid bumping into NPE issues
456 * with auto-unboxing.
457 *
458 * @return This array node, to allow chaining
459 */
460 public ArrayNode add(Integer value) {
461 if (value == null) {
462 return addNull();
463 }
464 return _add(numberNode(value.intValue()));
465 }
466
467 /**
468 * Method for adding specified number at the end of this array.
469 *
470 * @return This array node, to allow chaining
471 */
472 public ArrayNode add(long v) { return _add(numberNode(v)); }
473
474 /**
475 * Alternative method that we need to avoid bumping into NPE issues
476 * with auto-unboxing.
477 *
478 * @return This array node, to allow chaining
479 */
480 public ArrayNode add(Long value) {
481 if (value == null) {
482 return addNull();
483 }
484 return _add(numberNode(value.longValue()));
485 }
486
487 /**
488 * Method for adding specified number at the end of this array.
489 *
490 * @return This array node, to allow chaining
491 */
492 public ArrayNode add(float v) {
493 return _add(numberNode(v));
494 }
495
496 /**
497 * Alternative method that we need to avoid bumping into NPE issues
498 * with auto-unboxing.
499 *
500 * @return This array node, to allow chaining
501 */
502 public ArrayNode add(Float value) {
503 if (value == null) {
504 return addNull();
505 }
506 return _add(numberNode(value.floatValue()));
507 }
508
509 /**
510 * Method for adding specified number at the end of this array.
511 *
512 * @return This array node, to allow chaining
513 */
514 public ArrayNode add(double v) {
515 return _add(numberNode(v));
516 }
517
518 /**
519 * Alternative method that we need to avoid bumping into NPE issues
520 * with auto-unboxing.
521 *
522 * @return This array node, to allow chaining
523 */
524 public ArrayNode add(Double value) {
525 if (value == null) {
526 return addNull();
527 }
528 return _add(numberNode(value.doubleValue()));
529 }
530
531 /**
532 * Method for adding specified number at the end of this array.
533 *
534 * @return This array node, to allow chaining
535 */
536 public ArrayNode add(BigDecimal v) {
537 if (v == null) {
538 return addNull();
539 }
540 return _add(numberNode(v));
541 }
542
543 /**
544 * Method for adding specified number at the end of this array.
545 *
546 * @return This array node, to allow chaining
547 *
548 * @since 2.9
549 */
550 public ArrayNode add(BigInteger v) {
551 if (v == null) {
552 return addNull();
553 }
554 return _add(numberNode(v));
555 }
556
557 /**
558 * Method for adding specified String value at the end of this array.
559 *
560 * @return This array node, to allow chaining
561 */
562 public ArrayNode add(String v) {
563 if (v == null) {
564 return addNull();
565 }
566 return _add(textNode(v));
567 }
568
569 /**
570 * Method for adding specified boolean value at the end of this array.
571 *
572 * @return This array node, to allow chaining
573 */
574 public ArrayNode add(boolean v) {
575 return _add(booleanNode(v));
576 }
577
578 /**
579 * Alternative method that we need to avoid bumping into NPE issues
580 * with auto-unboxing.
581 *
582 * @return This array node, to allow chaining
583 */
584 public ArrayNode add(Boolean value) {
585 if (value == null) {
586 return addNull();
587 }
588 return _add(booleanNode(value.booleanValue()));
589 }
590
591 /**
592 * Method for adding specified binary value at the end of this array
593 * (note: when serializing as JSON, will be output Base64 encoded)
594 *
595 * @return This array node, to allow chaining
596 */
597 public ArrayNode add(byte[] v) {
598 if (v == null) {
599 return addNull();
600 }
601 return _add(binaryNode(v));
602 }
603
604 /**
605 * Method for creating an array node, inserting it at the
606 * specified point in the array,
607 * and returning the <b>newly created array</b>
608 * (note: NOT 'this' array)
609 */
610 public ArrayNode insertArray(int index)
611 {
612 ArrayNode n = arrayNode();
613 _insert(index, n);
614 return n;
615 }
616
617 /**
618 * Method for creating an {@link ObjectNode}, appending it at the end
619 * of this array, and returning the <b>newly created node</b>
620 * (note: NOT 'this' array)
621 *
622 * @return Newly constructed ObjectNode
623 */
624 public ObjectNode insertObject(int index)
625 {
626 ObjectNode n = objectNode();
627 _insert(index, n);
628 return n;
629 }
630
631 /**
632 * Method that will construct a POJONode and
633 * insert it at specified position in this array.
634 *
635 * @return This array node, to allow chaining
636 */
637 public ArrayNode insertPOJO(int index, Object value)
638 {
639 if (value == null) {
640 return insertNull(index);
641 }
642 return _insert(index, pojoNode(value));
643 }
644
645 /**
646 * Method that will insert a null value
647 * at specified position in this array.
648 *
649 * @return This array node, to allow chaining
650 */
651 public ArrayNode insertNull(int index)
652 {
653 _insert(index, nullNode());
654 return this;
655 }
656
657 /**
658 * Method that will insert specified numeric value
659 * at specified position in this array.
660 *
661 * @return This array node, to allow chaining
662 */
663 public ArrayNode insert(int index, int v) {
664 _insert(index, numberNode(v));
665 return this;
666 }
667
668 /**
669 * Alternative method that we need to avoid bumping into NPE issues
670 * with auto-unboxing.
671 *
672 * @return This array node, to allow chaining
673 */
674 public ArrayNode insert(int index, Integer value) {
675 if (value == null) {
676 insertNull(index);
677 } else {
678 _insert(index, numberNode(value.intValue()));
679 }
680 return this;
681 }
682
683 /**
684 * Method that will insert specified numeric value
685 * at specified position in this array.
686 *
687 * @return This array node, to allow chaining
688 */
689 public ArrayNode insert(int index, long v) {
690 return _insert(index, numberNode(v));
691 }
692
693 /**
694 * Alternative method that we need to avoid bumping into NPE issues
695 * with auto-unboxing.
696 *
697 * @return This array node, to allow chaining
698 */
699 public ArrayNode insert(int index, Long value) {
700 if (value == null) {
701 return insertNull(index);
702 }
703 return _insert(index, numberNode(value.longValue()));
704 }
705
706 /**
707 * Method that will insert specified numeric value
708 * at specified position in this array.
709 *
710 * @return This array node, to allow chaining
711 */
712 public ArrayNode insert(int index, float v) {
713 return _insert(index, numberNode(v));
714 }
715
716 /**
717 * Alternative method that we need to avoid bumping into NPE issues
718 * with auto-unboxing.
719 *
720 * @return This array node, to allow chaining
721 */
722 public ArrayNode insert(int index, Float value) {
723 if (value == null) {
724 return insertNull(index);
725 }
726 return _insert(index, numberNode(value.floatValue()));
727 }
728
729 /**
730 * Method that will insert specified numeric value
731 * at specified position in this array.
732 *
733 * @return This array node, to allow chaining
734 */
735 public ArrayNode insert(int index, double v) {
736 return _insert(index, numberNode(v));
737 }
738
739 /**
740 * Alternative method that we need to avoid bumping into NPE issues
741 * with auto-unboxing.
742 *
743 * @return This array node, to allow chaining
744 */
745 public ArrayNode insert(int index, Double value) {
746 if (value == null) {
747 return insertNull(index);
748 }
749 return _insert(index, numberNode(value.doubleValue()));
750 }
751
752 /**
753 * Method that will insert specified numeric value
754 * at specified position in this array.
755 *
756 * @return This array node, to allow chaining
757 */
758 public ArrayNode insert(int index, BigDecimal v) {
759 if (v == null) {
760 return insertNull(index);
761 }
762 return _insert(index, numberNode(v));
763 }
764
765 /**
766 * Method that will insert specified numeric value
767 * at specified position in this array.
768 *
769 * @return This array node, to allow chaining
770 *
771 * @since 2.9
772 */
773 public ArrayNode insert(int index, BigInteger v) {
774 if (v == null) {
775 return insertNull(index);
776 }
777 return _insert(index, numberNode(v));
778 }
779
780 /**
781 * Method that will insert specified String
782 * at specified position in this array.
783 *
784 * @return This array node, to allow chaining
785 */
786 public ArrayNode insert(int index, String v) {
787 if (v == null) {
788 return insertNull(index);
789 }
790 return _insert(index, textNode(v));
791 }
792
793 /**
794 * Method that will insert specified String
795 * at specified position in this array.
796 *
797 * @return This array node, to allow chaining
798 */
799 public ArrayNode insert(int index, boolean v) {
800 return _insert(index, booleanNode(v));
801 }
802
803 /**
804 * Alternative method that we need to avoid bumping into NPE issues
805 * with auto-unboxing.
806 *
807 * @return This array node, to allow chaining
808 */
809 public ArrayNode insert(int index, Boolean value) {
810 if (value == null) {
811 return insertNull(index);
812 }
813 return _insert(index, booleanNode(value.booleanValue()));
814 }
815
816 /**
817 * Method that will insert specified binary value
818 * at specified position in this array
819 * (note: when written as JSON, will be Base64 encoded)
820 *
821 * @return This array node, to allow chaining
822 */
823 public ArrayNode insert(int index, byte[] v) {
824 if (v == null) {
825 return insertNull(index);
826 }
827 return _insert(index, binaryNode(v));
828 }
829
830 /*
831 /**********************************************************
832 /* Standard methods
833 /**********************************************************
834 */
835
836 @Override
837 public boolean equals(Object o)
838 {
839 if (o == this) return true;
840 if (o == null) return false;
841 if (o instanceof ArrayNode) {
842 return _children.equals(((ArrayNode) o)._children);
843 }
844 return false;
845 }
846
847 /**
848 * @since 2.3
849 */
850 protected boolean _childrenEqual(ArrayNode other) {
851 return _children.equals(other._children);
852 }
853
854 @Override
855 public int hashCode() {
856 return _children.hashCode();
857 }
858
859 /*
860 /**********************************************************
861 /* Internal methods (overridable)
862 /**********************************************************
863 */
864
865 protected ArrayNode _add(JsonNode node) {
866 _children.add(node);
867 return this;
868 }
869
870 protected ArrayNode _insert(int index, JsonNode node)
871 {
872 if (index < 0) {
873 _children.add(0, node);
874 } else if (index >= _children.size()) {
875 _children.add(node);
876 } else {
877 _children.add(index, node);
878 }
879 return this;
880 }
881 }
882