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