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 
ArrayNode(JsonNodeFactory nf)32     public ArrayNode(JsonNodeFactory nf) {
33         super(nf);
34         _children = new ArrayList<JsonNode>();
35     }
36 
37     /**
38      * @since 2.8
39      */
ArrayNode(JsonNodeFactory nf, int capacity)40     public ArrayNode(JsonNodeFactory nf, int capacity) {
41         super(nf);
42         _children = new ArrayList<JsonNode>(capacity);
43     }
44 
45     /**
46      * @since 2.7
47      */
ArrayNode(JsonNodeFactory nf, List<JsonNode> children)48     public ArrayNode(JsonNodeFactory nf, List<JsonNode> children) {
49         super(nf);
50         _children = children;
51     }
52 
53     @Override
_at(JsonPointer ptr)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
deepCopy()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
isEmpty(SerializerProvider serializers)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
getNodeType()89     public JsonNodeType getNodeType() {
90         return JsonNodeType.ARRAY;
91     }
92 
93     @Override
isArray()94     public boolean isArray() {
95         return true;
96     }
97 
asToken()98     @Override public JsonToken asToken() { return JsonToken.START_ARRAY; }
99 
100     @Override
size()101     public int size() {
102         return _children.size();
103     }
104 
105     @Override // since 2.10
isEmpty()106     public boolean isEmpty() { return _children.isEmpty(); }
107 
108     @Override
elements()109     public Iterator<JsonNode> elements() {
110         return _children.iterator();
111     }
112 
113     @Override
get(int index)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
get(String fieldName)122     public JsonNode get(String fieldName) { return null; }
123 
124     @Override
path(String fieldName)125     public JsonNode path(String fieldName) { return MissingNode.getInstance(); }
126 
127     @Override
path(int index)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
required(int index)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
equals(Comparator<JsonNode> comparator, JsonNode o)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
serialize(JsonGenerator f, SerializerProvider provider)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
serializeWithType(JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer)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
findValue(String fieldName)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
findValues(String fieldName, List<JsonNode> foundSoFar)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
findValuesAsText(String fieldName, List<String> foundSoFar)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
findParent(String fieldName)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
findParents(String fieldName, List<JsonNode> foundSoFar)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      */
set(int index, JsonNode value)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      */
add(JsonNode value)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      */
addAll(ArrayNode other)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      */
addAll(Collection<? extends JsonNode> nodes)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      */
insert(int index, JsonNode value)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      */
remove(int index)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
removeAll()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      */
addArray()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      */
addObject()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      */
addPOJO(Object value)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      */
addRawValue(RawValue raw)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      */
addNull()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      */
add(int v)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      */
add(Integer value)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      */
add(long v)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      */
add(Long value)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      */
add(float v)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      */
add(Float value)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      */
add(double v)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      */
add(Double value)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      */
add(BigDecimal v)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      */
add(BigInteger v)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      */
add(String v)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      */
add(boolean v)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      */
add(Boolean value)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      */
add(byte[] v)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      */
insertArray(int index)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      */
insertObject(int index)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      */
insertPOJO(int index, Object value)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      */
insertNull(int index)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      */
insert(int index, int v)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      */
insert(int index, Integer value)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      */
insert(int index, long v)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      */
insert(int index, Long value)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      */
insert(int index, float v)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      */
insert(int index, Float value)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      */
insert(int index, double v)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      */
insert(int index, Double value)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      */
insert(int index, BigDecimal v)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      */
insert(int index, BigInteger v)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      */
insert(int index, String v)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      */
insert(int index, boolean v)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      */
insert(int index, Boolean value)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      */
insert(int index, byte[] v)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
equals(Object o)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      */
_childrenEqual(ArrayNode other)850     protected boolean _childrenEqual(ArrayNode other) {
851         return _children.equals(other._children);
852     }
853 
854     @Override
hashCode()855     public int hashCode() {
856         return _children.hashCode();
857     }
858 
859     /*
860     /**********************************************************
861     /* Internal methods (overridable)
862     /**********************************************************
863      */
864 
_add(JsonNode node)865     protected ArrayNode _add(JsonNode node) {
866         _children.add(node);
867         return this;
868     }
869 
_insert(int index, JsonNode node)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