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