package com.fasterxml.jackson.databind.node;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.util.RawValue;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

Node that maps to JSON Object structures in JSON content.

Note: class was final temporarily for Jackson 2.2.

/** * Node that maps to JSON Object structures in JSON content. *<p> * Note: class was <code>final</code> temporarily for Jackson 2.2. */
public class ObjectNode extends ContainerNode<ObjectNode> { // Note: LinkedHashMap for backwards compatibility protected final Map<String, JsonNode> _children; public ObjectNode(JsonNodeFactory nc) { super(nc); _children = new LinkedHashMap<String, JsonNode>(); }
Since:2.4
/** * @since 2.4 */
public ObjectNode(JsonNodeFactory nc, Map<String, JsonNode> kids) { super(nc); _children = kids; } @Override protected JsonNode _at(JsonPointer ptr) { return get(ptr.getMatchingProperty()); } /* Question: should this delegate to `JsonNodeFactory`? It does not absolutely * have to, as long as sub-types override the method but... */ // note: co-variant for type safety @SuppressWarnings("unchecked") @Override public ObjectNode deepCopy() { ObjectNode ret = new ObjectNode(_nodeFactory); for (Map.Entry<String, JsonNode> entry: _children.entrySet()) ret._children.put(entry.getKey(), entry.getValue().deepCopy()); return ret; } /* /********************************************************** /* Overrides for JsonSerializable.Base /********************************************************** */ @Override public boolean isEmpty(SerializerProvider serializers) { return _children.isEmpty(); } /* /********************************************************** /* Implementation of core JsonNode API /********************************************************** */ @Override public JsonNodeType getNodeType() { return JsonNodeType.OBJECT; } @Override public final boolean isObject() { return true; } @Override public JsonToken asToken() { return JsonToken.START_OBJECT; } @Override public int size() { return _children.size(); } @Override public Iterator<JsonNode> elements() { return _children.values().iterator(); } @Override public JsonNode get(int index) { return null; } @Override public JsonNode get(String fieldName) { return _children.get(fieldName); } @Override public Iterator<String> fieldNames() { return _children.keySet().iterator(); } @Override public JsonNode path(int index) { return MissingNode.getInstance(); } @Override public JsonNode path(String fieldName) { JsonNode n = _children.get(fieldName); if (n != null) { return n; } return MissingNode.getInstance(); }
Method to use for accessing all fields (with both names and values) of this JSON Object.
/** * Method to use for accessing all fields (with both names * and values) of this JSON Object. */
@Override public Iterator<Map.Entry<String, JsonNode>> fields() { return _children.entrySet().iterator(); } @Override public ObjectNode with(String propertyName) { JsonNode n = _children.get(propertyName); if (n != null) { if (n instanceof ObjectNode) { return (ObjectNode) n; } throw new UnsupportedOperationException("Property '" + propertyName + "' has value that is not of type ObjectNode (but " + n .getClass().getName() + ")"); } ObjectNode result = objectNode(); _children.put(propertyName, result); return result; } @Override public ArrayNode withArray(String propertyName) { JsonNode n = _children.get(propertyName); if (n != null) { if (n instanceof ArrayNode) { return (ArrayNode) n; } throw new UnsupportedOperationException("Property '" + propertyName + "' has value that is not of type ArrayNode (but " + n .getClass().getName() + ")"); } ArrayNode result = arrayNode(); _children.put(propertyName, result); return result; } @Override public boolean equals(Comparator<JsonNode> comparator, JsonNode o) { if (!(o instanceof ObjectNode)) { return false; } ObjectNode other = (ObjectNode) o; Map<String, JsonNode> m1 = _children; Map<String, JsonNode> m2 = other._children; final int len = m1.size(); if (m2.size() != len) { return false; } for (Map.Entry<String, JsonNode> entry : m1.entrySet()) { JsonNode v2 = m2.get(entry.getKey()); if ((v2 == null) || !entry.getValue().equals(comparator, v2)) { return false; } } return true; } /* /********************************************************** /* Public API, finding value nodes /********************************************************** */ @Override public JsonNode findValue(String fieldName) { for (Map.Entry<String, JsonNode> entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { return entry.getValue(); } JsonNode value = entry.getValue().findValue(fieldName); if (value != null) { return value; } } return null; } @Override public List<JsonNode> findValues(String fieldName, List<JsonNode> foundSoFar) { for (Map.Entry<String, JsonNode> entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { if (foundSoFar == null) { foundSoFar = new ArrayList<JsonNode>(); } foundSoFar.add(entry.getValue()); } else { // only add children if parent not added foundSoFar = entry.getValue().findValues(fieldName, foundSoFar); } } return foundSoFar; } @Override public List<String> findValuesAsText(String fieldName, List<String> foundSoFar) { for (Map.Entry<String, JsonNode> entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { if (foundSoFar == null) { foundSoFar = new ArrayList<String>(); } foundSoFar.add(entry.getValue().asText()); } else { // only add children if parent not added foundSoFar = entry.getValue().findValuesAsText(fieldName, foundSoFar); } } return foundSoFar; } @Override public ObjectNode findParent(String fieldName) { for (Map.Entry<String, JsonNode> entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { return this; } JsonNode value = entry.getValue().findParent(fieldName); if (value != null) { return (ObjectNode) value; } } return null; } @Override public List<JsonNode> findParents(String fieldName, List<JsonNode> foundSoFar) { for (Map.Entry<String, JsonNode> entry : _children.entrySet()) { if (fieldName.equals(entry.getKey())) { if (foundSoFar == null) { foundSoFar = new ArrayList<JsonNode>(); } foundSoFar.add(this); } else { // only add children if parent not added foundSoFar = entry.getValue() .findParents(fieldName, foundSoFar); } } return foundSoFar; } /* /********************************************************** /* Public API, serialization /********************************************************** */
Method that can be called to serialize this node and all of its descendants using specified JSON generator.
/** * Method that can be called to serialize this node and * all of its descendants using specified JSON generator. */
@Override public void serialize(JsonGenerator g, SerializerProvider provider) throws IOException { @SuppressWarnings("deprecation") boolean trimEmptyArray = (provider != null) && !provider.isEnabled(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS); g.writeStartObject(this); for (Map.Entry<String, JsonNode> en : _children.entrySet()) { /* 17-Feb-2009, tatu: Can we trust that all nodes will always * extend BaseJsonNode? Or if not, at least implement * JsonSerializable? Let's start with former, change if * we must. */ BaseJsonNode value = (BaseJsonNode) en.getValue(); // as per [databind#867], see if WRITE_EMPTY_JSON_ARRAYS feature is disabled, // if the feature is disabled, then should not write an empty array // to the output, so continue to the next element in the iteration if (trimEmptyArray && value.isArray() && value.isEmpty(provider)) { continue; } g.writeFieldName(en.getKey()); value.serialize(g, provider); } g.writeEndObject(); } @Override public void serializeWithType(JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer) throws IOException { @SuppressWarnings("deprecation") boolean trimEmptyArray = (provider != null) && !provider.isEnabled(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS); WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, typeSer.typeId(this, JsonToken.START_OBJECT)); for (Map.Entry<String, JsonNode> en : _children.entrySet()) { BaseJsonNode value = (BaseJsonNode) en.getValue(); // check if WRITE_EMPTY_JSON_ARRAYS feature is disabled, // if the feature is disabled, then should not write an empty array // to the output, so continue to the next element in the iteration if (trimEmptyArray && value.isArray() && value.isEmpty(provider)) { continue; } g.writeFieldName(en.getKey()); value.serialize(g, provider); } typeSer.writeTypeSuffix(g, typeIdDef); } /* /********************************************************** /* Extended ObjectNode API, mutators, since 2.1 /********************************************************** */
Method that will set specified field, replacing old value, if any. Note that this is identical to replace(String, JsonNode), except for return value.

NOTE: added to replace those uses of put(String, JsonNode) where chaining with 'this' is desired.

Params:
  • value – to set field to; if null, will be converted to a NullNode first (to remove field entry, call remove instead)
Returns:This node after adding/replacing property value (to allow chaining)
Since:2.1
/** * Method that will set specified field, replacing old value, if any. * Note that this is identical to {@link #replace(String, JsonNode)}, * except for return value. *<p> * NOTE: added to replace those uses of {@link #put(String, JsonNode)} * where chaining with 'this' is desired. * * @param value to set field to; if null, will be converted * to a {@link NullNode} first (to remove field entry, call * {@link #remove} instead) * * @return This node after adding/replacing property value (to allow chaining) * * @since 2.1 */
public JsonNode set(String fieldName, JsonNode value) { if (value == null) { value = nullNode(); } _children.put(fieldName, value); return this; }
Method for adding given properties to this object node, overriding any existing values for those properties.
Params:
  • properties – Properties to add
Returns:This node after adding/replacing property values (to allow chaining)
Since:2.1
/** * Method for adding given properties to this object node, overriding * any existing values for those properties. * * @param properties Properties to add * * @return This node after adding/replacing property values (to allow chaining) * * @since 2.1 */
public JsonNode setAll(Map<String,? extends JsonNode> properties) { for (Map.Entry<String,? extends JsonNode> en : properties.entrySet()) { JsonNode n = en.getValue(); if (n == null) { n = nullNode(); } _children.put(en.getKey(), n); } return this; }
Method for adding all properties of the given Object, overriding any existing values for those properties.
Params:
  • other – Object of which properties to add to this object
Returns:This node after addition (to allow chaining)
Since:2.1
/** * Method for adding all properties of the given Object, overriding * any existing values for those properties. * * @param other Object of which properties to add to this object * * @return This node after addition (to allow chaining) * * @since 2.1 */
public JsonNode setAll(ObjectNode other) { _children.putAll(other._children); return this; }
Method for replacing value of specific property with passed value, and returning value (or null if none).
Params:
  • fieldName – Property of which value to replace
  • value – Value to set property to, replacing old value if any
Returns:Old value of the property; null if there was no such property with value
Since:2.1
/** * Method for replacing value of specific property with passed * value, and returning value (or null if none). * * @param fieldName Property of which value to replace * @param value Value to set property to, replacing old value if any * * @return Old value of the property; null if there was no such property * with value * * @since 2.1 */
public JsonNode replace(String fieldName, JsonNode value) { if (value == null) { // let's not store 'raw' nulls but nodes value = nullNode(); } return _children.put(fieldName, value); }
Method for removing field entry from this ObjectNode, and returning instance after removal.
Returns:This node after removing entry (if any)
Since:2.1
/** * Method for removing field entry from this ObjectNode, and * returning instance after removal. * * @return This node after removing entry (if any) * * @since 2.1 */
public JsonNode without(String fieldName) { _children.remove(fieldName); return this; }
Method for removing specified field properties out of this ObjectNode.
Params:
  • fieldNames – Names of fields to remove
Returns:This node after removing entries
Since:2.1
/** * Method for removing specified field properties out of * this ObjectNode. * * @param fieldNames Names of fields to remove * * @return This node after removing entries * * @since 2.1 */
public ObjectNode without(Collection<String> fieldNames) { _children.keySet().removeAll(fieldNames); return this; } /* /********************************************************** /* Extended ObjectNode API, mutators, generic /********************************************************** */
Method that will set specified field, replacing old value, if any.
Params:
  • value – to set field to; if null, will be converted to a NullNode first (to remove field entry, call remove instead)
Returns:Old value of the field, if any; null if there was no old value.
Deprecated:Since 2.4 use either set(String, JsonNode) or replace(String, JsonNode),
/** * Method that will set specified field, replacing old value, if any. * * @param value to set field to; if null, will be converted * to a {@link NullNode} first (to remove field entry, call * {@link #remove} instead) * * @return Old value of the field, if any; null if there was no * old value. * * @deprecated Since 2.4 use either {@link #set(String,JsonNode)} or {@link #replace(String,JsonNode)}, */
@Deprecated public JsonNode put(String fieldName, JsonNode value) { if (value == null) { // let's not store 'raw' nulls but nodes value = nullNode(); } return _children.put(fieldName, value); }
Method for removing field entry from this ObjectNode. Will return value of the field, if such field existed; null if not.
Returns:Value of specified field, if it existed; null if not
/** * Method for removing field entry from this ObjectNode. * Will return value of the field, if such field existed; * null if not. * * @return Value of specified field, if it existed; null if not */
public JsonNode remove(String fieldName) { return _children.remove(fieldName); }
Method for removing specified field properties out of this ObjectNode.
Params:
  • fieldNames – Names of fields to remove
Returns:This node after removing entries
/** * Method for removing specified field properties out of * this ObjectNode. * * @param fieldNames Names of fields to remove * * @return This node after removing entries */
public ObjectNode remove(Collection<String> fieldNames) { _children.keySet().removeAll(fieldNames); return this; }
Method for removing all field properties, such that this ObjectNode will contain no properties after call.
Returns:This node after removing all entries
/** * Method for removing all field properties, such that this * ObjectNode will contain no properties after call. * * @return This node after removing all entries */
@Override public ObjectNode removeAll() { _children.clear(); return this; }
Method for adding given properties to this object node, overriding any existing values for those properties.
Params:
  • properties – Properties to add
Returns:This node after adding/replacing property values (to allow chaining)
Deprecated:Since 2.4 use setAll(Map<String,? extends JsonNode>),
/** * Method for adding given properties to this object node, overriding * any existing values for those properties. * * @param properties Properties to add * * @return This node after adding/replacing property values (to allow chaining) * * @deprecated Since 2.4 use {@link #setAll(Map)}, */
@Deprecated public JsonNode putAll(Map<String,? extends JsonNode> properties) { return setAll(properties); }
Method for adding all properties of the given Object, overriding any existing values for those properties.
Params:
  • other – Object of which properties to add to this object
Returns:This node (to allow chaining)
Deprecated:Since 2.4 use setAll(ObjectNode),
/** * Method for adding all properties of the given Object, overriding * any existing values for those properties. * * @param other Object of which properties to add to this object * * @return This node (to allow chaining) * * @deprecated Since 2.4 use {@link #setAll(ObjectNode)}, */
@Deprecated public JsonNode putAll(ObjectNode other) { return setAll(other); }
Method for removing all field properties out of this ObjectNode except for ones specified in argument.
Params:
  • fieldNames – Fields to retain in this ObjectNode
Returns:This node (to allow call chaining)
/** * Method for removing all field properties out of this ObjectNode * <b>except</b> for ones specified in argument. * * @param fieldNames Fields to <b>retain</b> in this ObjectNode * * @return This node (to allow call chaining) */
public ObjectNode retain(Collection<String> fieldNames) { _children.keySet().retainAll(fieldNames); return this; }
Method for removing all field properties out of this ObjectNode except for ones specified in argument.
Params:
  • fieldNames – Fields to retain in this ObjectNode
Returns:This node (to allow call chaining)
/** * Method for removing all field properties out of this ObjectNode * <b>except</b> for ones specified in argument. * * @param fieldNames Fields to <b>retain</b> in this ObjectNode * * @return This node (to allow call chaining) */
public ObjectNode retain(String... fieldNames) { return retain(Arrays.asList(fieldNames)); } /* /********************************************************** /* Extended ObjectNode API, mutators, typed /********************************************************** */
Method that will construct an ArrayNode and add it as a field of this ObjectNode, replacing old value, if any.

NOTE: Unlike all put(...) methods, return value is NOT this ObjectNode, but the newly created ArrayNode instance.

Returns:Newly constructed ArrayNode (NOT the old value, which could be of any type)
/** * Method that will construct an ArrayNode and add it as a * field of this ObjectNode, replacing old value, if any. *<p> * <b>NOTE</b>: Unlike all <b>put(...)</b> methods, return value * is <b>NOT</b> this <code>ObjectNode</code>, but the * <b>newly created</b> <code>ArrayNode</code> instance. * * @return Newly constructed ArrayNode (NOT the old value, * which could be of any type) */
public ArrayNode putArray(String fieldName) { ArrayNode n = arrayNode(); _put(fieldName, n); return n; }
Method that will construct an ObjectNode and add it as a field of this ObjectNode, replacing old value, if any.

NOTE: Unlike all put(...) methods, return value is NOT this ObjectNode, but the newly created ObjectNode instance.

Returns:Newly constructed ObjectNode (NOT the old value, which could be of any type)
/** * Method that will construct an ObjectNode and add it as a * field of this ObjectNode, replacing old value, if any. *<p> * <b>NOTE</b>: Unlike all <b>put(...)</b> methods, return value * is <b>NOT</b> this <code>ObjectNode</code>, but the * <b>newly created</b> <code>ObjectNode</code> instance. * * @return Newly constructed ObjectNode (NOT the old value, * which could be of any type) */
public ObjectNode putObject(String fieldName) { ObjectNode n = objectNode(); _put(fieldName, n); return n; }
Returns:This node (to allow chaining)
/** * @return This node (to allow chaining) */
public ObjectNode putPOJO(String fieldName, Object pojo) { return _put(fieldName, pojoNode(pojo)); }
Since:2.6
/** * @since 2.6 */
public ObjectNode putRawValue(String fieldName, RawValue raw) { return _put(fieldName, rawValueNode(raw)); }
Returns:This node (to allow chaining)
/** * @return This node (to allow chaining) */
public ObjectNode putNull(String fieldName) { _children.put(fieldName, nullNode()); return this; }
Method for setting value of a field to specified numeric value.
Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified numeric value. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, short v) { return _put(fieldName, numberNode(v)); }
Alternative method that we need to avoid bumping into NPE issues with auto-unboxing.
Returns:This node (to allow chaining)
/** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, Short v) { return _put(fieldName, (v == null) ? nullNode() : numberNode(v.shortValue())); }
Method for setting value of a field to specified numeric value. The underlying JsonNode that will be added is constructed using JsonNodeFactory.numberNode(int), and may be "smaller" (like ShortNode) in cases where value fits within range of a smaller integral numeric value.
Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified numeric value. * The underlying {@link JsonNode} that will be added is constructed * using {@link JsonNodeFactory#numberNode(int)}, and may be * "smaller" (like {@link ShortNode}) in cases where value fits within * range of a smaller integral numeric value. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, int v) { return _put(fieldName, numberNode(v)); }
Alternative method that we need to avoid bumping into NPE issues with auto-unboxing.
Returns:This node (to allow chaining)
/** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, Integer v) { return _put(fieldName, (v == null) ? nullNode() : numberNode(v.intValue())); }
Method for setting value of a field to specified numeric value. The underlying JsonNode that will be added is constructed using JsonNodeFactory.numberNode(long), and may be "smaller" (like IntNode) in cases where value fits within range of a smaller integral numeric value.
Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified numeric value. * The underlying {@link JsonNode} that will be added is constructed * using {@link JsonNodeFactory#numberNode(long)}, and may be * "smaller" (like {@link IntNode}) in cases where value fits within * range of a smaller integral numeric value. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, long v) { return _put(fieldName, numberNode(v)); }
Method for setting value of a field to specified numeric value. The underlying JsonNode that will be added is constructed using JsonNodeFactory.numberNode(Long), and may be "smaller" (like IntNode) in cases where value fits within range of a smaller integral numeric value.

Note that this is alternative to put(String, long) needed to avoid bumping into NPE issues with auto-unboxing.

Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified numeric value. * The underlying {@link JsonNode} that will be added is constructed * using {@link JsonNodeFactory#numberNode(Long)}, and may be * "smaller" (like {@link IntNode}) in cases where value fits within * range of a smaller integral numeric value. * <p> * Note that this is alternative to {@link #put(String, long)} needed to avoid * bumping into NPE issues with auto-unboxing. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, Long v) { return _put(fieldName, (v == null) ? nullNode() : numberNode(v.longValue())); }
Method for setting value of a field to specified numeric value.
Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified numeric value. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, float v) { return _put(fieldName, numberNode(v)); }
Alternative method that we need to avoid bumping into NPE issues with auto-unboxing.
Returns:This node (to allow chaining)
/** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, Float v) { return _put(fieldName, (v == null) ? nullNode() : numberNode(v.floatValue())); }
Method for setting value of a field to specified numeric value.
Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified numeric value. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, double v) { return _put(fieldName, numberNode(v)); }
Alternative method that we need to avoid bumping into NPE issues with auto-unboxing.
Returns:This node (to allow chaining)
/** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, Double v) { return _put(fieldName, (v == null) ? nullNode() : numberNode(v.doubleValue())); }
Method for setting value of a field to specified numeric value.
Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified numeric value. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, BigDecimal v) { return _put(fieldName, (v == null) ? nullNode() : numberNode(v)); }
Method for setting value of a field to specified numeric value.
Returns:This node (to allow chaining)
Since:2.9
/** * Method for setting value of a field to specified numeric value. * * @return This node (to allow chaining) * * @since 2.9 */
public ObjectNode put(String fieldName, BigInteger v) { return _put(fieldName, (v == null) ? nullNode() : numberNode(v)); }
Method for setting value of a field to specified String value.
Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified String value. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, String v) { return _put(fieldName, (v == null) ? nullNode() : textNode(v)); }
Method for setting value of a field to specified String value.
Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified String value. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, boolean v) { return _put(fieldName, booleanNode(v)); }
Alternative method that we need to avoid bumping into NPE issues with auto-unboxing.
Returns:This node (to allow chaining)
/** * Alternative method that we need to avoid bumping into NPE issues * with auto-unboxing. * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, Boolean v) { return _put(fieldName, (v == null) ? nullNode() : booleanNode(v.booleanValue())); }
Method for setting value of a field to specified binary value
Returns:This node (to allow chaining)
/** * Method for setting value of a field to specified binary value * * @return This node (to allow chaining) */
public ObjectNode put(String fieldName, byte[] v) { return _put(fieldName, (v == null) ? nullNode() : binaryNode(v)); } /* /********************************************************** /* Standard methods /********************************************************** */ @Override public boolean equals(Object o) { if (o == this) return true; if (o == null) return false; if (o instanceof ObjectNode) { return _childrenEqual((ObjectNode) o); } return false; }
Since:2.3
/** * @since 2.3 */
protected boolean _childrenEqual(ObjectNode other) { return _children.equals(other._children); } @Override public int hashCode() { return _children.hashCode(); } @Override public String toString() { StringBuilder sb = new StringBuilder(32 + (size() << 4)); sb.append("{"); int count = 0; for (Map.Entry<String, JsonNode> en : _children.entrySet()) { if (count > 0) { sb.append(","); } ++count; TextNode.appendQuoted(sb, en.getKey()); sb.append(':'); sb.append(en.getValue().toString()); } sb.append("}"); return sb.toString(); } /* /********************************************************** /* Internal methods (overridable) /********************************************************** */ protected ObjectNode _put(String fieldName, JsonNode value) { _children.put(fieldName, value); return this; } }