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
28 public ObjectNode(JsonNodeFactory nc) {
29 super(nc);
30 _children = new LinkedHashMap<String, JsonNode>();
31 }
32
33 /**
34 * @since 2.4
35 */
36 public ObjectNode(JsonNodeFactory nc, Map<String, JsonNode> kids) {
37 super(nc);
38 _children = kids;
39 }
40
41 @Override
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
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
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
80 public JsonNodeType getNodeType() {
81 return JsonNodeType.OBJECT;
82 }
83
84 @Override
85 public final boolean isObject() {
86 return true;
87 }
88
89 @Override public JsonToken asToken() { return JsonToken.START_OBJECT; }
90
91 @Override
92 public int size() {
93 return _children.size();
94 }
95
96 @Override // since 2.10
97 public boolean isEmpty() { return _children.isEmpty(); }
98
99 @Override
100 public Iterator<JsonNode> elements() {
101 return _children.values().iterator();
102 }
103
104 @Override
105 public JsonNode get(int index) { return null; }
106
107 @Override
108 public JsonNode get(String fieldName) {
109 return _children.get(fieldName);
110 }
111
112 @Override
113 public Iterator<String> fieldNames() {
114 return _children.keySet().iterator();
115 }
116
117 @Override
118 public JsonNode path(int index) {
119 return MissingNode.getInstance();
120 }
121
122 @Override
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
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
146 public Iterator<Map.Entry<String, JsonNode>> fields() {
147 return _children.entrySet().iterator();
148 }
149
150 @SuppressWarnings("unchecked")
151 @Override
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
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
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
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
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
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
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
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
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
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")
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")
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")
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 */
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")
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")
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
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 */
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 */
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
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
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
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 */
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 */
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 */
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 */
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 */
660 public ObjectNode putPOJO(String fieldName, Object pojo) {
661 return _put(fieldName, pojoNode(pojo));
662 }
663
664 /**
665 * @since 2.6
666 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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
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 */
876 protected boolean _childrenEqual(ObjectNode other)
877 {
878 return _children.equals(other._children);
879 }
880
881 @Override
882 public int hashCode()
883 {
884 return _children.hashCode();
885 }
886
887 /*
888 /**********************************************************
889 /* Internal methods (overridable)
890 /**********************************************************
891 */
892
893 protected ObjectNode _put(String fieldName, JsonNode value)
894 {
895 _children.put(fieldName, value);
896 return this;
897 }
898 }
899